]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit 'e18101137866b79045fee0ef996e696e68c920b4' into clippyup
authorflip1995 <philipp.krones@embecosm.com>
Thu, 4 Nov 2021 12:52:36 +0000 (12:52 +0000)
committerflip1995 <philipp.krones@embecosm.com>
Thu, 4 Nov 2021 12:52:36 +0000 (12:52 +0000)
217 files changed:
1  2 
src/tools/clippy/.cargo/config.toml
src/tools/clippy/.github/deploy.sh
src/tools/clippy/CHANGELOG.md
src/tools/clippy/CONTRIBUTING.md
src/tools/clippy/Cargo.toml
src/tools/clippy/clippy_dev/src/new_lint.rs
src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
src/tools/clippy/clippy_lints/src/casts/mod.rs
src/tools/clippy/clippy_lints/src/deprecated_lints.rs
src/tools/clippy/clippy_lints/src/dereference.rs
src/tools/clippy/clippy_lints/src/doc.rs
src/tools/clippy/clippy_lints/src/entry.rs
src/tools/clippy/clippy_lints/src/enum_variants.rs
src/tools/clippy/clippy_lints/src/eta_reduction.rs
src/tools/clippy/clippy_lints/src/format.rs
src/tools/clippy/clippy_lints/src/if_not_else.rs
src/tools/clippy/clippy_lints/src/int_plus_one.rs
src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
src/tools/clippy/clippy_lints/src/lib.register_all.rs
src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
src/tools/clippy/clippy_lints/src/lib.register_lints.rs
src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
src/tools/clippy/clippy_lints/src/lib.register_style.rs
src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/lifetimes.rs
src/tools/clippy/clippy_lints/src/loops/utils.rs
src/tools/clippy/clippy_lints/src/manual_assert.rs
src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs
src/tools/clippy/clippy_lints/src/matches.rs
src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
src/tools/clippy/clippy_lints/src/misc_early/double_neg.rs
src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
src/tools/clippy/clippy_lints/src/misc_early/mod.rs
src/tools/clippy/clippy_lints/src/module_style.rs
src/tools/clippy/clippy_lints/src/needless_borrow.rs
src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
src/tools/clippy/clippy_lints/src/option_if_let_else.rs
src/tools/clippy/clippy_lints/src/ptr.rs
src/tools/clippy/clippy_lints/src/question_mark.rs
src/tools/clippy/clippy_lints/src/strings.rs
src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
src/tools/clippy/clippy_lints/src/unicode.rs
src/tools/clippy/clippy_lints/src/unit_hash.rs
src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
src/tools/clippy/clippy_utils/src/consts.rs
src/tools/clippy/clippy_utils/src/diagnostics.rs
src/tools/clippy/clippy_utils/src/higher.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/str_utils.rs
src/tools/clippy/doc/adding_lints.md
src/tools/clippy/rust-toolchain
src/tools/clippy/tests/compile-test.rs
src/tools/clippy/tests/missing-test-files.rs
src/tools/clippy/tests/ui-toml/functions_maxlines/test.rs
src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr
src/tools/clippy/tests/ui/assertions_on_constants.rs
src/tools/clippy/tests/ui/assertions_on_constants.stderr
src/tools/clippy/tests/ui/async_yields_async.fixed
src/tools/clippy/tests/ui/async_yields_async.rs
src/tools/clippy/tests/ui/async_yields_async.stderr
src/tools/clippy/tests/ui/await_holding_lock.rs
src/tools/clippy/tests/ui/await_holding_lock.stderr
src/tools/clippy/tests/ui/await_holding_refcell_ref.rs
src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr
src/tools/clippy/tests/ui/cast.rs
src/tools/clippy/tests/ui/cast.stderr
src/tools/clippy/tests/ui/crashes/auxiliary/ice-7868-aux.rs
src/tools/clippy/tests/ui/crashes/ice-3969.rs
src/tools/clippy/tests/ui/crashes/ice-3969.stderr
src/tools/clippy/tests/ui/crashes/ice-5207.rs
src/tools/clippy/tests/ui/crashes/ice-6252.rs
src/tools/clippy/tests/ui/crashes/ice-6252.stderr
src/tools/clippy/tests/ui/crashes/ice-7231.rs
src/tools/clippy/tests/ui/crashes/ice-7868.rs
src/tools/clippy/tests/ui/crashes/ice-7868.stderr
src/tools/clippy/tests/ui/crashes/ice-7869.rs
src/tools/clippy/tests/ui/crashes/ice-7869.stderr
src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs
src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs
src/tools/clippy/tests/ui/deprecated.rs
src/tools/clippy/tests/ui/deprecated.stderr
src/tools/clippy/tests/ui/diverging_sub_expression.rs
src/tools/clippy/tests/ui/diverging_sub_expression.stderr
src/tools/clippy/tests/ui/doc/doc-fixable.fixed
src/tools/clippy/tests/ui/doc/doc-fixable.rs
src/tools/clippy/tests/ui/doc/doc-fixable.stderr
src/tools/clippy/tests/ui/doc/issue_1832.rs
src/tools/clippy/tests/ui/doc/issue_902.rs
src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
src/tools/clippy/tests/ui/doc_errors.rs
src/tools/clippy/tests/ui/doc_errors.stderr
src/tools/clippy/tests/ui/doc_unsafe.rs
src/tools/clippy/tests/ui/enum_variants.stderr
src/tools/clippy/tests/ui/eval_order_dependence.rs
src/tools/clippy/tests/ui/eval_order_dependence.stderr
src/tools/clippy/tests/ui/fallible_impl_from.rs
src/tools/clippy/tests/ui/fallible_impl_from.stderr
src/tools/clippy/tests/ui/format.fixed
src/tools/clippy/tests/ui/format.rs
src/tools/clippy/tests/ui/format.stderr
src/tools/clippy/tests/ui/format_args.fixed
src/tools/clippy/tests/ui/format_args.rs
src/tools/clippy/tests/ui/format_args.stderr
src/tools/clippy/tests/ui/format_args_unfixable.rs
src/tools/clippy/tests/ui/future_not_send.rs
src/tools/clippy/tests/ui/future_not_send.stderr
src/tools/clippy/tests/ui/if_not_else.rs
src/tools/clippy/tests/ui/if_not_else.stderr
src/tools/clippy/tests/ui/implicit_hasher.rs
src/tools/clippy/tests/ui/implicit_hasher.stderr
src/tools/clippy/tests/ui/implicit_return.fixed
src/tools/clippy/tests/ui/implicit_return.rs
src/tools/clippy/tests/ui/implicit_return.stderr
src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed
src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs
src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr
src/tools/clippy/tests/ui/issue-7447.stderr
src/tools/clippy/tests/ui/issue_4266.rs
src/tools/clippy/tests/ui/issue_4266.stderr
src/tools/clippy/tests/ui/len_without_is_empty.rs
src/tools/clippy/tests/ui/len_without_is_empty.stderr
src/tools/clippy/tests/ui/literals.rs
src/tools/clippy/tests/ui/literals.stderr
src/tools/clippy/tests/ui/macro_use_imports.fixed
src/tools/clippy/tests/ui/macro_use_imports.rs
src/tools/clippy/tests/ui/macro_use_imports.stderr
src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
src/tools/clippy/tests/ui/manual_assert.fixed
src/tools/clippy/tests/ui/manual_assert.rs
src/tools/clippy/tests/ui/manual_async_fn.fixed
src/tools/clippy/tests/ui/manual_async_fn.rs
src/tools/clippy/tests/ui/manual_async_fn.stderr
src/tools/clippy/tests/ui/manual_map_option.fixed
src/tools/clippy/tests/ui/manual_map_option.rs
src/tools/clippy/tests/ui/manual_map_option.stderr
src/tools/clippy/tests/ui/match_overlapping_arm.rs
src/tools/clippy/tests/ui/match_ref_pats.rs
src/tools/clippy/tests/ui/match_str_case_mismatch.rs
src/tools/clippy/tests/ui/match_str_case_mismatch.stderr
src/tools/clippy/tests/ui/match_wild_err_arm.edition2018.stderr
src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr
src/tools/clippy/tests/ui/match_wild_err_arm.rs
src/tools/clippy/tests/ui/methods.rs
src/tools/clippy/tests/ui/methods.stderr
src/tools/clippy/tests/ui/missing-doc.rs
src/tools/clippy/tests/ui/missing-doc.stderr
src/tools/clippy/tests/ui/missing_panics_doc.rs
src/tools/clippy/tests/ui/missing_panics_doc.stderr
src/tools/clippy/tests/ui/needless_borrow_pat.rs
src/tools/clippy/tests/ui/needless_borrow_pat.stderr
src/tools/clippy/tests/ui/needless_lifetimes.rs
src/tools/clippy/tests/ui/needless_lifetimes.stderr
src/tools/clippy/tests/ui/needless_return.fixed
src/tools/clippy/tests/ui/needless_return.rs
src/tools/clippy/tests/ui/needless_return.stderr
src/tools/clippy/tests/ui/non_expressive_names.rs
src/tools/clippy/tests/ui/option_if_let_else.fixed
src/tools/clippy/tests/ui/option_if_let_else.rs
src/tools/clippy/tests/ui/option_if_let_else.stderr
src/tools/clippy/tests/ui/panic_in_result_fn.rs
src/tools/clippy/tests/ui/panic_in_result_fn.stderr
src/tools/clippy/tests/ui/ptr_arg.rs
src/tools/clippy/tests/ui/ptr_arg.stderr
src/tools/clippy/tests/ui/question_mark.fixed
src/tools/clippy/tests/ui/question_mark.rs
src/tools/clippy/tests/ui/question_mark.stderr
src/tools/clippy/tests/ui/redundant_clone.fixed
src/tools/clippy/tests/ui/redundant_clone.stderr
src/tools/clippy/tests/ui/ref_binding_to_reference.rs
src/tools/clippy/tests/ui/ref_binding_to_reference.stderr
src/tools/clippy/tests/ui/rename.fixed
src/tools/clippy/tests/ui/rename.rs
src/tools/clippy/tests/ui/rename.stderr
src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs
src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs
src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr
src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs
src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
src/tools/clippy/tests/ui/single_component_path_imports.fixed
src/tools/clippy/tests/ui/single_component_path_imports.rs
src/tools/clippy/tests/ui/single_component_path_imports.stderr
src/tools/clippy/tests/ui/single_component_path_imports_macro.fixed
src/tools/clippy/tests/ui/single_component_path_imports_macro.rs
src/tools/clippy/tests/ui/single_component_path_imports_macro.stderr
src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs
src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr
src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs
src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs
src/tools/clippy/tests/ui/string_slice.rs
src/tools/clippy/tests/ui/string_slice.stderr
src/tools/clippy/tests/ui/unit_hash.rs
src/tools/clippy/tests/ui/unit_hash.stderr
src/tools/clippy/tests/ui/unused_async.rs
src/tools/clippy/tests/ui/unused_async.stderr
src/tools/clippy/tests/ui/use_self.fixed
src/tools/clippy/tests/ui/use_self.rs
src/tools/clippy/tests/ui/use_self.stderr
src/tools/clippy/tests/ui/used_underscore_binding.rs
src/tools/clippy/tests/ui/used_underscore_binding.stderr
src/tools/clippy/tests/ui/wildcard_imports.fixed
src/tools/clippy/tests/ui/wildcard_imports.rs
src/tools/clippy/tests/ui/wildcard_imports.stderr
src/tools/clippy/tests/ui/wrong_self_convention.rs
src/tools/clippy/tests/ui/wrong_self_convention.stderr
src/tools/clippy/tests/ui/wrong_self_convention2.rs
src/tools/clippy/tests/ui/wrong_self_convention2.stderr
src/tools/clippy/tests/ui/wrong_self_conventions_mut.rs
src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr

index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..688473f2f9bfcee25d3d1f7484967cbcd1ec3154
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,10 @@@
++[alias]
++uitest = "test --test compile-test"
++dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
++lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml  -- "
++collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored"
++
++[build]
++# -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests
++rustflags = ["-Zunstable-options", "-Zbinary-dep-depinfo"]
++target-dir = "target"
index a3c57232f557c4b774cb53ecc7e10299db1bd8e6,0000000000000000000000000000000000000000..34225a5402904084617e9f19adaaa762d0aa5336
mode 100644,000000..100644
--- /dev/null
@@@ -1,65 -1,0 +1,66 @@@
-   ln -sf "$TAG_NAME" out/stable
 +#!/bin/bash
 +
 +set -ex
 +
 +echo "Removing the current docs for master"
 +rm -rf out/master/ || exit 0
 +
 +echo "Making the docs for master"
 +mkdir out/master/
 +cp util/gh-pages/index.html out/master
 +cp util/gh-pages/lints.json out/master
 +
 +if [[ -n $TAG_NAME ]]; then
 +  echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it"
 +  cp -Tr out/master "out/$TAG_NAME"
++  rm -f out/stable
++  ln -s "$TAG_NAME" out/stable
 +fi
 +
 +if [[ $BETA = "true" ]]; then
 +  echo "Update documentation for the beta release"
 +  cp -r out/master/* out/beta
 +fi
 +
 +# Generate version index that is shown as root index page
 +cp util/gh-pages/versions.html out/index.html
 +
 +echo "Making the versions.json file"
 +python3 ./util/versions.py out
 +
 +# Now let's go have some fun with the cloned repo
 +cd out
 +git config user.name "GHA CI"
 +git config user.email "gha@ci.invalid"
 +
 +if [[ -n $TAG_NAME ]]; then
 +  # track files, so that the following check works
 +  git add --intent-to-add "$TAG_NAME"
 +  if git diff --exit-code --quiet -- $TAG_NAME/; then
 +    echo "No changes to the output on this push; exiting."
 +    exit 0
 +  fi
 +  # Add the new dir
 +  git add "$TAG_NAME"
 +  # Update the symlink
 +  git add stable
 +  # Update versions file
 +  git add versions.json
 +  git commit -m "Add documentation for ${TAG_NAME} release: ${SHA}"
 +elif [[ $BETA = "true" ]]; then
 +  if git diff --exit-code --quiet -- beta/; then
 +    echo "No changes to the output on this push; exiting."
 +    exit 0
 +  fi
 +  git add beta
 +  git commit -m "Automatic deploy to GitHub Pages (beta): ${SHA}"
 +else
 +  if git diff --exit-code --quiet; then
 +    echo "No changes to the output on this push; exiting."
 +    exit 0
 +  fi
 +  git add .
 +  git commit -m "Automatic deploy to GitHub Pages: ${SHA}"
 +fi
 +
 +git push "$SSH_REPO" "$TARGET_BRANCH"
index 3b4c687209e11dfa8ebb9454ad8c4af571a9677f,0000000000000000000000000000000000000000..85a6a6be8b7f2618d9b515afc201e54f27781e13
mode 100644,000000..100644
--- /dev/null
@@@ -1,3116 -1,0 +1,3266 @@@
- [7bfc26e...master](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...master)
 +# Changelog
 +
 +All notable changes to this project will be documented in this file.
 +See [Changelog Update](doc/changelog_update.md) if you want to update this
 +document.
 +
 +## Unreleased / In Rust Nightly
 +
- Current beta, release 2021-10-21
++[b7f3f7f...master](https://github.com/rust-lang/rust-clippy/compare/b7f3f7f...master)
++
++## Rust 1.57
++
++Current beta, release 2021-12-02
++
++[7bfc26e...b7f3f7f](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...b7f3f7f)
++
++### New Lints
++
++* [`negative_feature_names`]
++  [#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
++* [`redundant_feature_names`]
++  [#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
++* [`mod_module_files`]
++  [#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
++* [`self_named_module_files`]
++  [#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
++* [`manual_split_once`]
++  [#7565](https://github.com/rust-lang/rust-clippy/pull/7565)
++* [`derivable_impls`]
++  [#7570](https://github.com/rust-lang/rust-clippy/pull/7570)
++* [`needless_option_as_deref`]
++  [#7596](https://github.com/rust-lang/rust-clippy/pull/7596)
++* [`iter_not_returning_iterator`]
++  [#7610](https://github.com/rust-lang/rust-clippy/pull/7610)
++* [`same_name_method`]
++  [#7653](https://github.com/rust-lang/rust-clippy/pull/7653)
++* [`manual_assert`] [#7669](https://github.com/rust-lang/rust-clippy/pull/7669)
++* [`non_send_fields_in_send_ty`]
++  [#7709](https://github.com/rust-lang/rust-clippy/pull/7709)
++* [`equatable_if_let`]
++  [#7762](https://github.com/rust-lang/rust-clippy/pull/7762)
++
++### Moves and Deprecations
++
++* Move [`shadow_unrelated`] to `restriction`
++  [#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
++* Move [`option_if_let_else`] to `nursery`
++  [#7568](https://github.com/rust-lang/rust-clippy/pull/7568)
++* Move [`branches_sharing_code`] to `nursery`
++  [#7595](https://github.com/rust-lang/rust-clippy/pull/7595)
++* Rename `if_let_some_result` to [`match_result_ok`] which now also handles
++  `while let` cases [#7608](https://github.com/rust-lang/rust-clippy/pull/7608)
++* Move [`many_single_char_names`] to `pedantic`
++  [#7671](https://github.com/rust-lang/rust-clippy/pull/7671)
++* Move [`float_cmp`] to `pedantic`
++  [#7692](https://github.com/rust-lang/rust-clippy/pull/7692)
++* Rename `box_vec` to [`box_collection`] and lint on more general cases
++  [#7693](https://github.com/rust-lang/rust-clippy/pull/7693)
++* Uplift `invalid_atomic_ordering` to rustc
++  [rust-lang/rust#84039](https://github.com/rust-lang/rust/pull/84039)
++
++### Enhancements
++
++* Rewrite the `shadow*` lints, so that they find a lot more shadows and are not
++  limited to certain patterns
++  [#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
++* The `avoid-breaking-exported-api` configuration now also works for
++  [`box_collection`], [`redundant_allocation`], [`rc_buffer`], [`vec_box`],
++  [`option_option`], [`linkedlist`], [`rc_mutex`]
++  [#7560](https://github.com/rust-lang/rust-clippy/pull/7560)
++* [`unnecessary_unwrap`]: Now also checks for `expect`s
++  [#7584](https://github.com/rust-lang/rust-clippy/pull/7584)
++* [`disallowed_method`]: Allow adding a reason that will be displayed with the
++  lint message
++  [#7621](https://github.com/rust-lang/rust-clippy/pull/7621)
++* [`approx_constant`]: Now checks the MSRV for `LOG10_2` and `LOG2_10`
++  [#7629](https://github.com/rust-lang/rust-clippy/pull/7629)
++* [`approx_constant`]: Add `TAU`
++  [#7642](https://github.com/rust-lang/rust-clippy/pull/7642)
++* [`needless_borrow`]: Now also lints on needless mutable borrows
++  [#7657](https://github.com/rust-lang/rust-clippy/pull/7657)
++* [`missing_safety_doc`]: Now also lints on unsafe traits
++  [#7734](https://github.com/rust-lang/rust-clippy/pull/7734)
++
++### False Positive Fixes
++
++* [`manual_map`]: No longer lints when the option is borrowed in the match and
++  also consumed in the arm
++  [#7531](https://github.com/rust-lang/rust-clippy/pull/7531)
++* [`filter_next`]: No longer lints if `filter` method is not the
++  `Iterator::filter` method
++  [#7562](https://github.com/rust-lang/rust-clippy/pull/7562)
++* [`manual_flatten`]: No longer lints if expression is used after `if let`
++  [#7566](https://github.com/rust-lang/rust-clippy/pull/7566)
++* [`option_if_let_else`]: Multiple fixes
++  [#7573](https://github.com/rust-lang/rust-clippy/pull/7573)
++    * `break` and `continue` statements local to the would-be closure are
++      allowed
++    * Don't lint in const contexts
++    * Don't lint when yield expressions are used
++    * Don't lint when the captures made by the would-be closure conflict with
++      the other branch
++    * Don't lint when a field of a local is used when the type could be
++      potentially moved from
++    * In some cases, don't lint when scrutinee expression conflicts with the
++      captures of the would-be closure
++* [`redundant_allocation`]: No longer lints on `Box<Box<dyn T>>` which replaces
++  wide pointers with thin pointers
++  [#7592](https://github.com/rust-lang/rust-clippy/pull/7592)
++* [`bool_assert_comparison`]: No longer lints on types that do not implement the
++  `Not` trait with `Output = bool`
++  [#7605](https://github.com/rust-lang/rust-clippy/pull/7605)
++* [`mut_range_bound`]: No longer lints on range bound mutations, that are
++  immediately followed by a `break;`
++  [#7607](https://github.com/rust-lang/rust-clippy/pull/7607)
++* [`mutable_key_type`]: Improve accuracy and document remaining false positives
++  and false negatives
++  [#7640](https://github.com/rust-lang/rust-clippy/pull/7640)
++* [`redundant_closure`]: Rewrite the lint to fix various false positives and
++  false negatives [#7661](https://github.com/rust-lang/rust-clippy/pull/7661)
++* [`large_enum_variant`]: No longer wrongly identifies the second largest
++  variant [#7677](https://github.com/rust-lang/rust-clippy/pull/7677)
++* [`needless_return`]: No longer lints on let-else expressions
++  [#7685](https://github.com/rust-lang/rust-clippy/pull/7685)
++* [`suspicious_else_formatting`]: No longer lints in proc-macros
++  [#7707](https://github.com/rust-lang/rust-clippy/pull/7707)
++* [`excessive_precision`]: No longer lints when in some cases the float was
++  already written in the shortest form
++  [#7722](https://github.com/rust-lang/rust-clippy/pull/7722)
++* [`doc_markdown`]: No longer lints on intra-doc links
++  [#7772](https://github.com/rust-lang/rust-clippy/pull/7772)
++
++### Suggestion Fixes/Improvements
++
++* [`unnecessary_operation`]: Recommend using an `assert!` instead of using a
++  function call in an indexing operation
++  [#7453](https://github.com/rust-lang/rust-clippy/pull/7453)
++* [`manual_split_once`]: Produce semantically equivalent suggestion when
++  `rsplitn` is used [#7663](https://github.com/rust-lang/rust-clippy/pull/7663)
++* [`while_let_on_iterator`]: Produce correct suggestion when using `&mut`
++  [#7690](https://github.com/rust-lang/rust-clippy/pull/7690)
++* [`manual_assert`]: No better handles complex conditions
++  [#7741](https://github.com/rust-lang/rust-clippy/pull/7741)
++* Correctly handle signs in exponents in numeric literals lints
++  [#7747](https://github.com/rust-lang/rust-clippy/pull/7747)
++* [`suspicious_map`]: Now also suggests to use `inspect` as an alternative
++  [#7770](https://github.com/rust-lang/rust-clippy/pull/7770)
++* Drop exponent from suggestion if it is 0 in numeric literals lints
++  [#7774](https://github.com/rust-lang/rust-clippy/pull/7774)
++
++### ICE Fixes
++
++* [`implicit_hasher`]
++  [#7761](https://github.com/rust-lang/rust-clippy/pull/7761)
++
++### Others
++
++* Clippy now uses the 2021
++  [Edition!](https://www.youtube.com/watch?v=q0aNduqb2Ro)
++  [#7664](https://github.com/rust-lang/rust-clippy/pull/7664)
 +
 +## Rust 1.56
 +
- ### New Lints
- * Renamed Lint: `if_let_some_result` is now called [`match_result_ok`]. Now also handles `while let` case.
++Current stable, released 2021-10-21
 +
 +[74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e)
 +
 +### New Lints
 +
 +* [`unwrap_or_else_default`]
 +  [#7516](https://github.com/rust-lang/rust-clippy/pull/7516)
 +
 +### Enhancements
 +
 +* [`needless_continue`]: Now also lints in `loop { continue; }` case
 +  [#7477](https://github.com/rust-lang/rust-clippy/pull/7477)
 +* [`disallowed_type`]: Now also primitive types can be disallowed
 +  [#7488](https://github.com/rust-lang/rust-clippy/pull/7488)
 +* [`manual_swap`]: Now also lints on xor swaps
 +  [#7506](https://github.com/rust-lang/rust-clippy/pull/7506)
 +* [`map_flatten`]: Now also lints on the `Result` type
 +  [#7522](https://github.com/rust-lang/rust-clippy/pull/7522)
 +* [`no_effect`]: Now also lints on inclusive ranges
 +  [#7556](https://github.com/rust-lang/rust-clippy/pull/7556)
 +
 +### False Positive Fixes
 +
 +* [`nonstandard_macro_braces`]: No longer lints on similar named nested macros
 +  [#7478](https://github.com/rust-lang/rust-clippy/pull/7478)
 +* [`too_many_lines`]: No longer lints in closures to avoid duplicated diagnostics
 +  [#7534](https://github.com/rust-lang/rust-clippy/pull/7534)
 +* [`similar_names`]: No longer complains about `iter` and `item` being too
 +  similar [#7546](https://github.com/rust-lang/rust-clippy/pull/7546)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`similar_names`]: No longer suggests to insert or add an underscore as a fix
 +  [#7221](https://github.com/rust-lang/rust-clippy/pull/7221)
 +* [`new_without_default`]: No longer shows the full qualified type path when
 +  suggesting adding a `Default` implementation
 +  [#7493](https://github.com/rust-lang/rust-clippy/pull/7493)
 +* [`while_let_on_iterator`]: Now suggests re-borrowing mutable references
 +  [#7520](https://github.com/rust-lang/rust-clippy/pull/7520)
 +* [`extend_with_drain`]: Improve code suggestion for mutable and immutable
 +  references [#7533](https://github.com/rust-lang/rust-clippy/pull/7533)
 +* [`trivially_copy_pass_by_ref`]: Now properly handles `Self` type
 +  [#7535](https://github.com/rust-lang/rust-clippy/pull/7535)
 +* [`never_loop`]: Now suggests using `if let` instead of a `for` loop when
 +  applicable [#7541](https://github.com/rust-lang/rust-clippy/pull/7541)
 +
 +### Documentation Improvements
 +
 +* Clippy now uses a lint to generate its lint documentation. [Lints all the way
 +  down](https://en.wikipedia.org/wiki/Turtles_all_the_way_down).
 +  [#7502](https://github.com/rust-lang/rust-clippy/pull/7502)
 +* Reworked Clippy's website:
 +  [#7172](https://github.com/rust-lang/rust-clippy/issues/7172)
 +  [#7279](https://github.com/rust-lang/rust-clippy/pull/7279)
 +  * Added applicability information about lints
 +  * Added a link to jump into the implementation
 +  * Improved loading times
 +  * Adapted some styling
 +* `cargo clippy --help` now also explains the `--fix` and `--no-deps` flag
 +  [#7492](https://github.com/rust-lang/rust-clippy/pull/7492)
 +* [`unnested_or_patterns`]: Removed `or_patterns` feature gate in the code
 +  example [#7507](https://github.com/rust-lang/rust-clippy/pull/7507)
 +
- Current stable, released 2021-09-09
 +## Rust 1.55
 +
- [`if_then_panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_panic
++Released 2021-09-09
 +
 +[3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561)
 +
 +### Important Changes
 +
 +* Stabilized `cargo clippy --fix` :tada:
 +  [#7405](https://github.com/rust-lang/rust-clippy/pull/7405)
 +
 +### New Lints
 +
 +* [`rc_mutex`]
 +  [#7316](https://github.com/rust-lang/rust-clippy/pull/7316)
 +* [`nonstandard_macro_braces`]
 +  [#7299](https://github.com/rust-lang/rust-clippy/pull/7299)
 +* [`strlen_on_c_strings`]
 +  [#7243](https://github.com/rust-lang/rust-clippy/pull/7243)
 +* [`self_named_constructors`]
 +  [#7403](https://github.com/rust-lang/rust-clippy/pull/7403)
 +* [`disallowed_script_idents`]
 +  [#7400](https://github.com/rust-lang/rust-clippy/pull/7400)
 +* [`disallowed_type`]
 +  [#7315](https://github.com/rust-lang/rust-clippy/pull/7315)
 +* [`missing_enforced_import_renames`]
 +  [#7300](https://github.com/rust-lang/rust-clippy/pull/7300)
 +* [`extend_with_drain`]
 +  [#7270](https://github.com/rust-lang/rust-clippy/pull/7270)
 +
 +### Moves and Deprecations
 +
 +* Moved [`from_iter_instead_of_collect`] to `pedantic`
 +  [#7375](https://github.com/rust-lang/rust-clippy/pull/7375)
 +* Added `suspicious` as a new lint group for *code that is most likely wrong or useless*
 +  [#7350](https://github.com/rust-lang/rust-clippy/pull/7350)
 +  * Moved [`blanket_clippy_restriction_lints`] to `suspicious`
 +  * Moved [`empty_loop`] to `suspicious`
 +  * Moved [`eval_order_dependence`] to `suspicious`
 +  * Moved [`float_equality_without_abs`] to `suspicious`
 +  * Moved [`for_loops_over_fallibles`] to `suspicious`
 +  * Moved [`misrefactored_assign_op`] to `suspicious`
 +  * Moved [`mut_range_bound`] to `suspicious`
 +  * Moved [`mutable_key_type`] to `suspicious`
 +  * Moved [`suspicious_arithmetic_impl`] to `suspicious`
 +  * Moved [`suspicious_assignment_formatting`] to `suspicious`
 +  * Moved [`suspicious_else_formatting`] to `suspicious`
 +  * Moved [`suspicious_map`] to `suspicious`
 +  * Moved [`suspicious_op_assign_impl`] to `suspicious`
 +  * Moved [`suspicious_unary_op_formatting`] to `suspicious`
 +
 +### Enhancements
 +
 +* [`while_let_on_iterator`]: Now suggests `&mut iter` inside closures
 +  [#7262](https://github.com/rust-lang/rust-clippy/pull/7262)
 +* [`doc_markdown`]:
 +  * Now detects unbalanced ticks
 +    [#7357](https://github.com/rust-lang/rust-clippy/pull/7357)
 +  * Add `FreeBSD` to the default configuration as an allowed identifier
 +    [#7334](https://github.com/rust-lang/rust-clippy/pull/7334)
 +* [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]: Now allows wildcards for enums with unstable
 +  or hidden variants
 +  [#7407](https://github.com/rust-lang/rust-clippy/pull/7407)
 +* [`redundant_allocation`]: Now additionally supports the `Arc<>` type
 +  [#7308](https://github.com/rust-lang/rust-clippy/pull/7308)
 +* [`blacklisted_name`]: Now allows blacklisted names in test code
 +  [#7379](https://github.com/rust-lang/rust-clippy/pull/7379)
 +* [`redundant_closure`]: Suggests `&mut` for `FnMut`
 +  [#7437](https://github.com/rust-lang/rust-clippy/pull/7437)
 +* [`disallowed_method`], [`disallowed_type`]: The configuration values `disallowed-method` and `disallowed-type`
 +  no longer require fully qualified paths
 +  [#7345](https://github.com/rust-lang/rust-clippy/pull/7345)
 +* [`zst_offset`]: Fixed lint invocation after it was accidentally suppressed
 +  [#7396](https://github.com/rust-lang/rust-clippy/pull/7396)
 +
 +### False Positive Fixes
 +
 +* [`default_numeric_fallback`]: No longer lints on float literals as function arguments
 +  [#7446](https://github.com/rust-lang/rust-clippy/pull/7446)
 +* [`use_self`]: No longer lints on type parameters
 +  [#7288](https://github.com/rust-lang/rust-clippy/pull/7288)
 +* [`unimplemented`]: Now ignores the `assert` and `debug_assert` macros
 +  [#7439](https://github.com/rust-lang/rust-clippy/pull/7439)
 +* [`branches_sharing_code`]: Now always checks for block expressions
 +  [#7462](https://github.com/rust-lang/rust-clippy/pull/7462)
 +* [`field_reassign_with_default`]: No longer triggers in macros
 +  [#7160](https://github.com/rust-lang/rust-clippy/pull/7160)
 +* [`redundant_clone`]: No longer lints on required clones for borrowed data
 +  [#7346](https://github.com/rust-lang/rust-clippy/pull/7346)
 +* [`default_numeric_fallback`]: No longer triggers in external macros
 +  [#7325](https://github.com/rust-lang/rust-clippy/pull/7325)
 +* [`needless_bool`]: No longer lints in macros
 +  [#7442](https://github.com/rust-lang/rust-clippy/pull/7442)
 +* [`useless_format`]: No longer triggers when additional text is being appended
 +  [#7442](https://github.com/rust-lang/rust-clippy/pull/7442)
 +* [`assertions_on_constants`]: `cfg!(...)` is no longer considered to be a constant
 +  [#7319](https://github.com/rust-lang/rust-clippy/pull/7319)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`needless_collect`]: Now show correct lint messages for shadowed values
 +  [#7289](https://github.com/rust-lang/rust-clippy/pull/7289)
 +* [`wrong_pub_self_convention`]: The deprecated message now suggest the correct configuration value
 +  [#7382](https://github.com/rust-lang/rust-clippy/pull/7382)
 +* [`semicolon_if_nothing_returned`]: Allow missing semicolon in blocks with only one expression
 +  [#7326](https://github.com/rust-lang/rust-clippy/pull/7326)
 +
 +### ICE Fixes
 +
 +* [`zero_sized_map_values`]
 +  [#7470](https://github.com/rust-lang/rust-clippy/pull/7470)
 +* [`redundant_pattern_matching`]
 +  [#7471](https://github.com/rust-lang/rust-clippy/pull/7471)
 +* [`modulo_one`]
 +  [#7473](https://github.com/rust-lang/rust-clippy/pull/7473)
 +* [`use_self`]
 +  [#7428](https://github.com/rust-lang/rust-clippy/pull/7428)
 +
 +## Rust 1.54
 +
 +Released 2021-07-29
 +
 +[7c7683c...3ae8faf](https://github.com/rust-lang/rust-clippy/compare/7c7683c...3ae8faf)
 +
 +### New Lints
 +
 +- [`ref_binding_to_reference`]
 +  [#7105](https://github.com/rust-lang/rust-clippy/pull/7105)
 +- [`needless_bitwise_bool`]
 +  [#7133](https://github.com/rust-lang/rust-clippy/pull/7133)
 +- [`unused_async`] [#7225](https://github.com/rust-lang/rust-clippy/pull/7225)
 +- [`manual_str_repeat`]
 +  [#7265](https://github.com/rust-lang/rust-clippy/pull/7265)
 +- [`suspicious_splitn`]
 +  [#7292](https://github.com/rust-lang/rust-clippy/pull/7292)
 +
 +### Moves and Deprecations
 +
 +- Deprecate `pub_enum_variant_names` and `wrong_pub_self_convention` in favor of
 +  the new `avoid-breaking-exported-api` config option (see
 +  [Enhancements](#1-54-enhancements))
 +  [#7187](https://github.com/rust-lang/rust-clippy/pull/7187)
 +- Move [`inconsistent_struct_constructor`] to `pedantic`
 +  [#7193](https://github.com/rust-lang/rust-clippy/pull/7193)
 +- Move [`needless_borrow`] to `style` (now warn-by-default)
 +  [#7254](https://github.com/rust-lang/rust-clippy/pull/7254)
 +- Move [`suspicious_operation_groupings`] to `nursery`
 +  [#7266](https://github.com/rust-lang/rust-clippy/pull/7266)
 +- Move [`semicolon_if_nothing_returned`] to `pedantic`
 +  [#7268](https://github.com/rust-lang/rust-clippy/pull/7268)
 +
 +### Enhancements <a name="1-54-enhancements"></a>
 +
 +- [`while_let_on_iterator`]: Now also lints in nested loops
 +  [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
 +- [`single_char_pattern`]: Now also lints on `strip_prefix` and `strip_suffix`
 +  [#7156](https://github.com/rust-lang/rust-clippy/pull/7156)
 +- [`needless_collect`]: Now also lints on assignments with type annotations
 +  [#7163](https://github.com/rust-lang/rust-clippy/pull/7163)
 +- [`if_then_some_else_none`]: Now works with the MSRV config
 +  [#7177](https://github.com/rust-lang/rust-clippy/pull/7177)
 +- Add `avoid-breaking-exported-api` config option for the lints
 +  [`enum_variant_names`], [`large_types_passed_by_value`],
 +  [`trivially_copy_pass_by_ref`], [`unnecessary_wraps`],
 +  [`upper_case_acronyms`], and [`wrong_self_convention`]. We recommend to set
 +  this configuration option to `false` before a major release (1.0/2.0/...) to
 +  clean up the API [#7187](https://github.com/rust-lang/rust-clippy/pull/7187)
 +- [`needless_collect`]: Now lints on even more data structures
 +  [#7188](https://github.com/rust-lang/rust-clippy/pull/7188)
 +- [`missing_docs_in_private_items`]: No longer sees `#[<name> = "<value>"]` like
 +  attributes as sufficient documentation
 +  [#7281](https://github.com/rust-lang/rust-clippy/pull/7281)
 +- [`needless_collect`], [`short_circuit_statement`], [`unnecessary_operation`]:
 +  Now work as expected when used with `allow`
 +  [#7282](https://github.com/rust-lang/rust-clippy/pull/7282)
 +
 +### False Positive Fixes
 +
 +- [`implicit_return`]: Now takes all diverging functions in account to avoid
 +  false positives [#6951](https://github.com/rust-lang/rust-clippy/pull/6951)
 +- [`while_let_on_iterator`]: No longer lints when the iterator is a struct field
 +  and the struct is used in the loop
 +  [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
 +- [`multiple_inherent_impl`]: No longer lints with generic arguments
 +  [#7089](https://github.com/rust-lang/rust-clippy/pull/7089)
 +- [`comparison_chain`]: No longer lints in a `const` context
 +  [#7118](https://github.com/rust-lang/rust-clippy/pull/7118)
 +- [`while_immutable_condition`]: Fix false positive where mutation in the loop
 +  variable wasn't picked up
 +  [#7144](https://github.com/rust-lang/rust-clippy/pull/7144)
 +- [`default_trait_access`]: No longer lints in macros
 +  [#7150](https://github.com/rust-lang/rust-clippy/pull/7150)
 +- [`needless_question_mark`]: No longer lints when the inner value is implicitly
 +  dereferenced [#7165](https://github.com/rust-lang/rust-clippy/pull/7165)
 +- [`unused_unit`]: No longer lints when multiple macro contexts are involved
 +  [#7167](https://github.com/rust-lang/rust-clippy/pull/7167)
 +- [`eval_order_dependence`]: Fix false positive in async context
 +  [#7174](https://github.com/rust-lang/rust-clippy/pull/7174)
 +- [`unnecessary_filter_map`]: No longer lints if the `filter_map` changes the
 +  type [#7175](https://github.com/rust-lang/rust-clippy/pull/7175)
 +- [`wrong_self_convention`]: No longer lints in trait implementations of
 +  non-`Copy` types [#7182](https://github.com/rust-lang/rust-clippy/pull/7182)
 +- [`suboptimal_flops`]: No longer lints on `powi(2)`
 +  [#7201](https://github.com/rust-lang/rust-clippy/pull/7201)
 +- [`wrong_self_convention`]: No longer lints if there is no implicit `self`
 +  [#7215](https://github.com/rust-lang/rust-clippy/pull/7215)
 +- [`option_if_let_else`]: No longer lints on `else if let` pattern
 +  [#7216](https://github.com/rust-lang/rust-clippy/pull/7216)
 +- [`use_self`], [`useless_conversion`]: Fix false positives when generic
 +  arguments are involved
 +  [#7223](https://github.com/rust-lang/rust-clippy/pull/7223)
 +- [`manual_unwrap_or`]: Fix false positive with deref coercion
 +  [#7233](https://github.com/rust-lang/rust-clippy/pull/7233)
 +- [`similar_names`]: No longer lints on `wparam`/`lparam`
 +  [#7255](https://github.com/rust-lang/rust-clippy/pull/7255)
 +- [`redundant_closure`]: No longer lints on using the `vec![]` macro in a
 +  closure [#7263](https://github.com/rust-lang/rust-clippy/pull/7263)
 +
 +### Suggestion Fixes/Improvements
 +
 +- [`implicit_return`]
 +  [#6951](https://github.com/rust-lang/rust-clippy/pull/6951)
 +    - Fix suggestion for async functions
 +    - Improve suggestion with macros
 +    - Suggest to change `break` to `return` when appropriate
 +- [`while_let_on_iterator`]: Now suggests `&mut iter` when necessary
 +  [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
 +- [`match_single_binding`]: Improve suggestion when match scrutinee has side
 +  effects [#7095](https://github.com/rust-lang/rust-clippy/pull/7095)
 +- [`needless_borrow`]: Now suggests to also change usage sites as needed
 +  [#7105](https://github.com/rust-lang/rust-clippy/pull/7105)
 +- [`write_with_newline`]: Improve suggestion when only `\n` is written to the
 +  buffer [#7183](https://github.com/rust-lang/rust-clippy/pull/7183)
 +- [`from_iter_instead_of_collect`]: The suggestion is now auto applicable also
 +  when a `<_ as Trait>::_` is involved
 +  [#7264](https://github.com/rust-lang/rust-clippy/pull/7264)
 +- [`not_unsafe_ptr_arg_deref`]: Improved error message
 +  [#7294](https://github.com/rust-lang/rust-clippy/pull/7294)
 +
 +### ICE Fixes
 +
 +- Fix ICE when running Clippy on `libstd`
 +  [#7140](https://github.com/rust-lang/rust-clippy/pull/7140)
 +- [`implicit_return`]
 +  [#7242](https://github.com/rust-lang/rust-clippy/pull/7242)
 +
 +## Rust 1.53
 +
 +Released 2021-06-17
 +
 +[6ed6f1e...7c7683c](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...7c7683c)
 +
 +### New Lints
 +
 +* [`option_filter_map`]
 +  [#6342](https://github.com/rust-lang/rust-clippy/pull/6342)
 +* [`branches_sharing_code`]
 +  [#6463](https://github.com/rust-lang/rust-clippy/pull/6463)
 +* [`needless_for_each`]
 +  [#6706](https://github.com/rust-lang/rust-clippy/pull/6706)
 +* [`if_then_some_else_none`]
 +  [#6859](https://github.com/rust-lang/rust-clippy/pull/6859)
 +* [`non_octal_unix_permissions`]
 +  [#7001](https://github.com/rust-lang/rust-clippy/pull/7001)
 +* [`unnecessary_self_imports`]
 +  [#7072](https://github.com/rust-lang/rust-clippy/pull/7072)
 +* [`bool_assert_comparison`]
 +  [#7083](https://github.com/rust-lang/rust-clippy/pull/7083)
 +* [`cloned_instead_of_copied`]
 +  [#7098](https://github.com/rust-lang/rust-clippy/pull/7098)
 +* [`flat_map_option`]
 +  [#7101](https://github.com/rust-lang/rust-clippy/pull/7101)
 +
 +### Moves and Deprecations
 +
 +* Deprecate [`filter_map`] lint
 +  [#7059](https://github.com/rust-lang/rust-clippy/pull/7059)
 +* Move [`transmute_ptr_to_ptr`] to `pedantic`
 +  [#7102](https://github.com/rust-lang/rust-clippy/pull/7102)
 +
 +### Enhancements
 +
 +* [`mem_replace_with_default`]: Also lint on common std constructors
 +  [#6820](https://github.com/rust-lang/rust-clippy/pull/6820)
 +* [`wrong_self_convention`]: Also lint on `to_*_mut` methods
 +  [#6828](https://github.com/rust-lang/rust-clippy/pull/6828)
 +* [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]:
 +  [#6863](https://github.com/rust-lang/rust-clippy/pull/6863)
 +    * Attempt to find a common path prefix in suggestion
 +    * Don't lint on `Option` and `Result`
 +    * Consider `Self` prefix
 +* [`explicit_deref_methods`]: Also lint on chained `deref` calls
 +  [#6865](https://github.com/rust-lang/rust-clippy/pull/6865)
 +* [`or_fun_call`]: Also lint on `unsafe` blocks
 +  [#6928](https://github.com/rust-lang/rust-clippy/pull/6928)
 +* [`vec_box`], [`linkedlist`], [`option_option`]: Also lint in `const` and
 +  `static` items [#6938](https://github.com/rust-lang/rust-clippy/pull/6938)
 +* [`search_is_some`]: Also check for `is_none`
 +  [#6942](https://github.com/rust-lang/rust-clippy/pull/6942)
 +* [`string_lit_as_bytes`]: Also lint on `into_bytes`
 +  [#6959](https://github.com/rust-lang/rust-clippy/pull/6959)
 +* [`len_without_is_empty`]: Also lint if function signatures of `len` and
 +  `is_empty` don't match
 +  [#6980](https://github.com/rust-lang/rust-clippy/pull/6980)
 +* [`redundant_pattern_matching`]: Also lint if the pattern is a `&` pattern
 +  [#6991](https://github.com/rust-lang/rust-clippy/pull/6991)
 +* [`clone_on_copy`]: Also lint on chained method calls taking `self` by value
 +  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
 +* [`missing_panics_doc`]: Also lint on `assert_eq!` and `assert_ne!`
 +  [#7029](https://github.com/rust-lang/rust-clippy/pull/7029)
 +* [`needless_return`]: Also lint in `async` functions
 +  [#7067](https://github.com/rust-lang/rust-clippy/pull/7067)
 +* [`unused_io_amount`]: Also lint on expressions like `_.read().ok()?`
 +  [#7100](https://github.com/rust-lang/rust-clippy/pull/7100)
 +* [`iter_cloned_collect`]: Also lint on large arrays, since const-generics are
 +  now stable [#7138](https://github.com/rust-lang/rust-clippy/pull/7138)
 +
 +### False Positive Fixes
 +
 +* [`upper_case_acronyms`]: No longer lints on public items
 +  [#6805](https://github.com/rust-lang/rust-clippy/pull/6805)
 +* [`suspicious_map`]: No longer lints when side effects may occur inside the
 +  `map` call [#6831](https://github.com/rust-lang/rust-clippy/pull/6831)
 +* [`manual_map`], [`manual_unwrap_or`]: No longer lints in `const` functions
 +  [#6917](https://github.com/rust-lang/rust-clippy/pull/6917)
 +* [`wrong_self_convention`]: Now respects `Copy` types
 +  [#6924](https://github.com/rust-lang/rust-clippy/pull/6924)
 +* [`needless_question_mark`]: No longer lints if the `?` and the `Some(..)` come
 +  from different macro contexts [#6935](https://github.com/rust-lang/rust-clippy/pull/6935)
 +* [`map_entry`]: Better detect if the entry API can be used
 +  [#6937](https://github.com/rust-lang/rust-clippy/pull/6937)
 +* [`or_fun_call`]: No longer lints on some `len` function calls
 +  [#6950](https://github.com/rust-lang/rust-clippy/pull/6950)
 +* [`new_ret_no_self`]: No longer lints when `Self` is returned with different
 +  generic arguments [#6952](https://github.com/rust-lang/rust-clippy/pull/6952)
 +* [`upper_case_acronyms`]: No longer lints on public items
 +  [#6981](https://github.com/rust-lang/rust-clippy/pull/6981)
 +* [`explicit_into_iter_loop`]: Only lint when `into_iter` is an implementation
 +  of `IntoIterator` [#6982](https://github.com/rust-lang/rust-clippy/pull/6982)
 +* [`expl_impl_clone_on_copy`]: Take generic constraints into account before
 +  suggesting to use `derive` instead
 +  [#6993](https://github.com/rust-lang/rust-clippy/pull/6993)
 +* [`missing_panics_doc`]: No longer lints when only debug-assertions are used
 +  [#6996](https://github.com/rust-lang/rust-clippy/pull/6996)
 +* [`clone_on_copy`]: Only lint when using the `Clone` trait
 +  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
 +* [`wrong_self_convention`]: No longer lints inside a trait implementation
 +  [#7002](https://github.com/rust-lang/rust-clippy/pull/7002)
 +* [`redundant_clone`]: No longer lints when the cloned value is modified while
 +  the clone is in use
 +  [#7011](https://github.com/rust-lang/rust-clippy/pull/7011)
 +* [`same_item_push`]: No longer lints if the `Vec` is used in the loop body
 +  [#7018](https://github.com/rust-lang/rust-clippy/pull/7018)
 +* [`cargo_common_metadata`]: Remove author requirement
 +  [#7026](https://github.com/rust-lang/rust-clippy/pull/7026)
 +* [`panic_in_result_fn`]: No longer lints on `debug_assert` family
 +  [#7060](https://github.com/rust-lang/rust-clippy/pull/7060)
 +* [`panic`]: No longer wrongfully lints on `debug_assert` with message
 +  [#7063](https://github.com/rust-lang/rust-clippy/pull/7063)
 +* [`wrong_self_convention`]: No longer lints in trait implementations where no
 +  `self` is involved [#7064](https://github.com/rust-lang/rust-clippy/pull/7064)
 +* [`missing_const_for_fn`]: No longer lints when unstable `const` function is
 +  involved [#7076](https://github.com/rust-lang/rust-clippy/pull/7076)
 +* [`suspicious_else_formatting`]: Allow Allman style braces
 +  [#7087](https://github.com/rust-lang/rust-clippy/pull/7087)
 +* [`inconsistent_struct_constructor`]: No longer lints in macros
 +  [#7097](https://github.com/rust-lang/rust-clippy/pull/7097)
 +* [`single_component_path_imports`]: No longer lints on macro re-exports
 +  [#7120](https://github.com/rust-lang/rust-clippy/pull/7120)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`redundant_pattern_matching`]: Add a note when applying this lint would
 +  change the drop order
 +  [#6568](https://github.com/rust-lang/rust-clippy/pull/6568)
 +* [`write_literal`], [`print_literal`]: Add auto-applicable suggestion
 +  [#6821](https://github.com/rust-lang/rust-clippy/pull/6821)
 +* [`manual_map`]: Fix suggestion for complex `if let ... else` chains
 +  [#6856](https://github.com/rust-lang/rust-clippy/pull/6856)
 +* [`inconsistent_struct_constructor`]: Make lint description and message clearer
 +  [#6892](https://github.com/rust-lang/rust-clippy/pull/6892)
 +* [`map_entry`]: Now suggests `or_insert`, `insert_with` or `match _.entry(_)`
 +  as appropriate [#6937](https://github.com/rust-lang/rust-clippy/pull/6937)
 +* [`manual_flatten`]: Suggest to insert `copied` if necessary
 +  [#6962](https://github.com/rust-lang/rust-clippy/pull/6962)
 +* [`redundant_slicing`]: Fix suggestion when a re-borrow might be required or
 +  when the value is from a macro call
 +  [#6975](https://github.com/rust-lang/rust-clippy/pull/6975)
 +* [`match_wildcard_for_single_variants`]: Fix suggestion for hidden variant
 +  [#6988](https://github.com/rust-lang/rust-clippy/pull/6988)
 +* [`clone_on_copy`]: Correct suggestion when the cloned value is a macro call
 +  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
 +* [`manual_map`]: Fix suggestion at the end of an if chain
 +  [#7004](https://github.com/rust-lang/rust-clippy/pull/7004)
 +* Fix needless parenthesis output in multiple lint suggestions
 +  [#7013](https://github.com/rust-lang/rust-clippy/pull/7013)
 +* [`needless_collect`]: Better explanation in the lint message
 +  [#7020](https://github.com/rust-lang/rust-clippy/pull/7020)
 +* [`useless_vec`]: Now considers mutability
 +  [#7036](https://github.com/rust-lang/rust-clippy/pull/7036)
 +* [`useless_format`]: Wrap the content in braces if necessary
 +  [#7092](https://github.com/rust-lang/rust-clippy/pull/7092)
 +* [`single_match`]: Don't suggest an equality check for types which don't
 +  implement `PartialEq`
 +  [#7093](https://github.com/rust-lang/rust-clippy/pull/7093)
 +* [`from_over_into`]: Mention type in help message
 +  [#7099](https://github.com/rust-lang/rust-clippy/pull/7099)
 +* [`manual_unwrap_or`]: Fix invalid code suggestion due to a macro call
 +  [#7136](https://github.com/rust-lang/rust-clippy/pull/7136)
 +
 +### ICE Fixes
 +
 +* [`macro_use_imports`]
 +  [#7022](https://github.com/rust-lang/rust-clippy/pull/7022)
 +* [`missing_panics_doc`]
 +  [#7034](https://github.com/rust-lang/rust-clippy/pull/7034)
 +* [`tabs_in_doc_comments`]
 +  [#7039](https://github.com/rust-lang/rust-clippy/pull/7039)
 +* [`missing_const_for_fn`]
 +  [#7128](https://github.com/rust-lang/rust-clippy/pull/7128)
 +
 +### Others
 +
 +* [Clippy's lint
 +  list](https://rust-lang.github.io/rust-clippy/master/index.html) now supports
 +  themes [#7030](https://github.com/rust-lang/rust-clippy/pull/7030)
 +* Lints that were uplifted to `rustc` now mention the new `rustc` name in the
 +  deprecation warning
 +  [#7056](https://github.com/rust-lang/rust-clippy/pull/7056)
 +
 +## Rust 1.52
 +
 +Released 2021-05-06
 +
 +[3e41797...6ed6f1e](https://github.com/rust-lang/rust-clippy/compare/3e41797...6ed6f1e)
 +
 +### New Lints
 +
 +* [`from_str_radix_10`]
 +  [#6717](https://github.com/rust-lang/rust-clippy/pull/6717)
 +* [`implicit_clone`]
 +  [#6730](https://github.com/rust-lang/rust-clippy/pull/6730)
 +* [`semicolon_if_nothing_returned`]
 +  [#6681](https://github.com/rust-lang/rust-clippy/pull/6681)
 +* [`manual_flatten`]
 +  [#6646](https://github.com/rust-lang/rust-clippy/pull/6646)
 +* [`inconsistent_struct_constructor`]
 +  [#6769](https://github.com/rust-lang/rust-clippy/pull/6769)
 +* [`iter_count`]
 +  [#6791](https://github.com/rust-lang/rust-clippy/pull/6791)
 +* [`default_numeric_fallback`]
 +  [#6662](https://github.com/rust-lang/rust-clippy/pull/6662)
 +* [`bytes_nth`]
 +  [#6695](https://github.com/rust-lang/rust-clippy/pull/6695)
 +* [`filter_map_identity`]
 +  [#6685](https://github.com/rust-lang/rust-clippy/pull/6685)
 +* [`manual_map`]
 +  [#6573](https://github.com/rust-lang/rust-clippy/pull/6573)
 +
 +### Moves and Deprecations
 +
 +* Moved [`upper_case_acronyms`] to `pedantic`
 +  [#6775](https://github.com/rust-lang/rust-clippy/pull/6775)
 +* Moved [`manual_map`] to `nursery`
 +  [#6796](https://github.com/rust-lang/rust-clippy/pull/6796)
 +* Moved [`unnecessary_wraps`] to `pedantic`
 +  [#6765](https://github.com/rust-lang/rust-clippy/pull/6765)
 +* Moved [`trivial_regex`] to `nursery`
 +  [#6696](https://github.com/rust-lang/rust-clippy/pull/6696)
 +* Moved [`naive_bytecount`] to `pedantic`
 +  [#6825](https://github.com/rust-lang/rust-clippy/pull/6825)
 +* Moved [`upper_case_acronyms`] to `style`
 +  [#6788](https://github.com/rust-lang/rust-clippy/pull/6788)
 +* Moved [`manual_map`] to `style`
 +  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
 +
 +### Enhancements
 +
 +* [`disallowed_method`]: Now supports functions in addition to methods
 +  [#6674](https://github.com/rust-lang/rust-clippy/pull/6674)
 +* [`upper_case_acronyms`]: Added a new configuration `upper-case-acronyms-aggressive` to
 +  trigger the lint if there is more than one uppercase character next to each other
 +  [#6788](https://github.com/rust-lang/rust-clippy/pull/6788)
 +* [`collapsible_match`]: Now supports block comparison with different value names
 +  [#6754](https://github.com/rust-lang/rust-clippy/pull/6754)
 +* [`unnecessary_wraps`]: Will now suggest removing unnecessary wrapped return unit type, like `Option<()>`
 +  [#6665](https://github.com/rust-lang/rust-clippy/pull/6665)
 +* Improved value usage detection in closures
 +  [#6698](https://github.com/rust-lang/rust-clippy/pull/6698)
 +
 +### False Positive Fixes
 +
 +* [`use_self`]: No longer lints in macros
 +  [#6833](https://github.com/rust-lang/rust-clippy/pull/6833)
 +* [`use_self`]: Fixed multiple false positives for: generics, associated types and derive implementations
 +  [#6179](https://github.com/rust-lang/rust-clippy/pull/6179)
 +* [`missing_inline_in_public_items`]: No longer lints for procedural macros
 +  [#6814](https://github.com/rust-lang/rust-clippy/pull/6814)
 +* [`inherent_to_string`]: No longer lints on functions with function generics
 +  [#6771](https://github.com/rust-lang/rust-clippy/pull/6771)
 +* [`doc_markdown`]: Add `OpenDNS` to the default configuration as an allowed identifier
 +  [#6783](https://github.com/rust-lang/rust-clippy/pull/6783)
 +* [`missing_panics_doc`]: No longer lints on [`unreachable!`](https://doc.rust-lang.org/std/macro.unreachable.html)
 +  [#6700](https://github.com/rust-lang/rust-clippy/pull/6700)
 +* [`collapsible_if`]: No longer lints on if statements with attributes
 +  [#6701](https://github.com/rust-lang/rust-clippy/pull/6701)
 +* [`match_same_arms`]: Only considers empty blocks as equal if the tokens contained are the same
 +  [#6843](https://github.com/rust-lang/rust-clippy/pull/6843)
 +* [`redundant_closure`]: Now ignores macros
 +  [#6871](https://github.com/rust-lang/rust-clippy/pull/6871)
 +* [`manual_map`]: Fixed false positives when control flow statements like `return`, `break` etc. are used
 +  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
 +* [`vec_init_then_push`]: Fixed false positives for loops and if statements
 +  [#6697](https://github.com/rust-lang/rust-clippy/pull/6697)
 +* [`len_without_is_empty`]: Will now consider multiple impl blocks and `#[allow]` on
 +  the `len` method as well as the type definition.
 +  [#6853](https://github.com/rust-lang/rust-clippy/pull/6853)
 +* [`let_underscore_drop`]: Only lints on types which implement `Drop`
 +  [#6682](https://github.com/rust-lang/rust-clippy/pull/6682)
 +* [`unit_arg`]: No longer lints on unit arguments when they come from a path expression.
 +  [#6601](https://github.com/rust-lang/rust-clippy/pull/6601)
 +* [`cargo_common_metadata`]: No longer lints if
 +  [`publish = false`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field)
 +  is defined in the manifest
 +  [#6650](https://github.com/rust-lang/rust-clippy/pull/6650)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`collapsible_match`]: Fixed lint message capitalization
 +  [#6766](https://github.com/rust-lang/rust-clippy/pull/6766)
 +* [`or_fun_call`]: Improved suggestions for `or_insert(vec![])`
 +  [#6790](https://github.com/rust-lang/rust-clippy/pull/6790)
 +* [`manual_map`]: No longer expands macros in the suggestions
 +  [#6801](https://github.com/rust-lang/rust-clippy/pull/6801)
 +* Aligned Clippy's lint messages with the rustc dev guide
 +  [#6787](https://github.com/rust-lang/rust-clippy/pull/6787)
 +
 +### ICE Fixes
 +
 +* [`zero_sized_map_values`]
 +  [#6866](https://github.com/rust-lang/rust-clippy/pull/6866)
 +
 +### Documentation Improvements
 +
 +* [`useless_format`]: Improved the documentation example
 +  [#6854](https://github.com/rust-lang/rust-clippy/pull/6854)
 +* Clippy's [`README.md`]: Includes a new subsection on running Clippy as a rustc wrapper
 +  [#6782](https://github.com/rust-lang/rust-clippy/pull/6782)
 +
 +### Others
 +* Running `cargo clippy` after `cargo check` now works as expected
 +  (`cargo clippy` and `cargo check` no longer shares the same build cache)
 +  [#6687](https://github.com/rust-lang/rust-clippy/pull/6687)
 +* Cargo now re-runs Clippy if arguments after `--` provided to `cargo clippy` are changed.
 +  [#6834](https://github.com/rust-lang/rust-clippy/pull/6834)
 +* Extracted Clippy's `utils` module into the new `clippy_utils` crate
 +  [#6756](https://github.com/rust-lang/rust-clippy/pull/6756)
 +* Clippy lintcheck tool improvements
 +  [#6800](https://github.com/rust-lang/rust-clippy/pull/6800)
 +  [#6735](https://github.com/rust-lang/rust-clippy/pull/6735)
 +  [#6764](https://github.com/rust-lang/rust-clippy/pull/6764)
 +  [#6708](https://github.com/rust-lang/rust-clippy/pull/6708)
 +  [#6780](https://github.com/rust-lang/rust-clippy/pull/6780)
 +  [#6686](https://github.com/rust-lang/rust-clippy/pull/6686)
 +
 +## Rust 1.51
 +
 +Released 2021-03-25
 +
 +[4911ab1...3e41797](https://github.com/rust-lang/rust-clippy/compare/4911ab1...3e41797)
 +
 +### New Lints
 +
 +* [`upper_case_acronyms`]
 +  [#6475](https://github.com/rust-lang/rust-clippy/pull/6475)
 +* [`from_over_into`] [#6476](https://github.com/rust-lang/rust-clippy/pull/6476)
 +* [`case_sensitive_file_extension_comparisons`]
 +  [#6500](https://github.com/rust-lang/rust-clippy/pull/6500)
 +* [`needless_question_mark`]
 +  [#6507](https://github.com/rust-lang/rust-clippy/pull/6507)
 +* [`missing_panics_doc`]
 +  [#6523](https://github.com/rust-lang/rust-clippy/pull/6523)
 +* [`redundant_slicing`]
 +  [#6528](https://github.com/rust-lang/rust-clippy/pull/6528)
 +* [`vec_init_then_push`]
 +  [#6538](https://github.com/rust-lang/rust-clippy/pull/6538)
 +* [`ptr_as_ptr`] [#6542](https://github.com/rust-lang/rust-clippy/pull/6542)
 +* [`collapsible_else_if`] (split out from `collapsible_if`)
 +  [#6544](https://github.com/rust-lang/rust-clippy/pull/6544)
 +* [`inspect_for_each`] [#6577](https://github.com/rust-lang/rust-clippy/pull/6577)
 +* [`manual_filter_map`]
 +  [#6591](https://github.com/rust-lang/rust-clippy/pull/6591)
 +* [`exhaustive_enums`]
 +  [#6617](https://github.com/rust-lang/rust-clippy/pull/6617)
 +* [`exhaustive_structs`]
 +  [#6617](https://github.com/rust-lang/rust-clippy/pull/6617)
 +
 +### Moves and Deprecations
 +
 +* Replace [`find_map`] with [`manual_find_map`]
 +  [#6591](https://github.com/rust-lang/rust-clippy/pull/6591)
 +* `unknown_clippy_lints` Now integrated in the `unknown_lints` rustc lint
 +  [#6653](https://github.com/rust-lang/rust-clippy/pull/6653)
 +
 +### Enhancements
 +
 +* [`ptr_arg`] Now also suggests to use `&Path` instead of `&PathBuf`
 +  [#6506](https://github.com/rust-lang/rust-clippy/pull/6506)
 +* [`cast_ptr_alignment`] Also lint when the `pointer::cast` method is used
 +  [#6557](https://github.com/rust-lang/rust-clippy/pull/6557)
 +* [`collapsible_match`] Now also deals with `&` and `*` operators in the `match`
 +  scrutinee [#6619](https://github.com/rust-lang/rust-clippy/pull/6619)
 +
 +### False Positive Fixes
 +
 +* [`similar_names`] Ignore underscore prefixed names
 +  [#6403](https://github.com/rust-lang/rust-clippy/pull/6403)
 +* [`print_literal`] and [`write_literal`] No longer lint numeric literals
 +  [#6408](https://github.com/rust-lang/rust-clippy/pull/6408)
 +* [`large_enum_variant`] No longer lints in external macros
 +  [#6485](https://github.com/rust-lang/rust-clippy/pull/6485)
 +* [`empty_enum`] Only lint if `never_type` feature is enabled
 +  [#6513](https://github.com/rust-lang/rust-clippy/pull/6513)
 +* [`field_reassign_with_default`] No longer lints in macros
 +  [#6553](https://github.com/rust-lang/rust-clippy/pull/6553)
 +* [`size_of_in_element_count`] No longer lints when dividing by element size
 +  [#6578](https://github.com/rust-lang/rust-clippy/pull/6578)
 +* [`needless_return`] No longer lints in macros
 +  [#6586](https://github.com/rust-lang/rust-clippy/pull/6586)
 +* [`match_overlapping_arm`] No longer lint when first arm is completely included
 +  in second arm [#6603](https://github.com/rust-lang/rust-clippy/pull/6603)
 +* [`doc_markdown`] Add `WebGL` to the default configuration as an allowed
 +  identifier [#6605](https://github.com/rust-lang/rust-clippy/pull/6605)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`field_reassign_with_default`] Don't expand macro in lint suggestion
 +  [#6531](https://github.com/rust-lang/rust-clippy/pull/6531)
 +* [`match_like_matches_macro`] Strip references in suggestion
 +  [#6532](https://github.com/rust-lang/rust-clippy/pull/6532)
 +* [`single_match`] Suggest `if` over `if let` when possible
 +  [#6574](https://github.com/rust-lang/rust-clippy/pull/6574)
 +* [`ref_in_deref`] Use parentheses correctly in suggestion
 +  [#6609](https://github.com/rust-lang/rust-clippy/pull/6609)
 +* [`stable_sort_primitive`] Clarify error message
 +  [#6611](https://github.com/rust-lang/rust-clippy/pull/6611)
 +
 +### ICE Fixes
 +
 +* [`zero_sized_map_values`]
 +  [#6582](https://github.com/rust-lang/rust-clippy/pull/6582)
 +
 +### Documentation Improvements
 +
 +* Improve search performance on the Clippy website and make it possible to
 +  directly search for lints on the GitHub issue tracker
 +  [#6483](https://github.com/rust-lang/rust-clippy/pull/6483)
 +* Clean up `README.md` by removing outdated paragraph
 +  [#6488](https://github.com/rust-lang/rust-clippy/pull/6488)
 +* [`await_holding_refcell_ref`] and [`await_holding_lock`]
 +  [#6585](https://github.com/rust-lang/rust-clippy/pull/6585)
 +* [`as_conversions`] [#6608](https://github.com/rust-lang/rust-clippy/pull/6608)
 +
 +### Others
 +
 +* Clippy now has a [Roadmap] for 2021. If you like to get involved in a bigger
 +  project, take a look at the [Roadmap project page]. All issues listed there
 +  are actively mentored
 +  [#6462](https://github.com/rust-lang/rust-clippy/pull/6462)
 +* The Clippy version number now corresponds to the Rust version number
 +  [#6526](https://github.com/rust-lang/rust-clippy/pull/6526)
 +* Fix oversight which caused Clippy to lint deps in some environments, where
 +  `CLIPPY_TESTS=true` was set somewhere
 +  [#6575](https://github.com/rust-lang/rust-clippy/pull/6575)
 +* Add `cargo dev-lintcheck` tool to the Clippy Dev Tool
 +  [#6469](https://github.com/rust-lang/rust-clippy/pull/6469)
 +
 +[Roadmap]: https://github.com/rust-lang/rust-clippy/blob/master/doc/roadmap-2021.md
 +[Roadmap project page]: https://github.com/rust-lang/rust-clippy/projects/3
 +
 +## Rust 1.50
 +
 +Released 2021-02-11
 +
 +[b20d4c1...4bd77a1](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...4bd77a1)
 +
 +### New Lints
 +
 +* [`suspicious_operation_groupings`] [#6086](https://github.com/rust-lang/rust-clippy/pull/6086)
 +* [`size_of_in_element_count`] [#6394](https://github.com/rust-lang/rust-clippy/pull/6394)
 +* [`unnecessary_wraps`] [#6070](https://github.com/rust-lang/rust-clippy/pull/6070)
 +* [`let_underscore_drop`] [#6305](https://github.com/rust-lang/rust-clippy/pull/6305)
 +* [`collapsible_match`] [#6402](https://github.com/rust-lang/rust-clippy/pull/6402)
 +* [`redundant_else`] [#6330](https://github.com/rust-lang/rust-clippy/pull/6330)
 +* [`zero_sized_map_values`] [#6218](https://github.com/rust-lang/rust-clippy/pull/6218)
 +* [`print_stderr`] [#6367](https://github.com/rust-lang/rust-clippy/pull/6367)
 +* [`string_from_utf8_as_bytes`] [#6134](https://github.com/rust-lang/rust-clippy/pull/6134)
 +
 +### Moves and Deprecations
 +
 +* Previously deprecated [`str_to_string`] and [`string_to_string`] have been un-deprecated
 +  as `restriction` lints [#6333](https://github.com/rust-lang/rust-clippy/pull/6333)
 +* Deprecate `panic_params` lint. This is now available in rustc as `non_fmt_panics`
 +  [#6351](https://github.com/rust-lang/rust-clippy/pull/6351)
 +* Move [`map_err_ignore`] to `restriction`
 +  [#6416](https://github.com/rust-lang/rust-clippy/pull/6416)
 +* Move [`await_holding_refcell_ref`] to `pedantic`
 +  [#6354](https://github.com/rust-lang/rust-clippy/pull/6354)
 +* Move [`await_holding_lock`] to `pedantic`
 +  [#6354](https://github.com/rust-lang/rust-clippy/pull/6354)
 +
 +### Enhancements
 +
 +* Add the `unreadable-literal-lint-fractions` configuration to disable
 +  the `unreadable_literal` lint for fractions
 +  [#6421](https://github.com/rust-lang/rust-clippy/pull/6421)
 +* [`clone_on_copy`]: Now shows the type in the lint message
 +  [#6443](https://github.com/rust-lang/rust-clippy/pull/6443)
 +* [`redundant_pattern_matching`]: Now also lints on `std::task::Poll`
 +  [#6339](https://github.com/rust-lang/rust-clippy/pull/6339)
 +* [`redundant_pattern_matching`]: Additionally also lints on `std::net::IpAddr`
 +  [#6377](https://github.com/rust-lang/rust-clippy/pull/6377)
 +* [`search_is_some`]: Now suggests `contains` instead of `find(foo).is_some()`
 +  [#6119](https://github.com/rust-lang/rust-clippy/pull/6119)
 +* [`clone_double_ref`]: Now prints the reference type in the lint message
 +  [#6442](https://github.com/rust-lang/rust-clippy/pull/6442)
 +* [`modulo_one`]: Now also lints on -1.
 +  [#6360](https://github.com/rust-lang/rust-clippy/pull/6360)
 +* [`empty_loop`]: Now lints no_std crates, too
 +  [#6205](https://github.com/rust-lang/rust-clippy/pull/6205)
 +* [`or_fun_call`]: Now also lints when indexing `HashMap` or `BTreeMap`
 +  [#6267](https://github.com/rust-lang/rust-clippy/pull/6267)
 +* [`wrong_self_convention`]: Now also lints in trait definitions
 +  [#6316](https://github.com/rust-lang/rust-clippy/pull/6316)
 +* [`needless_borrow`]: Print the type in the lint message
 +  [#6449](https://github.com/rust-lang/rust-clippy/pull/6449)
 +
 +[msrv_readme]: https://github.com/rust-lang/rust-clippy#specifying-the-minimum-supported-rust-version
 +
 +### False Positive Fixes
 +
 +* [`manual_range_contains`]: No longer lints in `const fn`
 +  [#6382](https://github.com/rust-lang/rust-clippy/pull/6382)
 +* [`unnecessary_lazy_evaluations`]: No longer lints if closure argument is used
 +  [#6370](https://github.com/rust-lang/rust-clippy/pull/6370)
 +* [`match_single_binding`]: Now ignores cases with `#[cfg()]` macros
 +  [#6435](https://github.com/rust-lang/rust-clippy/pull/6435)
 +* [`match_like_matches_macro`]: No longer lints on arms with attributes
 +  [#6290](https://github.com/rust-lang/rust-clippy/pull/6290)
 +* [`map_clone`]: No longer lints with deref and clone
 +  [#6269](https://github.com/rust-lang/rust-clippy/pull/6269)
 +* [`map_clone`]: No longer lints in the case of &mut
 +  [#6301](https://github.com/rust-lang/rust-clippy/pull/6301)
 +* [`needless_update`]: Now ignores `non_exhaustive` structs
 +  [#6464](https://github.com/rust-lang/rust-clippy/pull/6464)
 +* [`needless_collect`]: No longer lints when a collect is needed multiple times
 +  [#6313](https://github.com/rust-lang/rust-clippy/pull/6313)
 +* [`unnecessary_cast`] No longer lints cfg-dependent types
 +  [#6369](https://github.com/rust-lang/rust-clippy/pull/6369)
 +* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]:
 +  Both now ignore enums with frozen variants
 +  [#6110](https://github.com/rust-lang/rust-clippy/pull/6110)
 +* [`field_reassign_with_default`] No longer lint for private fields
 +  [#6537](https://github.com/rust-lang/rust-clippy/pull/6537)
 +
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`vec_box`]: Provide correct type scope suggestion
 +  [#6271](https://github.com/rust-lang/rust-clippy/pull/6271)
 +* [`manual_range_contains`]: Give correct suggestion when using floats
 +  [#6320](https://github.com/rust-lang/rust-clippy/pull/6320)
 +* [`unnecessary_lazy_evaluations`]: Don't always mark suggestion as MachineApplicable
 +  [#6272](https://github.com/rust-lang/rust-clippy/pull/6272)
 +* [`manual_async_fn`]: Improve suggestion formatting
 +  [#6294](https://github.com/rust-lang/rust-clippy/pull/6294)
 +* [`unnecessary_cast`]: Fix incorrectly formatted float literal suggestion
 +  [#6362](https://github.com/rust-lang/rust-clippy/pull/6362)
 +
 +### ICE Fixes
 +
 +* Fix a crash in [`from_iter_instead_of_collect`]
 +  [#6304](https://github.com/rust-lang/rust-clippy/pull/6304)
 +* Fix a silent crash when parsing doc comments in [`needless_doctest_main`]
 +  [#6458](https://github.com/rust-lang/rust-clippy/pull/6458)
 +
 +### Documentation Improvements
 +
 +* The lint website search has been improved ([#6477](https://github.com/rust-lang/rust-clippy/pull/6477)):
 +  * Searching for lints with dashes and spaces is possible now. For example
 +    `missing-errors-doc` and `missing errors doc` are now valid aliases for lint names
 +  * Improved fuzzy search in lint descriptions
 +* Various README improvements
 +  [#6287](https://github.com/rust-lang/rust-clippy/pull/6287)
 +* Add known problems to [`comparison_chain`] documentation
 +  [#6390](https://github.com/rust-lang/rust-clippy/pull/6390)
 +* Fix example used in [`cargo_common_metadata`]
 +  [#6293](https://github.com/rust-lang/rust-clippy/pull/6293)
 +* Improve [`map_clone`] documentation
 +  [#6340](https://github.com/rust-lang/rust-clippy/pull/6340)
 +
 +### Others
 +
 +* You can now tell Clippy about the MSRV your project supports. Please refer to
 +  the specific README section to learn more about MSRV support [here][msrv_readme]
 +  [#6201](https://github.com/rust-lang/rust-clippy/pull/6201)
 +* Add `--no-deps` option to avoid running on path dependencies in workspaces
 +  [#6188](https://github.com/rust-lang/rust-clippy/pull/6188)
 +
 +## Rust 1.49
 +
 +Released 2020-12-31
 +
 +[e636b88...b20d4c1](https://github.com/rust-lang/rust-clippy/compare/e636b88...b20d4c1)
 +
 +### New Lints
 +
 +* [`field_reassign_with_default`] [#5911](https://github.com/rust-lang/rust-clippy/pull/5911)
 +* [`await_holding_refcell_ref`] [#6029](https://github.com/rust-lang/rust-clippy/pull/6029)
 +* [`disallowed_method`] [#6081](https://github.com/rust-lang/rust-clippy/pull/6081)
 +* [`inline_asm_x86_att_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
 +* [`inline_asm_x86_intel_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092)
 +* [`from_iter_instead_of_collect`] [#6101](https://github.com/rust-lang/rust-clippy/pull/6101)
 +* [`mut_mutex_lock`] [#6103](https://github.com/rust-lang/rust-clippy/pull/6103)
 +* [`single_element_loop`] [#6109](https://github.com/rust-lang/rust-clippy/pull/6109)
 +* [`manual_unwrap_or`] [#6123](https://github.com/rust-lang/rust-clippy/pull/6123)
 +* [`large_types_passed_by_value`] [#6135](https://github.com/rust-lang/rust-clippy/pull/6135)
 +* [`result_unit_err`] [#6157](https://github.com/rust-lang/rust-clippy/pull/6157)
 +* [`ref_option_ref`] [#6165](https://github.com/rust-lang/rust-clippy/pull/6165)
 +* [`manual_range_contains`] [#6177](https://github.com/rust-lang/rust-clippy/pull/6177)
 +* [`unusual_byte_groupings`] [#6183](https://github.com/rust-lang/rust-clippy/pull/6183)
 +* [`comparison_to_empty`] [#6226](https://github.com/rust-lang/rust-clippy/pull/6226)
 +* [`map_collect_result_unit`] [#6227](https://github.com/rust-lang/rust-clippy/pull/6227)
 +* [`manual_ok_or`] [#6233](https://github.com/rust-lang/rust-clippy/pull/6233)
 +
 +### Moves and Deprecations
 +
 +* Rename `single_char_push_str` to [`single_char_add_str`]
 +  [#6037](https://github.com/rust-lang/rust-clippy/pull/6037)
 +* Rename `zero_width_space` to [`invisible_characters`]
 +  [#6105](https://github.com/rust-lang/rust-clippy/pull/6105)
 +* Deprecate `drop_bounds` (uplifted)
 +  [#6111](https://github.com/rust-lang/rust-clippy/pull/6111)
 +* Move [`string_lit_as_bytes`] to `nursery`
 +  [#6117](https://github.com/rust-lang/rust-clippy/pull/6117)
 +* Move [`rc_buffer`] to `restriction`
 +  [#6128](https://github.com/rust-lang/rust-clippy/pull/6128)
 +
 +### Enhancements
 +
 +* [`manual_memcpy`]: Also lint when there are loop counters (and produce a
 +  reliable suggestion)
 +  [#5727](https://github.com/rust-lang/rust-clippy/pull/5727)
 +* [`single_char_add_str`]: Also lint on `String::insert_str`
 +  [#6037](https://github.com/rust-lang/rust-clippy/pull/6037)
 +* [`invisible_characters`]: Also lint the characters `\u{AD}` and `\u{2060}`
 +  [#6105](https://github.com/rust-lang/rust-clippy/pull/6105)
 +* [`eq_op`]: Also lint on the `assert_*!` macro family
 +  [#6167](https://github.com/rust-lang/rust-clippy/pull/6167)
 +* [`items_after_statements`]: Also lint in local macro expansions
 +  [#6176](https://github.com/rust-lang/rust-clippy/pull/6176)
 +* [`unnecessary_cast`]: Also lint casts on integer and float literals
 +  [#6187](https://github.com/rust-lang/rust-clippy/pull/6187)
 +* [`manual_unwrap_or`]: Also lint `Result::unwrap_or`
 +  [#6190](https://github.com/rust-lang/rust-clippy/pull/6190)
 +* [`match_like_matches_macro`]: Also lint when `match` has more than two arms
 +  [#6216](https://github.com/rust-lang/rust-clippy/pull/6216)
 +* [`integer_arithmetic`]: Better handle `/` an `%` operators
 +  [#6229](https://github.com/rust-lang/rust-clippy/pull/6229)
 +
 +### False Positive Fixes
 +
 +* [`needless_lifetimes`]: Bail out if the function has a `where` clause with the
 +  lifetime [#5978](https://github.com/rust-lang/rust-clippy/pull/5978)
 +* [`explicit_counter_loop`]: No longer lints, when loop counter is used after it
 +  is incremented [#6076](https://github.com/rust-lang/rust-clippy/pull/6076)
 +* [`or_fun_call`]: Revert changes addressing the handling of `const fn`
 +  [#6077](https://github.com/rust-lang/rust-clippy/pull/6077)
 +* [`needless_range_loop`]: No longer lints, when the iterable is used in the
 +  range [#6102](https://github.com/rust-lang/rust-clippy/pull/6102)
 +* [`inconsistent_digit_grouping`]: Fix bug when using floating point exponent
 +  [#6104](https://github.com/rust-lang/rust-clippy/pull/6104)
 +* [`mistyped_literal_suffixes`]: No longer lints on the fractional part of a
 +  float (e.g. `713.32_64`)
 +  [#6114](https://github.com/rust-lang/rust-clippy/pull/6114)
 +* [`invalid_regex`]: No longer lint on unicode characters within `bytes::Regex`
 +  [#6132](https://github.com/rust-lang/rust-clippy/pull/6132)
 +* [`boxed_local`]: No longer lints on `extern fn` arguments
 +  [#6133](https://github.com/rust-lang/rust-clippy/pull/6133)
 +* [`needless_lifetimes`]: Fix regression, where lifetime is used in `where`
 +  clause [#6198](https://github.com/rust-lang/rust-clippy/pull/6198)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`unnecessary_sort_by`]: Avoid dereferencing the suggested closure parameter
 +  [#6078](https://github.com/rust-lang/rust-clippy/pull/6078)
 +* [`needless_arbitrary_self_type`]: Correctly handle expanded code
 +  [#6093](https://github.com/rust-lang/rust-clippy/pull/6093)
 +* [`useless_format`]: Preserve raw strings in suggestion
 +  [#6151](https://github.com/rust-lang/rust-clippy/pull/6151)
 +* [`empty_loop`]: Suggest alternatives
 +  [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
 +* [`borrowed_box`]: Correctly add parentheses in suggestion
 +  [#6200](https://github.com/rust-lang/rust-clippy/pull/6200)
 +* [`unused_unit`]: Improve suggestion formatting
 +  [#6247](https://github.com/rust-lang/rust-clippy/pull/6247)
 +
 +### Documentation Improvements
 +
 +* Some doc improvements:
 +    * [`rc_buffer`] [#6090](https://github.com/rust-lang/rust-clippy/pull/6090)
 +    * [`empty_loop`] [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
 +* [`doc_markdown`]: Document problematic link text style
 +  [#6107](https://github.com/rust-lang/rust-clippy/pull/6107)
 +
 +## Rust 1.48
 +
 +Released 2020-11-19
 +
 +[09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88)
 +
 +### New lints
 +
 +* [`self_assignment`] [#5894](https://github.com/rust-lang/rust-clippy/pull/5894)
 +* [`unnecessary_lazy_evaluations`] [#5720](https://github.com/rust-lang/rust-clippy/pull/5720)
 +* [`manual_strip`] [#6038](https://github.com/rust-lang/rust-clippy/pull/6038)
 +* [`map_err_ignore`] [#5998](https://github.com/rust-lang/rust-clippy/pull/5998)
 +* [`rc_buffer`] [#6044](https://github.com/rust-lang/rust-clippy/pull/6044)
 +* [`to_string_in_display`] [#5831](https://github.com/rust-lang/rust-clippy/pull/5831)
 +* `single_char_push_str` [#5881](https://github.com/rust-lang/rust-clippy/pull/5881)
 +
 +### Moves and Deprecations
 +
 +* Downgrade [`verbose_bit_mask`] to pedantic
 +  [#6036](https://github.com/rust-lang/rust-clippy/pull/6036)
 +
 +### Enhancements
 +
 +* Extend [`precedence`] to handle chains of methods combined with unary negation
 +  [#5928](https://github.com/rust-lang/rust-clippy/pull/5928)
 +* [`useless_vec`]: add a configuration value for the maximum allowed size on the stack
 +  [#5907](https://github.com/rust-lang/rust-clippy/pull/5907)
 +* [`suspicious_arithmetic_impl`]: extend to implementations of `BitAnd`, `BitOr`, `BitXor`, `Rem`, `Shl`, and `Shr`
 +  [#5884](https://github.com/rust-lang/rust-clippy/pull/5884)
 +* `invalid_atomic_ordering`: detect misuse of `compare_exchange`, `compare_exchange_weak`, and `fetch_update`
 +  [#6025](https://github.com/rust-lang/rust-clippy/pull/6025)
 +* Avoid [`redundant_pattern_matching`] triggering in macros
 +  [#6069](https://github.com/rust-lang/rust-clippy/pull/6069)
 +* [`option_if_let_else`]: distinguish pure from impure `else` expressions
 +  [#5937](https://github.com/rust-lang/rust-clippy/pull/5937)
 +* [`needless_doctest_main`]: parse doctests instead of using textual search
 +  [#5912](https://github.com/rust-lang/rust-clippy/pull/5912)
 +* [`wildcard_imports`]: allow `prelude` to appear in any segment of an import
 +  [#5929](https://github.com/rust-lang/rust-clippy/pull/5929)
 +* Re-enable [`len_zero`] for ranges now that `range_is_empty` is stable
 +  [#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
 +* [`option_as_ref_deref`]: catch fully-qualified calls to `Deref::deref` and `DerefMut::deref_mut`
 +  [#5933](https://github.com/rust-lang/rust-clippy/pull/5933)
 +
 +### False Positive Fixes
 +
 +* [`useless_attribute`]: permit allowing [`wildcard_imports`] and [`enum_glob_use`]
 +  [#5994](https://github.com/rust-lang/rust-clippy/pull/5994)
 +* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts
 +  [#5999](https://github.com/rust-lang/rust-clippy/pull/5999)
 +* [`redundant_closure_call`]: take into account usages of the closure in nested functions and closures
 +  [#5920](https://github.com/rust-lang/rust-clippy/pull/5920)
 +* Fix false positive in [`borrow_interior_mutable_const`] when referencing a field behind a pointer
 +  [#5949](https://github.com/rust-lang/rust-clippy/pull/5949)
 +* [`doc_markdown`]: allow using "GraphQL" without backticks
 +  [#5996](https://github.com/rust-lang/rust-clippy/pull/5996)
 +* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self`
 +  [#5971](https://github.com/rust-lang/rust-clippy/pull/5971)
 +* [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays
 +  [#6034](https://github.com/rust-lang/rust-clippy/pull/6034)
 +* [`should_implement_trait`]: ignore methods with lifetime parameters
 +  [#5725](https://github.com/rust-lang/rust-clippy/pull/5725)
 +* [`needless_return`]: avoid linting if a temporary borrows a local variable
 +  [#5903](https://github.com/rust-lang/rust-clippy/pull/5903)
 +* Restrict [`unnecessary_sort_by`] to non-reference, Copy types
 +  [#6006](https://github.com/rust-lang/rust-clippy/pull/6006)
 +* Avoid suggesting `from_bits`/`to_bits` in const contexts in [`transmute_int_to_float`]
 +  [#5919](https://github.com/rust-lang/rust-clippy/pull/5919)
 +* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]: improve detection of interior mutable types
 +  [#6046](https://github.com/rust-lang/rust-clippy/pull/6046)
 +
 +### Suggestion Fixes/Improvements
 +
 +* [`let_and_return`]: add a cast to the suggestion when the return expression has adjustments
 +  [#5946](https://github.com/rust-lang/rust-clippy/pull/5946)
 +* [`useless_conversion`]: show the type in the error message
 +  [#6035](https://github.com/rust-lang/rust-clippy/pull/6035)
 +* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message
 +  [#5892](https://github.com/rust-lang/rust-clippy/pull/5892)
 +* [`float_cmp`] and [`float_cmp_const`]: change wording to make margin of error less ambiguous
 +  [#6043](https://github.com/rust-lang/rust-clippy/pull/6043)
 +* [`default_trait_access`]: do not use unnecessary type parameters in the suggestion
 +  [#5993](https://github.com/rust-lang/rust-clippy/pull/5993)
 +* [`collapsible_if`]: don't use expanded code in the suggestion
 +  [#5992](https://github.com/rust-lang/rust-clippy/pull/5992)
 +* Do not suggest empty format strings in [`print_with_newline`] and [`write_with_newline`]
 +  [#6042](https://github.com/rust-lang/rust-clippy/pull/6042)
 +* [`unit_arg`]: improve the readability of the suggestion
 +  [#5931](https://github.com/rust-lang/rust-clippy/pull/5931)
 +* [`stable_sort_primitive`]: print the type that is being sorted in the lint message
 +  [#5935](https://github.com/rust-lang/rust-clippy/pull/5935)
 +* Show line count and max lines in [`too_many_lines`] lint message
 +  [#6009](https://github.com/rust-lang/rust-clippy/pull/6009)
 +* Keep parentheses in the suggestion of [`useless_conversion`] where applicable
 +  [#5900](https://github.com/rust-lang/rust-clippy/pull/5900)
 +* [`option_map_unit_fn`] and [`result_map_unit_fn`]: print the unit type `()` explicitly
 +  [#6024](https://github.com/rust-lang/rust-clippy/pull/6024)
 +* [`redundant_allocation`]: suggest replacing `Rc<Box<T>>` with `Rc<T>`
 +  [#5899](https://github.com/rust-lang/rust-clippy/pull/5899)
 +* Make lint messages adhere to rustc dev guide conventions
 +  [#5893](https://github.com/rust-lang/rust-clippy/pull/5893)
 +
 +### ICE Fixes
 +
 +* Fix ICE in [`repeat_once`]
 +  [#5948](https://github.com/rust-lang/rust-clippy/pull/5948)
 +
 +### Documentation Improvements
 +
 +* [`mutable_key_type`]: explain potential for false positives when the interior mutable type is not accessed in the `Hash` implementation
 +  [#6019](https://github.com/rust-lang/rust-clippy/pull/6019)
 +* [`unnecessary_mut_passed`]: fix typo
 +  [#5913](https://github.com/rust-lang/rust-clippy/pull/5913)
 +* Add example of false positive to [`ptr_arg`] docs.
 +  [#5885](https://github.com/rust-lang/rust-clippy/pull/5885)
 +* [`box_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection), [`vec_box`] and [`borrowed_box`]: add link to the documentation of `Box`
 +  [#6023](https://github.com/rust-lang/rust-clippy/pull/6023)
 +
 +## Rust 1.47
 +
 +Released 2020-10-08
 +
 +[c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400)
 +
 +### New lints
 +
 +* [`derive_ord_xor_partial_ord`] [#5848](https://github.com/rust-lang/rust-clippy/pull/5848)
 +* [`trait_duplication_in_bounds`] [#5852](https://github.com/rust-lang/rust-clippy/pull/5852)
 +* [`map_identity`] [#5694](https://github.com/rust-lang/rust-clippy/pull/5694)
 +* [`unit_return_expecting_ord`] [#5737](https://github.com/rust-lang/rust-clippy/pull/5737)
 +* [`pattern_type_mismatch`] [#4841](https://github.com/rust-lang/rust-clippy/pull/4841)
 +* [`repeat_once`] [#5773](https://github.com/rust-lang/rust-clippy/pull/5773)
 +* [`same_item_push`] [#5825](https://github.com/rust-lang/rust-clippy/pull/5825)
 +* [`needless_arbitrary_self_type`] [#5869](https://github.com/rust-lang/rust-clippy/pull/5869)
 +* [`match_like_matches_macro`] [#5769](https://github.com/rust-lang/rust-clippy/pull/5769)
 +* [`stable_sort_primitive`] [#5809](https://github.com/rust-lang/rust-clippy/pull/5809)
 +* [`blanket_clippy_restriction_lints`] [#5750](https://github.com/rust-lang/rust-clippy/pull/5750)
 +* [`option_if_let_else`] [#5301](https://github.com/rust-lang/rust-clippy/pull/5301)
 +
 +### Moves and Deprecations
 +
 +* Deprecate [`regex_macro`] lint
 +  [#5760](https://github.com/rust-lang/rust-clippy/pull/5760)
 +* Move [`range_minus_one`] to `pedantic`
 +  [#5752](https://github.com/rust-lang/rust-clippy/pull/5752)
 +
 +### Enhancements
 +
 +* Improve [`needless_collect`] by catching `collect` calls followed by `iter` or `into_iter` calls
 +  [#5837](https://github.com/rust-lang/rust-clippy/pull/5837)
 +* [`panic`], [`todo`], [`unimplemented`] and [`unreachable`] now detect calls with formatting
 +  [#5811](https://github.com/rust-lang/rust-clippy/pull/5811)
 +* Detect more cases of [`suboptimal_flops`] and [`imprecise_flops`]
 +  [#5443](https://github.com/rust-lang/rust-clippy/pull/5443)
 +* Handle asymmetrical implementations of `PartialEq` in [`cmp_owned`]
 +  [#5701](https://github.com/rust-lang/rust-clippy/pull/5701)
 +* Make it possible to allow [`unsafe_derive_deserialize`]
 +  [#5870](https://github.com/rust-lang/rust-clippy/pull/5870)
 +* Catch `ord.min(a).max(b)` where a < b in [`min_max`]
 +  [#5871](https://github.com/rust-lang/rust-clippy/pull/5871)
 +* Make [`clone_on_copy`] suggestion machine applicable
 +  [#5745](https://github.com/rust-lang/rust-clippy/pull/5745)
 +* Enable [`len_zero`] on ranges now that `is_empty` is stable on them
 +  [#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
 +
 +### False Positive Fixes
 +
 +* Avoid triggering [`or_fun_call`] with const fns that take no arguments
 +  [#5889](https://github.com/rust-lang/rust-clippy/pull/5889)
 +* Fix [`redundant_closure_call`] false positive for closures that have multiple calls
 +  [#5800](https://github.com/rust-lang/rust-clippy/pull/5800)
 +* Don't lint cases involving `ManuallyDrop` in [`redundant_clone`]
 +  [#5824](https://github.com/rust-lang/rust-clippy/pull/5824)
 +* Treat a single expression the same as a single statement in the 2nd arm of a match in [`single_match_else`]
 +  [#5771](https://github.com/rust-lang/rust-clippy/pull/5771)
 +* Don't trigger [`unnested_or_patterns`] if the feature `or_patterns` is not enabled
 +  [#5758](https://github.com/rust-lang/rust-clippy/pull/5758)
 +* Avoid linting if key borrows in [`unnecessary_sort_by`]
 +  [#5756](https://github.com/rust-lang/rust-clippy/pull/5756)
 +* Consider `Try` impl for `Poll` when generating suggestions in [`try_err`]
 +  [#5857](https://github.com/rust-lang/rust-clippy/pull/5857)
 +* Take input lifetimes into account in `manual_async_fn`
 +  [#5859](https://github.com/rust-lang/rust-clippy/pull/5859)
 +* Fix multiple false positives in [`type_repetition_in_bounds`] and add a configuration option
 +  [#5761](https://github.com/rust-lang/rust-clippy/pull/5761)
 +* Limit the [`suspicious_arithmetic_impl`] lint to one binary operation
 +  [#5820](https://github.com/rust-lang/rust-clippy/pull/5820)
 +
 +### Suggestion Fixes/Improvements
 +
 +* Improve readability of [`shadow_unrelated`] suggestion by truncating the RHS snippet
 +  [#5788](https://github.com/rust-lang/rust-clippy/pull/5788)
 +* Suggest `filter_map` instead of `flat_map` when mapping to `Option` in [`map_flatten`]
 +  [#5846](https://github.com/rust-lang/rust-clippy/pull/5846)
 +* Ensure suggestion is shown correctly for long method call chains in [`iter_nth_zero`]
 +  [#5793](https://github.com/rust-lang/rust-clippy/pull/5793)
 +* Drop borrow operator in suggestions of [`redundant_pattern_matching`]
 +  [#5815](https://github.com/rust-lang/rust-clippy/pull/5815)
 +* Add suggestion for [`iter_skip_next`]
 +  [#5843](https://github.com/rust-lang/rust-clippy/pull/5843)
 +* Improve [`collapsible_if`] fix suggestion
 +  [#5732](https://github.com/rust-lang/rust-clippy/pull/5732)
 +
 +### ICE Fixes
 +
 +* Fix ICE caused by [`needless_collect`]
 +  [#5877](https://github.com/rust-lang/rust-clippy/pull/5877)
 +* Fix ICE caused by [`unnested_or_patterns`]
 +  [#5784](https://github.com/rust-lang/rust-clippy/pull/5784)
 +
 +### Documentation Improvements
 +
 +* Fix grammar of [`await_holding_lock`] documentation
 +  [#5748](https://github.com/rust-lang/rust-clippy/pull/5748)
 +
 +### Others
 +
 +* Make lints adhere to the rustc dev guide
 +  [#5888](https://github.com/rust-lang/rust-clippy/pull/5888)
 +
 +## Rust 1.46
 +
 +Released 2020-08-27
 +
 +[7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa)
 +
 +### New lints
 +
 +* [`unnested_or_patterns`] [#5378](https://github.com/rust-lang/rust-clippy/pull/5378)
 +* [`iter_next_slice`] [#5597](https://github.com/rust-lang/rust-clippy/pull/5597)
 +* [`unnecessary_sort_by`] [#5623](https://github.com/rust-lang/rust-clippy/pull/5623)
 +* [`vec_resize_to_zero`] [#5637](https://github.com/rust-lang/rust-clippy/pull/5637)
 +
 +### Moves and Deprecations
 +
 +* Move [`cast_ptr_alignment`] to pedantic [#5667](https://github.com/rust-lang/rust-clippy/pull/5667)
 +
 +### Enhancements
 +
 +* Improve [`mem_replace_with_uninit`] lint [#5695](https://github.com/rust-lang/rust-clippy/pull/5695)
 +
 +### False Positive Fixes
 +
 +* [`len_zero`]: Avoid linting ranges when the `range_is_empty` feature is not enabled
 +  [#5656](https://github.com/rust-lang/rust-clippy/pull/5656)
 +* [`let_and_return`]: Don't lint if a temporary borrow is involved
 +  [#5680](https://github.com/rust-lang/rust-clippy/pull/5680)
 +* [`reversed_empty_ranges`]: Avoid linting `N..N` in for loop arguments in
 +  [#5692](https://github.com/rust-lang/rust-clippy/pull/5692)
 +* [`if_same_then_else`]: Don't assume multiplication is always commutative
 +  [#5702](https://github.com/rust-lang/rust-clippy/pull/5702)
 +* [`blacklisted_name`]: Remove `bar` from the default configuration
 +  [#5712](https://github.com/rust-lang/rust-clippy/pull/5712)
 +* [`redundant_pattern_matching`]: Avoid suggesting non-`const fn` calls in const contexts
 +  [#5724](https://github.com/rust-lang/rust-clippy/pull/5724)
 +
 +### Suggestion Fixes/Improvements
 +
 +* Fix suggestion of [`unit_arg`] lint, so that it suggest semantic equivalent code
 +  [#4455](https://github.com/rust-lang/rust-clippy/pull/4455)
 +* Add auto applicable suggestion to [`macro_use_imports`]
 +  [#5279](https://github.com/rust-lang/rust-clippy/pull/5279)
 +
 +### ICE Fixes
 +
 +* Fix ICE in the `consts` module of Clippy [#5709](https://github.com/rust-lang/rust-clippy/pull/5709)
 +
 +### Documentation Improvements
 +
 +* Improve code examples across multiple lints [#5664](https://github.com/rust-lang/rust-clippy/pull/5664)
 +
 +### Others
 +
 +* Introduce a `--rustc` flag to `clippy-driver`, which turns `clippy-driver`
 +  into `rustc` and passes all the given arguments to `rustc`. This is especially
 +  useful for tools that need the `rustc` version Clippy was compiled with,
 +  instead of the Clippy version. E.g. `clippy-driver --rustc --version` will
 +  print the output of `rustc --version`.
 +  [#5178](https://github.com/rust-lang/rust-clippy/pull/5178)
 +* New issue templates now make it easier to complain if Clippy is too annoying
 +  or not annoying enough! [#5735](https://github.com/rust-lang/rust-clippy/pull/5735)
 +
 +## Rust 1.45
 +
 +Released 2020-07-16
 +
 +[891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1)
 +
 +### New lints
 +
 +* [`match_wildcard_for_single_variants`] [#5582](https://github.com/rust-lang/rust-clippy/pull/5582)
 +* [`unsafe_derive_deserialize`] [#5493](https://github.com/rust-lang/rust-clippy/pull/5493)
 +* [`if_let_mutex`] [#5332](https://github.com/rust-lang/rust-clippy/pull/5332)
 +* [`mismatched_target_os`] [#5506](https://github.com/rust-lang/rust-clippy/pull/5506)
 +* [`await_holding_lock`] [#5439](https://github.com/rust-lang/rust-clippy/pull/5439)
 +* [`match_on_vec_items`] [#5522](https://github.com/rust-lang/rust-clippy/pull/5522)
 +* [`manual_async_fn`] [#5576](https://github.com/rust-lang/rust-clippy/pull/5576)
 +* [`reversed_empty_ranges`] [#5583](https://github.com/rust-lang/rust-clippy/pull/5583)
 +* [`manual_non_exhaustive`] [#5550](https://github.com/rust-lang/rust-clippy/pull/5550)
 +
 +### Moves and Deprecations
 +
 +* Downgrade [`match_bool`] to pedantic [#5408](https://github.com/rust-lang/rust-clippy/pull/5408)
 +* Downgrade [`match_wild_err_arm`] to pedantic and update help messages. [#5622](https://github.com/rust-lang/rust-clippy/pull/5622)
 +* Downgrade [`useless_let_if_seq`] to nursery. [#5599](https://github.com/rust-lang/rust-clippy/pull/5599)
 +* Generalize `option_and_then_some` and rename to [`bind_instead_of_map`]. [#5529](https://github.com/rust-lang/rust-clippy/pull/5529)
 +* Rename `identity_conversion` to [`useless_conversion`]. [#5568](https://github.com/rust-lang/rust-clippy/pull/5568)
 +* Merge `block_in_if_condition_expr` and `block_in_if_condition_stmt` into [`blocks_in_if_conditions`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_map_unwrap_or`, `option_map_unwrap_or_else` and `result_map_unwrap_or_else` into [`map_unwrap_or`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_unwrap_used` and `result_unwrap_used` into [`unwrap_used`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `option_expect_used` and `result_expect_used` into [`expect_used`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +* Merge `for_loop_over_option` and `for_loop_over_result` into [`for_loops_over_fallibles`].
 +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
 +
 +### Enhancements
 +
 +* Avoid running cargo lints when not enabled to improve performance. [#5505](https://github.com/rust-lang/rust-clippy/pull/5505)
 +* Extend [`useless_conversion`] with `TryFrom` and `TryInto`. [#5631](https://github.com/rust-lang/rust-clippy/pull/5631)
 +* Lint also in type parameters and where clauses in [`unused_unit`]. [#5592](https://github.com/rust-lang/rust-clippy/pull/5592)
 +* Do not suggest deriving `Default` in [`new_without_default`]. [#5616](https://github.com/rust-lang/rust-clippy/pull/5616)
 +
 +### False Positive Fixes
 +
 +* [`while_let_on_iterator`] [#5525](https://github.com/rust-lang/rust-clippy/pull/5525)
 +* [`empty_line_after_outer_attr`] [#5609](https://github.com/rust-lang/rust-clippy/pull/5609)
 +* [`unnecessary_unwrap`] [#5558](https://github.com/rust-lang/rust-clippy/pull/5558)
 +* [`comparison_chain`] [#5596](https://github.com/rust-lang/rust-clippy/pull/5596)
 +* Don't trigger [`used_underscore_binding`] in await desugaring. [#5535](https://github.com/rust-lang/rust-clippy/pull/5535)
 +* Don't trigger [`borrowed_box`] on mutable references. [#5491](https://github.com/rust-lang/rust-clippy/pull/5491)
 +* Allow `1 << 0` in [`identity_op`]. [#5602](https://github.com/rust-lang/rust-clippy/pull/5602)
 +* Allow `use super::*;` glob imports in [`wildcard_imports`]. [#5564](https://github.com/rust-lang/rust-clippy/pull/5564)
 +* Whitelist more words in [`doc_markdown`]. [#5611](https://github.com/rust-lang/rust-clippy/pull/5611)
 +* Skip dev and build deps in [`multiple_crate_versions`]. [#5636](https://github.com/rust-lang/rust-clippy/pull/5636)
 +* Honor `allow` attribute on arguments in [`ptr_arg`]. [#5647](https://github.com/rust-lang/rust-clippy/pull/5647)
 +* Honor lint level attributes for [`redundant_field_names`], [`just_underscores_and_digits`], [`many_single_char_names`]
 +and [`similar_names`]. [#5651](https://github.com/rust-lang/rust-clippy/pull/5651)
 +* Ignore calls to `len` in [`or_fun_call`]. [#4429](https://github.com/rust-lang/rust-clippy/pull/4429)
 +
 +### Suggestion Improvements
 +
 +* Simplify suggestions in [`manual_memcpy`]. [#5536](https://github.com/rust-lang/rust-clippy/pull/5536)
 +* Fix suggestion in [`redundant_pattern_matching`] for macros. [#5511](https://github.com/rust-lang/rust-clippy/pull/5511)
 +* Avoid suggesting `copied()` for mutable references in [`map_clone`]. [#5530](https://github.com/rust-lang/rust-clippy/pull/5530)
 +* Improve help message for [`clone_double_ref`]. [#5547](https://github.com/rust-lang/rust-clippy/pull/5547)
 +
 +### ICE Fixes
 +
 +* Fix ICE caused in unwrap module. [#5590](https://github.com/rust-lang/rust-clippy/pull/5590)
 +* Fix ICE on rustc test issue-69020-assoc-const-arith-overflow.rs [#5499](https://github.com/rust-lang/rust-clippy/pull/5499)
 +
 +### Documentation
 +
 +* Clarify the documentation of [`unnecessary_mut_passed`]. [#5639](https://github.com/rust-lang/rust-clippy/pull/5639)
 +* Extend example for [`unneeded_field_pattern`]. [#5541](https://github.com/rust-lang/rust-clippy/pull/5541)
 +
 +## Rust 1.44
 +
 +Released 2020-06-04
 +
 +[204bb9b...891e1a8](https://github.com/rust-lang/rust-clippy/compare/204bb9b...891e1a8)
 +
 +### New lints
 +
 +* [`explicit_deref_methods`] [#5226](https://github.com/rust-lang/rust-clippy/pull/5226)
 +* [`implicit_saturating_sub`] [#5427](https://github.com/rust-lang/rust-clippy/pull/5427)
 +* [`macro_use_imports`] [#5230](https://github.com/rust-lang/rust-clippy/pull/5230)
 +* [`verbose_file_reads`] [#5272](https://github.com/rust-lang/rust-clippy/pull/5272)
 +* [`future_not_send`] [#5423](https://github.com/rust-lang/rust-clippy/pull/5423)
 +* [`redundant_pub_crate`] [#5319](https://github.com/rust-lang/rust-clippy/pull/5319)
 +* [`large_const_arrays`] [#5248](https://github.com/rust-lang/rust-clippy/pull/5248)
 +* [`result_map_or_into_option`] [#5415](https://github.com/rust-lang/rust-clippy/pull/5415)
 +* [`redundant_allocation`] [#5349](https://github.com/rust-lang/rust-clippy/pull/5349)
 +* [`fn_address_comparisons`] [#5294](https://github.com/rust-lang/rust-clippy/pull/5294)
 +* [`vtable_address_comparisons`] [#5294](https://github.com/rust-lang/rust-clippy/pull/5294)
 +
 +
 +### Moves and Deprecations
 +
 +* Deprecate [`replace_consts`] lint [#5380](https://github.com/rust-lang/rust-clippy/pull/5380)
 +* Move [`cognitive_complexity`] to nursery [#5428](https://github.com/rust-lang/rust-clippy/pull/5428)
 +* Move [`useless_transmute`] to nursery [#5364](https://github.com/rust-lang/rust-clippy/pull/5364)
 +* Downgrade [`inefficient_to_string`] to pedantic [#5412](https://github.com/rust-lang/rust-clippy/pull/5412)
 +* Downgrade [`option_option`] to pedantic [#5401](https://github.com/rust-lang/rust-clippy/pull/5401)
 +* Downgrade [`unreadable_literal`] to pedantic [#5419](https://github.com/rust-lang/rust-clippy/pull/5419)
 +* Downgrade [`let_unit_value`] to pedantic [#5409](https://github.com/rust-lang/rust-clippy/pull/5409)
 +* Downgrade [`trivially_copy_pass_by_ref`] to pedantic [#5410](https://github.com/rust-lang/rust-clippy/pull/5410)
 +* Downgrade [`implicit_hasher`] to pedantic [#5411](https://github.com/rust-lang/rust-clippy/pull/5411)
 +
 +### Enhancements
 +
 +* On _nightly_ you can now use `cargo clippy --fix -Z unstable-options` to
 +  auto-fix lints that support this [#5363](https://github.com/rust-lang/rust-clippy/pull/5363)
 +* Make [`redundant_clone`] also trigger on cases where the cloned value is not
 +  consumed. [#5304](https://github.com/rust-lang/rust-clippy/pull/5304)
 +* Expand [`integer_arithmetic`] to also disallow bit-shifting [#5430](https://github.com/rust-lang/rust-clippy/pull/5430)
 +* [`option_as_ref_deref`] now detects more deref cases [#5425](https://github.com/rust-lang/rust-clippy/pull/5425)
 +* [`large_enum_variant`] now report the sizes of the largest and second-largest variants [#5466](https://github.com/rust-lang/rust-clippy/pull/5466)
 +* [`bool_comparison`] now also checks for inequality comparisons that can be
 +  written more concisely [#5365](https://github.com/rust-lang/rust-clippy/pull/5365)
 +* Expand [`clone_on_copy`] to work in method call arguments as well [#5441](https://github.com/rust-lang/rust-clippy/pull/5441)
 +* [`redundant_pattern_matching`] now also handles `while let` [#5483](https://github.com/rust-lang/rust-clippy/pull/5483)
 +* [`integer_arithmetic`] now also lints references of integers [#5329](https://github.com/rust-lang/rust-clippy/pull/5329)
 +* Expand [`float_cmp_const`] to also work on arrays [#5345](https://github.com/rust-lang/rust-clippy/pull/5345)
 +* Trigger [`map_flatten`] when map is called on an `Option` [#5473](https://github.com/rust-lang/rust-clippy/pull/5473)
 +
 +### False Positive Fixes
 +
 +* [`many_single_char_names`] [#5468](https://github.com/rust-lang/rust-clippy/pull/5468)
 +* [`should_implement_trait`] [#5437](https://github.com/rust-lang/rust-clippy/pull/5437)
 +* [`unused_self`] [#5387](https://github.com/rust-lang/rust-clippy/pull/5387)
 +* [`redundant_clone`] [#5453](https://github.com/rust-lang/rust-clippy/pull/5453)
 +* [`precedence`] [#5445](https://github.com/rust-lang/rust-clippy/pull/5445)
 +* [`suspicious_op_assign_impl`] [#5424](https://github.com/rust-lang/rust-clippy/pull/5424)
 +* [`needless_lifetimes`] [#5293](https://github.com/rust-lang/rust-clippy/pull/5293)
 +* [`redundant_pattern`] [#5287](https://github.com/rust-lang/rust-clippy/pull/5287)
 +* [`inconsistent_digit_grouping`] [#5451](https://github.com/rust-lang/rust-clippy/pull/5451)
 +
 +
 +### Suggestion Improvements
 +
 +* Improved [`question_mark`] lint suggestion so that it doesn't add redundant `as_ref()` [#5481](https://github.com/rust-lang/rust-clippy/pull/5481)
 +* Improve the suggested placeholder in [`option_map_unit_fn`] [#5292](https://github.com/rust-lang/rust-clippy/pull/5292)
 +* Improve suggestion for [`match_single_binding`] when triggered inside a closure [#5350](https://github.com/rust-lang/rust-clippy/pull/5350)
 +
 +### ICE Fixes
 +
 +* Handle the unstable `trivial_bounds` feature [#5296](https://github.com/rust-lang/rust-clippy/pull/5296)
 +* `shadow_*` lints [#5297](https://github.com/rust-lang/rust-clippy/pull/5297)
 +
 +### Documentation
 +
 +* Fix documentation generation for configurable lints [#5353](https://github.com/rust-lang/rust-clippy/pull/5353)
 +* Update documentation for [`new_ret_no_self`] [#5448](https://github.com/rust-lang/rust-clippy/pull/5448)
 +* The documentation for [`option_option`] now suggest using a tri-state enum [#5403](https://github.com/rust-lang/rust-clippy/pull/5403)
 +* Fix bit mask example in [`verbose_bit_mask`] documentation [#5454](https://github.com/rust-lang/rust-clippy/pull/5454)
 +* [`wildcard_imports`] documentation now mentions that `use ...::prelude::*` is
 +  not linted [#5312](https://github.com/rust-lang/rust-clippy/pull/5312)
 +
 +## Rust 1.43
 +
 +Released 2020-04-23
 +
 +[4ee1206...204bb9b](https://github.com/rust-lang/rust-clippy/compare/4ee1206...204bb9b)
 +
 +### New lints
 +
 +* [`imprecise_flops`] [#4897](https://github.com/rust-lang/rust-clippy/pull/4897)
 +* [`suboptimal_flops`] [#4897](https://github.com/rust-lang/rust-clippy/pull/4897)
 +* [`wildcard_imports`] [#5029](https://github.com/rust-lang/rust-clippy/pull/5029)
 +* [`single_component_path_imports`] [#5058](https://github.com/rust-lang/rust-clippy/pull/5058)
 +* [`match_single_binding`] [#5061](https://github.com/rust-lang/rust-clippy/pull/5061)
 +* [`let_underscore_lock`] [#5101](https://github.com/rust-lang/rust-clippy/pull/5101)
 +* [`struct_excessive_bools`] [#5125](https://github.com/rust-lang/rust-clippy/pull/5125)
 +* [`fn_params_excessive_bools`] [#5125](https://github.com/rust-lang/rust-clippy/pull/5125)
 +* [`option_env_unwrap`] [#5148](https://github.com/rust-lang/rust-clippy/pull/5148)
 +* [`lossy_float_literal`] [#5202](https://github.com/rust-lang/rust-clippy/pull/5202)
 +* [`rest_pat_in_fully_bound_structs`] [#5258](https://github.com/rust-lang/rust-clippy/pull/5258)
 +
 +### Moves and Deprecations
 +
 +* Move [`unneeded_field_pattern`] to pedantic group [#5200](https://github.com/rust-lang/rust-clippy/pull/5200)
 +
 +### Enhancements
 +
 +* Make [`missing_errors_doc`] lint also trigger on `async` functions
 +  [#5181](https://github.com/rust-lang/rust-clippy/pull/5181)
 +* Add more constants to [`approx_constant`] [#5193](https://github.com/rust-lang/rust-clippy/pull/5193)
 +* Extend [`question_mark`] lint [#5266](https://github.com/rust-lang/rust-clippy/pull/5266)
 +
 +### False Positive Fixes
 +
 +* [`use_debug`] [#5047](https://github.com/rust-lang/rust-clippy/pull/5047)
 +* [`unnecessary_unwrap`] [#5132](https://github.com/rust-lang/rust-clippy/pull/5132)
 +* [`zero_prefixed_literal`] [#5170](https://github.com/rust-lang/rust-clippy/pull/5170)
 +* [`missing_const_for_fn`] [#5216](https://github.com/rust-lang/rust-clippy/pull/5216)
 +
 +### Suggestion Improvements
 +
 +* Improve suggestion when blocks of code are suggested [#5134](https://github.com/rust-lang/rust-clippy/pull/5134)
 +
 +### ICE Fixes
 +
 +* `misc_early` lints [#5129](https://github.com/rust-lang/rust-clippy/pull/5129)
 +* [`missing_errors_doc`] [#5213](https://github.com/rust-lang/rust-clippy/pull/5213)
 +* Fix ICE when evaluating `usize`s [#5256](https://github.com/rust-lang/rust-clippy/pull/5256)
 +
 +### Documentation
 +
 +* Improve documentation of [`iter_nth_zero`]
 +* Add documentation pages for stable releases [#5171](https://github.com/rust-lang/rust-clippy/pull/5171)
 +
 +### Others
 +
 +* Clippy now completely runs on GitHub Actions [#5190](https://github.com/rust-lang/rust-clippy/pull/5190)
 +
 +
 +## Rust 1.42
 +
 +Released 2020-03-12
 +
 +[69f99e7...4ee1206](https://github.com/rust-lang/rust-clippy/compare/69f99e7...4ee1206)
 +
 +### New lints
 +
 +* [`filetype_is_file`] [#4543](https://github.com/rust-lang/rust-clippy/pull/4543)
 +* [`let_underscore_must_use`] [#4823](https://github.com/rust-lang/rust-clippy/pull/4823)
 +* [`modulo_arithmetic`] [#4867](https://github.com/rust-lang/rust-clippy/pull/4867)
 +* [`mem_replace_with_default`] [#4881](https://github.com/rust-lang/rust-clippy/pull/4881)
 +* [`mutable_key_type`] [#4885](https://github.com/rust-lang/rust-clippy/pull/4885)
 +* [`option_as_ref_deref`] [#4945](https://github.com/rust-lang/rust-clippy/pull/4945)
 +* [`wildcard_in_or_patterns`] [#4960](https://github.com/rust-lang/rust-clippy/pull/4960)
 +* [`iter_nth_zero`] [#4966](https://github.com/rust-lang/rust-clippy/pull/4966)
 +* `invalid_atomic_ordering` [#4999](https://github.com/rust-lang/rust-clippy/pull/4999)
 +* [`skip_while_next`] [#5067](https://github.com/rust-lang/rust-clippy/pull/5067)
 +
 +### Moves and Deprecations
 +
 +* Move [`transmute_float_to_int`] from nursery to complexity group
 +  [#5015](https://github.com/rust-lang/rust-clippy/pull/5015)
 +* Move [`range_plus_one`] to pedantic group [#5057](https://github.com/rust-lang/rust-clippy/pull/5057)
 +* Move [`debug_assert_with_mut_call`] to nursery group [#5106](https://github.com/rust-lang/rust-clippy/pull/5106)
 +* Deprecate `unused_label` [#4930](https://github.com/rust-lang/rust-clippy/pull/4930)
 +
 +### Enhancements
 +
 +* Lint vectored IO in [`unused_io_amount`] [#5027](https://github.com/rust-lang/rust-clippy/pull/5027)
 +* Make [`vec_box`] configurable by adding a size threshold [#5081](https://github.com/rust-lang/rust-clippy/pull/5081)
 +* Also lint constants in [`cmp_nan`] [#4910](https://github.com/rust-lang/rust-clippy/pull/4910)
 +* Fix false negative in [`expect_fun_call`] [#4915](https://github.com/rust-lang/rust-clippy/pull/4915)
 +* Fix false negative in [`redundant_clone`] [#5017](https://github.com/rust-lang/rust-clippy/pull/5017)
 +
 +### False Positive Fixes
 +
 +* [`map_clone`] [#4937](https://github.com/rust-lang/rust-clippy/pull/4937)
 +* [`replace_consts`] [#4977](https://github.com/rust-lang/rust-clippy/pull/4977)
 +* [`let_and_return`] [#5008](https://github.com/rust-lang/rust-clippy/pull/5008)
 +* [`eq_op`] [#5079](https://github.com/rust-lang/rust-clippy/pull/5079)
 +* [`possible_missing_comma`] [#5083](https://github.com/rust-lang/rust-clippy/pull/5083)
 +* [`debug_assert_with_mut_call`] [#5106](https://github.com/rust-lang/rust-clippy/pull/5106)
 +* Don't trigger [`let_underscore_must_use`] in external macros
 +  [#5082](https://github.com/rust-lang/rust-clippy/pull/5082)
 +* Don't trigger [`empty_loop`] in `no_std` crates [#5086](https://github.com/rust-lang/rust-clippy/pull/5086)
 +
 +### Suggestion Improvements
 +
 +* `option_map_unwrap_or` [#4634](https://github.com/rust-lang/rust-clippy/pull/4634)
 +* [`wildcard_enum_match_arm`] [#4934](https://github.com/rust-lang/rust-clippy/pull/4934)
 +* [`cognitive_complexity`] [#4935](https://github.com/rust-lang/rust-clippy/pull/4935)
 +* [`decimal_literal_representation`] [#4956](https://github.com/rust-lang/rust-clippy/pull/4956)
 +* `unknown_clippy_lints` [#4963](https://github.com/rust-lang/rust-clippy/pull/4963)
 +* [`explicit_into_iter_loop`] [#4978](https://github.com/rust-lang/rust-clippy/pull/4978)
 +* [`useless_attribute`] [#5022](https://github.com/rust-lang/rust-clippy/pull/5022)
 +* `if_let_some_result` [#5032](https://github.com/rust-lang/rust-clippy/pull/5032)
 +
 +### ICE fixes
 +
 +* [`unsound_collection_transmute`] [#4975](https://github.com/rust-lang/rust-clippy/pull/4975)
 +
 +### Documentation
 +
 +* Improve documentation of [`empty_enum`], [`replace_consts`], [`redundant_clone`], and [`iterator_step_by_zero`]
 +
 +
 +## Rust 1.41
 +
 +Released 2020-01-30
 +
 +[c8e3cfb...69f99e7](https://github.com/rust-lang/rust-clippy/compare/c8e3cfb...69f99e7)
 +
 +* New Lints:
 +  * [`exit`] [#4697](https://github.com/rust-lang/rust-clippy/pull/4697)
 +  * [`to_digit_is_some`] [#4801](https://github.com/rust-lang/rust-clippy/pull/4801)
 +  * [`tabs_in_doc_comments`] [#4806](https://github.com/rust-lang/rust-clippy/pull/4806)
 +  * [`large_stack_arrays`] [#4807](https://github.com/rust-lang/rust-clippy/pull/4807)
 +  * [`same_functions_in_if_condition`] [#4814](https://github.com/rust-lang/rust-clippy/pull/4814)
 +  * [`zst_offset`] [#4816](https://github.com/rust-lang/rust-clippy/pull/4816)
 +  * [`as_conversions`] [#4821](https://github.com/rust-lang/rust-clippy/pull/4821)
 +  * [`missing_errors_doc`] [#4884](https://github.com/rust-lang/rust-clippy/pull/4884)
 +  * [`transmute_float_to_int`] [#4889](https://github.com/rust-lang/rust-clippy/pull/4889)
 +* Remove plugin interface, see
 +  [Inside Rust Blog](https://blog.rust-lang.org/inside-rust/2019/11/04/Clippy-removes-plugin-interface.html) for
 +  details [#4714](https://github.com/rust-lang/rust-clippy/pull/4714)
 +* Move [`use_self`] to nursery group [#4863](https://github.com/rust-lang/rust-clippy/pull/4863)
 +* Deprecate `into_iter_on_array` [#4788](https://github.com/rust-lang/rust-clippy/pull/4788)
 +* Expand [`string_lit_as_bytes`] to also trigger when literal has escapes
 +  [#4808](https://github.com/rust-lang/rust-clippy/pull/4808)
 +* Fix false positive in `comparison_chain` [#4842](https://github.com/rust-lang/rust-clippy/pull/4842)
 +* Fix false positive in `while_immutable_condition` [#4730](https://github.com/rust-lang/rust-clippy/pull/4730)
 +* Fix false positive in `explicit_counter_loop` [#4803](https://github.com/rust-lang/rust-clippy/pull/4803)
 +* Fix false positive in `must_use_candidate` [#4794](https://github.com/rust-lang/rust-clippy/pull/4794)
 +* Fix false positive in `print_with_newline` and `write_with_newline`
 +  [#4769](https://github.com/rust-lang/rust-clippy/pull/4769)
 +* Fix false positive in `derive_hash_xor_eq` [#4766](https://github.com/rust-lang/rust-clippy/pull/4766)
 +* Fix false positive in `missing_inline_in_public_items` [#4870](https://github.com/rust-lang/rust-clippy/pull/4870)
 +* Fix false positive in `string_add` [#4880](https://github.com/rust-lang/rust-clippy/pull/4880)
 +* Fix false positive in `float_arithmetic` [#4851](https://github.com/rust-lang/rust-clippy/pull/4851)
 +* Fix false positive in `cast_sign_loss` [#4883](https://github.com/rust-lang/rust-clippy/pull/4883)
 +* Fix false positive in `manual_swap` [#4877](https://github.com/rust-lang/rust-clippy/pull/4877)
 +* Fix ICEs occurring while checking some block expressions [#4772](https://github.com/rust-lang/rust-clippy/pull/4772)
 +* Fix ICE in `use_self` [#4776](https://github.com/rust-lang/rust-clippy/pull/4776)
 +* Fix ICEs related to `const_generics` [#4780](https://github.com/rust-lang/rust-clippy/pull/4780)
 +* Display help when running `clippy-driver` without arguments, instead of ICEing
 +  [#4810](https://github.com/rust-lang/rust-clippy/pull/4810)
 +* Clippy has its own ICE message now [#4588](https://github.com/rust-lang/rust-clippy/pull/4588)
 +* Show deprecated lints in the documentation again [#4757](https://github.com/rust-lang/rust-clippy/pull/4757)
 +* Improve Documentation by adding positive examples to some lints
 +  [#4832](https://github.com/rust-lang/rust-clippy/pull/4832)
 +
 +## Rust 1.40
 +
 +Released 2019-12-19
 +
 +[4e7e71b...c8e3cfb](https://github.com/rust-lang/rust-clippy/compare/4e7e71b...c8e3cfb)
 +
 +* New Lints:
 +  * [`unneeded_wildcard_pattern`] [#4537](https://github.com/rust-lang/rust-clippy/pull/4537)
 +  * [`needless_doctest_main`] [#4603](https://github.com/rust-lang/rust-clippy/pull/4603)
 +  * [`suspicious_unary_op_formatting`] [#4615](https://github.com/rust-lang/rust-clippy/pull/4615)
 +  * [`debug_assert_with_mut_call`] [#4680](https://github.com/rust-lang/rust-clippy/pull/4680)
 +  * [`unused_self`] [#4619](https://github.com/rust-lang/rust-clippy/pull/4619)
 +  * [`inefficient_to_string`] [#4683](https://github.com/rust-lang/rust-clippy/pull/4683)
 +  * [`must_use_unit`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`must_use_candidate`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`double_must_use`] [#4560](https://github.com/rust-lang/rust-clippy/pull/4560)
 +  * [`comparison_chain`] [#4569](https://github.com/rust-lang/rust-clippy/pull/4569)
 +  * [`unsound_collection_transmute`] [#4592](https://github.com/rust-lang/rust-clippy/pull/4592)
 +  * [`panic`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * [`unreachable`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * [`todo`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * `option_expect_used` [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +  * `result_expect_used` [#4657](https://github.com/rust-lang/rust-clippy/pull/4657)
 +* Move `redundant_clone` to perf group [#4509](https://github.com/rust-lang/rust-clippy/pull/4509)
 +* Move `manual_mul_add` to nursery group [#4736](https://github.com/rust-lang/rust-clippy/pull/4736)
 +* Expand `unit_cmp` to also work with `assert_eq!`, `debug_assert_eq!`, `assert_ne!` and `debug_assert_ne!` [#4613](https://github.com/rust-lang/rust-clippy/pull/4613)
 +* Expand `integer_arithmetic` to also detect mutating arithmetic like `+=` [#4585](https://github.com/rust-lang/rust-clippy/pull/4585)
 +* Fix false positive in `nonminimal_bool` [#4568](https://github.com/rust-lang/rust-clippy/pull/4568)
 +* Fix false positive in `missing_safety_doc` [#4611](https://github.com/rust-lang/rust-clippy/pull/4611)
 +* Fix false positive in `cast_sign_loss` [#4614](https://github.com/rust-lang/rust-clippy/pull/4614)
 +* Fix false positive in `redundant_clone` [#4509](https://github.com/rust-lang/rust-clippy/pull/4509)
 +* Fix false positive in `try_err` [#4721](https://github.com/rust-lang/rust-clippy/pull/4721)
 +* Fix false positive in `toplevel_ref_arg` [#4570](https://github.com/rust-lang/rust-clippy/pull/4570)
 +* Fix false positive in `multiple_inherent_impl` [#4593](https://github.com/rust-lang/rust-clippy/pull/4593)
 +* Improve more suggestions and tests in preparation for the unstable `cargo fix --clippy` [#4575](https://github.com/rust-lang/rust-clippy/pull/4575)
 +* Improve suggestion for `zero_ptr` [#4599](https://github.com/rust-lang/rust-clippy/pull/4599)
 +* Improve suggestion for `explicit_counter_loop` [#4691](https://github.com/rust-lang/rust-clippy/pull/4691)
 +* Improve suggestion for `mul_add` [#4602](https://github.com/rust-lang/rust-clippy/pull/4602)
 +* Improve suggestion for `assertions_on_constants` [#4635](https://github.com/rust-lang/rust-clippy/pull/4635)
 +* Fix ICE in `use_self` [#4671](https://github.com/rust-lang/rust-clippy/pull/4671)
 +* Fix ICE when encountering const casts [#4590](https://github.com/rust-lang/rust-clippy/pull/4590)
 +
 +## Rust 1.39
 +
 +Released 2019-11-07
 +
 +[3aea860...4e7e71b](https://github.com/rust-lang/rust-clippy/compare/3aea860...4e7e71b)
 +
 +* New Lints:
 +  * [`uninit_assumed_init`] [#4479](https://github.com/rust-lang/rust-clippy/pull/4479)
 +  * [`flat_map_identity`] [#4231](https://github.com/rust-lang/rust-clippy/pull/4231)
 +  * [`missing_safety_doc`] [#4535](https://github.com/rust-lang/rust-clippy/pull/4535)
 +  * [`mem_replace_with_uninit`] [#4511](https://github.com/rust-lang/rust-clippy/pull/4511)
 +  * [`suspicious_map`] [#4394](https://github.com/rust-lang/rust-clippy/pull/4394)
 +  * `option_and_then_some` [#4386](https://github.com/rust-lang/rust-clippy/pull/4386)
 +  * [`manual_saturating_arithmetic`] [#4498](https://github.com/rust-lang/rust-clippy/pull/4498)
 +* Deprecate `unused_collect` lint. This is fully covered by rustc's `#[must_use]` on `collect` [#4348](https://github.com/rust-lang/rust-clippy/pull/4348)
 +* Move `type_repetition_in_bounds` to pedantic group [#4403](https://github.com/rust-lang/rust-clippy/pull/4403)
 +* Move `cast_lossless` to pedantic group [#4539](https://github.com/rust-lang/rust-clippy/pull/4539)
 +* `temporary_cstring_as_ptr` now catches more cases [#4425](https://github.com/rust-lang/rust-clippy/pull/4425)
 +* `use_self` now works in constructors, too [#4525](https://github.com/rust-lang/rust-clippy/pull/4525)
 +* `cargo_common_metadata` now checks for license files [#4518](https://github.com/rust-lang/rust-clippy/pull/4518)
 +* `cognitive_complexity` now includes the measured complexity in the warning message [#4469](https://github.com/rust-lang/rust-clippy/pull/4469)
 +* Fix false positives in `block_in_if_*` lints [#4458](https://github.com/rust-lang/rust-clippy/pull/4458)
 +* Fix false positive in `cast_lossless` [#4473](https://github.com/rust-lang/rust-clippy/pull/4473)
 +* Fix false positive in `clone_on_copy` [#4411](https://github.com/rust-lang/rust-clippy/pull/4411)
 +* Fix false positive in `deref_addrof` [#4487](https://github.com/rust-lang/rust-clippy/pull/4487)
 +* Fix false positive in `too_many_lines` [#4490](https://github.com/rust-lang/rust-clippy/pull/4490)
 +* Fix false positive in `new_ret_no_self` [#4365](https://github.com/rust-lang/rust-clippy/pull/4365)
 +* Fix false positive in `manual_swap` [#4478](https://github.com/rust-lang/rust-clippy/pull/4478)
 +* Fix false positive in `missing_const_for_fn` [#4450](https://github.com/rust-lang/rust-clippy/pull/4450)
 +* Fix false positive in `extra_unused_lifetimes` [#4477](https://github.com/rust-lang/rust-clippy/pull/4477)
 +* Fix false positive in `inherent_to_string` [#4460](https://github.com/rust-lang/rust-clippy/pull/4460)
 +* Fix false positive in `map_entry` [#4495](https://github.com/rust-lang/rust-clippy/pull/4495)
 +* Fix false positive in `unused_unit` [#4445](https://github.com/rust-lang/rust-clippy/pull/4445)
 +* Fix false positive in `redundant_pattern` [#4489](https://github.com/rust-lang/rust-clippy/pull/4489)
 +* Fix false positive in `wrong_self_convention` [#4369](https://github.com/rust-lang/rust-clippy/pull/4369)
 +* Improve various suggestions and tests in preparation for the unstable `cargo fix --clippy` [#4558](https://github.com/rust-lang/rust-clippy/pull/4558)
 +* Improve suggestions for `redundant_pattern_matching` [#4352](https://github.com/rust-lang/rust-clippy/pull/4352)
 +* Improve suggestions for `explicit_write` [#4544](https://github.com/rust-lang/rust-clippy/pull/4544)
 +* Improve suggestion for `or_fun_call` [#4522](https://github.com/rust-lang/rust-clippy/pull/4522)
 +* Improve suggestion for `match_as_ref` [#4446](https://github.com/rust-lang/rust-clippy/pull/4446)
 +* Improve suggestion for `unnecessary_fold_span` [#4382](https://github.com/rust-lang/rust-clippy/pull/4382)
 +* Add suggestions for `unseparated_literal_suffix` [#4401](https://github.com/rust-lang/rust-clippy/pull/4401)
 +* Add suggestions for `char_lit_as_u8` [#4418](https://github.com/rust-lang/rust-clippy/pull/4418)
 +
 +## Rust 1.38
 +
 +Released 2019-09-26
 +
 +[e3cb40e...3aea860](https://github.com/rust-lang/rust-clippy/compare/e3cb40e...3aea860)
 +
 +* New Lints:
 +  * [`main_recursion`] [#4203](https://github.com/rust-lang/rust-clippy/pull/4203)
 +  * [`inherent_to_string`] [#4259](https://github.com/rust-lang/rust-clippy/pull/4259)
 +  * [`inherent_to_string_shadow_display`] [#4259](https://github.com/rust-lang/rust-clippy/pull/4259)
 +  * [`type_repetition_in_bounds`] [#3766](https://github.com/rust-lang/rust-clippy/pull/3766)
 +  * [`try_err`] [#4222](https://github.com/rust-lang/rust-clippy/pull/4222)
 +* Move `{unnnecessary,panicking}_unwrap` out of nursery [#4307](https://github.com/rust-lang/rust-clippy/pull/4307)
 +* Extend the `use_self` lint to suggest uses of `Self::Variant` [#4308](https://github.com/rust-lang/rust-clippy/pull/4308)
 +* Improve suggestion for needless return [#4262](https://github.com/rust-lang/rust-clippy/pull/4262)
 +* Add auto-fixable suggestion for `let_unit` [#4337](https://github.com/rust-lang/rust-clippy/pull/4337)
 +* Fix false positive in `pub_enum_variant_names` and `enum_variant_names` [#4345](https://github.com/rust-lang/rust-clippy/pull/4345)
 +* Fix false positive in `cast_ptr_alignment` [#4257](https://github.com/rust-lang/rust-clippy/pull/4257)
 +* Fix false positive in `string_lit_as_bytes` [#4233](https://github.com/rust-lang/rust-clippy/pull/4233)
 +* Fix false positive in `needless_lifetimes` [#4266](https://github.com/rust-lang/rust-clippy/pull/4266)
 +* Fix false positive in `float_cmp` [#4275](https://github.com/rust-lang/rust-clippy/pull/4275)
 +* Fix false positives in `needless_return` [#4274](https://github.com/rust-lang/rust-clippy/pull/4274)
 +* Fix false negative in `match_same_arms` [#4246](https://github.com/rust-lang/rust-clippy/pull/4246)
 +* Fix incorrect suggestion for `needless_bool` [#4335](https://github.com/rust-lang/rust-clippy/pull/4335)
 +* Improve suggestion for `cast_ptr_alignment` [#4257](https://github.com/rust-lang/rust-clippy/pull/4257)
 +* Improve suggestion for `single_char_literal` [#4361](https://github.com/rust-lang/rust-clippy/pull/4361)
 +* Improve suggestion for `len_zero` [#4314](https://github.com/rust-lang/rust-clippy/pull/4314)
 +* Fix ICE in `implicit_hasher` [#4268](https://github.com/rust-lang/rust-clippy/pull/4268)
 +* Fix allow bug in `trivially_copy_pass_by_ref` [#4250](https://github.com/rust-lang/rust-clippy/pull/4250)
 +
 +## Rust 1.37
 +
 +Released 2019-08-15
 +
 +[082cfa7...e3cb40e](https://github.com/rust-lang/rust-clippy/compare/082cfa7...e3cb40e)
 +
 +* New Lints:
 +  * [`checked_conversions`] [#4088](https://github.com/rust-lang/rust-clippy/pull/4088)
 +  * [`get_last_with_len`] [#3832](https://github.com/rust-lang/rust-clippy/pull/3832)
 +  * [`integer_division`] [#4195](https://github.com/rust-lang/rust-clippy/pull/4195)
 +* Renamed Lint: `const_static_lifetime` is now called [`redundant_static_lifetimes`].
 +  The lint now covers statics in addition to consts [#4162](https://github.com/rust-lang/rust-clippy/pull/4162)
 +* [`match_same_arms`] now warns for all identical arms, instead of only the first one [#4102](https://github.com/rust-lang/rust-clippy/pull/4102)
 +* [`needless_return`] now works with void functions [#4220](https://github.com/rust-lang/rust-clippy/pull/4220)
 +* Fix false positive in [`redundant_closure`] [#4190](https://github.com/rust-lang/rust-clippy/pull/4190)
 +* Fix false positive in [`useless_attribute`] [#4107](https://github.com/rust-lang/rust-clippy/pull/4107)
 +* Fix incorrect suggestion for [`float_cmp`] [#4214](https://github.com/rust-lang/rust-clippy/pull/4214)
 +* Add suggestions for [`print_with_newline`] and [`write_with_newline`] [#4136](https://github.com/rust-lang/rust-clippy/pull/4136)
 +* Improve suggestions for `option_map_unwrap_or_else` and `result_map_unwrap_or_else` [#4164](https://github.com/rust-lang/rust-clippy/pull/4164)
 +* Improve suggestions for [`non_ascii_literal`] [#4119](https://github.com/rust-lang/rust-clippy/pull/4119)
 +* Improve diagnostics for [`let_and_return`] [#4137](https://github.com/rust-lang/rust-clippy/pull/4137)
 +* Improve diagnostics for [`trivially_copy_pass_by_ref`] [#4071](https://github.com/rust-lang/rust-clippy/pull/4071)
 +* Add macro check for [`unreadable_literal`] [#4099](https://github.com/rust-lang/rust-clippy/pull/4099)
 +
 +## Rust 1.36
 +
 +Released 2019-07-04
 +
 +[eb9f9b1...082cfa7](https://github.com/rust-lang/rust-clippy/compare/eb9f9b1...082cfa7)
 +
 +* New lints: [`find_map`], [`filter_map_next`] [#4039](https://github.com/rust-lang/rust-clippy/pull/4039)
 +* New lint: [`path_buf_push_overwrite`] [#3954](https://github.com/rust-lang/rust-clippy/pull/3954)
 +* Move `path_buf_push_overwrite` to the nursery [#4013](https://github.com/rust-lang/rust-clippy/pull/4013)
 +* Split [`redundant_closure`] into [`redundant_closure`] and [`redundant_closure_for_method_calls`] [#4110](https://github.com/rust-lang/rust-clippy/pull/4101)
 +* Allow allowing of [`toplevel_ref_arg`] lint [#4007](https://github.com/rust-lang/rust-clippy/pull/4007)
 +* Fix false negative in [`or_fun_call`] pertaining to nested constructors [#4084](https://github.com/rust-lang/rust-clippy/pull/4084)
 +* Fix false positive in [`or_fun_call`] pertaining to enum variant constructors [#4018](https://github.com/rust-lang/rust-clippy/pull/4018)
 +* Fix false positive in [`useless_let_if_seq`] pertaining to interior mutability [#4035](https://github.com/rust-lang/rust-clippy/pull/4035)
 +* Fix false positive in [`redundant_closure`] pertaining to non-function types [#4008](https://github.com/rust-lang/rust-clippy/pull/4008)
 +* Fix false positive in [`let_and_return`] pertaining to attributes on `let`s [#4024](https://github.com/rust-lang/rust-clippy/pull/4024)
 +* Fix false positive in [`module_name_repetitions`] lint pertaining to attributes [#4006](https://github.com/rust-lang/rust-clippy/pull/4006)
 +* Fix false positive on [`assertions_on_constants`] pertaining to `debug_assert!` [#3989](https://github.com/rust-lang/rust-clippy/pull/3989)
 +* Improve suggestion in [`map_clone`] to suggest `.copied()` where applicable  [#3970](https://github.com/rust-lang/rust-clippy/pull/3970) [#4043](https://github.com/rust-lang/rust-clippy/pull/4043)
 +* Improve suggestion for [`search_is_some`] [#4049](https://github.com/rust-lang/rust-clippy/pull/4049)
 +* Improve suggestion applicability for [`naive_bytecount`] [#3984](https://github.com/rust-lang/rust-clippy/pull/3984)
 +* Improve suggestion applicability for [`while_let_loop`] [#3975](https://github.com/rust-lang/rust-clippy/pull/3975)
 +* Improve diagnostics for [`too_many_arguments`] [#4053](https://github.com/rust-lang/rust-clippy/pull/4053)
 +* Improve diagnostics for [`cast_lossless`] [#4021](https://github.com/rust-lang/rust-clippy/pull/4021)
 +* Deal with macro checks in desugarings better [#4082](https://github.com/rust-lang/rust-clippy/pull/4082)
 +* Add macro check for [`unnecessary_cast`]  [#4026](https://github.com/rust-lang/rust-clippy/pull/4026)
 +* Remove [`approx_constant`]'s documentation's "Known problems" section. [#4027](https://github.com/rust-lang/rust-clippy/pull/4027)
 +* Fix ICE in [`suspicious_else_formatting`] [#3960](https://github.com/rust-lang/rust-clippy/pull/3960)
 +* Fix ICE in [`decimal_literal_representation`] [#3931](https://github.com/rust-lang/rust-clippy/pull/3931)
 +
 +
 +## Rust 1.35
 +
 +Released 2019-05-20
 +
 +[1fac380..37f5c1e](https://github.com/rust-lang/rust-clippy/compare/1fac380...37f5c1e)
 +
 +* New lint: `drop_bounds` to detect `T: Drop` bounds
 +* Split [`redundant_closure`] into [`redundant_closure`] and [`redundant_closure_for_method_calls`] [#4110](https://github.com/rust-lang/rust-clippy/pull/4101)
 +* Rename `cyclomatic_complexity` to [`cognitive_complexity`], start work on making lint more practical for Rust code
 +* Move [`get_unwrap`] to the restriction category
 +* Improve suggestions for [`iter_cloned_collect`]
 +* Improve suggestions for [`cast_lossless`] to suggest suffixed literals
 +* Fix false positives in [`print_with_newline`] and [`write_with_newline`] pertaining to raw strings
 +* Fix false positive in [`needless_range_loop`] pertaining to structs without a `.iter()`
 +* Fix false positive in [`bool_comparison`] pertaining to non-bool types
 +* Fix false positive in [`redundant_closure`] pertaining to differences in borrows
 +* Fix false positive in `option_map_unwrap_or` on non-copy types
 +* Fix false positives in [`missing_const_for_fn`] pertaining to macros and trait method impls
 +* Fix false positive in [`needless_pass_by_value`] pertaining to procedural macros
 +* Fix false positive in [`needless_continue`] pertaining to loop labels
 +* Fix false positive for [`boxed_local`] pertaining to arguments moved into closures
 +* Fix false positive for [`use_self`] in nested functions
 +* Fix suggestion for [`expect_fun_call`] (https://github.com/rust-lang/rust-clippy/pull/3846)
 +* Fix suggestion for [`explicit_counter_loop`] to deal with parenthesizing range variables
 +* Fix suggestion for [`single_char_pattern`] to correctly escape single quotes
 +* Avoid triggering [`redundant_closure`] in macros
 +* ICE fixes: [#3805](https://github.com/rust-lang/rust-clippy/pull/3805), [#3772](https://github.com/rust-lang/rust-clippy/pull/3772), [#3741](https://github.com/rust-lang/rust-clippy/pull/3741)
 +
 +## Rust 1.34
 +
 +Released 2019-04-10
 +
 +[1b89724...1fac380](https://github.com/rust-lang/rust-clippy/compare/1b89724...1fac380)
 +
 +* New lint: [`assertions_on_constants`] to detect for example `assert!(true)`
 +* New lint: [`dbg_macro`] to detect uses of the `dbg!` macro
 +* New lint: [`missing_const_for_fn`] that can suggest functions to be made `const`
 +* New lint: [`too_many_lines`] to detect functions with excessive LOC. It can be
 +  configured using the `too-many-lines-threshold` configuration.
 +* New lint: [`wildcard_enum_match_arm`] to check for wildcard enum matches using `_`
 +* Expand `redundant_closure` to also work for methods (not only functions)
 +* Fix ICEs in `vec_box`, `needless_pass_by_value` and `implicit_hasher`
 +* Fix false positive in `cast_sign_loss`
 +* Fix false positive in `integer_arithmetic`
 +* Fix false positive in `unit_arg`
 +* Fix false positives in `implicit_return`
 +* Add suggestion to `explicit_write`
 +* Improve suggestions for `question_mark` lint
 +* Fix incorrect suggestion for `cast_lossless`
 +* Fix incorrect suggestion for `expect_fun_call`
 +* Fix incorrect suggestion for `needless_bool`
 +* Fix incorrect suggestion for `needless_range_loop`
 +* Fix incorrect suggestion for `use_self`
 +* Fix incorrect suggestion for `while_let_on_iterator`
 +* Clippy is now slightly easier to invoke in non-cargo contexts. See
 +  [#3665][pull3665] for more details.
 +* We now have [improved documentation][adding_lints] on how to add new lints
 +
 +## Rust 1.33
 +
 +Released 2019-02-26
 +
 +[b2601be...1b89724](https://github.com/rust-lang/rust-clippy/compare/b2601be...1b89724)
 +
 +* New lints: [`implicit_return`], [`vec_box`], [`cast_ref_to_mut`]
 +* The `rust-clippy` repository is now part of the `rust-lang` org.
 +* Rename `stutter` to `module_name_repetitions`
 +* Merge `new_without_default_derive` into `new_without_default` lint
 +* Move `large_digit_groups` from `style` group to `pedantic`
 +* Expand `bool_comparison` to check for `<`, `<=`, `>`, `>=`, and `!=`
 +  comparisons against booleans
 +* Expand `no_effect` to detect writes to constants such as `A_CONST.field = 2`
 +* Expand `redundant_clone` to work on struct fields
 +* Expand `suspicious_else_formatting` to detect `if .. {..} {..}`
 +* Expand `use_self` to work on tuple structs and also in local macros
 +* Fix ICE in `result_map_unit_fn` and `option_map_unit_fn`
 +* Fix false positives in `implicit_return`
 +* Fix false positives in `use_self`
 +* Fix false negative in `clone_on_copy`
 +* Fix false positive in `doc_markdown`
 +* Fix false positive in `empty_loop`
 +* Fix false positive in `if_same_then_else`
 +* Fix false positive in `infinite_iter`
 +* Fix false positive in `question_mark`
 +* Fix false positive in `useless_asref`
 +* Fix false positive in `wildcard_dependencies`
 +* Fix false positive in `write_with_newline`
 +* Add suggestion to `explicit_write`
 +* Improve suggestions for `question_mark` lint
 +* Fix incorrect suggestion for `get_unwrap`
 +
 +## Rust 1.32
 +
 +Released 2019-01-17
 +
 +[2e26fdc2...b2601be](https://github.com/rust-lang/rust-clippy/compare/2e26fdc2...b2601be)
 +
 +* New lints: [`slow_vector_initialization`], `mem_discriminant_non_enum`,
 +  [`redundant_clone`], [`wildcard_dependencies`],
 +  [`into_iter_on_ref`], `into_iter_on_array`, [`deprecated_cfg_attr`],
 +  [`cargo_common_metadata`]
 +* Add support for `u128` and `i128` to integer related lints
 +* Add float support to `mistyped_literal_suffixes`
 +* Fix false positives in `use_self`
 +* Fix false positives in `missing_comma`
 +* Fix false positives in `new_ret_no_self`
 +* Fix false positives in `possible_missing_comma`
 +* Fix false positive in `integer_arithmetic` in constant items
 +* Fix false positive in `needless_borrow`
 +* Fix false positive in `out_of_bounds_indexing`
 +* Fix false positive in `new_without_default_derive`
 +* Fix false positive in `string_lit_as_bytes`
 +* Fix false negative in `out_of_bounds_indexing`
 +* Fix false negative in `use_self`. It will now also check existential types
 +* Fix incorrect suggestion for `redundant_closure_call`
 +* Fix various suggestions that contained expanded macros
 +* Fix `bool_comparison` triggering 3 times on on on the same code
 +* Expand `trivially_copy_pass_by_ref` to work on trait methods
 +* Improve suggestion for `needless_range_loop`
 +* Move `needless_pass_by_value` from `pedantic` group to `style`
 +
 +## Rust 1.31
 +
 +Released 2018-12-06
 +
 +[125907ad..2e26fdc2](https://github.com/rust-lang/rust-clippy/compare/125907ad..2e26fdc2)
 +
 +* Clippy has been relicensed under a dual MIT / Apache license.
 +  See [#3093](https://github.com/rust-lang/rust-clippy/issues/3093) for more
 +  information.
 +* With Rust 1.31, Clippy is no longer available via crates.io. The recommended
 +  installation method is via `rustup component add clippy`.
 +* New lints: [`redundant_pattern_matching`], [`unnecessary_filter_map`],
 +  [`unused_unit`], [`map_flatten`], [`mem_replace_option_with_none`]
 +* Fix ICE in `if_let_redundant_pattern_matching`
 +* Fix ICE in `needless_pass_by_value` when encountering a generic function
 +  argument with a lifetime parameter
 +* Fix ICE in `needless_range_loop`
 +* Fix ICE in `single_char_pattern` when encountering a constant value
 +* Fix false positive in `assign_op_pattern`
 +* Fix false positive in `boxed_local` on trait implementations
 +* Fix false positive in `cmp_owned`
 +* Fix false positive in `collapsible_if` when conditionals have comments
 +* Fix false positive in `double_parens`
 +* Fix false positive in `excessive_precision`
 +* Fix false positive in `explicit_counter_loop`
 +* Fix false positive in `fn_to_numeric_cast_with_truncation`
 +* Fix false positive in `map_clone`
 +* Fix false positive in `new_ret_no_self`
 +* Fix false positive in `new_without_default` when `new` is unsafe
 +* Fix false positive in `type_complexity` when using extern types
 +* Fix false positive in `useless_format`
 +* Fix false positive in `wrong_self_convention`
 +* Fix incorrect suggestion for `excessive_precision`
 +* Fix incorrect suggestion for `expect_fun_call`
 +* Fix incorrect suggestion for `get_unwrap`
 +* Fix incorrect suggestion for `useless_format`
 +* `fn_to_numeric_cast_with_truncation` lint can be disabled again
 +* Improve suggestions for `manual_memcpy`
 +* Improve help message for `needless_lifetimes`
 +
 +## Rust 1.30
 +
 +Released 2018-10-25
 +
 +[14207503...125907ad](https://github.com/rust-lang/rust-clippy/compare/14207503...125907ad)
 +
 +* Deprecate `assign_ops` lint
 +* New lints: [`mistyped_literal_suffixes`], [`ptr_offset_with_cast`],
 +  [`needless_collect`], [`copy_iterator`]
 +* `cargo clippy -V` now includes the Clippy commit hash of the Rust
 +  Clippy component
 +* Fix ICE in `implicit_hasher`
 +* Fix ICE when encountering `println!("{}" a);`
 +* Fix ICE when encountering a macro call in match statements
 +* Fix false positive in `default_trait_access`
 +* Fix false positive in `trivially_copy_pass_by_ref`
 +* Fix false positive in `similar_names`
 +* Fix false positive in `redundant_field_name`
 +* Fix false positive in `expect_fun_call`
 +* Fix false negative in `identity_conversion`
 +* Fix false negative in `explicit_counter_loop`
 +* Fix `range_plus_one` suggestion and false negative
 +* `print_with_newline` / `write_with_newline`: don't warn about string with several `\n`s in them
 +* Fix `useless_attribute` to also whitelist `unused_extern_crates`
 +* Fix incorrect suggestion for `single_char_pattern`
 +* Improve suggestion for `identity_conversion` lint
 +* Move `explicit_iter_loop` and `explicit_into_iter_loop` from `style` group to `pedantic`
 +* Move `range_plus_one` and `range_minus_one` from `nursery` group to `complexity`
 +* Move `shadow_unrelated` from `restriction` group to `pedantic`
 +* Move `indexing_slicing` from `pedantic` group to `restriction`
 +
 +## Rust 1.29
 +
 +Released 2018-09-13
 +
 +[v0.0.212...14207503](https://github.com/rust-lang/rust-clippy/compare/v0.0.212...14207503)
 +
 +* :tada: :tada: **Rust 1.29 is the first stable Rust that includes a bundled Clippy** :tada:
 +  :tada:
 +  You can now run `rustup component add clippy-preview` and then `cargo
 +  clippy` to run Clippy. This should put an end to the continuous nightly
 +  upgrades for Clippy users.
 +* Clippy now follows the Rust versioning scheme instead of its own
 +* Fix ICE when encountering a `while let (..) = x.iter()` construct
 +* Fix false positives in `use_self`
 +* Fix false positive in `trivially_copy_pass_by_ref`
 +* Fix false positive in `useless_attribute` lint
 +* Fix false positive in `print_literal`
 +* Fix `use_self` regressions
 +* Improve lint message for `neg_cmp_op_on_partial_ord`
 +* Improve suggestion highlight for `single_char_pattern`
 +* Improve suggestions for various print/write macro lints
 +* Improve website header
 +
 +## 0.0.212 (2018-07-10)
 +* Rustup to *rustc 1.29.0-nightly (e06c87544 2018-07-06)*
 +
 +## 0.0.211
 +* Rustup to *rustc 1.28.0-nightly (e3bf634e0 2018-06-28)*
 +
 +## 0.0.210
 +* Rustup to *rustc 1.28.0-nightly (01cc982e9 2018-06-24)*
 +
 +## 0.0.209
 +* Rustup to *rustc 1.28.0-nightly (523097979 2018-06-18)*
 +
 +## 0.0.208
 +* Rustup to *rustc 1.28.0-nightly (86a8f1a63 2018-06-17)*
 +
 +## 0.0.207
 +* Rustup to *rustc 1.28.0-nightly (2a0062974 2018-06-09)*
 +
 +## 0.0.206
 +* Rustup to *rustc 1.28.0-nightly (5bf68db6e 2018-05-28)*
 +
 +## 0.0.205
 +* Rustup to *rustc 1.28.0-nightly (990d8aa74 2018-05-25)*
 +* Rename `unused_lifetimes` to `extra_unused_lifetimes` because of naming conflict with new rustc lint
 +
 +## 0.0.204
 +* Rustup to *rustc 1.28.0-nightly (71e87be38 2018-05-22)*
 +
 +## 0.0.203
 +* Rustup to *rustc 1.28.0-nightly (a3085756e 2018-05-19)*
 +* Clippy attributes are now of the form `clippy::cyclomatic_complexity` instead of `clippy(cyclomatic_complexity)`
 +
 +## 0.0.202
 +* Rustup to *rustc 1.28.0-nightly (952f344cd 2018-05-18)*
 +
 +## 0.0.201
 +* Rustup to *rustc 1.27.0-nightly (2f2a11dfc 2018-05-16)*
 +
 +## 0.0.200
 +* Rustup to *rustc 1.27.0-nightly (9fae15374 2018-05-13)*
 +
 +## 0.0.199
 +* Rustup to *rustc 1.27.0-nightly (ff2ac35db 2018-05-12)*
 +
 +## 0.0.198
 +* Rustup to *rustc 1.27.0-nightly (acd3871ba 2018-05-10)*
 +
 +## 0.0.197
 +* Rustup to *rustc 1.27.0-nightly (428ea5f6b 2018-05-06)*
 +
 +## 0.0.196
 +* Rustup to *rustc 1.27.0-nightly (e82261dfb 2018-05-03)*
 +
 +## 0.0.195
 +* Rustup to *rustc 1.27.0-nightly (ac3c2288f 2018-04-18)*
 +
 +## 0.0.194
 +* Rustup to *rustc 1.27.0-nightly (bd40cbbe1 2018-04-14)*
 +* New lints: [`cast_ptr_alignment`], [`transmute_ptr_to_ptr`], [`write_literal`], [`write_with_newline`], [`writeln_empty_string`]
 +
 +## 0.0.193
 +* Rustup to *rustc 1.27.0-nightly (eeea94c11 2018-04-06)*
 +
 +## 0.0.192
 +* Rustup to *rustc 1.27.0-nightly (fb44b4c0e 2018-04-04)*
 +* New lint: [`print_literal`]
 +
 +## 0.0.191
 +* Rustup to *rustc 1.26.0-nightly (ae544ee1c 2018-03-29)*
 +* Lint audit; categorize lints as style, correctness, complexity, pedantic, nursery, restriction.
 +
 +## 0.0.190
 +* Fix a bunch of intermittent cargo bugs
 +
 +## 0.0.189
 +* Rustup to *rustc 1.26.0-nightly (5508b2714 2018-03-18)*
 +
 +## 0.0.188
 +* Rustup to *rustc 1.26.0-nightly (392645394 2018-03-15)*
 +* New lint: [`while_immutable_condition`]
 +
 +## 0.0.187
 +* Rustup to *rustc 1.26.0-nightly (322d7f7b9 2018-02-25)*
 +* New lints: [`redundant_field_names`], [`suspicious_arithmetic_impl`], [`suspicious_op_assign_impl`]
 +
 +## 0.0.186
 +* Rustup to *rustc 1.25.0-nightly (0c6091fbd 2018-02-04)*
 +* Various false positive fixes
 +
 +## 0.0.185
 +* Rustup to *rustc 1.25.0-nightly (56733bc9f 2018-02-01)*
 +* New lint: [`question_mark`]
 +
 +## 0.0.184
 +* Rustup to *rustc 1.25.0-nightly (90eb44a58 2018-01-29)*
 +* New lints: [`double_comparisons`], [`empty_line_after_outer_attr`]
 +
 +## 0.0.183
 +* Rustup to *rustc 1.25.0-nightly (21882aad7 2018-01-28)*
 +* New lint: [`misaligned_transmute`]
 +
 +## 0.0.182
 +* Rustup to *rustc 1.25.0-nightly (a0dcecff9 2018-01-24)*
 +* New lint: [`decimal_literal_representation`]
 +
 +## 0.0.181
 +* Rustup to *rustc 1.25.0-nightly (97520ccb1 2018-01-21)*
 +* New lints: [`else_if_without_else`], [`option_option`], [`unit_arg`], [`unnecessary_fold`]
 +* Removed `unit_expr`
 +* Various false positive fixes for [`needless_pass_by_value`]
 +
 +## 0.0.180
 +* Rustup to *rustc 1.25.0-nightly (3f92e8d89 2018-01-14)*
 +
 +## 0.0.179
 +* Rustup to *rustc 1.25.0-nightly (61452e506 2018-01-09)*
 +
 +## 0.0.178
 +* Rustup to *rustc 1.25.0-nightly (ee220daca 2018-01-07)*
 +
 +## 0.0.177
 +* Rustup to *rustc 1.24.0-nightly (250b49205 2017-12-21)*
 +* New lint: [`match_as_ref`]
 +
 +## 0.0.176
 +* Rustup to *rustc 1.24.0-nightly (0077d128d 2017-12-14)*
 +
 +## 0.0.175
 +* Rustup to *rustc 1.24.0-nightly (bb42071f6 2017-12-01)*
 +
 +## 0.0.174
 +* Rustup to *rustc 1.23.0-nightly (63739ab7b 2017-11-21)*
 +
 +## 0.0.173
 +* Rustup to *rustc 1.23.0-nightly (33374fa9d 2017-11-20)*
 +
 +## 0.0.172
 +* Rustup to *rustc 1.23.0-nightly (d0f8e2913 2017-11-16)*
 +
 +## 0.0.171
 +* Rustup to *rustc 1.23.0-nightly (ff0f5de3b 2017-11-14)*
 +
 +## 0.0.170
 +* Rustup to *rustc 1.23.0-nightly (d6b06c63a 2017-11-09)*
 +
 +## 0.0.169
 +* Rustup to *rustc 1.23.0-nightly (3b82e4c74 2017-11-05)*
 +* New lints: [`just_underscores_and_digits`], `result_map_unwrap_or_else`, [`transmute_bytes_to_str`]
 +
 +## 0.0.168
 +* Rustup to *rustc 1.23.0-nightly (f0fe716db 2017-10-30)*
 +
 +## 0.0.167
 +* Rustup to *rustc 1.23.0-nightly (90ef3372e 2017-10-29)*
 +* New lints: `const_static_lifetime`, [`erasing_op`], [`fallible_impl_from`], [`println_empty_string`], [`useless_asref`]
 +
 +## 0.0.166
 +* Rustup to *rustc 1.22.0-nightly (b7960878b 2017-10-18)*
 +* New lints: [`explicit_write`], `identity_conversion`, [`implicit_hasher`], `invalid_ref`, [`option_map_or_none`],
 +  [`range_minus_one`], [`range_plus_one`], [`transmute_int_to_bool`], [`transmute_int_to_char`],
 +  [`transmute_int_to_float`]
 +
 +## 0.0.165
 +* Rust upgrade to rustc 1.22.0-nightly (0e6f4cf51 2017-09-27)
 +* New lint: [`mut_range_bound`]
 +
 +## 0.0.164
 +* Update to *rustc 1.22.0-nightly (6c476ce46 2017-09-25)*
 +* New lint: [`int_plus_one`]
 +
 +## 0.0.163
 +* Update to *rustc 1.22.0-nightly (14039a42a 2017-09-22)*
 +
 +## 0.0.162
 +* Update to *rustc 1.22.0-nightly (0701b37d9 2017-09-18)*
 +* New lint: [`chars_last_cmp`]
 +* Improved suggestions for [`needless_borrow`], [`ptr_arg`],
 +
 +## 0.0.161
 +* Update to *rustc 1.22.0-nightly (539f2083d 2017-09-13)*
 +
 +## 0.0.160
 +* Update to *rustc 1.22.0-nightly (dd08c3070 2017-09-12)*
 +
 +## 0.0.159
 +* Update to *rustc 1.22.0-nightly (eba374fb2 2017-09-11)*
 +* New lint: [`clone_on_ref_ptr`]
 +
 +## 0.0.158
 +* New lint: [`manual_memcpy`]
 +* [`cast_lossless`] no longer has redundant parentheses in its suggestions
 +* Update to *rustc 1.22.0-nightly (dead08cb3 2017-09-08)*
 +
 +## 0.0.157 - 2017-09-04
 +* Update to *rustc 1.22.0-nightly (981ce7d8d 2017-09-03)*
 +* New lint: `unit_expr`
 +
 +## 0.0.156 - 2017-09-03
 +* Update to *rustc 1.22.0-nightly (744dd6c1d 2017-09-02)*
 +
 +## 0.0.155
 +* Update to *rustc 1.21.0-nightly (c11f689d2 2017-08-29)*
 +* New lint: [`infinite_iter`], [`maybe_infinite_iter`], [`cast_lossless`]
 +
 +## 0.0.154
 +* Update to *rustc 1.21.0-nightly (2c0558f63 2017-08-24)*
 +* Fix [`use_self`] triggering inside derives
 +* Add support for linting an entire workspace with `cargo clippy --all`
 +* New lint: [`naive_bytecount`]
 +
 +## 0.0.153
 +* Update to *rustc 1.21.0-nightly (8c303ed87 2017-08-20)*
 +* New lint: [`use_self`]
 +
 +## 0.0.152
 +* Update to *rustc 1.21.0-nightly (df511d554 2017-08-14)*
 +
 +## 0.0.151
 +* Update to *rustc 1.21.0-nightly (13d94d5fa 2017-08-10)*
 +
 +## 0.0.150
 +* Update to *rustc 1.21.0-nightly (215e0b10e 2017-08-08)*
 +
 +## 0.0.148
 +* Update to *rustc 1.21.0-nightly (37c7d0ebb 2017-07-31)*
 +* New lints: [`unreadable_literal`], [`inconsistent_digit_grouping`], [`large_digit_groups`]
 +
 +## 0.0.147
 +* Update to *rustc 1.21.0-nightly (aac223f4f 2017-07-30)*
 +
 +## 0.0.146
 +* Update to *rustc 1.21.0-nightly (52a330969 2017-07-27)*
 +* Fixes false positives in `inline_always`
 +* Fixes false negatives in `panic_params`
 +
 +## 0.0.145
 +* Update to *rustc 1.20.0-nightly (afe145d22 2017-07-23)*
 +
 +## 0.0.144
 +* Update to *rustc 1.20.0-nightly (086eaa78e 2017-07-15)*
 +
 +## 0.0.143
 +* Update to *rustc 1.20.0-nightly (d84693b93 2017-07-09)*
 +* Fix `cargo clippy` crashing on `dylib` projects
 +* Fix false positives around `nested_while_let` and `never_loop`
 +
 +## 0.0.142
 +* Update to *rustc 1.20.0-nightly (067971139 2017-07-02)*
 +
 +## 0.0.141
 +* Rewrite of the `doc_markdown` lint.
 +* Deprecated [`range_step_by_zero`]
 +* New lint: [`iterator_step_by_zero`]
 +* New lint: [`needless_borrowed_reference`]
 +* Update to *rustc 1.20.0-nightly (69c65d296 2017-06-28)*
 +
 +## 0.0.140 - 2017-06-16
 +* Update to *rustc 1.19.0-nightly (258ae6dd9 2017-06-15)*
 +
 +## 0.0.139 — 2017-06-10
 +* Update to *rustc 1.19.0-nightly (4bf5c99af 2017-06-10)*
 +* Fix bugs with for loop desugaring
 +* Check for [`AsRef`]/[`AsMut`] arguments in [`wrong_self_convention`]
 +
 +## 0.0.138 — 2017-06-05
 +* Update to *rustc 1.19.0-nightly (0418fa9d3 2017-06-04)*
 +
 +## 0.0.137 — 2017-06-05
 +* Update to *rustc 1.19.0-nightly (6684d176c 2017-06-03)*
 +
 +## 0.0.136 — 2017—05—26
 +* Update to *rustc 1.19.0-nightly (557967766 2017-05-26)*
 +
 +## 0.0.135 — 2017—05—24
 +* Update to *rustc 1.19.0-nightly (5b13bff52 2017-05-23)*
 +
 +## 0.0.134 — 2017—05—19
 +* Update to *rustc 1.19.0-nightly (0ed1ec9f9 2017-05-18)*
 +
 +## 0.0.133 — 2017—05—14
 +* Update to *rustc 1.19.0-nightly (826d8f385 2017-05-13)*
 +
 +## 0.0.132 — 2017—05—05
 +* Fix various bugs and some ices
 +
 +## 0.0.131 — 2017—05—04
 +* Update to *rustc 1.19.0-nightly (2d4ed8e0c 2017-05-03)*
 +
 +## 0.0.130 — 2017—05—03
 +* Update to *rustc 1.19.0-nightly (6a5fc9eec 2017-05-02)*
 +
 +## 0.0.129 — 2017-05-01
 +* Update to *rustc 1.19.0-nightly (06fb4d256 2017-04-30)*
 +
 +## 0.0.128 — 2017-04-28
 +* Update to *rustc 1.18.0-nightly (94e884b63 2017-04-27)*
 +
 +## 0.0.127 — 2017-04-27
 +* Update to *rustc 1.18.0-nightly (036983201 2017-04-26)*
 +* New lint: [`needless_continue`]
 +
 +## 0.0.126 — 2017-04-24
 +* Update to *rustc 1.18.0-nightly (2bd4b5c6d 2017-04-23)*
 +
 +## 0.0.125 — 2017-04-19
 +* Update to *rustc 1.18.0-nightly (9f2abadca 2017-04-18)*
 +
 +## 0.0.124 — 2017-04-16
 +* Update to *rustc 1.18.0-nightly (d5cf1cb64 2017-04-15)*
 +
 +## 0.0.123 — 2017-04-07
 +* Fix various false positives
 +
 +## 0.0.122 — 2017-04-07
 +* Rustup to *rustc 1.18.0-nightly (91ae22a01 2017-04-05)*
 +* New lint: [`op_ref`]
 +
 +## 0.0.121 — 2017-03-21
 +* Rustup to *rustc 1.17.0-nightly (134c4a0f0 2017-03-20)*
 +
 +## 0.0.120 — 2017-03-17
 +* Rustup to *rustc 1.17.0-nightly (0aeb9c129 2017-03-15)*
 +
 +## 0.0.119 — 2017-03-13
 +* Rustup to *rustc 1.17.0-nightly (824c9ebbd 2017-03-12)*
 +
 +## 0.0.118 — 2017-03-05
 +* Rustup to *rustc 1.17.0-nightly (b1e31766d 2017-03-03)*
 +
 +## 0.0.117 — 2017-03-01
 +* Rustup to *rustc 1.17.0-nightly (be760566c 2017-02-28)*
 +
 +## 0.0.116 — 2017-02-28
 +* Fix `cargo clippy` on 64 bit windows systems
 +
 +## 0.0.115 — 2017-02-27
 +* Rustup to *rustc 1.17.0-nightly (60a0edc6c 2017-02-26)*
 +* New lints: [`zero_ptr`], [`never_loop`], [`mut_from_ref`]
 +
 +## 0.0.114 — 2017-02-08
 +* Rustup to *rustc 1.17.0-nightly (c49d10207 2017-02-07)*
 +* Tests are now ui tests (testing the exact output of rustc)
 +
 +## 0.0.113 — 2017-02-04
 +* Rustup to *rustc 1.16.0-nightly (eedaa94e3 2017-02-02)*
 +* New lint: [`large_enum_variant`]
 +* `explicit_into_iter_loop` provides suggestions
 +
 +## 0.0.112 — 2017-01-27
 +* Rustup to *rustc 1.16.0-nightly (df8debf6d 2017-01-25)*
 +
 +## 0.0.111 — 2017-01-21
 +* Rustup to *rustc 1.16.0-nightly (a52da95ce 2017-01-20)*
 +
 +## 0.0.110 — 2017-01-20
 +* Add badges and categories to `Cargo.toml`
 +
 +## 0.0.109 — 2017-01-19
 +* Update to *rustc 1.16.0-nightly (c07a6ae77 2017-01-17)*
 +
 +## 0.0.108 — 2017-01-12
 +* Update to *rustc 1.16.0-nightly (2782e8f8f 2017-01-12)*
 +
 +## 0.0.107 — 2017-01-11
 +* Update regex dependency
 +* Fix FP when matching `&&mut` by `&ref`
 +* Reintroduce `for (_, x) in &mut hash_map` -> `for x in hash_map.values_mut()`
 +* New lints: [`unused_io_amount`], [`forget_ref`], [`short_circuit_statement`]
 +
 +## 0.0.106 — 2017-01-04
 +* Fix FP introduced by rustup in [`wrong_self_convention`]
 +
 +## 0.0.105 — 2017-01-04
 +* Update to *rustc 1.16.0-nightly (468227129 2017-01-03)*
 +* New lints: [`deref_addrof`], [`double_parens`], [`pub_enum_variant_names`]
 +* Fix suggestion in [`new_without_default`]
 +* FP fix in [`absurd_extreme_comparisons`]
 +
 +## 0.0.104 — 2016-12-15
 +* Update to *rustc 1.15.0-nightly (8f02c429a 2016-12-15)*
 +
 +## 0.0.103 — 2016-11-25
 +* Update to *rustc 1.15.0-nightly (d5814b03e 2016-11-23)*
 +
 +## 0.0.102 — 2016-11-24
 +* Update to *rustc 1.15.0-nightly (3bf2be9ce 2016-11-22)*
 +
 +## 0.0.101 — 2016-11-23
 +* Update to *rustc 1.15.0-nightly (7b3eeea22 2016-11-21)*
 +* New lint: [`string_extend_chars`]
 +
 +## 0.0.100 — 2016-11-20
 +* Update to *rustc 1.15.0-nightly (ac635aa95 2016-11-18)*
 +
 +## 0.0.99 — 2016-11-18
 +* Update to rustc 1.15.0-nightly (0ed951993 2016-11-14)
 +* New lint: [`get_unwrap`]
 +
 +## 0.0.98 — 2016-11-08
 +* Fixes an issue due to a change in how cargo handles `--sysroot`, which broke `cargo clippy`
 +
 +## 0.0.97 — 2016-11-03
 +* For convenience, `cargo clippy` defines a `cargo-clippy` feature. This was
 +  previously added for a short time under the name `clippy` but removed for
 +  compatibility.
 +* `cargo clippy --help` is more helping (and less helpful :smile:)
 +* Rustup to *rustc 1.14.0-nightly (5665bdf3e 2016-11-02)*
 +* New lints: [`if_let_redundant_pattern_matching`], [`partialeq_ne_impl`]
 +
 +## 0.0.96 — 2016-10-22
 +* Rustup to *rustc 1.14.0-nightly (f09420685 2016-10-20)*
 +* New lint: [`iter_skip_next`]
 +
 +## 0.0.95 — 2016-10-06
 +* Rustup to *rustc 1.14.0-nightly (3210fd5c2 2016-10-05)*
 +
 +## 0.0.94 — 2016-10-04
 +* Fixes bustage on Windows due to forbidden directory name
 +
 +## 0.0.93 — 2016-10-03
 +* Rustup to *rustc 1.14.0-nightly (144af3e97 2016-10-02)*
 +* `option_map_unwrap_or` and `option_map_unwrap_or_else` are now
 +  allowed by default.
 +* New lint: [`explicit_into_iter_loop`]
 +
 +## 0.0.92 — 2016-09-30
 +* Rustup to *rustc 1.14.0-nightly (289f3a4ca 2016-09-29)*
 +
 +## 0.0.91 — 2016-09-28
 +* Rustup to *rustc 1.13.0-nightly (d0623cf7b 2016-09-26)*
 +
 +## 0.0.90 — 2016-09-09
 +* Rustup to *rustc 1.13.0-nightly (f1f40f850 2016-09-09)*
 +
 +## 0.0.89 — 2016-09-06
 +* Rustup to *rustc 1.13.0-nightly (cbe4de78e 2016-09-05)*
 +
 +## 0.0.88 — 2016-09-04
 +* Rustup to *rustc 1.13.0-nightly (70598e04f 2016-09-03)*
 +* The following lints are not new but were only usable through the `clippy`
 +  lint groups: [`filter_next`], `for_loop_over_option`,
 +  `for_loop_over_result` and [`match_overlapping_arm`]. You should now be
 +  able to `#[allow/deny]` them individually and they are available directly
 +  through `cargo clippy`.
 +
 +## 0.0.87 — 2016-08-31
 +* Rustup to *rustc 1.13.0-nightly (eac41469d 2016-08-30)*
 +* New lints: [`builtin_type_shadow`]
 +* Fix FP in [`zero_prefixed_literal`] and `0b`/`0o`
 +
 +## 0.0.86 — 2016-08-28
 +* Rustup to *rustc 1.13.0-nightly (a23064af5 2016-08-27)*
 +* New lints: [`missing_docs_in_private_items`], [`zero_prefixed_literal`]
 +
 +## 0.0.85 — 2016-08-19
 +* Fix ICE with [`useless_attribute`]
 +* [`useless_attribute`] ignores `unused_imports` on `use` statements
 +
 +## 0.0.84 — 2016-08-18
 +* Rustup to *rustc 1.13.0-nightly (aef6971ca 2016-08-17)*
 +
 +## 0.0.83 — 2016-08-17
 +* Rustup to *rustc 1.12.0-nightly (1bf5fa326 2016-08-16)*
 +* New lints: [`print_with_newline`], [`useless_attribute`]
 +
 +## 0.0.82 — 2016-08-17
 +* Rustup to *rustc 1.12.0-nightly (197be89f3 2016-08-15)*
 +* New lint: [`module_inception`]
 +
 +## 0.0.81 — 2016-08-14
 +* Rustup to *rustc 1.12.0-nightly (1deb02ea6 2016-08-12)*
 +* New lints: [`eval_order_dependence`], [`mixed_case_hex_literals`], [`unseparated_literal_suffix`]
 +* False positive fix in [`too_many_arguments`]
 +* Addition of functionality to [`needless_borrow`]
 +* Suggestions for [`clone_on_copy`]
 +* Bug fix in [`wrong_self_convention`]
 +* Doc improvements
 +
 +## 0.0.80 — 2016-07-31
 +* Rustup to *rustc 1.12.0-nightly (1225e122f 2016-07-30)*
 +* New lints: [`misrefactored_assign_op`], [`serde_api_misuse`]
 +
 +## 0.0.79 — 2016-07-10
 +* Rustup to *rustc 1.12.0-nightly (f93aaf84c 2016-07-09)*
 +* Major suggestions refactoring
 +
 +## 0.0.78 — 2016-07-02
 +* Rustup to *rustc 1.11.0-nightly (01411937f 2016-07-01)*
 +* New lints: [`wrong_transmute`], [`double_neg`], [`filter_map`]
 +* For compatibility, `cargo clippy` does not defines the `clippy` feature
 +  introduced in 0.0.76 anymore
 +* [`collapsible_if`] now considers `if let`
 +
 +## 0.0.77 — 2016-06-21
 +* Rustup to *rustc 1.11.0-nightly (5522e678b 2016-06-20)*
 +* New lints: `stutter` and [`iter_nth`]
 +
 +## 0.0.76 — 2016-06-10
 +* Rustup to *rustc 1.11.0-nightly (7d2f75a95 2016-06-09)*
 +* `cargo clippy` now automatically defines the `clippy` feature
 +* New lint: [`not_unsafe_ptr_arg_deref`]
 +
 +## 0.0.75 — 2016-06-08
 +* Rustup to *rustc 1.11.0-nightly (763f9234b 2016-06-06)*
 +
 +## 0.0.74 — 2016-06-07
 +* Fix bug with `cargo-clippy` JSON parsing
 +* Add the `CLIPPY_DISABLE_DOCS_LINKS` environment variable to deactivate the
 +  “for further information visit *lint-link*” message.
 +
 +## 0.0.73 — 2016-06-05
 +* Fix false positives in [`useless_let_if_seq`]
 +
 +## 0.0.72 — 2016-06-04
 +* Fix false positives in [`useless_let_if_seq`]
 +
 +## 0.0.71 — 2016-05-31
 +* Rustup to *rustc 1.11.0-nightly (a967611d8 2016-05-30)*
 +* New lint: [`useless_let_if_seq`]
 +
 +## 0.0.70 — 2016-05-28
 +* Rustup to *rustc 1.10.0-nightly (7bddce693 2016-05-27)*
 +* [`invalid_regex`] and [`trivial_regex`] can now warn on `RegexSet::new`,
 +  `RegexBuilder::new` and byte regexes
 +
 +## 0.0.69 — 2016-05-20
 +* Rustup to *rustc 1.10.0-nightly (476fe6eef 2016-05-21)*
 +* [`used_underscore_binding`] has been made `Allow` temporarily
 +
 +## 0.0.68 — 2016-05-17
 +* Rustup to *rustc 1.10.0-nightly (cd6a40017 2016-05-16)*
 +* New lint: [`unnecessary_operation`]
 +
 +## 0.0.67 — 2016-05-12
 +* Rustup to *rustc 1.10.0-nightly (22ac88f1a 2016-05-11)*
 +
 +## 0.0.66 — 2016-05-11
 +* New `cargo clippy` subcommand
 +* New lints: [`assign_op_pattern`], [`assign_ops`], [`needless_borrow`]
 +
 +## 0.0.65 — 2016-05-08
 +* Rustup to *rustc 1.10.0-nightly (62e2b2fb7 2016-05-06)*
 +* New lints: [`float_arithmetic`], [`integer_arithmetic`]
 +
 +## 0.0.64 — 2016-04-26
 +* Rustup to *rustc 1.10.0-nightly (645dd013a 2016-04-24)*
 +* New lints: `temporary_cstring_as_ptr`, [`unsafe_removed_from_name`], and [`mem_forget`]
 +
 +## 0.0.63 — 2016-04-08
 +* Rustup to *rustc 1.9.0-nightly (7979dd608 2016-04-07)*
 +
 +## 0.0.62 — 2016-04-07
 +* Rustup to *rustc 1.9.0-nightly (bf5da36f1 2016-04-06)*
 +
 +## 0.0.61 — 2016-04-03
 +* Rustup to *rustc 1.9.0-nightly (5ab11d72c 2016-04-02)*
 +* New lint: [`invalid_upcast_comparisons`]
 +
 +## 0.0.60 — 2016-04-01
 +* Rustup to *rustc 1.9.0-nightly (e1195c24b 2016-03-31)*
 +
 +## 0.0.59 — 2016-03-31
 +* Rustup to *rustc 1.9.0-nightly (30a3849f2 2016-03-30)*
 +* New lints: [`logic_bug`], [`nonminimal_bool`]
 +* Fixed: [`match_same_arms`] now ignores arms with guards
 +* Improved: [`useless_vec`] now warns on `for … in vec![…]`
 +
 +## 0.0.58 — 2016-03-27
 +* Rustup to *rustc 1.9.0-nightly (d5a91e695 2016-03-26)*
 +* New lint: [`doc_markdown`]
 +
 +## 0.0.57 — 2016-03-27
 +* Update to *rustc 1.9.0-nightly (a1e29daf1 2016-03-25)*
 +* Deprecated lints: [`str_to_string`], [`string_to_string`], [`unstable_as_slice`], [`unstable_as_mut_slice`]
 +* New lint: [`crosspointer_transmute`]
 +
 +## 0.0.56 — 2016-03-23
 +* Update to *rustc 1.9.0-nightly (0dcc413e4 2016-03-22)*
 +* New lints: [`many_single_char_names`] and [`similar_names`]
 +
 +## 0.0.55 — 2016-03-21
 +* Update to *rustc 1.9.0-nightly (02310fd31 2016-03-19)*
 +
 +## 0.0.54 — 2016-03-16
 +* Update to *rustc 1.9.0-nightly (c66d2380a 2016-03-15)*
 +
 +## 0.0.53 — 2016-03-15
 +* Add a [configuration file]
 +
 +## ~~0.0.52~~
 +
 +## 0.0.51 — 2016-03-13
 +* Add `str` to types considered by [`len_zero`]
 +* New lints: [`indexing_slicing`]
 +
 +## 0.0.50 — 2016-03-11
 +* Update to *rustc 1.9.0-nightly (c9629d61c 2016-03-10)*
 +
 +## 0.0.49 — 2016-03-09
 +* Update to *rustc 1.9.0-nightly (eabfc160f 2016-03-08)*
 +* New lints: [`overflow_check_conditional`], `unused_label`, [`new_without_default`]
 +
 +## 0.0.48 — 2016-03-07
 +* Fixed: ICE in [`needless_range_loop`] with globals
 +
 +## 0.0.47 — 2016-03-07
 +* Update to *rustc 1.9.0-nightly (998a6720b 2016-03-07)*
 +* New lint: [`redundant_closure_call`]
 +
 +[`AsMut`]: https://doc.rust-lang.org/std/convert/trait.AsMut.html
 +[`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html
 +[configuration file]: ./rust-clippy#configuration
 +[pull3665]: https://github.com/rust-lang/rust-clippy/pull/3665
 +[adding_lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md
 +[`README.md`]: https://github.com/rust-lang/rust-clippy/blob/master/README.md
 +
 +<!-- lint disable no-unused-definitions -->
 +<!-- begin autogenerated links to lint list -->
 +[`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
 +[`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
 +[`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
 +[`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
 +[`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
 +[`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern
 +[`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops
 +[`async_yields_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#async_yields_async
 +[`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock
 +[`await_holding_refcell_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_refcell_ref
 +[`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask
 +[`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map
 +[`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name
 +[`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints
 +[`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions
 +[`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison
 +[`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
 +[`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
 +[`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
 +[`box_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection
 +[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
 +[`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
 +[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
 +[`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth
 +[`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata
 +[`case_sensitive_file_extension_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#case_sensitive_file_extension_comparisons
 +[`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless
 +[`cast_possible_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_truncation
 +[`cast_possible_wrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_wrap
 +[`cast_precision_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_precision_loss
 +[`cast_ptr_alignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ptr_alignment
 +[`cast_ref_to_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ref_to_mut
 +[`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss
 +[`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8
 +[`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp
 +[`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp
 +[`checked_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions
 +[`clone_double_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref
 +[`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy
 +[`clone_on_ref_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_ref_ptr
 +[`cloned_instead_of_copied`]: https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied
 +[`cmp_nan`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_nan
 +[`cmp_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_null
 +[`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned
 +[`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity
 +[`collapsible_else_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if
 +[`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
 +[`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match
 +[`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
 +[`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
 +[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
 +[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
 +[`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
 +[`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro
 +[`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
 +[`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
 +[`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
 +[`default_numeric_fallback`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback
 +[`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access
 +[`deprecated_cfg_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr
 +[`deprecated_semver`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_semver
 +[`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof
 +[`derivable_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls
 +[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
 +[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
 +[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
 +[`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents
 +[`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
 +[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
 +[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 +[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
 +[`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
 +[`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
 +[`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
 +[`drop_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy
 +[`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
 +[`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
 +[`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
 +[`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
 +[`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum
 +[`empty_line_after_outer_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_outer_attr
 +[`empty_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_loop
 +[`enum_clike_unportable_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_clike_unportable_variant
 +[`enum_glob_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_glob_use
 +[`enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names
 +[`eq_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#eq_op
 +[`equatable_if_let`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_if_let
 +[`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op
 +[`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
 +[`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision
 +[`exhaustive_enums`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_enums
 +[`exhaustive_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_structs
 +[`exit`]: https://rust-lang.github.io/rust-clippy/master/index.html#exit
 +[`expect_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_fun_call
 +[`expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_used
 +[`expl_impl_clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#expl_impl_clone_on_copy
 +[`explicit_counter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_counter_loop
 +[`explicit_deref_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_deref_methods
 +[`explicit_into_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_into_iter_loop
 +[`explicit_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop
 +[`explicit_write`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_write
 +[`extend_from_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_from_slice
 +[`extend_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_with_drain
 +[`extra_unused_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes
 +[`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from
 +[`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
 +[`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file
 +[`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map
 +[`filter_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_identity
 +[`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next
 +[`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next
 +[`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map
 +[`flat_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_identity
 +[`flat_map_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_option
 +[`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic
 +[`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp
 +[`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const
 +[`float_equality_without_abs`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_equality_without_abs
 +[`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons
 +[`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools
 +[`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
 +[`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any
 +[`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
 +[`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map
 +[`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
 +[`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
 +[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
 +[`format_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_in_format_args
 +[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
 +[`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
 +[`from_str_radix_10`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_str_radix_10
 +[`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
 +[`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
 +[`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
 +[`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op
 +[`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex
 +[`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
 +[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
 +[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
 +[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
 +[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
 +[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
 +[`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
 +[`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
 +[`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub
 +[`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
 +[`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
 +[`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor
 +[`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing
 +[`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask
 +[`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string
 +[`infallible_destructuring_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_destructuring_match
 +[`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter
 +[`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string
 +[`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display
 +[`inline_always`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_always
 +[`inline_asm_x86_att_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_att_syntax
 +[`inline_asm_x86_intel_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_intel_syntax
 +[`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body
 +[`inspect_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#inspect_for_each
 +[`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
 +[`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
 +[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
 +[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
 +[`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage
 +[`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
 +[`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
 +[`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters
 +[`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements
 +[`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect
 +[`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count
 +[`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
 +[`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice
 +[`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator
 +[`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth
 +[`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero
 +[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
 +[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
 +[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
 +[`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays
 +[`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups
 +[`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
 +[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
 +[`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value
 +[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
 +[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
 +[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
 +[`let_underscore_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_drop
 +[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
 +[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
 +[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
 +[`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist
 +[`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
 +[`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
 +[`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
 +[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
++[`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
 +[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
 +[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
 +[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
 +[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
 +[`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
 +[`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
 +[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
 +[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
 +[`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
 +[`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
 +[`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once
 +[`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat
 +[`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
 +[`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
 +[`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
 +[`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
 +[`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
 +[`map_collect_result_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_collect_result_unit
 +[`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
 +[`map_err_ignore`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_err_ignore
 +[`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten
 +[`map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_identity
 +[`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
 +[`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref
 +[`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool
 +[`match_like_matches_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro
 +[`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items
 +[`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm
 +[`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats
 +[`match_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_result_ok
 +[`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms
 +[`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding
 +[`match_str_case_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_str_case_mismatch
 +[`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
 +[`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
 +[`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
 +[`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget
 +[`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none
 +[`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default
 +[`mem_replace_with_uninit`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_uninit
 +[`min_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_max
 +[`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute
 +[`mismatched_target_os`]: https://rust-lang.github.io/rust-clippy/master/index.html#mismatched_target_os
 +[`misrefactored_assign_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#misrefactored_assign_op
 +[`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn
 +[`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
 +[`missing_enforced_import_renames`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames
 +[`missing_errors_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc
 +[`missing_inline_in_public_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_inline_in_public_items
 +[`missing_panics_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc
 +[`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc
 +[`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes
 +[`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals
 +[`mod_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#mod_module_files
 +[`module_inception`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_inception
 +[`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions
 +[`modulo_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic
 +[`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one
 +[`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
 +[`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
 +[`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate
 +[`must_use_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_unit
 +[`mut_from_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref
 +[`mut_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_mut
 +[`mut_mutex_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_mutex_lock
 +[`mut_range_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_range_bound
 +[`mutable_key_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type
 +[`mutex_atomic`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_atomic
 +[`mutex_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_integer
 +[`naive_bytecount`]: https://rust-lang.github.io/rust-clippy/master/index.html#naive_bytecount
 +[`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type
 +[`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool
 +[`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool
 +[`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
 +[`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference
 +[`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect
 +[`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue
 +[`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main
 +[`needless_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each
 +[`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
 +[`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref
 +[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
 +[`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark
 +[`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop
 +[`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
 +[`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update
 +[`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord
 +[`neg_multiply`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_multiply
 +[`negative_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#negative_feature_names
 +[`never_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#never_loop
 +[`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self
 +[`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
 +[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
 +[`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
 +[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
 +[`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
 +[`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
 +[`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool
 +[`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
 +[`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces
 +[`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref
 +[`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect
 +[`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
 +[`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref
 +[`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap
 +[`option_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_filter_map
 +[`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
 +[`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none
 +[`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn
 +[`option_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option
 +[`or_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call
 +[`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
 +[`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
 +[`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic
 +[`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
 +[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
 +[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
 +[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
 +[`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
 +[`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
 +[`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
 +[`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal
 +[`print_stderr`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr
 +[`print_stdout`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout
 +[`print_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_with_newline
 +[`println_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#println_empty_string
 +[`ptr_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg
 +[`ptr_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr
 +[`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq
 +[`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
 +[`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
 +[`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark
 +[`range_minus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_minus_one
 +[`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
 +[`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
 +[`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len
 +[`rc_buffer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer
 +[`rc_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex
 +[`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
 +[`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
 +[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
 +[`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call
 +[`redundant_closure_for_method_calls`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_for_method_calls
 +[`redundant_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else
 +[`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names
 +[`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
 +[`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
 +[`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
 +[`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
 +[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
 +[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
 +[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
 +[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
 +[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
 +[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
 +[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
 +[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
 +[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
 +[`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
 +[`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
 +[`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err
 +[`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
 +[`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
 +[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
 +[`same_name_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_name_method
 +[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
 +[`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment
 +[`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors
 +[`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files
 +[`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
++[`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix
 +[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
 +[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
 +[`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same
 +[`shadow_unrelated`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated
 +[`short_circuit_statement`]: https://rust-lang.github.io/rust-clippy/master/index.html#short_circuit_statement
 +[`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq
 +[`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
 +[`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
 +[`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
 +[`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
 +[`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports
 +[`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop
 +[`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
 +[`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
 +[`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count
 +[`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
 +[`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
 +[`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
 +[`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string
 +[`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
 +[`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign
 +[`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
 +[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
 +[`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
++[`string_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_slice
 +[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
 +[`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
 +[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
 +[`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops
 +[`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
 +[`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting
 +[`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting
 +[`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
 +[`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
 +[`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings
 +[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
 +[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
 +[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
 +[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
 +[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
 +[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
 +[`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args
 +[`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
 +[`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
 +[`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
 +[`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg
 +[`trailing_empty_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#trailing_empty_array
 +[`trait_duplication_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#trait_duplication_in_bounds
 +[`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str
 +[`transmute_float_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_float_to_int
 +[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
 +[`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
 +[`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
 +[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
 +[`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
 +[`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
 +[`transmutes_expressible_as_ptr_casts`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmutes_expressible_as_ptr_casts
 +[`transmuting_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmuting_null
 +[`trivial_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivial_regex
 +[`trivially_copy_pass_by_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref
 +[`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err
 +[`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
 +[`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
 +[`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks
 +[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
 +[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
 +[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
 +[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
 +[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec
 +[`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg
 +[`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
++[`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash
 +[`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
 +[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
 +[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
 +[`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold
 +[`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations
 +[`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
 +[`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
 +[`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports
 +[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
 +[`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
 +[`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps
 +[`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern
 +[`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern
 +[`unnested_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns
 +[`unreachable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreachable
 +[`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal
 +[`unsafe_derive_deserialize`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_derive_deserialize
 +[`unsafe_removed_from_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_removed_from_name
 +[`unsafe_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_vector_initialization
 +[`unseparated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#unseparated_literal_suffix
 +[`unsound_collection_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsound_collection_transmute
 +[`unstable_as_mut_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_mut_slice
 +[`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice
 +[`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async
 +[`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
 +[`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
 +[`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
 +[`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
 +[`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
 +[`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result
 +[`unwrap_or_else_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_else_default
 +[`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
 +[`upper_case_acronyms`]: https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms
 +[`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug
 +[`use_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_self
 +[`used_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_binding
 +[`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref
 +[`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute
 +[`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
 +[`useless_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
 +[`useless_let_if_seq`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_let_if_seq
 +[`useless_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_transmute
 +[`useless_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec
 +[`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box
 +[`vec_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_init_then_push
 +[`vec_resize_to_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_resize_to_zero
 +[`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask
 +[`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
 +[`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons
 +[`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition
 +[`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop
 +[`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
 +[`wildcard_dependencies`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_dependencies
 +[`wildcard_enum_match_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_enum_match_arm
 +[`wildcard_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports
 +[`wildcard_in_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_in_or_patterns
 +[`write_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_literal
 +[`write_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_with_newline
 +[`writeln_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#writeln_empty_string
 +[`wrong_pub_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_pub_self_convention
 +[`wrong_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention
 +[`wrong_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_transmute
 +[`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero
 +[`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
 +[`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr
 +[`zero_sized_map_values`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_sized_map_values
 +[`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
 +<!-- end autogenerated links to lint list -->
index 4273fda4e640d5d9356a5d63f166db26224fc603,0000000000000000000000000000000000000000..97ff31b4bc5a3181727c5d8230ea463a6c1c170a
mode 100644,000000..100644
--- /dev/null
@@@ -1,381 -1,0 +1,383 @@@
-     # Make sure to change `your-github-name` to your github name in the following command
 +# Contributing to Clippy
 +
 +Hello fellow Rustacean! Great to see your interest in compiler internals and lints!
 +
 +**First**: if you're unsure or afraid of _anything_, just ask or submit the issue or pull request anyway. You won't be
 +yelled at for giving it your best effort. The worst that can happen is that you'll be politely asked to change
 +something. We appreciate any sort of contributions, and don't want a wall of rules to get in the way of that.
 +
 +Clippy welcomes contributions from everyone. There are many ways to contribute to Clippy and the following document
 +explains how you can contribute and how to get started.  If you have any questions about contributing or need help with
 +anything, feel free to ask questions on issues or visit the `#clippy` on [Zulip].
 +
 +All contributors are expected to follow the [Rust Code of Conduct].
 +
 +- [Contributing to Clippy](#contributing-to-clippy)
 +  - [Getting started](#getting-started)
 +    - [High level approach](#high-level-approach)
 +    - [Finding something to fix/improve](#finding-something-to-fiximprove)
 +  - [Writing code](#writing-code)
 +  - [Getting code-completion for rustc internals to work](#getting-code-completion-for-rustc-internals-to-work)
 +    - [IntelliJ Rust](#intellij-rust)
 +    - [Rust Analyzer](#rust-analyzer)
 +  - [How Clippy works](#how-clippy-works)
 +  - [Syncing changes between Clippy and `rust-lang/rust`](#syncing-changes-between-clippy-and-rust-langrust)
 +    - [Patching git-subtree to work with big repos](#patching-git-subtree-to-work-with-big-repos)
 +    - [Performing the sync from `rust-lang/rust` to Clippy](#performing-the-sync-from-rust-langrust-to-clippy)
 +    - [Performing the sync from Clippy to `rust-lang/rust`](#performing-the-sync-from-clippy-to-rust-langrust)
 +    - [Defining remotes](#defining-remotes)
 +  - [Issue and PR triage](#issue-and-pr-triage)
 +  - [Bors and Homu](#bors-and-homu)
 +  - [Contributions](#contributions)
 +
 +[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/clippy
 +[Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct
 +
 +## Getting started
 +
 +**Note: If this is your first time contributing to Clippy, you should
 +first read the [Basics docs](doc/basics.md).**
 +
 +### High level approach
 +
 +1. Find something to fix/improve
 +2. Change code (likely some file in `clippy_lints/src/`)
 +3. Follow the instructions in the [Basics docs](doc/basics.md) to get set up
 +4. Run `cargo test` in the root directory and wiggle code until it passes
 +5. Open a PR (also can be done after 2. if you run into problems)
 +
 +### Finding something to fix/improve
 +
 +All issues on Clippy are mentored, if you want help simply ask @Manishearth, @flip1995, @phansch
 +or @llogiq directly by mentioning them in the issue or over on [Zulip]. This list may be out of date.
 +All currently active mentors can be found [here](https://github.com/rust-lang/highfive/blob/master/highfive/configs/rust-lang/rust-clippy.json#L3)
 +
 +Some issues are easier than others. The [`good-first-issue`] label can be used to find the easy
 +issues. You can use `@rustbot claim` to assign the issue to yourself.
 +
 +There are also some abandoned PRs, marked with [`S-inactive-closed`].
 +Pretty often these PRs are nearly completed and just need some extra steps
 +(formatting, addressing review comments, ...) to be merged. If you want to
 +complete such a PR, please leave a comment in the PR and open a new one based
 +on it.
 +
 +Issues marked [`T-AST`] involve simple matching of the syntax tree structure,
 +and are generally easier than [`T-middle`] issues, which involve types
 +and resolved paths.
 +
 +[`T-AST`] issues will generally need you to match against a predefined syntax structure.
 +To figure out how this syntax structure is encoded in the AST, it is recommended to run
 +`rustc -Z ast-json` on an example of the structure and compare with the [nodes in the AST docs].
 +Usually the lint will end up to be a nested series of matches and ifs, [like so][deep-nesting].
 +But we can make it nest-less by using [if_chain] macro, [like this][nest-less].
 +
 +[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good-first-issue`]
 +first. Sometimes they are only somewhat involved code wise, but not difficult per-se.
 +Note that [`E-medium`] issues may require some knowledge of Clippy internals or some
 +debugging to find the actual problem behind the issue.
 +
 +[`T-middle`] issues can be more involved and require verifying types. The [`ty`] module contains a
 +lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of
 +an AST expression). `match_def_path()` in Clippy's `utils` module can also be useful.
 +
 +[`good-first-issue`]: https://github.com/rust-lang/rust-clippy/labels/good-first-issue
 +[`S-inactive-closed`]: https://github.com/rust-lang/rust-clippy/pulls?q=is%3Aclosed+label%3AS-inactive-closed
 +[`T-AST`]: https://github.com/rust-lang/rust-clippy/labels/T-AST
 +[`T-middle`]: https://github.com/rust-lang/rust-clippy/labels/T-middle
 +[`E-medium`]: https://github.com/rust-lang/rust-clippy/labels/E-medium
 +[`ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty
 +[nodes in the AST docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/
 +[deep-nesting]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/mem_forget.rs#L29-L43
 +[if_chain]: https://docs.rs/if_chain/*/if_chain
 +[nest-less]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/bit_mask.rs#L124-L150
 +
 +## Writing code
 +
 +Have a look at the [docs for writing lints][adding_lints] for more details.
 +
 +If you want to add a new lint or change existing ones apart from bugfixing, it's
 +also a good idea to give the [stability guarantees][rfc_stability] and
 +[lint categories][rfc_lint_cats] sections of the [Clippy 1.0 RFC][clippy_rfc] a
 +quick read.
 +
 +[adding_lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md
 +[clippy_rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md
 +[rfc_stability]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#stability-guarantees
 +[rfc_lint_cats]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories
 +
 +## Getting code-completion for rustc internals to work
 +
 +### IntelliJ Rust
 +Unfortunately, [`IntelliJ Rust`][IntelliJ_rust_homepage] does not (yet?) understand how Clippy uses compiler-internals
 +using `extern crate` and it also needs to be able to read the source files of the rustc-compiler which are not
 +available via a `rustup` component at the time of writing.
 +To work around this, you need to have a copy of the [rustc-repo][rustc_repo] available which can be obtained via
 +`git clone https://github.com/rust-lang/rust/`.
 +Then you can run a `cargo dev` command to automatically make Clippy use the rustc-repo via path-dependencies
 +which `IntelliJ Rust` will be able to understand.
 +Run `cargo dev setup intellij --repo-path <repo-path>` where `<repo-path>` is a path to the rustc repo
 +you just cloned.
 +The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to
 +Clippys `Cargo.toml`s and should allow `IntelliJ Rust` to understand most of the types that Clippy uses.
 +Just make sure to remove the dependencies again before finally making a pull request!
 +
 +[rustc_repo]: https://github.com/rust-lang/rust/
 +[IntelliJ_rust_homepage]: https://intellij-rust.github.io/
 +
 +### Rust Analyzer
 +As of [#6869][6869], [`rust-analyzer`][ra_homepage] can understand that Clippy uses compiler-internals
 +using `extern crate` when `package.metadata.rust-analyzer.rustc_private` is set to `true` in Clippys `Cargo.toml.`
 +You will required a `nightly` toolchain with the `rustc-dev` component installed.
 +Make sure that in the `rust-analyzer` configuration, you set
 +```
 +{ "rust-analyzer.rustcSource": "discover" }
 +```
 +and
 +```
 +{ "rust-analyzer.updates.channel": "nightly" }
 +```
 +You should be able to see information on things like `Expr` or `EarlyContext` now if you hover them, also
 +a lot more type hints.
 +This will work with `rust-analyzer 2021-03-15` shipped in nightly `1.52.0-nightly (107896c32 2021-03-15)` or later.
 +
 +[ra_homepage]: https://rust-analyzer.github.io/
 +[6869]: https://github.com/rust-lang/rust-clippy/pull/6869
 +
 +## How Clippy works
 +
 +[`clippy_lints/src/lib.rs`][lint_crate_entry] imports all the different lint modules and registers in the [`LintStore`].
 +For example, the [`else_if_without_else`][else_if_without_else] lint is registered like this:
 +
 +```rust
 +// ./clippy_lints/src/lib.rs
 +
 +// ...
 +pub mod else_if_without_else;
 +// ...
 +
 +pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
 +    // ...
 +    store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
 +    // ...
 +
 +    store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
 +        // ...
 +        LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
 +        // ...
 +    ]);
 +}
 +```
 +
 +The [`rustc_lint::LintStore`][`LintStore`] provides two methods to register lints:
 +[register_early_pass][reg_early_pass] and [register_late_pass][reg_late_pass]. Both take an object
 +that implements an [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass] respectively. This is done in
 +every single lint. It's worth noting that the majority of `clippy_lints/src/lib.rs` is autogenerated by `cargo dev
 +update_lints`. When you are writing your own lint, you can use that script to save you some time.
 +
 +```rust
 +// ./clippy_lints/src/else_if_without_else.rs
 +
 +use rustc_lint::{EarlyLintPass, EarlyContext};
 +
 +// ...
 +
 +pub struct ElseIfWithoutElse;
 +
 +// ...
 +
 +impl EarlyLintPass for ElseIfWithoutElse {
 +    // ... the functions needed, to make the lint work
 +}
 +```
 +
 +The difference between `EarlyLintPass` and `LateLintPass` is that the methods of the `EarlyLintPass` trait only provide
 +AST information. The methods of the `LateLintPass` trait are executed after type checking and contain type information
 +via the `LateContext` parameter.
 +
 +That's why the `else_if_without_else` example uses the `register_early_pass` function. Because the
 +[actual lint logic][else_if_without_else] does not depend on any type information.
 +
 +[lint_crate_entry]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs
 +[else_if_without_else]: https://github.com/rust-lang/rust-clippy/blob/4253aa7137cb7378acc96133c787e49a345c2b3c/clippy_lints/src/else_if_without_else.rs
 +[`LintStore`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html
 +[reg_early_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_early_pass
 +[reg_late_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_late_pass
 +[early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html
 +[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
 +
 +## Syncing changes between Clippy and [`rust-lang/rust`]
 +
 +Clippy currently gets built with a pinned nightly version.
 +
 +In the `rust-lang/rust` repository, where rustc resides, there's a copy of Clippy
 +that compiler hackers modify from time to time to adapt to changes in the unstable
 +API of the compiler.
 +
 +We need to sync these changes back to this repository periodically, and the changes
 +made to this repository in the meantime also need to be synced to the `rust-lang/rust` repository.
 +
 +To avoid flooding the `rust-lang/rust` PR queue, this two-way sync process is done
 +in a bi-weekly basis if there's no urgent changes. This is done starting on the day of
 +the Rust stable release and then every other week. That way we guarantee that we keep
 +this repo up to date with the latest compiler API, and every feature in Clippy is available
 +for 2 weeks in nightly, before it can get to beta. For reference, the first sync
 +following this cadence was performed the 2020-08-27.
 +
 +This process is described in detail in the following sections. For general information
 +about `subtree`s in the Rust repository see [Rust's `CONTRIBUTING.md`][subtree].
 +
 +### Patching git-subtree to work with big repos
 +
 +Currently there's a bug in `git-subtree` that prevents it from working properly
 +with the [`rust-lang/rust`] repo. There's an open PR to fix that, but it's stale.
 +Before continuing with the following steps, we need to manually apply that fix to
 +our local copy of `git-subtree`.
 +
 +You can get the patched version of `git-subtree` from [here][gitgitgadget-pr].
 +Put this file under `/usr/lib/git-core` (taking a backup of the previous file)
 +and make sure it has the proper permissions:
 +
 +```bash
 +sudo cp --backup /path/to/patched/git-subtree.sh /usr/lib/git-core/git-subtree
 +sudo chmod --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree
 +sudo chown --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree
 +```
 +
 +_Note:_ The first time running `git subtree push` a cache has to be built. This
 +involves going through the complete Clippy history once. For this you have to
 +increase the stack limit though, which you can do with `ulimit -s 60000`.
 +Make sure to run the `ulimit` command from the same session you call git subtree.
 +
 +_Note:_ If you are a Debian user, `dash` is the shell used by default for scripts instead of `sh`.
 +This shell has a hardcoded recursion limit set to 1000. In order to make this process work,
 +you need to force the script to run `bash` instead. You can do this by editing the first
 +line of the `git-subtree` script and changing `sh` to `bash`.
 +
 +### Performing the sync from [`rust-lang/rust`] to Clippy
 +
 +Here is a TL;DR version of the sync process (all of the following commands have
 +to be run inside the `rust` directory):
 +
 +1. Clone the [`rust-lang/rust`] repository or make sure it is up to date.
 +2. Checkout the commit from the latest available nightly. You can get it using `rustup check`.
 +3. Sync the changes to the rust-copy of Clippy to your Clippy fork:
 +    ```bash
++    # Make sure to change `your-github-name` to your github name in the following command. Also be
++    # sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand
++    # because changes cannot be fast forwarded
 +    git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust
 +    ```
 +
 +    _Note:_ This will directly push to the remote repository. You can also push
 +    to your local copy by replacing the remote address with `/path/to/rust-clippy`
 +    directory.
 +
 +    _Note:_ Most of the time you have to create a merge commit in the
 +    `rust-clippy` repo (this has to be done in the Clippy repo, not in the
 +    rust-copy of Clippy):
 +    ```bash
 +    git fetch origin && git fetch upstream
 +    git checkout sync-from-rust
 +    git merge upstream/master
 +    ```
 +4. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to
 +   accelerate the process ping the `@rust-lang/clippy` team in your PR and/or
 +   ~~annoy~~ ask them in the [Zulip] stream.)
 +
 +### Performing the sync from Clippy to [`rust-lang/rust`]
 +
 +All of the following commands have to be run inside the `rust` directory.
 +
 +1. Make sure Clippy itself is up-to-date by following the steps outlined in the previous
 +section if necessary.
 +
 +2. Sync the `rust-lang/rust-clippy` master to the rust-copy of Clippy:
 +    ```bash
 +    git checkout -b sync-from-clippy
 +    git subtree pull -P src/tools/clippy https://github.com/rust-lang/rust-clippy master
 +    ```
 +3. Open a PR to [`rust-lang/rust`]
 +
 +### Defining remotes
 +
 +You may want to define remotes, so you don't have to type out the remote
 +addresses on every sync. You can do this with the following commands (these
 +commands still have to be run inside the `rust` directory):
 +
 +```bash
 +# Set clippy-upstream remote for pulls
 +$ git remote add clippy-upstream https://github.com/rust-lang/rust-clippy
 +# Make sure to not push to the upstream repo
 +$ git remote set-url --push clippy-upstream DISABLED
 +# Set clippy-origin remote to your fork for pushes
 +$ git remote add clippy-origin git@github.com:your-github-name/rust-clippy
 +# Set a local remote
 +$ git remote add clippy-local /path/to/rust-clippy
 +```
 +
 +You can then sync with the remote names from above, e.g.:
 +
 +```bash
 +$ git subtree push -P src/tools/clippy clippy-local sync-from-rust
 +```
 +
 +[gitgitgadget-pr]: https://github.com/gitgitgadget/git/pull/493
 +[subtree]: https://rustc-dev-guide.rust-lang.org/contributing.html#external-dependencies-subtree
 +[`rust-lang/rust`]: https://github.com/rust-lang/rust
 +
 +## Issue and PR triage
 +
 +Clippy is following the [Rust triage procedure][triage] for issues and pull
 +requests.
 +
 +However, we are a smaller project with all contributors being volunteers
 +currently. Between writing new lints, fixing issues, reviewing pull requests and
 +responding to issues there may not always be enough time to stay on top of it
 +all.
 +
 +Our highest priority is fixing [crashes][l-crash] and [bugs][l-bug], for example
 +an ICE in a popular crate that many other crates depend on. We don't
 +want Clippy to crash on your code and we want it to be as reliable as the
 +suggestions from Rust compiler errors.
 +
 +We have prioritization labels and a sync-blocker label, which are described below.
 +- [P-low][p-low]: Requires attention (fix/response/evaluation) by a team member but isn't urgent.
 +- [P-medium][p-medium]: Should be addressed by a team member until the next sync.
 +- [P-high][p-high]: Should be immediately addressed and will require an out-of-cycle sync or a backport.
 +- [L-sync-blocker][l-sync-blocker]: An issue that "blocks" a sync.
 +Or rather: before the sync this should be addressed,
 +e.g. by removing a lint again, so it doesn't hit beta/stable.
 +
 +## Bors and Homu
 +
 +We use a bot powered by [Homu][homu] to help automate testing and landing of pull
 +requests in Clippy. The bot's username is @bors.
 +
 +You can find the Clippy bors queue [here][homu_queue].
 +
 +If you have @bors permissions, you can find an overview of the available
 +commands [here][homu_instructions].
 +
 +[triage]: https://forge.rust-lang.org/release/triage-procedure.html
 +[l-crash]: https://github.com/rust-lang/rust-clippy/labels/L-crash
 +[l-bug]: https://github.com/rust-lang/rust-clippy/labels/L-bug
 +[p-low]: https://github.com/rust-lang/rust-clippy/labels/P-low
 +[p-medium]: https://github.com/rust-lang/rust-clippy/labels/P-medium
 +[p-high]: https://github.com/rust-lang/rust-clippy/labels/P-high
 +[l-sync-blocker]: https://github.com/rust-lang/rust-clippy/labels/L-sync-blocker
 +[homu]: https://github.com/rust-lang/homu
 +[homu_instructions]: https://bors.rust-lang.org/
 +[homu_queue]: https://bors.rust-lang.org/queue/clippy
 +
 +## Contributions
 +
 +Contributions to Clippy should be made in the form of GitHub pull requests. Each pull request will
 +be reviewed by a core contributor (someone with permission to land patches) and either landed in the
 +main tree or given feedback for changes that would be required.
 +
 +All code in this repository is under the [Apache-2.0] or the [MIT] license.
 +
 +<!-- adapted from https://github.com/servo/servo/blob/master/CONTRIBUTING.md -->
 +
 +[Apache-2.0]: https://www.apache.org/licenses/LICENSE-2.0
 +[MIT]: https://opensource.org/licenses/MIT
index d475aaa3ee0671cec1a7941e44a2aac6a3ab322e,0000000000000000000000000000000000000000..602877bb9d6831dfd824f6d0e8a4fdf143e96b59
mode 100644,000000..100644
--- /dev/null
@@@ -1,62 -1,0 +1,62 @@@
- compiletest_rs = { version = "0.7", features = ["tmp"] }
 +[package]
 +name = "clippy"
 +version = "0.1.58"
 +description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 +repository = "https://github.com/rust-lang/rust-clippy"
 +readme = "README.md"
 +license = "MIT OR Apache-2.0"
 +keywords = ["clippy", "lint", "plugin"]
 +categories = ["development-tools", "development-tools::cargo-plugins"]
 +build = "build.rs"
 +edition = "2021"
 +publish = false
 +
 +[[bin]]
 +name = "cargo-clippy"
 +test = false
 +path = "src/main.rs"
 +
 +[[bin]]
 +name = "clippy-driver"
 +path = "src/driver.rs"
 +
 +[dependencies]
 +clippy_lints = { version = "0.1", path = "clippy_lints" }
 +semver = "1.0"
 +rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
 +tempfile = { version = "3.2", optional = true }
 +
 +[dev-dependencies]
 +cargo_metadata = "0.14"
++compiletest_rs = { version = "0.7.1", features = ["tmp"] }
 +tester = "0.9"
 +regex = "1.5"
 +# This is used by the `collect-metadata` alias.
 +filetime = "0.2"
 +
 +# A noop dependency that changes in the Rust repository, it's a bit of a hack.
 +# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
 +# for more information.
 +rustc-workspace-hack = "1.0"
 +
 +# UI test dependencies
 +clippy_utils = { path = "clippy_utils" }
 +derive-new = "0.5"
 +if_chain = "1.0"
 +itertools = "0.10"
 +quote = "1.0"
 +serde = { version = "1.0", features = ["derive"] }
 +syn = { version = "1.0", features = ["full"] }
 +
 +[build-dependencies]
 +rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
 +
 +[features]
 +deny-warnings = ["clippy_lints/deny-warnings"]
 +integration = ["tempfile"]
 +internal-lints = ["clippy_lints/internal-lints"]
 +metadata-collector-lint = ["internal-lints", "clippy_lints/metadata-collector-lint"]
 +
 +[package.metadata.rust-analyzer]
 +# This package uses #[feature(rustc_private)]
 +rustc_private = true
index 25320907bb492767f36da58f48e97d0b2d366477,0000000000000000000000000000000000000000..43a478ee77db826975fcbda09202af1381a2981b
mode 100644,000000..100644
--- /dev/null
@@@ -1,280 -1,0 +1,298 @@@
-     create_test(&lint).context("Unable to create a test for the new lint")
 +use crate::clippy_project_root;
 +use indoc::indoc;
 +use std::fs::{self, OpenOptions};
 +use std::io::prelude::*;
 +use std::io::{self, ErrorKind};
 +use std::path::{Path, PathBuf};
 +
 +struct LintData<'a> {
 +    pass: &'a str,
 +    name: &'a str,
 +    category: &'a str,
 +    project_root: PathBuf,
 +}
 +
 +trait Context {
 +    fn context<C: AsRef<str>>(self, text: C) -> Self;
 +}
 +
 +impl<T> Context for io::Result<T> {
 +    fn context<C: AsRef<str>>(self, text: C) -> Self {
 +        match self {
 +            Ok(t) => Ok(t),
 +            Err(e) => {
 +                let message = format!("{}: {}", text.as_ref(), e);
 +                Err(io::Error::new(ErrorKind::Other, message))
 +            },
 +        }
 +    }
 +}
 +
 +/// Creates the files required to implement and test a new lint and runs `update_lints`.
 +///
 +/// # Errors
 +///
 +/// This function errors out if the files couldn't be created or written to.
 +pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>, msrv: bool) -> io::Result<()> {
 +    let lint = LintData {
 +        pass: pass.expect("`pass` argument is validated by clap"),
 +        name: lint_name.expect("`name` argument is validated by clap"),
 +        category: category.expect("`category` argument is validated by clap"),
 +        project_root: clippy_project_root(),
 +    };
 +
 +    create_lint(&lint, msrv).context("Unable to create lint implementation")?;
-     let pass_name = lint.pass;
++    create_test(&lint).context("Unable to create a test for the new lint")?;
++    add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")
 +}
 +
 +fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
 +    let lint_contents = get_lint_file_contents(lint, enable_msrv);
 +
 +    let lint_path = format!("clippy_lints/src/{}.rs", lint.name);
 +    write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())
 +}
 +
 +fn create_test(lint: &LintData<'_>) -> io::Result<()> {
 +    fn create_project_layout<P: Into<PathBuf>>(lint_name: &str, location: P, case: &str, hint: &str) -> io::Result<()> {
 +        let mut path = location.into().join(case);
 +        fs::create_dir(&path)?;
 +        write_file(path.join("Cargo.toml"), get_manifest_contents(lint_name, hint))?;
 +
 +        path.push("src");
 +        fs::create_dir(&path)?;
 +        let header = format!("// compile-flags: --crate-name={}", lint_name);
 +        write_file(path.join("main.rs"), get_test_file_contents(lint_name, Some(&header)))?;
 +
 +        Ok(())
 +    }
 +
 +    if lint.category == "cargo" {
 +        let relative_test_dir = format!("tests/ui-cargo/{}", lint.name);
 +        let test_dir = lint.project_root.join(relative_test_dir);
 +        fs::create_dir(&test_dir)?;
 +
 +        create_project_layout(lint.name, &test_dir, "fail", "Content that triggers the lint goes here")?;
 +        create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint")
 +    } else {
 +        let test_path = format!("tests/ui/{}.rs", lint.name);
 +        let test_contents = get_test_file_contents(lint.name, None);
 +        write_file(lint.project_root.join(test_path), test_contents)
 +    }
 +}
 +
++fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
++    let path = "clippy_lints/src/lib.rs";
++    let mut lib_rs = fs::read_to_string(path).context("reading")?;
++
++    let comment_start = lib_rs.find("// add lints here,").expect("Couldn't find comment");
++
++    let new_lint = if enable_msrv {
++        format!(
++            "store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n    ",
++            lint_pass = lint.pass,
++            module_name = lint.name,
++            camel_name = to_camel_case(lint.name),
++        )
++    } else {
++        format!(
++            "store.register_{lint_pass}_pass(|| Box::new({module_name}::{camel_name}));\n    ",
++            lint_pass = lint.pass,
++            module_name = lint.name,
++            camel_name = to_camel_case(lint.name),
++        )
++    };
++
++    lib_rs.insert_str(comment_start, &new_lint);
++
++    fs::write(path, lib_rs).context("writing")
++}
++
 +fn write_file<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
 +    fn inner(path: &Path, contents: &[u8]) -> io::Result<()> {
 +        OpenOptions::new()
 +            .write(true)
 +            .create_new(true)
 +            .open(path)?
 +            .write_all(contents)
 +    }
 +
 +    inner(path.as_ref(), contents.as_ref()).context(format!("writing to file: {}", path.as_ref().display()))
 +}
 +
 +fn to_camel_case(name: &str) -> String {
 +    name.split('_')
 +        .map(|s| {
 +            if s.is_empty() {
 +                String::from("")
 +            } else {
 +                [&s[0..1].to_uppercase(), &s[1..]].concat()
 +            }
 +        })
 +        .collect()
 +}
 +
 +fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String {
 +    let mut contents = format!(
 +        indoc! {"
 +            #![warn(clippy::{})]
 +
 +            fn main() {{
 +                // test code goes here
 +            }}
 +        "},
 +        lint_name
 +    );
 +
 +    if let Some(header) = header_commands {
 +        contents = format!("{}\n{}", header, contents);
 +    }
 +
 +    contents
 +}
 +
 +fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
 +    format!(
 +        indoc! {r#"
 +            # {}
 +
 +            [package]
 +            name = "{}"
 +            version = "0.1.0"
 +            publish = false
 +
 +            [workspace]
 +        "#},
 +        hint, lint_name
 +    )
 +}
 +
 +fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
 +    let mut result = String::new();
 +
 +    let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass {
 +        "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"),
 +        "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"),
 +        _ => {
 +            unreachable!("`pass_type` should only ever be `early` or `late`!");
 +        },
 +    };
 +
 +    let lint_name = lint.name;
-                 // TODO: Register the lint pass in `clippy_lints/src/lib.rs`,
-                 //       e.g. store.register_{pass_name}_pass(move || Box::new({module_name}::{name_camel}::new(msrv)));
 +    let category = lint.category;
 +    let name_camel = to_camel_case(lint.name);
 +    let name_upper = lint_name.to_uppercase();
 +
 +    result.push_str(&if enable_msrv {
 +        format!(
 +            indoc! {"
 +                use clippy_utils::msrvs;
 +                {pass_import}
 +                use rustc_lint::{{{context_import}, {pass_type}, LintContext}};
 +                use rustc_semver::RustcVersion;
 +                use rustc_session::{{declare_tool_lint, impl_lint_pass}};
 +
 +            "},
 +            pass_type = pass_type,
 +            pass_import = pass_import,
 +            context_import = context_import,
 +        )
 +    } else {
 +        format!(
 +            indoc! {"
 +                {pass_import}
 +                use rustc_lint::{{{context_import}, {pass_type}}};
 +                use rustc_session::{{declare_lint_pass, declare_tool_lint}};
 +
 +            "},
 +            pass_import = pass_import,
 +            pass_type = pass_type,
 +            context_import = context_import
 +        )
 +    });
 +
 +    result.push_str(&format!(
 +        indoc! {"
 +            declare_clippy_lint! {{
 +                /// ### What it does
 +                ///
 +                /// ### Why is this bad?
 +                ///
 +                /// ### Example
 +                /// ```rust
 +                /// // example code where clippy issues a warning
 +                /// ```
 +                /// Use instead:
 +                /// ```rust
 +                /// // example code which does not raise clippy warning
 +                /// ```
 +                pub {name_upper},
 +                {category},
 +                \"default lint description\"
 +            }}
 +        "},
 +        name_upper = name_upper,
 +        category = category,
 +    ));
 +
 +    result.push_str(&if enable_msrv {
 +        format!(
 +            indoc! {"
 +                pub struct {name_camel} {{
 +                    msrv: Option<RustcVersion>,
 +                }}
 +
 +                impl {name_camel} {{
 +                    #[must_use]
 +                    pub fn new(msrv: Option<RustcVersion>) -> Self {{
 +                        Self {{ msrv }}
 +                    }}
 +                }}
 +
 +                impl_lint_pass!({name_camel} => [{name_upper}]);
 +
 +                impl {pass_type}{pass_lifetimes} for {name_camel} {{
 +                    extract_msrv_attr!({context_import});
 +                }}
 +
-             pass_name = pass_name,
 +                // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed.
 +                // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`.
 +                // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
 +            "},
 +            pass_type = pass_type,
 +            pass_lifetimes = pass_lifetimes,
-             module_name = lint_name,
 +            name_upper = name_upper,
 +            name_camel = name_camel,
-                 //
-                 // TODO: Register the lint pass in `clippy_lints/src/lib.rs`,
-                 //       e.g. store.register_{pass_name}_pass(|| Box::new({module_name}::{name_camel}));
 +            context_import = context_import,
 +        )
 +    } else {
 +        format!(
 +            indoc! {"
 +                declare_lint_pass!({name_camel} => [{name_upper}]);
 +
 +                impl {pass_type}{pass_lifetimes} for {name_camel} {{}}
-             pass_name = pass_name,
 +            "},
 +            pass_type = pass_type,
 +            pass_lifetimes = pass_lifetimes,
-             module_name = lint_name,
 +            name_upper = name_upper,
 +            name_camel = name_camel,
 +        )
 +    });
 +
 +    result
 +}
 +
 +#[test]
 +fn test_camel_case() {
 +    let s = "a_lint";
 +    let s2 = to_camel_case(s);
 +    assert_eq!(s2, "ALint");
 +
 +    let name = "a_really_long_new_lint";
 +    let name2 = to_camel_case(name);
 +    assert_eq!(name2, "AReallyLongNewLint");
 +
 +    let name3 = "lint__name";
 +    let name4 = to_camel_case(name3);
 +    assert_eq!(name4, "LintName");
 +}
index 833ad122e0d4e20c46ae07f32c94157a4120f218,0000000000000000000000000000000000000000..4af412ccaf35d7d0946429c5b997f9ae7081792e
mode 100644,000000..100644
--- /dev/null
@@@ -1,54 -1,0 +1,127 @@@
- use rustc_hir::Expr;
++use clippy_utils::consts::{constant, Constant};
 +use clippy_utils::diagnostics::span_lint;
++use clippy_utils::expr_or_init;
 +use clippy_utils::ty::is_isize_or_usize;
- pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
++use rustc_hir::{BinOpKind, Expr, ExprKind};
 +use rustc_lint::LateContext;
 +use rustc_middle::ty::{self, FloatTy, Ty};
 +
 +use super::{utils, CAST_POSSIBLE_TRUNCATION};
 +
-             let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
++fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
++    if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) {
++        Some(c)
++    } else {
++        None
++    }
++}
++
++fn get_constant_bits(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u64> {
++    constant_int(cx, expr).map(|c| u64::from(128 - c.leading_zeros()))
++}
++
++fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: bool) -> u64 {
++    match expr_or_init(cx, expr).kind {
++        ExprKind::Cast(inner, _) => apply_reductions(cx, nbits, inner, signed),
++        ExprKind::Block(block, _) => block.expr.map_or(nbits, |e| apply_reductions(cx, nbits, e, signed)),
++        ExprKind::Binary(op, left, right) => match op.node {
++            BinOpKind::Div => {
++                apply_reductions(cx, nbits, left, signed)
++                    - (if signed {
++                        0 // let's be conservative here
++                    } else {
++                        // by dividing by 1, we remove 0 bits, etc.
++                        get_constant_bits(cx, right).map_or(0, |b| b.saturating_sub(1))
++                    })
++            },
++            BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right)
++                .unwrap_or(u64::max_value())
++                .min(apply_reductions(cx, nbits, left, signed)),
++            BinOpKind::Shr => {
++                apply_reductions(cx, nbits, left, signed)
++                    - constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))
++            },
++            _ => nbits,
++        },
++        ExprKind::MethodCall(method, _, [left, right], _) => {
++            if signed {
++                return nbits;
++            }
++            let max_bits = if method.ident.as_str() == "min" {
++                get_constant_bits(cx, right)
++            } else {
++                None
++            };
++            apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
++        },
++        ExprKind::MethodCall(method, _, [_, lo, hi], _) => {
++            if method.ident.as_str() == "clamp" {
++                //FIXME: make this a diagnostic item
++                if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) {
++                    return lo_bits.max(hi_bits);
++                }
++            }
++            nbits
++        },
++        ExprKind::MethodCall(method, _, [_value], _) => {
++            if method.ident.name.as_str() == "signum" {
++                0 // do not lint if cast comes from a `signum` function
++            } else {
++                nbits
++            }
++        },
++        _ => nbits,
++    }
++}
++
++pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
 +    let msg = match (cast_from.is_integral(), cast_to.is_integral()) {
 +        (true, true) => {
++            let from_nbits = apply_reductions(
++                cx,
++                utils::int_ty_to_nbits(cast_from, cx.tcx),
++                cast_expr,
++                cast_from.is_signed(),
++            );
 +            let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
 +
 +            let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) {
 +                (true, true) | (false, false) => (to_nbits < from_nbits, ""),
 +                (true, false) => (
 +                    to_nbits <= 32,
 +                    if to_nbits == 32 {
 +                        " on targets with 64-bit wide pointers"
 +                    } else {
 +                        ""
 +                    },
 +                ),
 +                (false, true) => (from_nbits == 64, " on targets with 32-bit wide pointers"),
 +            };
 +
 +            if !should_lint {
 +                return;
 +            }
 +
 +            format!(
 +                "casting `{}` to `{}` may truncate the value{}",
 +                cast_from, cast_to, suffix,
 +            )
 +        },
 +
 +        (false, true) => {
 +            format!("casting `{}` to `{}` may truncate the value", cast_from, cast_to)
 +        },
 +
 +        (_, _) => {
 +            if matches!(cast_from.kind(), &ty::Float(FloatTy::F64))
 +                && matches!(cast_to.kind(), &ty::Float(FloatTy::F32))
 +            {
 +                "casting `f64` to `f32` may truncate the value".to_string()
 +            } else {
 +                return;
 +            }
 +        },
 +    };
 +
 +    span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg);
 +}
index f0800c6a6f18f788bbb2804b20aaba1b8b362fc6,0000000000000000000000000000000000000000..233abd178943e9bc20b2685c68fd55f03d46a9c3
mode 100644,000000..100644
--- /dev/null
@@@ -1,445 -1,0 +1,445 @@@
-                 cast_possible_truncation::check(cx, expr, cast_from, cast_to);
 +mod cast_lossless;
 +mod cast_possible_truncation;
 +mod cast_possible_wrap;
 +mod cast_precision_loss;
 +mod cast_ptr_alignment;
 +mod cast_ref_to_mut;
 +mod cast_sign_loss;
 +mod char_lit_as_u8;
 +mod fn_to_numeric_cast;
 +mod fn_to_numeric_cast_any;
 +mod fn_to_numeric_cast_with_truncation;
 +mod ptr_as_ptr;
 +mod unnecessary_cast;
 +mod utils;
 +
 +use clippy_utils::is_hir_ty_cfg_dependant;
 +use rustc_hir::{Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts from any numerical to a float type where
 +    /// the receiving type cannot store all values from the original type without
 +    /// rounding errors. This possible rounding is to be expected, so this lint is
 +    /// `Allow` by default.
 +    ///
 +    /// Basically, this warns on casting any integer with 32 or more bits to `f32`
 +    /// or any 64-bit integer to `f64`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's not bad at all. But in some applications it can be
 +    /// helpful to know where precision loss can take place. This lint can help find
 +    /// those places in the code.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = u64::MAX;
 +    /// x as f64;
 +    /// ```
 +    pub CAST_PRECISION_LOSS,
 +    pedantic,
 +    "casts that cause loss of precision, e.g., `x as f32` where `x: u64`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts from a signed to an unsigned numerical
 +    /// type. In this case, negative values wrap around to large positive values,
 +    /// which can be quite surprising in practice. However, as the cast works as
 +    /// defined, this lint is `Allow` by default.
 +    ///
 +    /// ### Why is this bad?
 +    /// Possibly surprising results. You can activate this lint
 +    /// as a one-time check to see where numerical wrapping can arise.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let y: i8 = -1;
 +    /// y as u128; // will return 18446744073709551615
 +    /// ```
 +    pub CAST_SIGN_LOSS,
 +    pedantic,
 +    "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts between numerical types that may
 +    /// truncate large values. This is expected behavior, so the cast is `Allow` by
 +    /// default.
 +    ///
 +    /// ### Why is this bad?
 +    /// In some problem domains, it is good practice to avoid
 +    /// truncation. This lint can be activated to help assess where additional
 +    /// checks could be beneficial.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn as_u8(x: u64) -> u8 {
 +    ///     x as u8
 +    /// }
 +    /// ```
 +    pub CAST_POSSIBLE_TRUNCATION,
 +    pedantic,
 +    "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts from an unsigned type to a signed type of
 +    /// the same size. Performing such a cast is a 'no-op' for the compiler,
 +    /// i.e., nothing is changed at the bit level, and the binary representation of
 +    /// the value is reinterpreted. This can cause wrapping if the value is too big
 +    /// for the target signed type. However, the cast works as defined, so this lint
 +    /// is `Allow` by default.
 +    ///
 +    /// ### Why is this bad?
 +    /// While such a cast is not bad in itself, the results can
 +    /// be surprising when this is not the intended behavior, as demonstrated by the
 +    /// example below.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// u32::MAX as i32; // will yield a value of `-1`
 +    /// ```
 +    pub CAST_POSSIBLE_WRAP,
 +    pedantic,
 +    "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts between numerical types that may
 +    /// be replaced by safe conversion functions.
 +    ///
 +    /// ### Why is this bad?
 +    /// Rust's `as` keyword will perform many kinds of
 +    /// conversions, including silently lossy conversions. Conversion functions such
 +    /// as `i32::from` will only perform lossless conversions. Using the conversion
 +    /// functions prevents conversions from turning into silent lossy conversions if
 +    /// the types of the input expressions ever change, and make it easier for
 +    /// people reading the code to know that the conversion is lossless.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn as_u64(x: u8) -> u64 {
 +    ///     x as u64
 +    /// }
 +    /// ```
 +    ///
 +    /// Using `::from` would look like this:
 +    ///
 +    /// ```rust
 +    /// fn as_u64(x: u8) -> u64 {
 +    ///     u64::from(x)
 +    /// }
 +    /// ```
 +    pub CAST_LOSSLESS,
 +    pedantic,
 +    "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts to the same type, casts of int literals to integer types
 +    /// and casts of float literals to float types.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's just unnecessary.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = 2i32 as i32;
 +    /// let _ = 0.5 as f32;
 +    /// ```
 +    ///
 +    /// Better:
 +    ///
 +    /// ```rust
 +    /// let _ = 2_i32;
 +    /// let _ = 0.5_f32;
 +    /// ```
 +    pub UNNECESSARY_CAST,
 +    complexity,
 +    "cast to the same type, e.g., `x as i32` where `x: i32`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts, using `as` or `pointer::cast`,
 +    /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer
 +    ///
 +    /// ### Why is this bad?
 +    /// Dereferencing the resulting pointer may be undefined
 +    /// behavior.
 +    ///
 +    /// ### Known problems
 +    /// Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
 +    /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like
 +    /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = (&1u8 as *const u8) as *const u16;
 +    /// let _ = (&mut 1u8 as *mut u8) as *mut u16;
 +    ///
 +    /// (&1u8 as *const u8).cast::<u16>();
 +    /// (&mut 1u8 as *mut u8).cast::<u16>();
 +    /// ```
 +    pub CAST_PTR_ALIGNMENT,
 +    pedantic,
 +    "cast from a pointer to a more-strictly-aligned pointer"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts of function pointers to something other than usize
 +    ///
 +    /// ### Why is this bad?
 +    /// Casting a function pointer to anything other than usize/isize is not portable across
 +    /// architectures, because you end up losing bits if the target type is too small or end up with a
 +    /// bunch of extra bits that waste space and add more instructions to the final binary than
 +    /// strictly necessary for the problem
 +    ///
 +    /// Casting to isize also doesn't make sense since there are no signed addresses.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// fn fun() -> i32 { 1 }
 +    /// let a = fun as i64;
 +    ///
 +    /// // Good
 +    /// fn fun2() -> i32 { 1 }
 +    /// let a = fun2 as usize;
 +    /// ```
 +    pub FN_TO_NUMERIC_CAST,
 +    style,
 +    "casting a function pointer to a numeric type other than usize"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts of a function pointer to a numeric type not wide enough to
 +    /// store address.
 +    ///
 +    /// ### Why is this bad?
 +    /// Such a cast discards some bits of the function's address. If this is intended, it would be more
 +    /// clearly expressed by casting to usize first, then casting the usize to the intended type (with
 +    /// a comment) to perform the truncation.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// fn fn1() -> i16 {
 +    ///     1
 +    /// };
 +    /// let _ = fn1 as i32;
 +    ///
 +    /// // Better: Cast to usize first, then comment with the reason for the truncation
 +    /// fn fn2() -> i16 {
 +    ///     1
 +    /// };
 +    /// let fn_ptr = fn2 as usize;
 +    /// let fn_ptr_truncated = fn_ptr as i32;
 +    /// ```
 +    pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
 +    style,
 +    "casting a function pointer to a numeric type not wide enough to store the address"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts of a function pointer to any integer type.
 +    ///
 +    /// ### Why is this bad?
 +    /// Casting a function pointer to an integer can have surprising results and can occur
 +    /// accidentally if parantheses are omitted from a function call. If you aren't doing anything
 +    /// low-level with function pointers then you can opt-out of casting functions to integers in
 +    /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
 +    /// pointer casts in your code.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad: fn1 is cast as `usize`
 +    /// fn fn1() -> u16 {
 +    ///     1
 +    /// };
 +    /// let _ = fn1 as usize;
 +    ///
 +    /// // Good: maybe you intended to call the function?
 +    /// fn fn2() -> u16 {
 +    ///     1
 +    /// };
 +    /// let _ = fn2() as usize;
 +    ///
 +    /// // Good: maybe you intended to cast it to a function type?
 +    /// fn fn3() -> u16 {
 +    ///     1
 +    /// }
 +    /// let _ = fn3 as fn() -> u16;
 +    /// ```
 +    pub FN_TO_NUMERIC_CAST_ANY,
 +    restriction,
 +    "casting a function pointer to any integer type"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for casts of `&T` to `&mut T` anywhere in the code.
 +    ///
 +    /// ### Why is this bad?
 +    /// It’s basically guaranteed to be undefined behaviour.
 +    /// `UnsafeCell` is the only way to obtain aliasable data that is considered
 +    /// mutable.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// fn x(r: &i32) {
 +    ///     unsafe {
 +    ///         *(r as *const _ as *mut _) += 1;
 +    ///     }
 +    /// }
 +    /// ```
 +    ///
 +    /// Instead consider using interior mutability types.
 +    ///
 +    /// ```rust
 +    /// use std::cell::UnsafeCell;
 +    ///
 +    /// fn x(r: &UnsafeCell<i32>) {
 +    ///     unsafe {
 +    ///         *r.get() += 1;
 +    ///     }
 +    /// }
 +    /// ```
 +    pub CAST_REF_TO_MUT,
 +    correctness,
 +    "a cast of reference to a mutable pointer"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for expressions where a character literal is cast
 +    /// to `u8` and suggests using a byte literal instead.
 +    ///
 +    /// ### Why is this bad?
 +    /// In general, casting values to smaller types is
 +    /// error-prone and should be avoided where possible. In the particular case of
 +    /// converting a character literal to u8, it is easy to avoid by just using a
 +    /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
 +    /// than `'a' as u8`.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// 'x' as u8
 +    /// ```
 +    ///
 +    /// A better version, using the byte literal:
 +    ///
 +    /// ```rust,ignore
 +    /// b'x'
 +    /// ```
 +    pub CHAR_LIT_AS_U8,
 +    complexity,
 +    "casting a character literal to `u8` truncates"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `as` casts between raw pointers without changing its mutability,
 +    /// namely `*const T` to `*const U` and `*mut T` to `*mut U`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Though `as` casts between raw pointers is not terrible, `pointer::cast` is safer because
 +    /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let ptr: *const u32 = &42_u32;
 +    /// let mut_ptr: *mut u32 = &mut 42_u32;
 +    /// let _ = ptr as *const i32;
 +    /// let _ = mut_ptr as *mut i32;
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// let ptr: *const u32 = &42_u32;
 +    /// let mut_ptr: *mut u32 = &mut 42_u32;
 +    /// let _ = ptr.cast::<i32>();
 +    /// let _ = mut_ptr.cast::<i32>();
 +    /// ```
 +    pub PTR_AS_PTR,
 +    pedantic,
 +    "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`"
 +}
 +
 +pub struct Casts {
 +    msrv: Option<RustcVersion>,
 +}
 +
 +impl Casts {
 +    #[must_use]
 +    pub fn new(msrv: Option<RustcVersion>) -> Self {
 +        Self { msrv }
 +    }
 +}
 +
 +impl_lint_pass!(Casts => [
 +    CAST_PRECISION_LOSS,
 +    CAST_SIGN_LOSS,
 +    CAST_POSSIBLE_TRUNCATION,
 +    CAST_POSSIBLE_WRAP,
 +    CAST_LOSSLESS,
 +    CAST_REF_TO_MUT,
 +    CAST_PTR_ALIGNMENT,
 +    UNNECESSARY_CAST,
 +    FN_TO_NUMERIC_CAST_ANY,
 +    FN_TO_NUMERIC_CAST,
 +    FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
 +    CHAR_LIT_AS_U8,
 +    PTR_AS_PTR,
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Casts {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +
 +        if let ExprKind::Cast(cast_expr, cast_to) = expr.kind {
 +            if is_hir_ty_cfg_dependant(cx, cast_to) {
 +                return;
 +            }
 +            let (cast_from, cast_to) = (
 +                cx.typeck_results().expr_ty(cast_expr),
 +                cx.typeck_results().expr_ty(expr),
 +            );
 +
 +            if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
 +                return;
 +            }
 +
 +            fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
 +            fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
 +            fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
 +            if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
++                cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
 +                cast_possible_wrap::check(cx, expr, cast_from, cast_to);
 +                cast_precision_loss::check(cx, expr, cast_from, cast_to);
 +                cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to);
 +                cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
 +            }
 +        }
 +
 +        cast_ref_to_mut::check(cx, expr);
 +        cast_ptr_alignment::check(cx, expr);
 +        char_lit_as_u8::check(cx, expr);
 +        ptr_as_ptr::check(cx, expr, &self.msrv);
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
index c604516742ce5a1a510862792bc48cb7fdb1b01e,0000000000000000000000000000000000000000..9d8524ec91cc6e08f7c2ea056aabb58f3103e02e
mode 100644,000000..100644
--- /dev/null
@@@ -1,194 -1,0 +1,197 @@@
++// NOTE: if you add a deprecated lint in this file, please add a corresponding test in
++// tests/ui/deprecated.rs
++
 +/// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This
 +/// enables the simple extraction of the metadata without changing the current deprecation
 +/// declaration.
 +pub struct ClippyDeprecatedLint;
 +
 +macro_rules! declare_deprecated_lint {
 +    { $(#[$attr:meta])* pub $name: ident, $_reason: expr} => {
 +        $(#[$attr])*
 +        #[allow(dead_code)]
 +        pub static $name: ClippyDeprecatedLint = ClippyDeprecatedLint {};
 +    }
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// This used to check for `assert!(a == b)` and recommend
 +    /// replacement with `assert_eq!(a, b)`, but this is no longer needed after RFC 2011.
 +    pub SHOULD_ASSERT_EQ,
 +    "`assert!()` will be more flexible with RFC 2011"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// This used to check for `Vec::extend`, which was slower than
 +    /// `Vec::extend_from_slice`. Thanks to specialization, this is no longer true.
 +    pub EXTEND_FROM_SLICE,
 +    "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// `Range::step_by(0)` used to be linted since it's
 +    /// an infinite iterator, which is better expressed by `iter::repeat`,
 +    /// but the method has been removed for `Iterator::step_by` which panics
 +    /// if given a zero
 +    pub RANGE_STEP_BY_ZERO,
 +    "`iterator.step_by(0)` panics nowadays"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// This used to check for `Vec::as_slice`, which was unstable with good
 +    /// stable alternatives. `Vec::as_slice` has now been stabilized.
 +    pub UNSTABLE_AS_SLICE,
 +    "`Vec::as_slice` has been stabilized in 1.7"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// This used to check for `Vec::as_mut_slice`, which was unstable with good
 +    /// stable alternatives. `Vec::as_mut_slice` has now been stabilized.
 +    pub UNSTABLE_AS_MUT_SLICE,
 +    "`Vec::as_mut_slice` has been stabilized in 1.7"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// This lint should never have applied to non-pointer types, as transmuting
 +    /// between non-pointer types of differing alignment is well-defined behavior (it's semantically
 +    /// equivalent to a memcpy). This lint has thus been refactored into two separate lints:
 +    /// cast_ptr_alignment and transmute_ptr_to_ptr.
 +    pub MISALIGNED_TRANSMUTE,
 +    "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// This lint is too subjective, not having a good reason for being in clippy.
 +    /// Additionally, compound assignment operators may be overloaded separately from their non-assigning
 +    /// counterparts, so this lint may suggest a change in behavior or the code may not compile.
 +    pub ASSIGN_OPS,
 +    "using compound assignment operators (e.g., `+=`) is harmless"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// The original rule will only lint for `if let`. After
 +    /// making it support to lint `match`, naming as `if let` is not suitable for it.
 +    /// So, this lint is deprecated.
 +    pub IF_LET_REDUNDANT_PATTERN_MATCHING,
 +    "this lint has been changed to redundant_pattern_matching"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// This lint used to suggest replacing `let mut vec =
 +    /// Vec::with_capacity(n); vec.set_len(n);` with `let vec = vec![0; n];`. The
 +    /// replacement has very different performance characteristics so the lint is
 +    /// deprecated.
 +    pub UNSAFE_VECTOR_INITIALIZATION,
 +    "the replacement suggested by this lint had substantially different behavior"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// This lint has been superseded by #[must_use] in rustc.
 +    pub UNUSED_COLLECT,
 +    "`collect` has been marked as #[must_use] in rustc and that covers all cases of this lint"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// Associated-constants are now preferred.
 +    pub REPLACE_CONSTS,
 +    "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// The regex! macro does not exist anymore.
 +    pub REGEX_MACRO,
 +    "the regex! macro has been removed from the regex crate in 2018"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// This lint has been replaced by `manual_find_map`, a
 +    /// more specific lint.
 +    pub FIND_MAP,
 +    "this lint has been replaced by `manual_find_map`, a more specific lint"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// This lint has been replaced by `manual_filter_map`, a
 +    /// more specific lint.
 +    pub FILTER_MAP,
 +    "this lint has been replaced by `manual_filter_map`, a more specific lint"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// The `avoid_breaking_exported_api` config option was added, which
 +    /// enables the `enum_variant_names` lint for public items.
 +    /// ```
 +    pub PUB_ENUM_VARIANT_NAMES,
 +    "set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items"
 +}
 +
 +declare_deprecated_lint! {
 +    /// ### What it does
 +    /// Nothing. This lint has been deprecated.
 +    ///
 +    /// ### Deprecation reason
 +    /// The `avoid_breaking_exported_api` config option was added, which
 +    /// enables the `wrong_self_conversion` lint for public items.
 +    pub WRONG_PUB_SELF_CONVENTION,
 +    "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items"
 +}
index 7825e5f6ed52e45f9f715c0cb2b93fd55a4fc9ca,0000000000000000000000000000000000000000..ce59311c4aa96acac5154ce00f02e3d0a746fa99
mode 100644,000000..100644
--- /dev/null
@@@ -1,304 -1,0 +1,304 @@@
-                     }
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::source::snippet_with_context;
 +use clippy_utils::ty::peel_mid_ty_refs;
 +use clippy_utils::{get_parent_node, in_macro, is_lint_allowed};
 +use rustc_ast::util::parser::PREC_PREFIX;
 +use rustc_errors::Applicability;
 +use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::{self, Ty, TyCtxt, TyS, TypeckResults};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::{symbol::sym, Span};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for explicit `deref()` or `deref_mut()` method calls.
 +    ///
 +    /// ### Why is this bad?
 +    /// Dereferencing by `&*x` or `&mut *x` is clearer and more concise,
 +    /// when not part of a method chain.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// use std::ops::Deref;
 +    /// let a: &mut String = &mut String::from("foo");
 +    /// let b: &str = a.deref();
 +    /// ```
 +    /// Could be written as:
 +    /// ```rust
 +    /// let a: &mut String = &mut String::from("foo");
 +    /// let b = &*a;
 +    /// ```
 +    ///
 +    /// This lint excludes
 +    /// ```rust,ignore
 +    /// let _ = d.unwrap().deref();
 +    /// ```
 +    pub EXPLICIT_DEREF_METHODS,
 +    pedantic,
 +    "Explicit use of deref or deref_mut method while not in a method chain."
 +}
 +
 +impl_lint_pass!(Dereferencing => [
 +    EXPLICIT_DEREF_METHODS,
 +]);
 +
 +#[derive(Default)]
 +pub struct Dereferencing {
 +    state: Option<(State, StateData)>,
 +
 +    // While parsing a `deref` method call in ufcs form, the path to the function is itself an
 +    // expression. This is to store the id of that expression so it can be skipped when
 +    // `check_expr` is called for it.
 +    skip_expr: Option<HirId>,
 +}
 +
 +struct StateData {
 +    /// Span of the top level expression
 +    span: Span,
 +    /// The required mutability
 +    target_mut: Mutability,
 +}
 +
 +enum State {
 +    // Any number of deref method calls.
 +    DerefMethod {
 +        // The number of calls in a sequence which changed the referenced type
 +        ty_changed_count: usize,
 +        is_final_ufcs: bool,
 +    },
 +}
 +
 +// A reference operation considered by this lint pass
 +enum RefOp {
 +    Method(Mutability),
 +    Deref,
 +    AddrOf,
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for Dereferencing {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        // Skip path expressions from deref calls. e.g. `Deref::deref(e)`
 +        if Some(expr.hir_id) == self.skip_expr.take() {
 +            return;
 +        }
 +
 +        // Stop processing sub expressions when a macro call is seen
 +        if in_macro(expr.span) {
 +            if let Some((state, data)) = self.state.take() {
 +                report(cx, expr, state, data);
 +            }
 +            return;
 +        }
 +
 +        let typeck = cx.typeck_results();
 +        let (kind, sub_expr) = if let Some(x) = try_parse_ref_op(cx.tcx, typeck, expr) {
 +            x
 +        } else {
 +            // The whole chain of reference operations has been seen
 +            if let Some((state, data)) = self.state.take() {
 +                report(cx, expr, state, data);
 +            }
 +            return;
 +        };
 +
 +        match (self.state.take(), kind) {
 +            (None, kind) => {
 +                let parent = get_parent_node(cx.tcx, expr.hir_id);
 +                let expr_ty = typeck.expr_ty(expr);
 +
 +                match kind {
 +                    RefOp::Method(target_mut)
 +                        if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
 +                            && is_linted_explicit_deref_position(parent, expr.hir_id, expr.span) =>
 +                    {
 +                        self.state = Some((
 +                            State::DerefMethod {
 +                                ty_changed_count: if deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)) {
 +                                    0
 +                                } else {
 +                                    1
 +                                },
 +                                is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
 +                            },
 +                            StateData {
 +                                span: expr.span,
 +                                target_mut,
 +                            },
 +                        ));
++                    },
 +                    _ => (),
 +                }
 +            },
 +            (Some((State::DerefMethod { ty_changed_count, .. }, data)), RefOp::Method(_)) => {
 +                self.state = Some((
 +                    State::DerefMethod {
 +                        ty_changed_count: if deref_method_same_type(typeck.expr_ty(expr), typeck.expr_ty(sub_expr)) {
 +                            ty_changed_count
 +                        } else {
 +                            ty_changed_count + 1
 +                        },
 +                        is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
 +                    },
 +                    data,
 +                ));
 +            },
 +
 +            (Some((state, data)), _) => report(cx, expr, state, data),
 +        }
 +    }
 +}
 +
 +fn try_parse_ref_op(
 +    tcx: TyCtxt<'tcx>,
 +    typeck: &'tcx TypeckResults<'_>,
 +    expr: &'tcx Expr<'_>,
 +) -> Option<(RefOp, &'tcx Expr<'tcx>)> {
 +    let (def_id, arg) = match expr.kind {
 +        ExprKind::MethodCall(_, _, [arg], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
 +        ExprKind::Call(
 +            Expr {
 +                kind: ExprKind::Path(path),
 +                hir_id,
 +                ..
 +            },
 +            [arg],
 +        ) => (typeck.qpath_res(path, *hir_id).opt_def_id()?, arg),
 +        ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => {
 +            return Some((RefOp::Deref, sub_expr));
 +        },
 +        ExprKind::AddrOf(BorrowKind::Ref, _, sub_expr) => return Some((RefOp::AddrOf, sub_expr)),
 +        _ => return None,
 +    };
 +    if tcx.is_diagnostic_item(sym::deref_method, def_id) {
 +        Some((RefOp::Method(Mutability::Not), arg))
 +    } else if tcx.trait_of_item(def_id)? == tcx.lang_items().deref_mut_trait()? {
 +        Some((RefOp::Method(Mutability::Mut), arg))
 +    } else {
 +        None
 +    }
 +}
 +
 +// Checks whether the type for a deref call actually changed the type, not just the mutability of
 +// the reference.
 +fn deref_method_same_type(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
 +    match (result_ty.kind(), arg_ty.kind()) {
 +        (ty::Ref(_, result_ty, _), ty::Ref(_, arg_ty, _)) => TyS::same_type(result_ty, arg_ty),
 +
 +        // The result type for a deref method is always a reference
 +        // Not matching the previous pattern means the argument type is not a reference
 +        // This means that the type did change
 +        _ => false,
 +    }
 +}
 +
 +// Checks whether the parent node is a suitable context for switching from a deref method to the
 +// deref operator.
 +fn is_linted_explicit_deref_position(parent: Option<Node<'_>>, child_id: HirId, child_span: Span) -> bool {
 +    let parent = match parent {
 +        Some(Node::Expr(e)) if e.span.ctxt() == child_span.ctxt() => e,
 +        _ => return true,
 +    };
 +    match parent.kind {
 +        // Leave deref calls in the middle of a method chain.
 +        // e.g. x.deref().foo()
 +        ExprKind::MethodCall(_, _, [self_arg, ..], _) if self_arg.hir_id == child_id => false,
 +
 +        // Leave deref calls resulting in a called function
 +        // e.g. (x.deref())()
 +        ExprKind::Call(func_expr, _) if func_expr.hir_id == child_id => false,
 +
 +        // Makes an ugly suggestion
 +        // e.g. *x.deref() => *&*x
 +        ExprKind::Unary(UnOp::Deref, _)
 +        // Postfix expressions would require parens
 +        | ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
 +        | ExprKind::Field(..)
 +        | ExprKind::Index(..)
 +        | ExprKind::Err => false,
 +
 +        ExprKind::Box(..)
 +        | ExprKind::ConstBlock(..)
 +        | ExprKind::Array(_)
 +        | ExprKind::Call(..)
 +        | ExprKind::MethodCall(..)
 +        | ExprKind::Tup(..)
 +        | ExprKind::Binary(..)
 +        | ExprKind::Unary(..)
 +        | ExprKind::Lit(..)
 +        | ExprKind::Cast(..)
 +        | ExprKind::Type(..)
 +        | ExprKind::DropTemps(..)
 +        | ExprKind::If(..)
 +        | ExprKind::Loop(..)
 +        | ExprKind::Match(..)
 +        | ExprKind::Let(..)
 +        | ExprKind::Closure(..)
 +        | ExprKind::Block(..)
 +        | ExprKind::Assign(..)
 +        | ExprKind::AssignOp(..)
 +        | ExprKind::Path(..)
 +        | ExprKind::AddrOf(..)
 +        | ExprKind::Break(..)
 +        | ExprKind::Continue(..)
 +        | ExprKind::Ret(..)
 +        | ExprKind::InlineAsm(..)
 +        | ExprKind::LlvmInlineAsm(..)
 +        | ExprKind::Struct(..)
 +        | ExprKind::Repeat(..)
 +        | ExprKind::Yield(..) => true,
 +    }
 +}
 +
 +#[allow(clippy::needless_pass_by_value)]
 +fn report(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) {
 +    match state {
 +        State::DerefMethod {
 +            ty_changed_count,
 +            is_final_ufcs,
 +        } => {
 +            let mut app = Applicability::MachineApplicable;
 +            let (expr_str, expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
 +            let ty = cx.typeck_results().expr_ty(expr);
 +            let (_, ref_count) = peel_mid_ty_refs(ty);
 +            let deref_str = if ty_changed_count >= ref_count && ref_count != 0 {
 +                // a deref call changing &T -> &U requires two deref operators the first time
 +                // this occurs. One to remove the reference, a second to call the deref impl.
 +                "*".repeat(ty_changed_count + 1)
 +            } else {
 +                "*".repeat(ty_changed_count)
 +            };
 +            let addr_of_str = if ty_changed_count < ref_count {
 +                // Check if a reborrow from &mut T -> &T is required.
 +                if data.target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
 +                    "&*"
 +                } else {
 +                    ""
 +                }
 +            } else if data.target_mut == Mutability::Mut {
 +                "&mut "
 +            } else {
 +                "&"
 +            };
 +
 +            let expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX {
 +                format!("({})", expr_str)
 +            } else {
 +                expr_str.into_owned()
 +            };
 +
 +            span_lint_and_sugg(
 +                cx,
 +                EXPLICIT_DEREF_METHODS,
 +                data.span,
 +                match data.target_mut {
 +                    Mutability::Not => "explicit `deref` method call",
 +                    Mutability::Mut => "explicit `deref_mut` method call",
 +                },
 +                "try this",
 +                format!("{}{}{}", addr_of_str, deref_str, expr_str),
 +                app,
 +            );
 +        },
 +    }
 +}
index 5511c3ea9b6889701a2dbdfaf015fdec0fa5b987,0000000000000000000000000000000000000000..87ad5178ff0887d8971b220844b528659a251b8f
mode 100644,000000..100644
--- /dev/null
@@@ -1,819 -1,0 +1,835 @@@
- use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note};
- use clippy_utils::source::first_line_of_span;
 +use clippy_utils::attrs::is_doc_hidden;
- use rustc_errors::Handler;
++use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg};
++use clippy_utils::source::{first_line_of_span, snippet_with_applicability};
 +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 +use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty};
 +use if_chain::if_chain;
 +use itertools::Itertools;
 +use rustc_ast::ast::{Async, AttrKind, Attribute, FnKind, FnRetTy, ItemKind};
 +use rustc_ast::token::CommentKind;
 +use rustc_data_structures::fx::FxHashSet;
 +use rustc_data_structures::sync::Lrc;
 +use rustc_errors::emitter::EmitterWriter;
-     /// inside a link text would trip the parser. Therfore, documenting link with
++use rustc_errors::{Applicability, Handler};
 +use rustc_hir as hir;
 +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 +use rustc_hir::{AnonConst, Expr, ExprKind, QPath};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty;
 +use rustc_parse::maybe_new_parser_from_source_str;
 +use rustc_parse::parser::ForceCollect;
 +use rustc_session::parse::ParseSess;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::def_id::LocalDefId;
 +use rustc_span::edition::Edition;
 +use rustc_span::source_map::{BytePos, FilePathMapping, MultiSpan, SourceMap, Span};
 +use rustc_span::{sym, FileName, Pos};
 +use std::io;
 +use std::ops::Range;
 +use std::thread;
 +use url::Url;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the presence of `_`, `::` or camel-case words
 +    /// outside ticks in documentation.
 +    ///
 +    /// ### Why is this bad?
 +    /// *Rustdoc* supports markdown formatting, `_`, `::` and
 +    /// camel-case probably indicates some code which should be included between
 +    /// ticks. `_` can also be used for emphasis in markdown, this lint tries to
 +    /// consider that.
 +    ///
 +    /// ### Known problems
 +    /// Lots of bad docs won’t be fixed, what the lint checks
 +    /// for is limited, and there are still false positives. HTML elements and their
 +    /// content are not linted.
 +    ///
 +    /// In addition, when writing documentation comments, including `[]` brackets
-                 headers.safety |= in_heading && text.trim() == "Safety";
-                 headers.errors |= in_heading && text.trim() == "Errors";
-                 headers.panics |= in_heading && text.trim() == "Panics";
++    /// inside a link text would trip the parser. Therefore, documenting link with
 +    /// `[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec
 +    /// would fail.
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    /// /// Do something with the foo_bar parameter. See also
 +    /// /// that::other::module::foo.
 +    /// // ^ `foo_bar` and `that::other::module::foo` should be ticked.
 +    /// fn doit(foo_bar: usize) {}
 +    /// ```
 +    ///
 +    /// ```rust
 +    /// // Link text with `[]` brackets should be written as following:
 +    /// /// Consume the array and return the inner
 +    /// /// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec].
 +    /// /// [SmallVec]: SmallVec
 +    /// fn main() {}
 +    /// ```
 +    pub DOC_MARKDOWN,
 +    pedantic,
 +    "presence of `_`, `::` or camel-case outside backticks in documentation"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the doc comments of publicly visible
 +    /// unsafe functions and warns if there is no `# Safety` section.
 +    ///
 +    /// ### Why is this bad?
 +    /// Unsafe functions should document their safety
 +    /// preconditions, so that users can be sure they are using them safely.
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    ///# type Universe = ();
 +    /// /// This function should really be documented
 +    /// pub unsafe fn start_apocalypse(u: &mut Universe) {
 +    ///     unimplemented!();
 +    /// }
 +    /// ```
 +    ///
 +    /// At least write a line about safety:
 +    ///
 +    /// ```rust
 +    ///# type Universe = ();
 +    /// /// # Safety
 +    /// ///
 +    /// /// This function should not be called before the horsemen are ready.
 +    /// pub unsafe fn start_apocalypse(u: &mut Universe) {
 +    ///     unimplemented!();
 +    /// }
 +    /// ```
 +    pub MISSING_SAFETY_DOC,
 +    style,
 +    "`pub unsafe fn` without `# Safety` docs"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks the doc comments of publicly visible functions that
 +    /// return a `Result` type and warns if there is no `# Errors` section.
 +    ///
 +    /// ### Why is this bad?
 +    /// Documenting the type of errors that can be returned from a
 +    /// function can help callers write code to handle the errors appropriately.
 +    ///
 +    /// ### Examples
 +    /// Since the following function returns a `Result` it has an `# Errors` section in
 +    /// its doc comment:
 +    ///
 +    /// ```rust
 +    ///# use std::io;
 +    /// /// # Errors
 +    /// ///
 +    /// /// Will return `Err` if `filename` does not exist or the user does not have
 +    /// /// permission to read it.
 +    /// pub fn read(filename: String) -> io::Result<String> {
 +    ///     unimplemented!();
 +    /// }
 +    /// ```
 +    pub MISSING_ERRORS_DOC,
 +    pedantic,
 +    "`pub fn` returns `Result` without `# Errors` in doc comment"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks the doc comments of publicly visible functions that
 +    /// may panic and warns if there is no `# Panics` section.
 +    ///
 +    /// ### Why is this bad?
 +    /// Documenting the scenarios in which panicking occurs
 +    /// can help callers who do not want to panic to avoid those situations.
 +    ///
 +    /// ### Examples
 +    /// Since the following function may panic it has a `# Panics` section in
 +    /// its doc comment:
 +    ///
 +    /// ```rust
 +    /// /// # Panics
 +    /// ///
 +    /// /// Will panic if y is 0
 +    /// pub fn divide_by(x: i32, y: i32) -> i32 {
 +    ///     if y == 0 {
 +    ///         panic!("Cannot divide by 0")
 +    ///     } else {
 +    ///         x / y
 +    ///     }
 +    /// }
 +    /// ```
 +    pub MISSING_PANICS_DOC,
 +    pedantic,
 +    "`pub fn` may panic without `# Panics` in doc comment"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `fn main() { .. }` in doctests
 +    ///
 +    /// ### Why is this bad?
 +    /// The test can be shorter (and likely more readable)
 +    /// if the `fn main()` is left implicit.
 +    ///
 +    /// ### Examples
 +    /// ``````rust
 +    /// /// An example of a doctest with a `main()` function
 +    /// ///
 +    /// /// # Examples
 +    /// ///
 +    /// /// ```
 +    /// /// fn main() {
 +    /// ///     // this needs not be in an `fn`
 +    /// /// }
 +    /// /// ```
 +    /// fn needless_main() {
 +    ///     unimplemented!();
 +    /// }
 +    /// ``````
 +    pub NEEDLESS_DOCTEST_MAIN,
 +    style,
 +    "presence of `fn main() {` in code examples"
 +}
 +
 +#[allow(clippy::module_name_repetitions)]
 +#[derive(Clone)]
 +pub struct DocMarkdown {
 +    valid_idents: FxHashSet<String>,
 +    in_trait_impl: bool,
 +}
 +
 +impl DocMarkdown {
 +    pub fn new(valid_idents: FxHashSet<String>) -> Self {
 +        Self {
 +            valid_idents,
 +            in_trait_impl: false,
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(DocMarkdown =>
 +    [DOC_MARKDOWN, MISSING_SAFETY_DOC, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, NEEDLESS_DOCTEST_MAIN]
 +);
 +
 +impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
 +    fn check_crate(&mut self, cx: &LateContext<'tcx>) {
 +        let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
 +        check_attrs(cx, &self.valid_idents, attrs);
 +    }
 +
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 +        let attrs = cx.tcx.hir().attrs(item.hir_id());
 +        let headers = check_attrs(cx, &self.valid_idents, attrs);
 +        match item.kind {
 +            hir::ItemKind::Fn(ref sig, _, body_id) => {
 +                if !(is_entrypoint_fn(cx, item.def_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
 +                    let body = cx.tcx.hir().body(body_id);
 +                    let mut fpu = FindPanicUnwrap {
 +                        cx,
 +                        typeck_results: cx.tcx.typeck(item.def_id),
 +                        panic_span: None,
 +                    };
 +                    fpu.visit_expr(&body.value);
 +                    lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
 +                }
 +            },
 +            hir::ItemKind::Impl(ref impl_) => {
 +                self.in_trait_impl = impl_.of_trait.is_some();
 +            },
 +            hir::ItemKind::Trait(_, unsafety, ..) => {
 +                if !headers.safety && unsafety == hir::Unsafety::Unsafe {
 +                    span_lint(
 +                        cx,
 +                        MISSING_SAFETY_DOC,
 +                        item.span,
 +                        "docs for unsafe trait missing `# Safety` section",
 +                    );
 +                }
 +            },
 +            _ => (),
 +        }
 +    }
 +
 +    fn check_item_post(&mut self, _cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 +        if let hir::ItemKind::Impl { .. } = item.kind {
 +            self.in_trait_impl = false;
 +        }
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
 +        let attrs = cx.tcx.hir().attrs(item.hir_id());
 +        let headers = check_attrs(cx, &self.valid_idents, attrs);
 +        if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
 +            if !in_external_macro(cx.tcx.sess, item.span) {
 +                lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, None, None);
 +            }
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
 +        let attrs = cx.tcx.hir().attrs(item.hir_id());
 +        let headers = check_attrs(cx, &self.valid_idents, attrs);
 +        if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) {
 +            return;
 +        }
 +        if let hir::ImplItemKind::Fn(ref sig, body_id) = item.kind {
 +            let body = cx.tcx.hir().body(body_id);
 +            let mut fpu = FindPanicUnwrap {
 +                cx,
 +                typeck_results: cx.tcx.typeck(item.def_id),
 +                panic_span: None,
 +            };
 +            fpu.visit_expr(&body.value);
 +            lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
 +        }
 +    }
 +}
 +
 +fn lint_for_missing_headers<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    def_id: LocalDefId,
 +    span: impl Into<MultiSpan> + Copy,
 +    sig: &hir::FnSig<'_>,
 +    headers: DocHeaders,
 +    body_id: Option<hir::BodyId>,
 +    panic_span: Option<Span>,
 +) {
 +    if !cx.access_levels.is_exported(def_id) {
 +        return; // Private functions do not require doc comments
 +    }
 +
 +    // do not lint if any parent has `#[doc(hidden)]` attribute (#7347)
 +    if cx
 +        .tcx
 +        .hir()
 +        .parent_iter(cx.tcx.hir().local_def_id_to_hir_id(def_id))
 +        .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id)))
 +    {
 +        return;
 +    }
 +
 +    if !headers.safety && sig.header.unsafety == hir::Unsafety::Unsafe {
 +        span_lint(
 +            cx,
 +            MISSING_SAFETY_DOC,
 +            span,
 +            "unsafe function's docs miss `# Safety` section",
 +        );
 +    }
 +    if !headers.panics && panic_span.is_some() {
 +        span_lint_and_note(
 +            cx,
 +            MISSING_PANICS_DOC,
 +            span,
 +            "docs for function which may panic missing `# Panics` section",
 +            panic_span,
 +            "first possible panic found here",
 +        );
 +    }
 +    if !headers.errors {
 +        let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
 +        if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::Result) {
 +            span_lint(
 +                cx,
 +                MISSING_ERRORS_DOC,
 +                span,
 +                "docs for function returning `Result` missing `# Errors` section",
 +            );
 +        } else {
 +            if_chain! {
 +                if let Some(body_id) = body_id;
 +                if let Some(future) = cx.tcx.lang_items().future_trait();
 +                let typeck = cx.tcx.typeck_body(body_id);
 +                let body = cx.tcx.hir().body(body_id);
 +                let ret_ty = typeck.expr_ty(&body.value);
 +                if implements_trait(cx, ret_ty, future, &[]);
 +                if let ty::Opaque(_, subs) = ret_ty.kind();
 +                if let Some(gen) = subs.types().next();
 +                if let ty::Generator(_, subs, _) = gen.kind();
 +                if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::Result);
 +                then {
 +                    span_lint(
 +                        cx,
 +                        MISSING_ERRORS_DOC,
 +                        span,
 +                        "docs for function returning `Result` missing `# Errors` section",
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/// Cleanup documentation decoration.
 +///
 +/// We can't use `rustc_ast::attr::AttributeMethods::with_desugared_doc` or
 +/// `rustc_ast::parse::lexer::comments::strip_doc_comment_decoration` because we
 +/// need to keep track of
 +/// the spans but this function is inspired from the later.
 +#[allow(clippy::cast_possible_truncation)]
 +#[must_use]
 +pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: Span) -> (String, Vec<(usize, Span)>) {
 +    // one-line comments lose their prefix
 +    if comment_kind == CommentKind::Line {
 +        let mut doc = doc.to_owned();
 +        doc.push('\n');
 +        let len = doc.len();
 +        // +3 skips the opening delimiter
 +        return (doc, vec![(len, span.with_lo(span.lo() + BytePos(3)))]);
 +    }
 +
 +    let mut sizes = vec![];
 +    let mut contains_initial_stars = false;
 +    for line in doc.lines() {
 +        let offset = line.as_ptr() as usize - doc.as_ptr() as usize;
 +        debug_assert_eq!(offset as u32 as usize, offset);
 +        contains_initial_stars |= line.trim_start().starts_with('*');
 +        // +1 adds the newline, +3 skips the opening delimiter
 +        sizes.push((line.len() + 1, span.with_lo(span.lo() + BytePos(3 + offset as u32))));
 +    }
 +    if !contains_initial_stars {
 +        return (doc.to_string(), sizes);
 +    }
 +    // remove the initial '*'s if any
 +    let mut no_stars = String::with_capacity(doc.len());
 +    for line in doc.lines() {
 +        let mut chars = line.chars();
 +        for c in &mut chars {
 +            if c.is_whitespace() {
 +                no_stars.push(c);
 +            } else {
 +                no_stars.push(if c == '*' { ' ' } else { c });
 +                break;
 +            }
 +        }
 +        no_stars.push_str(chars.as_str());
 +        no_stars.push('\n');
 +    }
 +
 +    (no_stars, sizes)
 +}
 +
 +#[derive(Copy, Clone)]
 +struct DocHeaders {
 +    safety: bool,
 +    errors: bool,
 +    panics: bool,
 +}
 +
 +fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &'a [Attribute]) -> DocHeaders {
 +    use pulldown_cmark::{BrokenLink, CowStr, Options};
 +    /// We don't want the parser to choke on intra doc links. Since we don't
 +    /// actually care about rendering them, just pretend that all broken links are
 +    /// point to a fake address.
 +    #[allow(clippy::unnecessary_wraps)] // we're following a type signature
 +    fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowStr<'a>)> {
 +        Some(("fake".into(), "fake".into()))
 +    }
 +
 +    let mut doc = String::new();
 +    let mut spans = vec![];
 +
 +    for attr in attrs {
 +        if let AttrKind::DocComment(comment_kind, comment) = attr.kind {
 +            let (comment, current_spans) = strip_doc_comment_decoration(&comment.as_str(), comment_kind, attr.span);
 +            spans.extend_from_slice(&current_spans);
 +            doc.push_str(&comment);
 +        } else if attr.has_name(sym::doc) {
 +            // ignore mix of sugared and non-sugared doc
 +            // don't trigger the safety or errors check
 +            return DocHeaders {
 +                safety: true,
 +                errors: true,
 +                panics: true,
 +            };
 +        }
 +    }
 +
 +    let mut current = 0;
 +    for &mut (ref mut offset, _) in &mut spans {
 +        let offset_copy = *offset;
 +        *offset = current;
 +        current += offset_copy;
 +    }
 +
 +    if doc.is_empty() {
 +        return DocHeaders {
 +            safety: false,
 +            errors: false,
 +            panics: false,
 +        };
 +    }
 +
 +    let mut cb = fake_broken_link_callback;
 +
 +    let parser =
 +        pulldown_cmark::Parser::new_with_broken_link_callback(&doc, Options::empty(), Some(&mut cb)).into_offset_iter();
 +    // Iterate over all `Events` and combine consecutive events into one
 +    let events = parser.coalesce(|previous, current| {
 +        use pulldown_cmark::Event::Text;
 +
 +        let previous_range = previous.1;
 +        let current_range = current.1;
 +
 +        match (previous.0, current.0) {
 +            (Text(previous), Text(current)) => {
 +                let mut previous = previous.to_string();
 +                previous.push_str(&current);
 +                Ok((Text(previous.into()), previous_range))
 +            },
 +            (previous, current) => Err(((previous, previous_range), (current, current_range))),
 +        }
 +    });
 +    check_doc(cx, valid_idents, events, &spans)
 +}
 +
 +const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"];
 +
 +fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize>)>>(
 +    cx: &LateContext<'_>,
 +    valid_idents: &FxHashSet<String>,
 +    events: Events,
 +    spans: &[(usize, Span)],
 +) -> DocHeaders {
 +    // true if a safety header was found
 +    use pulldown_cmark::Event::{
 +        Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
 +    };
 +    use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph};
 +    use pulldown_cmark::{CodeBlockKind, CowStr};
 +
 +    let mut headers = DocHeaders {
 +        safety: false,
 +        errors: false,
 +        panics: false,
 +    };
 +    let mut in_code = false;
 +    let mut in_link = None;
 +    let mut in_heading = false;
 +    let mut is_rust = false;
 +    let mut edition = None;
 +    let mut ticks_unbalanced = false;
 +    let mut text_to_check: Vec<(CowStr<'_>, Span)> = Vec::new();
 +    let mut paragraph_span = spans.get(0).expect("function isn't called if doc comment is empty").1;
 +    for (event, range) in events {
 +        match event {
 +            Start(CodeBlock(ref kind)) => {
 +                in_code = true;
 +                if let CodeBlockKind::Fenced(lang) = kind {
 +                    for item in lang.split(',') {
 +                        if item == "ignore" {
 +                            is_rust = false;
 +                            break;
 +                        }
 +                        if let Some(stripped) = item.strip_prefix("edition") {
 +                            is_rust = true;
 +                            edition = stripped.parse::<Edition>().ok();
 +                        } else if item.is_empty() || RUST_CODE.contains(&item) {
 +                            is_rust = true;
 +                        }
 +                    }
 +                }
 +            },
 +            End(CodeBlock(_)) => {
 +                in_code = false;
 +                is_rust = false;
 +            },
 +            Start(Link(_, url, _)) => in_link = Some(url),
 +            End(Link(..)) => in_link = None,
 +            Start(Heading(_) | Paragraph | Item) => {
 +                if let Start(Heading(_)) = event {
 +                    in_heading = true;
 +                }
 +                ticks_unbalanced = false;
 +                let (_, span) = get_current_span(spans, range.start);
 +                paragraph_span = first_line_of_span(cx, span);
 +            },
 +            End(Heading(_) | Paragraph | Item) => {
 +                if let End(Heading(_)) = event {
 +                    in_heading = false;
 +                }
 +                if ticks_unbalanced {
 +                    span_lint_and_help(
 +                        cx,
 +                        DOC_MARKDOWN,
 +                        paragraph_span,
 +                        "backticks are unbalanced",
 +                        None,
 +                        "a backtick may be missing a pair",
 +                    );
 +                } else {
 +                    for (text, span) in text_to_check {
 +                        check_text(cx, valid_idents, &text, span);
 +                    }
 +                }
 +                text_to_check = Vec::new();
 +            },
 +            Start(_tag) | End(_tag) => (), // We don't care about other tags
 +            Html(_html) => (),             // HTML is weird, just ignore it
 +            SoftBreak | HardBreak | TaskListMarker(_) | Code(_) | Rule => (),
 +            FootnoteReference(text) | Text(text) => {
 +                let (begin, span) = get_current_span(spans, range.start);
 +                paragraph_span = paragraph_span.with_hi(span.hi());
 +                ticks_unbalanced |= text.contains('`') && !in_code;
 +                if Some(&text) == in_link.as_ref() || ticks_unbalanced {
 +                    // Probably a link of the form `<http://example.com>`
 +                    // Which are represented as a link to "http://example.com" with
 +                    // text "http://example.com" by pulldown-cmark
 +                    continue;
 +                }
-         // Or even as in `_foo bar_` which is emphasized.
-         let word = word.trim_matches(|c: char| !c.is_alphanumeric());
++                let trimmed_text = text.trim();
++                headers.safety |= in_heading && trimmed_text == "Safety";
++                headers.safety |= in_heading && trimmed_text == "Implementation safety";
++                headers.safety |= in_heading && trimmed_text == "Implementation Safety";
++                headers.errors |= in_heading && trimmed_text == "Errors";
++                headers.panics |= in_heading && trimmed_text == "Panics";
 +                if in_code {
 +                    if is_rust {
 +                        let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition());
 +                        check_code(cx, &text, edition, span);
 +                    }
 +                } else {
 +                    // Adjust for the beginning of the current `Event`
 +                    let span = span.with_lo(span.lo() + BytePos::from_usize(range.start - begin));
 +                    text_to_check.push((text, span));
 +                }
 +            },
 +        }
 +    }
 +    headers
 +}
 +
 +fn get_current_span(spans: &[(usize, Span)], idx: usize) -> (usize, Span) {
 +    let index = match spans.binary_search_by(|c| c.0.cmp(&idx)) {
 +        Ok(o) => o,
 +        Err(e) => e - 1,
 +    };
 +    spans[index]
 +}
 +
 +fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
 +    fn has_needless_main(code: String, edition: Edition) -> bool {
 +        rustc_driver::catch_fatal_errors(|| {
 +            rustc_span::create_session_globals_then(edition, || {
 +                let filename = FileName::anon_source_code(&code);
 +
 +                let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
 +                let emitter = EmitterWriter::new(Box::new(io::sink()), None, false, false, false, None, false);
 +                let handler = Handler::with_emitter(false, None, Box::new(emitter));
 +                let sess = ParseSess::with_span_handler(handler, sm);
 +
 +                let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) {
 +                    Ok(p) => p,
 +                    Err(errs) => {
 +                        for mut err in errs {
 +                            err.cancel();
 +                        }
 +                        return false;
 +                    },
 +                };
 +
 +                let mut relevant_main_found = false;
 +                loop {
 +                    match parser.parse_item(ForceCollect::No) {
 +                        Ok(Some(item)) => match &item.kind {
 +                            // Tests with one of these items are ignored
 +                            ItemKind::Static(..)
 +                            | ItemKind::Const(..)
 +                            | ItemKind::ExternCrate(..)
 +                            | ItemKind::ForeignMod(..) => return false,
 +                            // We found a main function ...
 +                            ItemKind::Fn(box FnKind(_, sig, _, Some(block))) if item.ident.name == sym::main => {
 +                                let is_async = matches!(sig.header.asyncness, Async::Yes { .. });
 +                                let returns_nothing = match &sig.decl.output {
 +                                    FnRetTy::Default(..) => true,
 +                                    FnRetTy::Ty(ty) if ty.kind.is_unit() => true,
 +                                    FnRetTy::Ty(_) => false,
 +                                };
 +
 +                                if returns_nothing && !is_async && !block.stmts.is_empty() {
 +                                    // This main function should be linted, but only if there are no other functions
 +                                    relevant_main_found = true;
 +                                } else {
 +                                    // This main function should not be linted, we're done
 +                                    return false;
 +                                }
 +                            },
 +                            // Another function was found; this case is ignored too
 +                            ItemKind::Fn(..) => return false,
 +                            _ => {},
 +                        },
 +                        Ok(None) => break,
 +                        Err(mut e) => {
 +                            e.cancel();
 +                            return false;
 +                        },
 +                    }
 +                }
 +
 +                relevant_main_found
 +            })
 +        })
 +        .ok()
 +        .unwrap_or_default()
 +    }
 +
 +    // Because of the global session, we need to create a new session in a different thread with
 +    // the edition we need.
 +    let text = text.to_owned();
 +    if thread::spawn(move || has_needless_main(text, edition))
 +        .join()
 +        .expect("thread::spawn failed")
 +    {
 +        span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
 +    }
 +}
 +
 +fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) {
 +    for word in text.split(|c: char| c.is_whitespace() || c == '\'') {
 +        // Trim punctuation as in `some comment (see foo::bar).`
 +        //                                                   ^^
-         if valid_idents.contains(word) {
++        // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix.
++        let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':');
 +
-     // We assume that mixed-case words are not meant to be put inside bacticks. (Issue #2343)
++        // Remove leading or trailing single `:` which may be part of a sentence.
++        if word.starts_with(':') && !word.starts_with("::") {
++            word = word.trim_start_matches(':');
++        }
++        if word.ends_with(':') && !word.ends_with("::") {
++            word = word.trim_end_matches(':');
++        }
++
++        if valid_idents.contains(word) || word.chars().all(|c| c == ':') {
 +            continue;
 +        }
 +
 +        // Adjust for the current word
 +        let offset = word.as_ptr() as usize - text.as_ptr() as usize;
 +        let span = Span::new(
 +            span.lo() + BytePos::from_usize(offset),
 +            span.lo() + BytePos::from_usize(offset + word.len()),
 +            span.ctxt(),
 +            span.parent(),
 +        );
 +
 +        check_word(cx, word, span);
 +    }
 +}
 +
 +fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
 +    /// Checks if a string is camel-case, i.e., contains at least two uppercase
 +    /// letters (`Clippy` is ok) and one lower-case letter (`NASA` is ok).
 +    /// Plurals are also excluded (`IDs` is ok).
 +    fn is_camel_case(s: &str) -> bool {
 +        if s.starts_with(|c: char| c.is_digit(10)) {
 +            return false;
 +        }
 +
 +        let s = s.strip_suffix('s').unwrap_or(s);
 +
 +        s.chars().all(char::is_alphanumeric)
 +            && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
 +            && s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
 +    }
 +
 +    fn has_underscore(s: &str) -> bool {
 +        s != "_" && !s.contains("\\_") && s.contains('_')
 +    }
 +
 +    fn has_hyphen(s: &str) -> bool {
 +        s != "-" && s.contains('-')
 +    }
 +
 +    if let Ok(url) = Url::parse(word) {
 +        // try to get around the fact that `foo::bar` parses as a valid URL
 +        if !url.cannot_be_a_base() {
 +            span_lint(
 +                cx,
 +                DOC_MARKDOWN,
 +                span,
 +                "you should put bare URLs between `<`/`>` or make a proper Markdown link",
 +            );
 +
 +            return;
 +        }
 +    }
 +
-         span_lint(
++    // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343)
 +    if has_underscore(word) && has_hyphen(word) {
 +        return;
 +    }
 +
 +    if has_underscore(word) || word.contains("::") || is_camel_case(word) {
-             &format!("you should put `{}` between ticks in the documentation", word),
++        let mut applicability = Applicability::MachineApplicable;
++
++        span_lint_and_sugg(
 +            cx,
 +            DOC_MARKDOWN,
 +            span,
-             let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
-             if is_type_diagnostic_item(self.cx, reciever_ty, sym::Option)
-                 || is_type_diagnostic_item(self.cx, reciever_ty, sym::Result)
++            "item in documentation is missing backticks",
++            "try",
++            format!("`{}`", snippet_with_applicability(cx, span, "..", &mut applicability)),
++            applicability,
 +        );
 +    }
 +}
 +
 +struct FindPanicUnwrap<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    panic_span: Option<Span>,
 +    typeck_results: &'tcx ty::TypeckResults<'tcx>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.panic_span.is_some() {
 +            return;
 +        }
 +
 +        // check for `begin_panic`
 +        if_chain! {
 +            if let ExprKind::Call(func_expr, _) = expr.kind;
 +            if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind;
 +            if let Some(path_def_id) = path.res.opt_def_id();
 +            if match_panic_def_id(self.cx, path_def_id);
 +            if is_expn_of(expr.span, "unreachable").is_none();
 +            if !is_expn_of_debug_assertions(expr.span);
 +            then {
 +                self.panic_span = Some(expr.span);
 +            }
 +        }
 +
 +        // check for `assert_eq` or `assert_ne`
 +        if is_expn_of(expr.span, "assert_eq").is_some() || is_expn_of(expr.span, "assert_ne").is_some() {
 +            self.panic_span = Some(expr.span);
 +        }
 +
 +        // check for `unwrap`
 +        if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
++            let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
++            if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
++                || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
 +            {
 +                self.panic_span = Some(expr.span);
 +            }
 +        }
 +
 +        // and check sub-expressions
 +        intravisit::walk_expr(self, expr);
 +    }
 +
 +    // Panics in const blocks will cause compilation to fail.
 +    fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
 +    }
 +}
 +
 +fn is_expn_of_debug_assertions(span: Span) -> bool {
 +    const MACRO_NAMES: &[&str] = &["debug_assert", "debug_assert_eq", "debug_assert_ne"];
 +    MACRO_NAMES.iter().any(|name| is_expn_of(span, name).is_some())
 +}
index ac6824672f66cbf90c13b7f7d9e6dfab2d009d4d,0000000000000000000000000000000000000000..57fd24bd4f04d81ca9263a905b84b258a100ae59
mode 100644,000000..100644
--- /dev/null
@@@ -1,660 -1,0 +1,663 @@@
-             [map, Expr {
-                 kind: ExprKind::AddrOf(_, _, key),
-                 span: key_span,
-                 ..
-             }],
 +use clippy_utils::higher;
 +use clippy_utils::{
 +    can_move_expr_to_closure_no_visit,
 +    diagnostics::span_lint_and_sugg,
 +    is_expr_final_block_expr, is_expr_used_or_unified, match_def_path, paths, peel_hir_expr_while,
 +    source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context},
 +    SpanlessEq,
 +};
 +use core::fmt::Write;
 +use rustc_errors::Applicability;
 +use rustc_hir::{
 +    hir_id::HirIdSet,
 +    intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor},
 +    Block, Expr, ExprKind, Guard, HirId, Pat, Stmt, StmtKind, UnOp,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::{Span, SyntaxContext, DUMMY_SP};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for uses of `contains_key` + `insert` on `HashMap`
 +    /// or `BTreeMap`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Using `entry` is more efficient.
 +    ///
 +    /// ### Known problems
 +    /// The suggestion may have type inference errors in some cases. e.g.
 +    /// ```rust
 +    /// let mut map = std::collections::HashMap::new();
 +    /// let _ = if !map.contains_key(&0) {
 +    ///     map.insert(0, 0)
 +    /// } else {
 +    ///     None
 +    /// };
 +    /// ```
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::collections::HashMap;
 +    /// # let mut map = HashMap::new();
 +    /// # let k = 1;
 +    /// # let v = 1;
 +    /// if !map.contains_key(&k) {
 +    ///     map.insert(k, v);
 +    /// }
 +    /// ```
 +    /// can both be rewritten as:
 +    /// ```rust
 +    /// # use std::collections::HashMap;
 +    /// # let mut map = HashMap::new();
 +    /// # let k = 1;
 +    /// # let v = 1;
 +    /// map.entry(k).or_insert(v);
 +    /// ```
 +    pub MAP_ENTRY,
 +    perf,
 +    "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`"
 +}
 +
 +declare_lint_pass!(HashMapPass => [MAP_ENTRY]);
 +
 +impl<'tcx> LateLintPass<'tcx> for HashMapPass {
 +    #[allow(clippy::too_many_lines)]
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        let (cond_expr, then_expr, else_expr) = match higher::If::hir(expr) {
 +            Some(higher::If { cond, then, r#else }) => (cond, then, r#else),
 +            _ => return,
 +        };
 +
 +        let (map_ty, contains_expr) = match try_parse_contains(cx, cond_expr) {
 +            Some(x) => x,
 +            None => return,
 +        };
 +
 +        let then_search = match find_insert_calls(cx, &contains_expr, then_expr) {
 +            Some(x) => x,
 +            None => return,
 +        };
 +
 +        let mut app = Applicability::MachineApplicable;
 +        let map_str = snippet_with_context(cx, contains_expr.map.span, contains_expr.call_ctxt, "..", &mut app).0;
 +        let key_str = snippet_with_context(cx, contains_expr.key.span, contains_expr.call_ctxt, "..", &mut app).0;
 +        let sugg = if let Some(else_expr) = else_expr {
 +            let else_search = match find_insert_calls(cx, &contains_expr, else_expr) {
 +                Some(search) => search,
 +                None => return,
 +            };
 +
 +            if then_search.edits.is_empty() && else_search.edits.is_empty() {
 +                // No insertions
 +                return;
 +            } else if then_search.edits.is_empty() || else_search.edits.is_empty() {
 +                // if .. { insert } else { .. } or if .. { .. } else { insert }
 +                let ((then_str, entry_kind), else_str) = match (else_search.edits.is_empty(), contains_expr.negated) {
 +                    (true, true) => (
 +                        then_search.snippet_vacant(cx, then_expr.span, &mut app),
 +                        snippet_with_applicability(cx, else_expr.span, "{ .. }", &mut app),
 +                    ),
 +                    (true, false) => (
 +                        then_search.snippet_occupied(cx, then_expr.span, &mut app),
 +                        snippet_with_applicability(cx, else_expr.span, "{ .. }", &mut app),
 +                    ),
 +                    (false, true) => (
 +                        else_search.snippet_occupied(cx, else_expr.span, &mut app),
 +                        snippet_with_applicability(cx, then_expr.span, "{ .. }", &mut app),
 +                    ),
 +                    (false, false) => (
 +                        else_search.snippet_vacant(cx, else_expr.span, &mut app),
 +                        snippet_with_applicability(cx, then_expr.span, "{ .. }", &mut app),
 +                    ),
 +                };
 +                format!(
 +                    "if let {}::{} = {}.entry({}) {} else {}",
 +                    map_ty.entry_path(),
 +                    entry_kind,
 +                    map_str,
 +                    key_str,
 +                    then_str,
 +                    else_str,
 +                )
 +            } else {
 +                // if .. { insert } else { insert }
 +                let ((then_str, then_entry), (else_str, else_entry)) = if contains_expr.negated {
 +                    (
 +                        then_search.snippet_vacant(cx, then_expr.span, &mut app),
 +                        else_search.snippet_occupied(cx, else_expr.span, &mut app),
 +                    )
 +                } else {
 +                    (
 +                        then_search.snippet_occupied(cx, then_expr.span, &mut app),
 +                        else_search.snippet_vacant(cx, else_expr.span, &mut app),
 +                    )
 +                };
 +                let indent_str = snippet_indent(cx, expr.span);
 +                let indent_str = indent_str.as_deref().unwrap_or("");
 +                format!(
 +                    "match {}.entry({}) {{\n{indent}    {entry}::{} => {}\n\
 +                        {indent}    {entry}::{} => {}\n{indent}}}",
 +                    map_str,
 +                    key_str,
 +                    then_entry,
 +                    reindent_multiline(then_str.into(), true, Some(4 + indent_str.len())),
 +                    else_entry,
 +                    reindent_multiline(else_str.into(), true, Some(4 + indent_str.len())),
 +                    entry = map_ty.entry_path(),
 +                    indent = indent_str,
 +                )
 +            }
 +        } else {
 +            if then_search.edits.is_empty() {
 +                // no insertions
 +                return;
 +            }
 +
 +            // if .. { insert }
 +            if !then_search.allow_insert_closure {
 +                let (body_str, entry_kind) = if contains_expr.negated {
 +                    then_search.snippet_vacant(cx, then_expr.span, &mut app)
 +                } else {
 +                    then_search.snippet_occupied(cx, then_expr.span, &mut app)
 +                };
 +                format!(
 +                    "if let {}::{} = {}.entry({}) {}",
 +                    map_ty.entry_path(),
 +                    entry_kind,
 +                    map_str,
 +                    key_str,
 +                    body_str,
 +                )
 +            } else if let Some(insertion) = then_search.as_single_insertion() {
 +                let value_str = snippet_with_context(cx, insertion.value.span, then_expr.span.ctxt(), "..", &mut app).0;
 +                if contains_expr.negated {
 +                    if insertion.value.can_have_side_effects() {
 +                        format!("{}.entry({}).or_insert_with(|| {});", map_str, key_str, value_str)
 +                    } else {
 +                        format!("{}.entry({}).or_insert({});", map_str, key_str, value_str)
 +                    }
 +                } else {
 +                    // TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here.
 +                    // This would need to be a different lint.
 +                    return;
 +                }
 +            } else {
 +                let block_str = then_search.snippet_closure(cx, then_expr.span, &mut app);
 +                if contains_expr.negated {
 +                    format!("{}.entry({}).or_insert_with(|| {});", map_str, key_str, block_str)
 +                } else {
 +                    // TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here.
 +                    // This would need to be a different lint.
 +                    return;
 +                }
 +            }
 +        };
 +
 +        span_lint_and_sugg(
 +            cx,
 +            MAP_ENTRY,
 +            expr.span,
 +            &format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name()),
 +            "try this",
 +            sugg,
 +            app,
 +        );
 +    }
 +}
 +
 +#[derive(Clone, Copy)]
 +enum MapType {
 +    Hash,
 +    BTree,
 +}
 +impl MapType {
 +    fn name(self) -> &'static str {
 +        match self {
 +            Self::Hash => "HashMap",
 +            Self::BTree => "BTreeMap",
 +        }
 +    }
 +    fn entry_path(self) -> &'static str {
 +        match self {
 +            Self::Hash => "std::collections::hash_map::Entry",
 +            Self::BTree => "std::collections::btree_map::Entry",
 +        }
 +    }
 +}
 +
 +struct ContainsExpr<'tcx> {
 +    negated: bool,
 +    map: &'tcx Expr<'tcx>,
 +    key: &'tcx Expr<'tcx>,
 +    call_ctxt: SyntaxContext,
 +}
 +fn try_parse_contains(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(MapType, ContainsExpr<'tcx>)> {
 +    let mut negated = false;
 +    let expr = peel_hir_expr_while(expr, |e| match e.kind {
 +        ExprKind::Unary(UnOp::Not, e) => {
 +            negated = !negated;
 +            Some(e)
 +        },
 +        _ => None,
 +    });
 +    match expr.kind {
 +        ExprKind::MethodCall(
 +            _,
 +            _,
++            [
++                map,
++                Expr {
++                    kind: ExprKind::AddrOf(_, _, key),
++                    span: key_span,
++                    ..
++                },
++            ],
 +            _,
 +        ) if key_span.ctxt() == expr.span.ctxt() => {
 +            let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
 +            let expr = ContainsExpr {
 +                negated,
 +                map,
 +                key,
 +                call_ctxt: expr.span.ctxt(),
 +            };
 +            if match_def_path(cx, id, &paths::BTREEMAP_CONTAINS_KEY) {
 +                Some((MapType::BTree, expr))
 +            } else if match_def_path(cx, id, &paths::HASHMAP_CONTAINS_KEY) {
 +                Some((MapType::Hash, expr))
 +            } else {
 +                None
 +            }
 +        },
 +        _ => None,
 +    }
 +}
 +
 +struct InsertExpr<'tcx> {
 +    map: &'tcx Expr<'tcx>,
 +    key: &'tcx Expr<'tcx>,
 +    value: &'tcx Expr<'tcx>,
 +}
 +fn try_parse_insert(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
 +    if let ExprKind::MethodCall(_, _, [map, key, value], _) = expr.kind {
 +        let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
 +        if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) {
 +            Some(InsertExpr { map, key, value })
 +        } else {
 +            None
 +        }
 +    } else {
 +        None
 +    }
 +}
 +
 +/// An edit that will need to be made to move the expression to use the entry api
 +#[derive(Clone, Copy)]
 +enum Edit<'tcx> {
 +    /// A semicolon that needs to be removed. Used to create a closure for `insert_with`.
 +    RemoveSemi(Span),
 +    /// An insertion into the map.
 +    Insertion(Insertion<'tcx>),
 +}
 +impl Edit<'tcx> {
 +    fn as_insertion(self) -> Option<Insertion<'tcx>> {
 +        if let Self::Insertion(i) = self { Some(i) } else { None }
 +    }
 +}
 +#[derive(Clone, Copy)]
 +struct Insertion<'tcx> {
 +    call: &'tcx Expr<'tcx>,
 +    value: &'tcx Expr<'tcx>,
 +}
 +
 +/// This visitor needs to do a multiple things:
 +/// * Find all usages of the map. An insertion can only be made before any other usages of the map.
 +/// * Determine if there's an insertion using the same key. There's no need for the entry api
 +///   otherwise.
 +/// * Determine if the final statement executed is an insertion. This is needed to use
 +///   `or_insert_with`.
 +/// * Determine if there's any sub-expression that can't be placed in a closure.
 +/// * Determine if there's only a single insert statement. `or_insert` can be used in this case.
 +#[allow(clippy::struct_excessive_bools)]
 +struct InsertSearcher<'cx, 'tcx> {
 +    cx: &'cx LateContext<'tcx>,
 +    /// The map expression used in the contains call.
 +    map: &'tcx Expr<'tcx>,
 +    /// The key expression used in the contains call.
 +    key: &'tcx Expr<'tcx>,
 +    /// The context of the top level block. All insert calls must be in the same context.
 +    ctxt: SyntaxContext,
 +    /// Whether this expression can be safely moved into a closure.
 +    allow_insert_closure: bool,
 +    /// Whether this expression can use the entry api.
 +    can_use_entry: bool,
 +    /// Whether this expression is the final expression in this code path. This may be a statement.
 +    in_tail_pos: bool,
 +    // Is this expression a single insert. A slightly better suggestion can be made in this case.
 +    is_single_insert: bool,
 +    /// If the visitor has seen the map being used.
 +    is_map_used: bool,
 +    /// The locations where changes need to be made for the suggestion.
 +    edits: Vec<Edit<'tcx>>,
 +    /// A stack of loops the visitor is currently in.
 +    loops: Vec<HirId>,
 +    /// Local variables created in the expression. These don't need to be captured.
 +    locals: HirIdSet,
 +}
 +impl<'tcx> InsertSearcher<'_, 'tcx> {
 +    /// Visit the expression as a branch in control flow. Multiple insert calls can be used, but
 +    /// only if they are on separate code paths. This will return whether the map was used in the
 +    /// given expression.
 +    fn visit_cond_arm(&mut self, e: &'tcx Expr<'_>) -> bool {
 +        let is_map_used = self.is_map_used;
 +        let in_tail_pos = self.in_tail_pos;
 +        self.visit_expr(e);
 +        let res = self.is_map_used;
 +        self.is_map_used = is_map_used;
 +        self.in_tail_pos = in_tail_pos;
 +        res
 +    }
 +
 +    /// Visits an expression which is not itself in a tail position, but other sibling expressions
 +    /// may be. e.g. if conditions
 +    fn visit_non_tail_expr(&mut self, e: &'tcx Expr<'_>) {
 +        let in_tail_pos = self.in_tail_pos;
 +        self.in_tail_pos = false;
 +        self.visit_expr(e);
 +        self.in_tail_pos = in_tail_pos;
 +    }
 +}
 +impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> {
 +    type Map = ErasedMap<'tcx>;
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +
 +    fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
 +        match stmt.kind {
 +            StmtKind::Semi(e) => {
 +                self.visit_expr(e);
 +
 +                if self.in_tail_pos && self.allow_insert_closure {
 +                    // The spans are used to slice the top level expression into multiple parts. This requires that
 +                    // they all come from the same part of the source code.
 +                    if stmt.span.ctxt() == self.ctxt && e.span.ctxt() == self.ctxt {
 +                        self.edits
 +                            .push(Edit::RemoveSemi(stmt.span.trim_start(e.span).unwrap_or(DUMMY_SP)));
 +                    } else {
 +                        self.allow_insert_closure = false;
 +                    }
 +                }
 +            },
 +            StmtKind::Expr(e) => self.visit_expr(e),
 +            StmtKind::Local(l) => {
 +                self.visit_pat(l.pat);
 +                if let Some(e) = l.init {
 +                    self.allow_insert_closure &= !self.in_tail_pos;
 +                    self.in_tail_pos = false;
 +                    self.is_single_insert = false;
 +                    self.visit_expr(e);
 +                }
 +            },
 +            StmtKind::Item(_) => {
 +                self.allow_insert_closure &= !self.in_tail_pos;
 +                self.is_single_insert = false;
 +            },
 +        }
 +    }
 +
 +    fn visit_block(&mut self, block: &'tcx Block<'_>) {
 +        // If the block is in a tail position, then the last expression (possibly a statement) is in the
 +        // tail position. The rest, however, are not.
 +        match (block.stmts, block.expr) {
 +            ([], None) => {
 +                self.allow_insert_closure &= !self.in_tail_pos;
 +            },
 +            ([], Some(expr)) => self.visit_expr(expr),
 +            (stmts, Some(expr)) => {
 +                let in_tail_pos = self.in_tail_pos;
 +                self.in_tail_pos = false;
 +                for stmt in stmts {
 +                    self.visit_stmt(stmt);
 +                }
 +                self.in_tail_pos = in_tail_pos;
 +                self.visit_expr(expr);
 +            },
 +            ([stmts @ .., stmt], None) => {
 +                let in_tail_pos = self.in_tail_pos;
 +                self.in_tail_pos = false;
 +                for stmt in stmts {
 +                    self.visit_stmt(stmt);
 +                }
 +                self.in_tail_pos = in_tail_pos;
 +                self.visit_stmt(stmt);
 +            },
 +        }
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if !self.can_use_entry {
 +            return;
 +        }
 +
 +        match try_parse_insert(self.cx, expr) {
 +            Some(insert_expr) if SpanlessEq::new(self.cx).eq_expr(self.map, insert_expr.map) => {
 +                // Multiple inserts, inserts with a different key, and inserts from a macro can't use the entry api.
 +                if self.is_map_used
 +                    || !SpanlessEq::new(self.cx).eq_expr(self.key, insert_expr.key)
 +                    || expr.span.ctxt() != self.ctxt
 +                {
 +                    self.can_use_entry = false;
 +                    return;
 +                }
 +
 +                self.edits.push(Edit::Insertion(Insertion {
 +                    call: expr,
 +                    value: insert_expr.value,
 +                }));
 +                self.is_map_used = true;
 +                self.allow_insert_closure &= self.in_tail_pos;
 +
 +                // The value doesn't affect whether there is only a single insert expression.
 +                let is_single_insert = self.is_single_insert;
 +                self.visit_non_tail_expr(insert_expr.value);
 +                self.is_single_insert = is_single_insert;
 +            },
 +            _ if SpanlessEq::new(self.cx).eq_expr(self.map, expr) => {
 +                self.is_map_used = true;
 +            },
 +            _ => match expr.kind {
 +                ExprKind::If(cond_expr, then_expr, Some(else_expr)) => {
 +                    self.is_single_insert = false;
 +                    self.visit_non_tail_expr(cond_expr);
 +                    // Each branch may contain it's own insert expression.
 +                    let mut is_map_used = self.visit_cond_arm(then_expr);
 +                    is_map_used |= self.visit_cond_arm(else_expr);
 +                    self.is_map_used = is_map_used;
 +                },
 +                ExprKind::Match(scrutinee_expr, arms, _) => {
 +                    self.is_single_insert = false;
 +                    self.visit_non_tail_expr(scrutinee_expr);
 +                    // Each branch may contain it's own insert expression.
 +                    let mut is_map_used = self.is_map_used;
 +                    for arm in arms {
 +                        self.visit_pat(arm.pat);
 +                        if let Some(Guard::If(guard) | Guard::IfLet(_, guard)) = arm.guard {
 +                            self.visit_non_tail_expr(guard);
 +                        }
 +                        is_map_used |= self.visit_cond_arm(arm.body);
 +                    }
 +                    self.is_map_used = is_map_used;
 +                },
 +                ExprKind::Loop(block, ..) => {
 +                    self.loops.push(expr.hir_id);
 +                    self.is_single_insert = false;
 +                    self.allow_insert_closure &= !self.in_tail_pos;
 +                    // Don't allow insertions inside of a loop.
 +                    let edit_len = self.edits.len();
 +                    self.visit_block(block);
 +                    if self.edits.len() != edit_len {
 +                        self.can_use_entry = false;
 +                    }
 +                    self.loops.pop();
 +                },
 +                ExprKind::Block(block, _) => self.visit_block(block),
 +                ExprKind::InlineAsm(_) | ExprKind::LlvmInlineAsm(_) => {
 +                    self.can_use_entry = false;
 +                },
 +                _ => {
 +                    self.allow_insert_closure &= !self.in_tail_pos;
 +                    self.allow_insert_closure &=
 +                        can_move_expr_to_closure_no_visit(self.cx, expr, &self.loops, &self.locals);
 +                    // Sub expressions are no longer in the tail position.
 +                    self.is_single_insert = false;
 +                    self.in_tail_pos = false;
 +                    walk_expr(self, expr);
 +                },
 +            },
 +        }
 +    }
 +
 +    fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) {
 +        p.each_binding_or_first(&mut |_, id, _, _| {
 +            self.locals.insert(id);
 +        });
 +    }
 +}
 +
 +struct InsertSearchResults<'tcx> {
 +    edits: Vec<Edit<'tcx>>,
 +    allow_insert_closure: bool,
 +    is_single_insert: bool,
 +}
 +impl InsertSearchResults<'tcx> {
 +    fn as_single_insertion(&self) -> Option<Insertion<'tcx>> {
 +        self.is_single_insert.then(|| self.edits[0].as_insertion().unwrap())
 +    }
 +
 +    fn snippet(
 +        &self,
 +        cx: &LateContext<'_>,
 +        mut span: Span,
 +        app: &mut Applicability,
 +        write_wrapped: impl Fn(&mut String, Insertion<'_>, SyntaxContext, &mut Applicability),
 +    ) -> String {
 +        let ctxt = span.ctxt();
 +        let mut res = String::new();
 +        for insertion in self.edits.iter().filter_map(|e| e.as_insertion()) {
 +            res.push_str(&snippet_with_applicability(
 +                cx,
 +                span.until(insertion.call.span),
 +                "..",
 +                app,
 +            ));
 +            if is_expr_used_or_unified(cx.tcx, insertion.call) {
 +                write_wrapped(&mut res, insertion, ctxt, app);
 +            } else {
 +                let _ = write!(
 +                    res,
 +                    "e.insert({})",
 +                    snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0
 +                );
 +            }
 +            span = span.trim_start(insertion.call.span).unwrap_or(DUMMY_SP);
 +        }
 +        res.push_str(&snippet_with_applicability(cx, span, "..", app));
 +        res
 +    }
 +
 +    fn snippet_occupied(&self, cx: &LateContext<'_>, span: Span, app: &mut Applicability) -> (String, &'static str) {
 +        (
 +            self.snippet(cx, span, app, |res, insertion, ctxt, app| {
 +                // Insertion into a map would return `Some(&mut value)`, but the entry returns `&mut value`
 +                let _ = write!(
 +                    res,
 +                    "Some(e.insert({}))",
 +                    snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0
 +                );
 +            }),
 +            "Occupied(mut e)",
 +        )
 +    }
 +
 +    fn snippet_vacant(&self, cx: &LateContext<'_>, span: Span, app: &mut Applicability) -> (String, &'static str) {
 +        (
 +            self.snippet(cx, span, app, |res, insertion, ctxt, app| {
 +                // Insertion into a map would return `None`, but the entry returns a mutable reference.
 +                let _ = if is_expr_final_block_expr(cx.tcx, insertion.call) {
 +                    write!(
 +                        res,
 +                        "e.insert({});\n{}None",
 +                        snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0,
 +                        snippet_indent(cx, insertion.call.span).as_deref().unwrap_or(""),
 +                    )
 +                } else {
 +                    write!(
 +                        res,
 +                        "{{ e.insert({}); None }}",
 +                        snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0,
 +                    )
 +                };
 +            }),
 +            "Vacant(e)",
 +        )
 +    }
 +
 +    fn snippet_closure(&self, cx: &LateContext<'_>, mut span: Span, app: &mut Applicability) -> String {
 +        let ctxt = span.ctxt();
 +        let mut res = String::new();
 +        for edit in &self.edits {
 +            match *edit {
 +                Edit::Insertion(insertion) => {
 +                    // Cut out the value from `map.insert(key, value)`
 +                    res.push_str(&snippet_with_applicability(
 +                        cx,
 +                        span.until(insertion.call.span),
 +                        "..",
 +                        app,
 +                    ));
 +                    res.push_str(&snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0);
 +                    span = span.trim_start(insertion.call.span).unwrap_or(DUMMY_SP);
 +                },
 +                Edit::RemoveSemi(semi_span) => {
 +                    // Cut out the semicolon. This allows the value to be returned from the closure.
 +                    res.push_str(&snippet_with_applicability(cx, span.until(semi_span), "..", app));
 +                    span = span.trim_start(semi_span).unwrap_or(DUMMY_SP);
 +                },
 +            }
 +        }
 +        res.push_str(&snippet_with_applicability(cx, span, "..", app));
 +        res
 +    }
 +}
 +
 +fn find_insert_calls(
 +    cx: &LateContext<'tcx>,
 +    contains_expr: &ContainsExpr<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +) -> Option<InsertSearchResults<'tcx>> {
 +    let mut s = InsertSearcher {
 +        cx,
 +        map: contains_expr.map,
 +        key: contains_expr.key,
 +        ctxt: expr.span.ctxt(),
 +        edits: Vec::new(),
 +        is_map_used: false,
 +        allow_insert_closure: true,
 +        can_use_entry: true,
 +        in_tail_pos: true,
 +        is_single_insert: true,
 +        loops: Vec::new(),
 +        locals: HirIdSet::default(),
 +    };
 +    s.visit_expr(expr);
 +    let allow_insert_closure = s.allow_insert_closure;
 +    let is_single_insert = s.is_single_insert;
 +    let edits = s.edits;
 +    s.can_use_entry.then(|| InsertSearchResults {
 +        edits,
 +        allow_insert_closure,
 +        is_single_insert,
 +    })
 +}
index 174260fabd228688c47943efa52d9cae07f84481,0000000000000000000000000000000000000000..404b67c8f29f2817a9e6f58c3fc55d3b588075e4
mode 100644,000000..100644
--- /dev/null
@@@ -1,306 -1,0 +1,288 @@@
- use clippy_utils::camel_case;
 +//! lint on enum variants that are prefixed or suffixed by the same characters
 +
- /// Returns the number of chars that match from the start
- #[must_use]
- fn partial_match(pre: &str, name: &str) -> usize {
-     let mut name_iter = name.chars();
-     let _ = name_iter.next_back(); // make sure the name is never fully matched
-     pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count()
- }
- /// Returns the number of chars that match from the end
- #[must_use]
- fn partial_rmatch(post: &str, name: &str) -> usize {
-     let mut name_iter = name.chars();
-     let _ = name_iter.next(); // make sure the name is never fully matched
-     post.chars()
-         .rev()
-         .zip(name_iter.rev())
-         .take_while(|&(l, r)| l == r)
-         .count()
- }
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 +use clippy_utils::source::is_present_in_source;
++use clippy_utils::str_utils::{self, count_match_end, count_match_start};
 +use rustc_hir::{EnumDef, Item, ItemKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::Span;
 +use rustc_span::symbol::Symbol;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Detects enumeration variants that are prefixed or suffixed
 +    /// by the same characters.
 +    ///
 +    /// ### Why is this bad?
 +    /// Enumeration variant names should specify their variant,
 +    /// not repeat the enumeration name.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// enum Cake {
 +    ///     BlackForestCake,
 +    ///     HummingbirdCake,
 +    ///     BattenbergCake,
 +    /// }
 +    /// ```
 +    /// Could be written as:
 +    /// ```rust
 +    /// enum Cake {
 +    ///     BlackForest,
 +    ///     Hummingbird,
 +    ///     Battenberg,
 +    /// }
 +    /// ```
 +    pub ENUM_VARIANT_NAMES,
 +    style,
 +    "enums where all variants share a prefix/postfix"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Detects type names that are prefixed or suffixed by the
 +    /// containing module's name.
 +    ///
 +    /// ### Why is this bad?
 +    /// It requires the user to type the module name twice.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// mod cake {
 +    ///     struct BlackForestCake;
 +    /// }
 +    /// ```
 +    /// Could be written as:
 +    /// ```rust
 +    /// mod cake {
 +    ///     struct BlackForest;
 +    /// }
 +    /// ```
 +    pub MODULE_NAME_REPETITIONS,
 +    pedantic,
 +    "type names prefixed/postfixed with their containing module's name"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for modules that have the same name as their
 +    /// parent module
 +    ///
 +    /// ### Why is this bad?
 +    /// A typical beginner mistake is to have `mod foo;` and
 +    /// again `mod foo { ..
 +    /// }` in `foo.rs`.
 +    /// The expectation is that items inside the inner `mod foo { .. }` are then
 +    /// available
 +    /// through `foo::x`, but they are only available through
 +    /// `foo::foo::x`.
 +    /// If this is done on purpose, it would be better to choose a more
 +    /// representative module name.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// // lib.rs
 +    /// mod foo;
 +    /// // foo.rs
 +    /// mod foo {
 +    ///     ...
 +    /// }
 +    /// ```
 +    pub MODULE_INCEPTION,
 +    style,
 +    "modules that have the same name as their parent module"
 +}
 +
 +pub struct EnumVariantNames {
 +    modules: Vec<(Symbol, String)>,
 +    threshold: u64,
 +    avoid_breaking_exported_api: bool,
 +}
 +
 +impl EnumVariantNames {
 +    #[must_use]
 +    pub fn new(threshold: u64, avoid_breaking_exported_api: bool) -> Self {
 +        Self {
 +            modules: Vec::new(),
 +            threshold,
 +            avoid_breaking_exported_api,
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(EnumVariantNames => [
 +    ENUM_VARIANT_NAMES,
 +    MODULE_NAME_REPETITIONS,
 +    MODULE_INCEPTION
 +]);
 +
-         if partial_match(item_name, &name) == item_name_chars
 +fn check_variant(
 +    cx: &LateContext<'_>,
 +    threshold: u64,
 +    def: &EnumDef<'_>,
 +    item_name: &str,
 +    item_name_chars: usize,
 +    span: Span,
 +) {
 +    if (def.variants.len() as u64) < threshold {
 +        return;
 +    }
 +    for var in def.variants {
 +        let name = var.ident.name.as_str();
-         if partial_rmatch(item_name, &name) == item_name_chars {
++        if count_match_start(item_name, &name).char_count == item_name_chars
 +            && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
 +            && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
 +        {
 +            span_lint(
 +                cx,
 +                ENUM_VARIANT_NAMES,
 +                var.span,
 +                "variant name starts with the enum's name",
 +            );
 +        }
-     let mut pre = &first[..camel_case::until(&*first)];
-     let mut post = &first[camel_case::from(&*first)..];
++        if count_match_end(item_name, &name).char_count == item_name_chars {
 +            span_lint(
 +                cx,
 +                ENUM_VARIANT_NAMES,
 +                var.span,
 +                "variant name ends with the enum's name",
 +            );
 +        }
 +    }
 +    let first = &def.variants[0].ident.name.as_str();
-         let pre_match = partial_match(pre, &name);
++    let mut pre = &first[..str_utils::camel_case_until(&*first).byte_index];
++    let mut post = &first[str_utils::camel_case_start(&*first).byte_index..];
 +    for var in def.variants {
 +        let name = var.ident.name.as_str();
 +
-         let pre_camel = camel_case::until(pre);
++        let pre_match = count_match_start(pre, &name).byte_count;
 +        pre = &pre[..pre_match];
-                 let last_camel = camel_case::until(&pre[..last]);
-                 pre = &pre[..last_camel];
++        let pre_camel = str_utils::camel_case_until(pre).byte_index;
 +        pre = &pre[..pre_camel];
 +        while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
 +            if next.is_numeric() {
 +                return;
 +            }
 +            if next.is_lowercase() {
 +                let last = pre.len() - last.len_utf8();
-         let post_match = partial_rmatch(post, &name);
-         let post_end = post.len() - post_match;
++                let last_camel = str_utils::camel_case_until(&pre[..last]);
++                pre = &pre[..last_camel.byte_index];
 +            } else {
 +                break;
 +            }
 +        }
 +
-         let post_camel = camel_case::from(post);
-         post = &post[post_camel..];
++        let post_match = count_match_end(post, &name);
++        let post_end = post.len() - post_match.byte_count;
 +        post = &post[post_end..];
-                     if item.vis.node.is_pub() {
-                         let matching = partial_match(mod_camel, &item_camel);
-                         let rmatching = partial_rmatch(mod_camel, &item_camel);
++        let post_camel = str_utils::camel_case_start(post);
++        post = &post[post_camel.byte_index..];
 +    }
 +    let (what, value) = match (pre.is_empty(), post.is_empty()) {
 +        (true, true) => return,
 +        (false, _) => ("pre", pre),
 +        (true, false) => ("post", post),
 +    };
 +    span_lint_and_help(
 +        cx,
 +        ENUM_VARIANT_NAMES,
 +        span,
 +        &format!("all variants have the same {}fix: `{}`", what, value),
 +        None,
 +        &format!(
 +            "remove the {}fixes and use full paths to \
 +             the variants instead of glob imports",
 +            what
 +        ),
 +    );
 +}
 +
 +#[must_use]
 +fn to_camel_case(item_name: &str) -> String {
 +    let mut s = String::new();
 +    let mut up = true;
 +    for c in item_name.chars() {
 +        if c.is_uppercase() {
 +            // we only turn snake case text into CamelCase
 +            return item_name.to_string();
 +        }
 +        if c == '_' {
 +            up = true;
 +            continue;
 +        }
 +        if up {
 +            up = false;
 +            s.extend(c.to_uppercase());
 +        } else {
 +            s.push(c);
 +        }
 +    }
 +    s
 +}
 +
 +impl LateLintPass<'_> for EnumVariantNames {
 +    fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) {
 +        let last = self.modules.pop();
 +        assert!(last.is_some());
 +    }
 +
 +    #[allow(clippy::similar_names)]
 +    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
 +        let item_name = item.ident.name.as_str();
 +        let item_name_chars = item_name.chars().count();
 +        let item_camel = to_camel_case(&item_name);
 +        if !item.span.from_expansion() && is_present_in_source(cx, item.span) {
 +            if let Some(&(ref mod_name, ref mod_camel)) = self.modules.last() {
 +                // constants don't have surrounding modules
 +                if !mod_camel.is_empty() {
 +                    if mod_name == &item.ident.name {
 +                        if let ItemKind::Mod(..) = item.kind {
 +                            span_lint(
 +                                cx,
 +                                MODULE_INCEPTION,
 +                                item.span,
 +                                "module has the same name as its containing module",
 +                            );
 +                        }
 +                    }
-                         if matching == nchars {
++                    // The `module_name_repetitions` lint should only trigger if the item has the module in its
++                    // name. Having the same name is accepted.
++                    if item.vis.node.is_pub() && item_camel.len() > mod_camel.len() {
++                        let matching = count_match_start(mod_camel, &item_camel);
++                        let rmatching = count_match_end(mod_camel, &item_camel);
 +                        let nchars = mod_camel.chars().count();
 +
 +                        let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();
 +
-                         if rmatching == nchars {
++                        if matching.char_count == nchars {
 +                            match item_camel.chars().nth(nchars) {
 +                                Some(c) if is_word_beginning(c) => span_lint(
 +                                    cx,
 +                                    MODULE_NAME_REPETITIONS,
 +                                    item.span,
 +                                    "item name starts with its containing module's name",
 +                                ),
 +                                _ => (),
 +                            }
 +                        }
++                        if rmatching.char_count == nchars {
 +                            span_lint(
 +                                cx,
 +                                MODULE_NAME_REPETITIONS,
 +                                item.span,
 +                                "item name ends with its containing module's name",
 +                            );
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +        if let ItemKind::Enum(ref def, _) = item.kind {
 +            if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.def_id)) {
 +                check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span);
 +            }
 +        }
 +        self.modules.push((item.ident.name, item_camel));
 +    }
 +}
index 765a6c7585a20a6ee3b5f4d09bd6f5b0319396ab,0000000000000000000000000000000000000000..9247343b52a5322f8c7ee09eec77de8b655ffcff
mode 100644,000000..100644
--- /dev/null
@@@ -1,215 -1,0 +1,218 @@@
-             [Adjustment {
-                 kind: Adjust::Deref(None),
-                 ..
-             }, Adjustment {
-                 kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
-                 ..
-             }] => {
 +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::higher::VecArgs;
 +use clippy_utils::source::snippet_opt;
 +use clippy_utils::usage::UsedAfterExprVisitor;
 +use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local_id};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::{Expr, ExprKind, Param, PatKind, Unsafety};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 +use rustc_middle::ty::subst::Subst;
 +use rustc_middle::ty::{self, ClosureKind, Ty, TypeFoldable};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for closures which just call another function where
 +    /// the function can be called directly. `unsafe` functions or calls where types
 +    /// get adjusted are ignored.
 +    ///
 +    /// ### Why is this bad?
 +    /// Needlessly creating a closure adds code for no benefit
 +    /// and gives the optimizer more work.
 +    ///
 +    /// ### Known problems
 +    /// If creating the closure inside the closure has a side-
 +    /// effect then moving the closure creation out will change when that side-
 +    /// effect runs.
 +    /// See [#1439](https://github.com/rust-lang/rust-clippy/issues/1439) for more details.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// // Bad
 +    /// xs.map(|x| foo(x))
 +    ///
 +    /// // Good
 +    /// xs.map(foo)
 +    /// ```
 +    /// where `foo(_)` is a plain function that takes the exact argument type of
 +    /// `x`.
 +    pub REDUNDANT_CLOSURE,
 +    style,
 +    "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for closures which only invoke a method on the closure
 +    /// argument and can be replaced by referencing the method directly.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's unnecessary to create the closure.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// Some('a').map(|s| s.to_uppercase());
 +    /// ```
 +    /// may be rewritten as
 +    /// ```rust,ignore
 +    /// Some('a').map(char::to_uppercase);
 +    /// ```
 +    pub REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
 +    pedantic,
 +    "redundant closures for method calls"
 +}
 +
 +declare_lint_pass!(EtaReduction => [REDUNDANT_CLOSURE, REDUNDANT_CLOSURE_FOR_METHOD_CALLS]);
 +
 +impl<'tcx> LateLintPass<'tcx> for EtaReduction {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if expr.span.from_expansion() {
 +            return;
 +        }
 +        let body = match expr.kind {
 +            ExprKind::Closure(_, _, id, _, _) => cx.tcx.hir().body(id),
 +            _ => return,
 +        };
 +        if body.value.span.from_expansion() {
 +            if body.params.is_empty() {
 +                if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, &body.value) {
 +                    // replace `|| vec![]` with `Vec::new`
 +                    span_lint_and_sugg(
 +                        cx,
 +                        REDUNDANT_CLOSURE,
 +                        expr.span,
 +                        "redundant closure",
 +                        "replace the closure with `Vec::new`",
 +                        "std::vec::Vec::new".into(),
 +                        Applicability::MachineApplicable,
 +                    );
 +                }
 +            }
 +            // skip `foo(|| macro!())`
 +            return;
 +        }
 +
 +        let closure_ty = cx.typeck_results().expr_ty(expr);
 +
 +        if_chain!(
 +            if let ExprKind::Call(callee, args) = body.value.kind;
 +            if let ExprKind::Path(_) = callee.kind;
 +            if check_inputs(cx, body.params, args);
 +            let callee_ty = cx.typeck_results().expr_ty_adjusted(callee);
 +            let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id)
 +                .map_or(callee_ty, |id| cx.tcx.type_of(id));
 +            if check_sig(cx, closure_ty, call_ty);
 +            let substs = cx.typeck_results().node_substs(callee.hir_id);
 +            // This fixes some false positives that I don't entirely understand
 +            if substs.is_empty() || !cx.typeck_results().expr_ty(expr).has_late_bound_regions();
 +            // A type param function ref like `T::f` is not 'static, however
 +            // it is if cast like `T::f as fn()`. This seems like a rustc bug.
 +            if !substs.types().any(|t| matches!(t.kind(), ty::Param(_)));
 +            then {
 +                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
 +                    if let Some(mut snippet) = snippet_opt(cx, callee.span) {
 +                        if_chain! {
 +                            if let ty::Closure(_, substs) = callee_ty.peel_refs().kind();
 +                            if substs.as_closure().kind() == ClosureKind::FnMut;
 +                            if get_enclosing_loop_or_closure(cx.tcx, expr).is_some()
 +                                || UsedAfterExprVisitor::is_found(cx, callee);
 +
 +                            then {
 +                                // Mutable closure is used after current expr; we cannot consume it.
 +                                snippet = format!("&mut {}", snippet);
 +                            }
 +                        }
 +                        diag.span_suggestion(
 +                            expr.span,
 +                            "replace the closure with the function itself",
 +                            snippet,
 +                            Applicability::MachineApplicable,
 +                        );
 +                    }
 +                });
 +            }
 +        );
 +
 +        if_chain!(
 +            if let ExprKind::MethodCall(path, _, args, _) = body.value.kind;
 +            if check_inputs(cx, body.params, args);
 +            let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
 +            let substs = cx.typeck_results().node_substs(body.value.hir_id);
 +            let call_ty = cx.tcx.type_of(method_def_id).subst(cx.tcx, substs);
 +            if check_sig(cx, closure_ty, call_ty);
 +            then {
 +                span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| {
 +                    let name = get_ufcs_type_name(cx, method_def_id);
 +                    diag.span_suggestion(
 +                        expr.span,
 +                        "replace the closure with the method itself",
 +                        format!("{}::{}", name, path.ident.name),
 +                        Applicability::MachineApplicable,
 +                    );
 +                })
 +            }
 +        );
 +    }
 +}
 +
 +fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_>]) -> bool {
 +    if params.len() != call_args.len() {
 +        return false;
 +    }
 +    std::iter::zip(params, call_args).all(|(param, arg)| {
 +        match param.pat.kind {
 +            PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
 +            _ => return false,
 +        }
 +        match *cx.typeck_results().expr_adjustments(arg) {
 +            [] => true,
++            [
++                Adjustment {
++                    kind: Adjust::Deref(None),
++                    ..
++                },
++                Adjustment {
++                    kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
++                    ..
++                },
++            ] => {
 +                // re-borrow with the same mutability is allowed
 +                let ty = cx.typeck_results().expr_ty(arg);
 +                matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into())
 +            },
 +            _ => false,
 +        }
 +    })
 +}
 +
 +fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
 +    let call_sig = call_ty.fn_sig(cx.tcx);
 +    if call_sig.unsafety() == Unsafety::Unsafe {
 +        return false;
 +    }
 +    if !closure_ty.has_late_bound_regions() {
 +        return true;
 +    }
 +    let substs = match closure_ty.kind() {
 +        ty::Closure(_, substs) => substs,
 +        _ => return false,
 +    };
 +    let closure_sig = cx.tcx.signature_unclosure(substs.as_closure().sig(), Unsafety::Normal);
 +    cx.tcx.erase_late_bound_regions(closure_sig) == cx.tcx.erase_late_bound_regions(call_sig)
 +}
 +
 +fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String {
 +    match cx.tcx.associated_item(method_def_id).container {
 +        ty::TraitContainer(def_id) => cx.tcx.def_path_str(def_id),
 +        ty::ImplContainer(def_id) => {
 +            let ty = cx.tcx.type_of(def_id);
 +            match ty.kind() {
 +                ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did),
 +                _ => ty.to_string(),
 +            }
 +        },
 +    }
 +}
index c22f9d0e170326c79fbdd0df8cc2228b27822aaf,0000000000000000000000000000000000000000..7169ac9ad6c5a50ce98062c8d1dcdaa465adea46
mode 100644,000000..100644
--- /dev/null
@@@ -1,102 -1,0 +1,118 @@@
-             if_chain! {
-                 if let [e] = &*format_args.format_string_parts;
-                 if let ExprKind::Lit(lit) = &e.kind;
-                 if let Some(s_src) = snippet_opt(cx, lit.span);
-                 then {
-                     // Simulate macro expansion, converting {{ and }} to { and }.
-                     let s_expand = s_src.replace("{{", "{").replace("}}", "}");
-                     let sugg = format!("{}.to_string()", s_expand);
-                     span_useless_format(cx, call_site, sugg, applicability);
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::higher::FormatExpn;
 +use clippy_utils::source::{snippet_opt, snippet_with_applicability};
 +use clippy_utils::sugg::Sugg;
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::symbol::kw;
 +use rustc_span::{sym, Span};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the use of `format!("string literal with no
 +    /// argument")` and `format!("{}", foo)` where `foo` is a string.
 +    ///
 +    /// ### Why is this bad?
 +    /// There is no point of doing that. `format!("foo")` can
 +    /// be replaced by `"foo".to_owned()` if you really need a `String`. The even
 +    /// worse `&format!("foo")` is often encountered in the wild. `format!("{}",
 +    /// foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()`
 +    /// if `foo: &str`.
 +    ///
 +    /// ### Examples
 +    /// ```rust
 +    ///
 +    /// // Bad
 +    /// let foo = "foo";
 +    /// format!("{}", foo);
 +    ///
 +    /// // Good
 +    /// foo.to_owned();
 +    /// ```
 +    pub USELESS_FORMAT,
 +    complexity,
 +    "useless use of `format!`"
 +}
 +
 +declare_lint_pass!(UselessFormat => [USELESS_FORMAT]);
 +
 +impl<'tcx> LateLintPass<'tcx> for UselessFormat {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        let FormatExpn { call_site, format_args } = match FormatExpn::parse(expr) {
 +            Some(e) if !e.call_site.from_expansion() => e,
 +            _ => return,
 +        };
 +
 +        let mut applicability = Applicability::MachineApplicable;
 +        if format_args.value_args.is_empty() {
++            if format_args.format_string_parts.is_empty() {
++                span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability);
++            } else {
++                if_chain! {
++                    if let [e] = &*format_args.format_string_parts;
++                    if let ExprKind::Lit(lit) = &e.kind;
++                    if let Some(s_src) = snippet_opt(cx, lit.span);
++                    then {
++                        // Simulate macro expansion, converting {{ and }} to { and }.
++                        let s_expand = s_src.replace("{{", "{").replace("}}", "}");
++                        let sugg = format!("{}.to_string()", s_expand);
++                        span_useless_format(cx, call_site, sugg, applicability);
++                    }
 +                }
 +            }
 +        } else if let [value] = *format_args.value_args {
 +            if_chain! {
 +                if format_args.format_string_symbols == [kw::Empty];
 +                if match cx.typeck_results().expr_ty(value).peel_refs().kind() {
 +                    ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did),
 +                    ty::Str => true,
 +                    _ => false,
 +                };
 +                if let Some(args) = format_args.args();
 +                if args.iter().all(|arg| arg.is_display() && !arg.has_string_formatting());
 +                then {
 +                    let is_new_string = match value.kind {
 +                        ExprKind::Binary(..) => true,
 +                        ExprKind::MethodCall(path, ..) => path.ident.name.as_str() == "to_string",
 +                        _ => false,
 +                    };
 +                    let sugg = if is_new_string {
 +                        snippet_with_applicability(cx, value.span, "..", &mut applicability).into_owned()
 +                    } else {
 +                        let sugg = Sugg::hir_with_applicability(cx, value, "<arg>", &mut applicability);
 +                        format!("{}.to_string()", sugg.maybe_par())
 +                    };
 +                    span_useless_format(cx, call_site, sugg, applicability);
 +                }
 +            }
 +        };
 +    }
 +}
 +
++fn span_useless_format_empty(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) {
++    span_lint_and_sugg(
++        cx,
++        USELESS_FORMAT,
++        span,
++        "useless use of `format!`",
++        "consider using `String::new()`",
++        sugg,
++        applicability,
++    );
++}
++
 +fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) {
 +    span_lint_and_sugg(
 +        cx,
 +        USELESS_FORMAT,
 +        span,
 +        "useless use of `format!`",
 +        "consider using `.to_string()`",
 +        sugg,
 +        applicability,
 +    );
 +}
index 3ce91d421baca8bc9efe4b9ae760c522c7f288ca,0000000000000000000000000000000000000000..ac938156237bf8f090feb281558f6301b685e6b0
mode 100644,000000..100644
--- /dev/null
@@@ -1,82 -1,0 +1,89 @@@
- use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp};
- use rustc_lint::{EarlyContext, EarlyLintPass};
- use rustc_middle::lint::in_external_macro;
 +//! lint on if branches that could be swapped so no `!` operation is necessary
 +//! on the condition
 +
 +use clippy_utils::diagnostics::span_lint_and_help;
- impl EarlyLintPass for IfNotElse {
-     fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
-         if in_external_macro(cx.sess, item.span) {
++use clippy_utils::is_else_clause;
++use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
++use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `!` or `!=` in an if condition with an
 +    /// else branch.
 +    ///
 +    /// ### Why is this bad?
 +    /// Negations reduce the readability of statements.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let v: Vec<usize> = vec![];
 +    /// # fn a() {}
 +    /// # fn b() {}
 +    /// if !v.is_empty() {
 +    ///     a()
 +    /// } else {
 +    ///     b()
 +    /// }
 +    /// ```
 +    ///
 +    /// Could be written:
 +    ///
 +    /// ```rust
 +    /// # let v: Vec<usize> = vec![];
 +    /// # fn a() {}
 +    /// # fn b() {}
 +    /// if v.is_empty() {
 +    ///     b()
 +    /// } else {
 +    ///     a()
 +    /// }
 +    /// ```
 +    pub IF_NOT_ELSE,
 +    pedantic,
 +    "`if` branches that could be swapped so no negation operation is necessary on the condition"
 +}
 +
 +declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
 +
-         if let ExprKind::If(ref cond, _, Some(ref els)) = item.kind {
++impl LateLintPass<'_> for IfNotElse {
++    fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
++        // While loops will be desugared to ExprKind::If. This will cause the lint to fire.
++        // To fix this, return early if this span comes from a macro or desugaring.
++        if item.span.from_expansion() {
 +            return;
 +        }
-                 match cond.kind {
++        if let ExprKind::If(cond, _, Some(els)) = item.kind {
 +            if let ExprKind::Block(..) = els.kind {
++                // Disable firing the lint in "else if" expressions.
++                if is_else_clause(cx.tcx, item) {
++                    return;
++                }
++
++                match cond.peel_drop_temps().kind {
 +                    ExprKind::Unary(UnOp::Not, _) => {
 +                        span_lint_and_help(
 +                            cx,
 +                            IF_NOT_ELSE,
 +                            item.span,
 +                            "unnecessary boolean `not` operation",
 +                            None,
 +                            "remove the `!` and swap the blocks of the `if`/`else`",
 +                        );
 +                    },
 +                    ExprKind::Binary(ref kind, _, _) if kind.node == BinOpKind::Ne => {
 +                        span_lint_and_help(
 +                            cx,
 +                            IF_NOT_ELSE,
 +                            item.span,
 +                            "unnecessary `!=` operation",
 +                            None,
 +                            "change to `==` and swap the blocks of the `if`/`else`",
 +                        );
 +                    },
 +                    _ => (),
 +                }
 +            }
 +        }
 +    }
 +}
index 49b69dd072a21352da51d21d4eb1a4c0bee2778f,0000000000000000000000000000000000000000..6850e0c34767cb0864a002b5ce498c3cc157c5a8
mode 100644,000000..100644
--- /dev/null
@@@ -1,171 -1,0 +1,171 @@@
-             }
 +//! lint on blocks unnecessarily using >= with a + 1 or - 1
 +
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::source::snippet_opt;
 +use rustc_ast::ast::{BinOpKind, Expr, ExprKind, Lit, LitKind};
 +use rustc_errors::Applicability;
 +use rustc_lint::{EarlyContext, EarlyLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability -- better to use `> y` instead of `>= y + 1`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let x = 1;
 +    /// # let y = 1;
 +    /// if x >= y + 1 {}
 +    /// ```
 +    ///
 +    /// Could be written as:
 +    ///
 +    /// ```rust
 +    /// # let x = 1;
 +    /// # let y = 1;
 +    /// if x > y {}
 +    /// ```
 +    pub INT_PLUS_ONE,
 +    complexity,
 +    "instead of using `x >= y + 1`, use `x > y`"
 +}
 +
 +declare_lint_pass!(IntPlusOne => [INT_PLUS_ONE]);
 +
 +// cases:
 +// BinOpKind::Ge
 +// x >= y + 1
 +// x - 1 >= y
 +//
 +// BinOpKind::Le
 +// x + 1 <= y
 +// x <= y - 1
 +
 +#[derive(Copy, Clone)]
 +enum Side {
 +    Lhs,
 +    Rhs,
 +}
 +
 +impl IntPlusOne {
 +    #[allow(clippy::cast_sign_loss)]
 +    fn check_lit(lit: &Lit, target_value: i128) -> bool {
 +        if let LitKind::Int(value, ..) = lit.kind {
 +            return value == (target_value as u128);
 +        }
 +        false
 +    }
 +
 +    fn check_binop(cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<String> {
 +        match (binop, &lhs.kind, &rhs.kind) {
 +            // case where `x - 1 >= ...` or `-1 + x >= ...`
 +            (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => {
 +                match (lhskind.node, &lhslhs.kind, &lhsrhs.kind) {
 +                    // `-1 + x`
 +                    (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => {
 +                        Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
 +                    },
 +                    // `x - 1`
 +                    (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
 +                        Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
 +                    },
 +                    _ => None,
 +                }
 +            },
 +            // case where `... >= y + 1` or `... >= 1 + y`
 +            (BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs))
 +                if rhskind.node == BinOpKind::Add =>
 +            {
 +                match (&rhslhs.kind, &rhsrhs.kind) {
 +                    // `y + 1` and `1 + y`
 +                    (&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => {
 +                        Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
 +                    },
 +                    (_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
 +                        Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
 +                    },
 +                    _ => None,
 +                }
-             }
++            },
 +            // case where `x + 1 <= ...` or `1 + x <= ...`
 +            (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _)
 +                if lhskind.node == BinOpKind::Add =>
 +            {
 +                match (&lhslhs.kind, &lhsrhs.kind) {
 +                    // `1 + x` and `x + 1`
 +                    (&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => {
 +                        Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
 +                    },
 +                    (_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
 +                        Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
 +                    },
 +                    _ => None,
 +                }
++            },
 +            // case where `... >= y - 1` or `... >= -1 + y`
 +            (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
 +                match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {
 +                    // `-1 + y`
 +                    (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => {
 +                        Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
 +                    },
 +                    // `y - 1`
 +                    (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
 +                        Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
 +                    },
 +                    _ => None,
 +                }
 +            },
 +            _ => None,
 +        }
 +    }
 +
 +    fn generate_recommendation(
 +        cx: &EarlyContext<'_>,
 +        binop: BinOpKind,
 +        node: &Expr,
 +        other_side: &Expr,
 +        side: Side,
 +    ) -> Option<String> {
 +        let binop_string = match binop {
 +            BinOpKind::Ge => ">",
 +            BinOpKind::Le => "<",
 +            _ => return None,
 +        };
 +        if let Some(snippet) = snippet_opt(cx, node.span) {
 +            if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) {
 +                let rec = match side {
 +                    Side::Lhs => Some(format!("{} {} {}", snippet, binop_string, other_side_snippet)),
 +                    Side::Rhs => Some(format!("{} {} {}", other_side_snippet, binop_string, snippet)),
 +                };
 +                return rec;
 +            }
 +        }
 +        None
 +    }
 +
 +    fn emit_warning(cx: &EarlyContext<'_>, block: &Expr, recommendation: String) {
 +        span_lint_and_sugg(
 +            cx,
 +            INT_PLUS_ONE,
 +            block.span,
 +            "unnecessary `>= y + 1` or `x - 1 >=`",
 +            "change it to",
 +            recommendation,
 +            Applicability::MachineApplicable, // snippet
 +        );
 +    }
 +}
 +
 +impl EarlyLintPass for IntPlusOne {
 +    fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
 +        if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.kind {
 +            if let Some(rec) = Self::check_binop(cx, kind.node, lhs, rhs) {
 +                Self::emit_warning(cx, item, rec);
 +            }
 +        }
 +    }
 +}
index b1f70b30c12cf1c1605b09ac48cf9fc9891fad3e,0000000000000000000000000000000000000000..82438d85c7a3a353128134b0736e587c4dc9d5f1
mode 100644,000000..100644
--- /dev/null
@@@ -1,222 -1,0 +1,160 @@@
- use std::cmp::Ordering;
 +use rustc_hir::{Expr, ExprKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::layout::LayoutOf;
 +use rustc_middle::ty::{self, IntTy, UintTy};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::Span;
 +
++use clippy_utils::comparisons;
 +use clippy_utils::comparisons::Rel;
- use clippy_utils::consts::{constant, Constant};
++use clippy_utils::consts::{constant_full_int, FullInt};
 +use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::source::snippet;
- use clippy_utils::{comparisons, sext};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for comparisons where the relation is always either
 +    /// true or false, but where one side has been upcast so that the comparison is
 +    /// necessary. Only integer types are checked.
 +    ///
 +    /// ### Why is this bad?
 +    /// An expression like `let x : u8 = ...; (x as u32) > 300`
 +    /// will mistakenly imply that it is possible for `x` to be outside the range of
 +    /// `u8`.
 +    ///
 +    /// ### Known problems
 +    /// https://github.com/rust-lang/rust-clippy/issues/886
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x: u8 = 1;
 +    /// (x as u32) > 300;
 +    /// ```
 +    pub INVALID_UPCAST_COMPARISONS,
 +    pedantic,
 +    "a comparison involving an upcast which is always true or false"
 +}
 +
 +declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
 +
- #[derive(Copy, Clone, Debug, Eq)]
- enum FullInt {
-     S(i128),
-     U(u128),
- }
- impl FullInt {
-     #[allow(clippy::cast_sign_loss)]
-     #[must_use]
-     fn cmp_s_u(s: i128, u: u128) -> Ordering {
-         if s < 0 {
-             Ordering::Less
-         } else if u > (i128::MAX as u128) {
-             Ordering::Greater
-         } else {
-             (s as u128).cmp(&u)
-         }
-     }
- }
- impl PartialEq for FullInt {
-     #[must_use]
-     fn eq(&self, other: &Self) -> bool {
-         self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal
-     }
- }
- impl PartialOrd for FullInt {
-     #[must_use]
-     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-         Some(match (self, other) {
-             (&Self::S(s), &Self::S(o)) => s.cmp(&o),
-             (&Self::U(s), &Self::U(o)) => s.cmp(&o),
-             (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o),
-             (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(),
-         })
-     }
- }
- impl Ord for FullInt {
-     #[must_use]
-     fn cmp(&self, other: &Self) -> Ordering {
-         self.partial_cmp(other)
-             .expect("`partial_cmp` for FullInt can never return `None`")
-     }
- }
 +fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
 +    if let ExprKind::Cast(cast_exp, _) = expr.kind {
 +        let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
 +        let cast_ty = cx.typeck_results().expr_ty(expr);
 +        // if it's a cast from i32 to u32 wrapping will invalidate all these checks
 +        if cx.layout_of(pre_cast_ty).ok().map(|l| l.size) == cx.layout_of(cast_ty).ok().map(|l| l.size) {
 +            return None;
 +        }
 +        match pre_cast_ty.kind() {
 +            ty::Int(int_ty) => Some(match int_ty {
 +                IntTy::I8 => (FullInt::S(i128::from(i8::MIN)), FullInt::S(i128::from(i8::MAX))),
 +                IntTy::I16 => (FullInt::S(i128::from(i16::MIN)), FullInt::S(i128::from(i16::MAX))),
 +                IntTy::I32 => (FullInt::S(i128::from(i32::MIN)), FullInt::S(i128::from(i32::MAX))),
 +                IntTy::I64 => (FullInt::S(i128::from(i64::MIN)), FullInt::S(i128::from(i64::MAX))),
 +                IntTy::I128 => (FullInt::S(i128::MIN), FullInt::S(i128::MAX)),
 +                IntTy::Isize => (FullInt::S(isize::MIN as i128), FullInt::S(isize::MAX as i128)),
 +            }),
 +            ty::Uint(uint_ty) => Some(match uint_ty {
 +                UintTy::U8 => (FullInt::U(u128::from(u8::MIN)), FullInt::U(u128::from(u8::MAX))),
 +                UintTy::U16 => (FullInt::U(u128::from(u16::MIN)), FullInt::U(u128::from(u16::MAX))),
 +                UintTy::U32 => (FullInt::U(u128::from(u32::MIN)), FullInt::U(u128::from(u32::MAX))),
 +                UintTy::U64 => (FullInt::U(u128::from(u64::MIN)), FullInt::U(u128::from(u64::MAX))),
 +                UintTy::U128 => (FullInt::U(u128::MIN), FullInt::U(u128::MAX)),
 +                UintTy::Usize => (FullInt::U(usize::MIN as u128), FullInt::U(usize::MAX as u128)),
 +            }),
 +            _ => None,
 +        }
 +    } else {
 +        None
 +    }
 +}
 +
- fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
-     let val = constant(cx, cx.typeck_results(), expr)?.0;
-     if let Constant::Int(const_int) = val {
-         match *cx.typeck_results().expr_ty(expr).kind() {
-             ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
-             ty::Uint(_) => Some(FullInt::U(const_int)),
-             _ => None,
-         }
-     } else {
-         None
-     }
- }
 +fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
 +    if let ExprKind::Cast(cast_val, _) = expr.kind {
 +        span_lint(
 +            cx,
 +            INVALID_UPCAST_COMPARISONS,
 +            span,
 +            &format!(
 +                "because of the numeric bounds on `{}` prior to casting, this expression is always {}",
 +                snippet(cx, cast_val.span, "the expression"),
 +                if always { "true" } else { "false" },
 +            ),
 +        );
 +    }
 +}
 +
 +fn upcast_comparison_bounds_err<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    span: Span,
 +    rel: comparisons::Rel,
 +    lhs_bounds: Option<(FullInt, FullInt)>,
 +    lhs: &'tcx Expr<'_>,
 +    rhs: &'tcx Expr<'_>,
 +    invert: bool,
 +) {
 +    if let Some((lb, ub)) = lhs_bounds {
-         if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
++        if let Some(norm_rhs_val) = constant_full_int(cx, cx.typeck_results(), rhs) {
 +            if rel == Rel::Eq || rel == Rel::Ne {
 +                if norm_rhs_val < lb || norm_rhs_val > ub {
 +                    err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
 +                }
 +            } else if match rel {
 +                Rel::Lt => {
 +                    if invert {
 +                        norm_rhs_val < lb
 +                    } else {
 +                        ub < norm_rhs_val
 +                    }
 +                },
 +                Rel::Le => {
 +                    if invert {
 +                        norm_rhs_val <= lb
 +                    } else {
 +                        ub <= norm_rhs_val
 +                    }
 +                },
 +                Rel::Eq | Rel::Ne => unreachable!(),
 +            } {
 +                err_upcast_comparison(cx, span, lhs, true);
 +            } else if match rel {
 +                Rel::Lt => {
 +                    if invert {
 +                        norm_rhs_val >= ub
 +                    } else {
 +                        lb >= norm_rhs_val
 +                    }
 +                },
 +                Rel::Le => {
 +                    if invert {
 +                        norm_rhs_val > ub
 +                    } else {
 +                        lb > norm_rhs_val
 +                    }
 +                },
 +                Rel::Eq | Rel::Ne => unreachable!(),
 +            } {
 +                err_upcast_comparison(cx, span, lhs, false);
 +            }
 +        }
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for InvalidUpcastComparisons {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if let ExprKind::Binary(ref cmp, lhs, rhs) = expr.kind {
 +            let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs);
 +            let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized {
 +                val
 +            } else {
 +                return;
 +            };
 +
 +            let lhs_bounds = numeric_cast_precast_bounds(cx, normalized_lhs);
 +            let rhs_bounds = numeric_cast_precast_bounds(cx, normalized_rhs);
 +
 +            upcast_comparison_bounds_err(cx, expr.span, rel, lhs_bounds, normalized_lhs, normalized_rhs, false);
 +            upcast_comparison_bounds_err(cx, expr.span, rel, rhs_bounds, normalized_rhs, normalized_lhs, true);
 +        }
 +    }
 +}
index c949ee23ecc7a94858ce40214e496a881c8a08fd,0000000000000000000000000000000000000000..15edb79d36c24d613653e870f38dc66ff94ca3e3
mode 100644,000000..100644
--- /dev/null
@@@ -1,308 -1,0 +1,309 @@@
-     LintId::of(if_then_panic::IF_THEN_PANIC),
 +// This file was generated by `cargo dev update_lints`.
 +// Use that command to update this file and do not edit by hand.
 +// Manual edits will be overwritten.
 +
 +store.register_group(true, "clippy::all", Some("clippy_all"), vec![
 +    LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
 +    LintId::of(approx_const::APPROX_CONSTANT),
 +    LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
 +    LintId::of(assign_ops::ASSIGN_OP_PATTERN),
 +    LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
 +    LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
 +    LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
 +    LintId::of(attrs::DEPRECATED_CFG_ATTR),
 +    LintId::of(attrs::DEPRECATED_SEMVER),
 +    LintId::of(attrs::MISMATCHED_TARGET_OS),
 +    LintId::of(attrs::USELESS_ATTRIBUTE),
 +    LintId::of(bit_mask::BAD_BIT_MASK),
 +    LintId::of(bit_mask::INEFFECTIVE_BIT_MASK),
 +    LintId::of(blacklisted_name::BLACKLISTED_NAME),
 +    LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
 +    LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
 +    LintId::of(booleans::LOGIC_BUG),
 +    LintId::of(booleans::NONMINIMAL_BOOL),
 +    LintId::of(casts::CAST_REF_TO_MUT),
 +    LintId::of(casts::CHAR_LIT_AS_U8),
 +    LintId::of(casts::FN_TO_NUMERIC_CAST),
 +    LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
 +    LintId::of(casts::UNNECESSARY_CAST),
 +    LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
 +    LintId::of(collapsible_if::COLLAPSIBLE_IF),
 +    LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
 +    LintId::of(comparison_chain::COMPARISON_CHAIN),
 +    LintId::of(copies::IFS_SAME_COND),
 +    LintId::of(copies::IF_SAME_THEN_ELSE),
 +    LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
 +    LintId::of(derivable_impls::DERIVABLE_IMPLS),
 +    LintId::of(derive::DERIVE_HASH_XOR_EQ),
 +    LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
 +    LintId::of(doc::MISSING_SAFETY_DOC),
 +    LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
 +    LintId::of(double_comparison::DOUBLE_COMPARISONS),
 +    LintId::of(double_parens::DOUBLE_PARENS),
 +    LintId::of(drop_forget_ref::DROP_COPY),
 +    LintId::of(drop_forget_ref::DROP_REF),
 +    LintId::of(drop_forget_ref::FORGET_COPY),
 +    LintId::of(drop_forget_ref::FORGET_REF),
 +    LintId::of(duration_subsec::DURATION_SUBSEC),
 +    LintId::of(entry::MAP_ENTRY),
 +    LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
 +    LintId::of(enum_variants::ENUM_VARIANT_NAMES),
 +    LintId::of(enum_variants::MODULE_INCEPTION),
 +    LintId::of(eq_op::EQ_OP),
 +    LintId::of(eq_op::OP_REF),
 +    LintId::of(erasing_op::ERASING_OP),
 +    LintId::of(escape::BOXED_LOCAL),
 +    LintId::of(eta_reduction::REDUNDANT_CLOSURE),
 +    LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION),
 +    LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
 +    LintId::of(explicit_write::EXPLICIT_WRITE),
 +    LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
 +    LintId::of(float_literal::EXCESSIVE_PRECISION),
 +    LintId::of(format::USELESS_FORMAT),
 +    LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
 +    LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
 +    LintId::of(formatting::POSSIBLE_MISSING_COMMA),
 +    LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
 +    LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
 +    LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
 +    LintId::of(from_over_into::FROM_OVER_INTO),
 +    LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
 +    LintId::of(functions::DOUBLE_MUST_USE),
 +    LintId::of(functions::MUST_USE_UNIT),
 +    LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
 +    LintId::of(functions::RESULT_UNIT_ERR),
 +    LintId::of(functions::TOO_MANY_ARGUMENTS),
 +    LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
 +    LintId::of(identity_op::IDENTITY_OP),
 +    LintId::of(if_let_mutex::IF_LET_MUTEX),
 +    LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
 +    LintId::of(infinite_iter::INFINITE_ITER),
 +    LintId::of(inherent_to_string::INHERENT_TO_STRING),
 +    LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
 +    LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
 +    LintId::of(int_plus_one::INT_PLUS_ONE),
 +    LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
 +    LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
 +    LintId::of(len_zero::COMPARISON_TO_EMPTY),
 +    LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
 +    LintId::of(len_zero::LEN_ZERO),
 +    LintId::of(let_underscore::LET_UNDERSCORE_LOCK),
 +    LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
 +    LintId::of(lifetimes::NEEDLESS_LIFETIMES),
 +    LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
 +    LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES),
 +    LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
 +    LintId::of(loops::EMPTY_LOOP),
 +    LintId::of(loops::EXPLICIT_COUNTER_LOOP),
 +    LintId::of(loops::FOR_KV_MAP),
 +    LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
 +    LintId::of(loops::ITER_NEXT_LOOP),
 +    LintId::of(loops::MANUAL_FLATTEN),
 +    LintId::of(loops::MANUAL_MEMCPY),
 +    LintId::of(loops::MUT_RANGE_BOUND),
 +    LintId::of(loops::NEEDLESS_COLLECT),
 +    LintId::of(loops::NEEDLESS_RANGE_LOOP),
 +    LintId::of(loops::NEVER_LOOP),
 +    LintId::of(loops::SAME_ITEM_PUSH),
 +    LintId::of(loops::SINGLE_ELEMENT_LOOP),
 +    LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
 +    LintId::of(loops::WHILE_LET_LOOP),
 +    LintId::of(loops::WHILE_LET_ON_ITERATOR),
 +    LintId::of(main_recursion::MAIN_RECURSION),
 +    LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
 +    LintId::of(manual_map::MANUAL_MAP),
 +    LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
 +    LintId::of(manual_strip::MANUAL_STRIP),
 +    LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
 +    LintId::of(map_clone::MAP_CLONE),
 +    LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
 +    LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
 +    LintId::of(match_result_ok::MATCH_RESULT_OK),
 +    LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH),
 +    LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
 +    LintId::of(matches::MATCH_AS_REF),
 +    LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
 +    LintId::of(matches::MATCH_OVERLAPPING_ARM),
 +    LintId::of(matches::MATCH_REF_PATS),
 +    LintId::of(matches::MATCH_SINGLE_BINDING),
 +    LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
 +    LintId::of(matches::SINGLE_MATCH),
 +    LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
 +    LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
 +    LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
 +    LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
 +    LintId::of(methods::BIND_INSTEAD_OF_MAP),
 +    LintId::of(methods::BYTES_NTH),
 +    LintId::of(methods::CHARS_LAST_CMP),
 +    LintId::of(methods::CHARS_NEXT_CMP),
 +    LintId::of(methods::CLONE_DOUBLE_REF),
 +    LintId::of(methods::CLONE_ON_COPY),
 +    LintId::of(methods::EXPECT_FUN_CALL),
 +    LintId::of(methods::EXTEND_WITH_DRAIN),
 +    LintId::of(methods::FILTER_MAP_IDENTITY),
 +    LintId::of(methods::FILTER_NEXT),
 +    LintId::of(methods::FLAT_MAP_IDENTITY),
 +    LintId::of(methods::INSPECT_FOR_EACH),
 +    LintId::of(methods::INTO_ITER_ON_REF),
 +    LintId::of(methods::ITERATOR_STEP_BY_ZERO),
 +    LintId::of(methods::ITER_CLONED_COLLECT),
 +    LintId::of(methods::ITER_COUNT),
 +    LintId::of(methods::ITER_NEXT_SLICE),
 +    LintId::of(methods::ITER_NTH),
 +    LintId::of(methods::ITER_NTH_ZERO),
 +    LintId::of(methods::ITER_SKIP_NEXT),
 +    LintId::of(methods::MANUAL_FILTER_MAP),
 +    LintId::of(methods::MANUAL_FIND_MAP),
 +    LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
 +    LintId::of(methods::MANUAL_SPLIT_ONCE),
 +    LintId::of(methods::MANUAL_STR_REPEAT),
 +    LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
 +    LintId::of(methods::MAP_IDENTITY),
 +    LintId::of(methods::NEW_RET_NO_SELF),
 +    LintId::of(methods::OK_EXPECT),
 +    LintId::of(methods::OPTION_AS_REF_DEREF),
 +    LintId::of(methods::OPTION_FILTER_MAP),
 +    LintId::of(methods::OPTION_MAP_OR_NONE),
 +    LintId::of(methods::OR_FUN_CALL),
 +    LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
 +    LintId::of(methods::SEARCH_IS_SOME),
 +    LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
 +    LintId::of(methods::SINGLE_CHAR_ADD_STR),
 +    LintId::of(methods::SINGLE_CHAR_PATTERN),
 +    LintId::of(methods::SKIP_WHILE_NEXT),
 +    LintId::of(methods::STRING_EXTEND_CHARS),
 +    LintId::of(methods::SUSPICIOUS_MAP),
 +    LintId::of(methods::SUSPICIOUS_SPLITN),
 +    LintId::of(methods::UNINIT_ASSUMED_INIT),
 +    LintId::of(methods::UNNECESSARY_FILTER_MAP),
 +    LintId::of(methods::UNNECESSARY_FOLD),
 +    LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
 +    LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
 +    LintId::of(methods::USELESS_ASREF),
 +    LintId::of(methods::WRONG_SELF_CONVENTION),
 +    LintId::of(methods::ZST_OFFSET),
 +    LintId::of(minmax::MIN_MAX),
 +    LintId::of(misc::CMP_NAN),
 +    LintId::of(misc::CMP_OWNED),
 +    LintId::of(misc::MODULO_ONE),
 +    LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
 +    LintId::of(misc::TOPLEVEL_REF_ARG),
 +    LintId::of(misc::ZERO_PTR),
 +    LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
 +    LintId::of(misc_early::DOUBLE_NEG),
 +    LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
 +    LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
 +    LintId::of(misc_early::REDUNDANT_PATTERN),
 +    LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
 +    LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
 +    LintId::of(mut_key::MUTABLE_KEY_TYPE),
 +    LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
 +    LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
 +    LintId::of(mutex_atomic::MUTEX_ATOMIC),
 +    LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
 +    LintId::of(needless_bool::BOOL_COMPARISON),
 +    LintId::of(needless_bool::NEEDLESS_BOOL),
 +    LintId::of(needless_borrow::NEEDLESS_BORROW),
 +    LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
 +    LintId::of(needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF),
 +    LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
 +    LintId::of(needless_update::NEEDLESS_UPDATE),
 +    LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
 +    LintId::of(neg_multiply::NEG_MULTIPLY),
 +    LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
 +    LintId::of(no_effect::NO_EFFECT),
 +    LintId::of(no_effect::UNNECESSARY_OPERATION),
 +    LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
 +    LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
 +    LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
 +    LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
++    LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
 +    LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
 +    LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
 +    LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
 +    LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
 +    LintId::of(precedence::PRECEDENCE),
 +    LintId::of(ptr::CMP_NULL),
 +    LintId::of(ptr::INVALID_NULL_PTR_USAGE),
 +    LintId::of(ptr::MUT_FROM_REF),
 +    LintId::of(ptr::PTR_ARG),
 +    LintId::of(ptr_eq::PTR_EQ),
 +    LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
 +    LintId::of(question_mark::QUESTION_MARK),
 +    LintId::of(ranges::MANUAL_RANGE_CONTAINS),
 +    LintId::of(ranges::RANGE_ZIP_WITH_LEN),
 +    LintId::of(ranges::REVERSED_EMPTY_RANGES),
 +    LintId::of(redundant_clone::REDUNDANT_CLONE),
 +    LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
 +    LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
 +    LintId::of(redundant_slicing::REDUNDANT_SLICING),
 +    LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
 +    LintId::of(reference::DEREF_ADDROF),
 +    LintId::of(reference::REF_IN_DEREF),
 +    LintId::of(regex::INVALID_REGEX),
 +    LintId::of(repeat_once::REPEAT_ONCE),
 +    LintId::of(returns::LET_AND_RETURN),
 +    LintId::of(returns::NEEDLESS_RETURN),
 +    LintId::of(self_assignment::SELF_ASSIGNMENT),
 +    LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
 +    LintId::of(serde_api::SERDE_API_MISUSE),
 +    LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
 +    LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
 +    LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
 +    LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
 +    LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
 +    LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
 +    LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
 +    LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
 +    LintId::of(swap::ALMOST_SWAPPED),
 +    LintId::of(swap::MANUAL_SWAP),
 +    LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
 +    LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT),
 +    LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
 +    LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY),
 +    LintId::of(transmute::CROSSPOINTER_TRANSMUTE),
 +    LintId::of(transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS),
 +    LintId::of(transmute::TRANSMUTE_BYTES_TO_STR),
 +    LintId::of(transmute::TRANSMUTE_FLOAT_TO_INT),
 +    LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
 +    LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
 +    LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
 +    LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
 +    LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
 +    LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
 +    LintId::of(transmute::WRONG_TRANSMUTE),
 +    LintId::of(transmuting_null::TRANSMUTING_NULL),
 +    LintId::of(try_err::TRY_ERR),
 +    LintId::of(types::BORROWED_BOX),
 +    LintId::of(types::BOX_COLLECTION),
 +    LintId::of(types::REDUNDANT_ALLOCATION),
 +    LintId::of(types::TYPE_COMPLEXITY),
 +    LintId::of(types::VEC_BOX),
 +    LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
 +    LintId::of(unicode::INVISIBLE_CHARACTERS),
 +    LintId::of(uninit_vec::UNINIT_VEC),
++    LintId::of(unit_hash::UNIT_HASH),
 +    LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
 +    LintId::of(unit_types::UNIT_ARG),
 +    LintId::of(unit_types::UNIT_CMP),
 +    LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
 +    LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
 +    LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY),
 +    LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
 +    LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
 +    LintId::of(unused_unit::UNUSED_UNIT),
 +    LintId::of(unwrap::PANICKING_UNWRAP),
 +    LintId::of(unwrap::UNNECESSARY_UNWRAP),
 +    LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
 +    LintId::of(useless_conversion::USELESS_CONVERSION),
 +    LintId::of(vec::USELESS_VEC),
 +    LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
 +    LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
 +    LintId::of(write::PRINTLN_EMPTY_STRING),
 +    LintId::of(write::PRINT_LITERAL),
 +    LintId::of(write::PRINT_WITH_NEWLINE),
 +    LintId::of(write::WRITELN_EMPTY_STRING),
 +    LintId::of(write::WRITE_LITERAL),
 +    LintId::of(write::WRITE_WITH_NEWLINE),
 +    LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
 +])
index ff56a6081fb57f8cbc44c08f785b2981900147f4,0000000000000000000000000000000000000000..4217fd3a3ea72c04af802f688f39d34f1f501c7a
mode 100644,000000..100644
--- /dev/null
@@@ -1,74 -1,0 +1,75 @@@
 +// This file was generated by `cargo dev update_lints`.
 +// Use that command to update this file and do not edit by hand.
 +// Manual edits will be overwritten.
 +
 +store.register_group(true, "clippy::correctness", Some("clippy_correctness"), vec![
 +    LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
 +    LintId::of(approx_const::APPROX_CONSTANT),
 +    LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
 +    LintId::of(attrs::DEPRECATED_SEMVER),
 +    LintId::of(attrs::MISMATCHED_TARGET_OS),
 +    LintId::of(attrs::USELESS_ATTRIBUTE),
 +    LintId::of(bit_mask::BAD_BIT_MASK),
 +    LintId::of(bit_mask::INEFFECTIVE_BIT_MASK),
 +    LintId::of(booleans::LOGIC_BUG),
 +    LintId::of(casts::CAST_REF_TO_MUT),
 +    LintId::of(copies::IFS_SAME_COND),
 +    LintId::of(copies::IF_SAME_THEN_ELSE),
 +    LintId::of(derive::DERIVE_HASH_XOR_EQ),
 +    LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
 +    LintId::of(drop_forget_ref::DROP_COPY),
 +    LintId::of(drop_forget_ref::DROP_REF),
 +    LintId::of(drop_forget_ref::FORGET_COPY),
 +    LintId::of(drop_forget_ref::FORGET_REF),
 +    LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
 +    LintId::of(eq_op::EQ_OP),
 +    LintId::of(erasing_op::ERASING_OP),
 +    LintId::of(formatting::POSSIBLE_MISSING_COMMA),
 +    LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
 +    LintId::of(if_let_mutex::IF_LET_MUTEX),
 +    LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
 +    LintId::of(infinite_iter::INFINITE_ITER),
 +    LintId::of(inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
 +    LintId::of(inline_fn_without_body::INLINE_FN_WITHOUT_BODY),
 +    LintId::of(let_underscore::LET_UNDERSCORE_LOCK),
 +    LintId::of(literal_representation::MISTYPED_LITERAL_SUFFIXES),
 +    LintId::of(loops::ITER_NEXT_LOOP),
 +    LintId::of(loops::NEVER_LOOP),
 +    LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
 +    LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH),
 +    LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
 +    LintId::of(methods::CLONE_DOUBLE_REF),
 +    LintId::of(methods::ITERATOR_STEP_BY_ZERO),
 +    LintId::of(methods::SUSPICIOUS_SPLITN),
 +    LintId::of(methods::UNINIT_ASSUMED_INIT),
 +    LintId::of(methods::ZST_OFFSET),
 +    LintId::of(minmax::MIN_MAX),
 +    LintId::of(misc::CMP_NAN),
 +    LintId::of(misc::MODULO_ONE),
 +    LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
 +    LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
 +    LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
 +    LintId::of(ptr::INVALID_NULL_PTR_USAGE),
 +    LintId::of(ptr::MUT_FROM_REF),
 +    LintId::of(ranges::REVERSED_EMPTY_RANGES),
 +    LintId::of(regex::INVALID_REGEX),
 +    LintId::of(self_assignment::SELF_ASSIGNMENT),
 +    LintId::of(serde_api::SERDE_API_MISUSE),
 +    LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
 +    LintId::of(swap::ALMOST_SWAPPED),
 +    LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY),
 +    LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
 +    LintId::of(transmute::WRONG_TRANSMUTE),
 +    LintId::of(transmuting_null::TRANSMUTING_NULL),
 +    LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
 +    LintId::of(unicode::INVISIBLE_CHARACTERS),
 +    LintId::of(uninit_vec::UNINIT_VEC),
++    LintId::of(unit_hash::UNIT_HASH),
 +    LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
 +    LintId::of(unit_types::UNIT_CMP),
 +    LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
 +    LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
 +    LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
 +    LintId::of(unwrap::PANICKING_UNWRAP),
 +    LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
 +])
index e8dd3708c8ed406dc3f92b6bff81332d49d9757e,0000000000000000000000000000000000000000..2cb86418e3cb5df2cc946ba79a8095fe48de7be0
mode 100644,000000..100644
--- /dev/null
@@@ -1,518 -1,0 +1,521 @@@
-     if_then_panic::IF_THEN_PANIC,
 +// This file was generated by `cargo dev update_lints`.
 +// Use that command to update this file and do not edit by hand.
 +// Manual edits will be overwritten.
 +
 +store.register_lints(&[
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::CLIPPY_LINTS_INTERNAL,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::COMPILER_LINT_FUNCTIONS,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::DEFAULT_LINT,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::IF_CHAIN_STYLE,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::INTERNING_DEFINED_SYMBOL,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::INVALID_PATHS,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::LINT_WITHOUT_LINT_PASS,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::OUTER_EXPN_EXPN_DATA,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::PRODUCE_ICE,
 +    #[cfg(feature = "internal-lints")]
 +    utils::internal_lints::UNNECESSARY_SYMBOL_STR,
 +    absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS,
 +    approx_const::APPROX_CONSTANT,
 +    arithmetic::FLOAT_ARITHMETIC,
 +    arithmetic::INTEGER_ARITHMETIC,
 +    as_conversions::AS_CONVERSIONS,
 +    asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
 +    asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
 +    assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
 +    assign_ops::ASSIGN_OP_PATTERN,
 +    assign_ops::MISREFACTORED_ASSIGN_OP,
 +    async_yields_async::ASYNC_YIELDS_ASYNC,
 +    attrs::BLANKET_CLIPPY_RESTRICTION_LINTS,
 +    attrs::DEPRECATED_CFG_ATTR,
 +    attrs::DEPRECATED_SEMVER,
 +    attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
 +    attrs::INLINE_ALWAYS,
 +    attrs::MISMATCHED_TARGET_OS,
 +    attrs::USELESS_ATTRIBUTE,
 +    await_holding_invalid::AWAIT_HOLDING_LOCK,
 +    await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
 +    bit_mask::BAD_BIT_MASK,
 +    bit_mask::INEFFECTIVE_BIT_MASK,
 +    bit_mask::VERBOSE_BIT_MASK,
 +    blacklisted_name::BLACKLISTED_NAME,
 +    blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
 +    bool_assert_comparison::BOOL_ASSERT_COMPARISON,
 +    booleans::LOGIC_BUG,
 +    booleans::NONMINIMAL_BOOL,
 +    bytecount::NAIVE_BYTECOUNT,
 +    cargo_common_metadata::CARGO_COMMON_METADATA,
 +    case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
 +    casts::CAST_LOSSLESS,
 +    casts::CAST_POSSIBLE_TRUNCATION,
 +    casts::CAST_POSSIBLE_WRAP,
 +    casts::CAST_PRECISION_LOSS,
 +    casts::CAST_PTR_ALIGNMENT,
 +    casts::CAST_REF_TO_MUT,
 +    casts::CAST_SIGN_LOSS,
 +    casts::CHAR_LIT_AS_U8,
 +    casts::FN_TO_NUMERIC_CAST,
 +    casts::FN_TO_NUMERIC_CAST_ANY,
 +    casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
 +    casts::PTR_AS_PTR,
 +    casts::UNNECESSARY_CAST,
 +    checked_conversions::CHECKED_CONVERSIONS,
 +    cognitive_complexity::COGNITIVE_COMPLEXITY,
 +    collapsible_if::COLLAPSIBLE_ELSE_IF,
 +    collapsible_if::COLLAPSIBLE_IF,
 +    collapsible_match::COLLAPSIBLE_MATCH,
 +    comparison_chain::COMPARISON_CHAIN,
 +    copies::BRANCHES_SHARING_CODE,
 +    copies::IFS_SAME_COND,
 +    copies::IF_SAME_THEN_ELSE,
 +    copies::SAME_FUNCTIONS_IN_IF_CONDITION,
 +    copy_iterator::COPY_ITERATOR,
 +    create_dir::CREATE_DIR,
 +    dbg_macro::DBG_MACRO,
 +    default::DEFAULT_TRAIT_ACCESS,
 +    default::FIELD_REASSIGN_WITH_DEFAULT,
 +    default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
 +    dereference::EXPLICIT_DEREF_METHODS,
 +    derivable_impls::DERIVABLE_IMPLS,
 +    derive::DERIVE_HASH_XOR_EQ,
 +    derive::DERIVE_ORD_XOR_PARTIAL_ORD,
 +    derive::EXPL_IMPL_CLONE_ON_COPY,
 +    derive::UNSAFE_DERIVE_DESERIALIZE,
 +    disallowed_method::DISALLOWED_METHOD,
 +    disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,
 +    disallowed_type::DISALLOWED_TYPE,
 +    doc::DOC_MARKDOWN,
 +    doc::MISSING_ERRORS_DOC,
 +    doc::MISSING_PANICS_DOC,
 +    doc::MISSING_SAFETY_DOC,
 +    doc::NEEDLESS_DOCTEST_MAIN,
 +    double_comparison::DOUBLE_COMPARISONS,
 +    double_parens::DOUBLE_PARENS,
 +    drop_forget_ref::DROP_COPY,
 +    drop_forget_ref::DROP_REF,
 +    drop_forget_ref::FORGET_COPY,
 +    drop_forget_ref::FORGET_REF,
 +    duration_subsec::DURATION_SUBSEC,
 +    else_if_without_else::ELSE_IF_WITHOUT_ELSE,
 +    empty_enum::EMPTY_ENUM,
 +    entry::MAP_ENTRY,
 +    enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT,
 +    enum_variants::ENUM_VARIANT_NAMES,
 +    enum_variants::MODULE_INCEPTION,
 +    enum_variants::MODULE_NAME_REPETITIONS,
 +    eq_op::EQ_OP,
 +    eq_op::OP_REF,
 +    equatable_if_let::EQUATABLE_IF_LET,
 +    erasing_op::ERASING_OP,
 +    escape::BOXED_LOCAL,
 +    eta_reduction::REDUNDANT_CLOSURE,
 +    eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
 +    eval_order_dependence::DIVERGING_SUB_EXPRESSION,
 +    eval_order_dependence::EVAL_ORDER_DEPENDENCE,
 +    excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
 +    excessive_bools::STRUCT_EXCESSIVE_BOOLS,
 +    exhaustive_items::EXHAUSTIVE_ENUMS,
 +    exhaustive_items::EXHAUSTIVE_STRUCTS,
 +    exit::EXIT,
 +    explicit_write::EXPLICIT_WRITE,
 +    fallible_impl_from::FALLIBLE_IMPL_FROM,
 +    feature_name::NEGATIVE_FEATURE_NAMES,
 +    feature_name::REDUNDANT_FEATURE_NAMES,
 +    float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS,
 +    float_literal::EXCESSIVE_PRECISION,
 +    float_literal::LOSSY_FLOAT_LITERAL,
 +    floating_point_arithmetic::IMPRECISE_FLOPS,
 +    floating_point_arithmetic::SUBOPTIMAL_FLOPS,
 +    format::USELESS_FORMAT,
 +    format_args::FORMAT_IN_FORMAT_ARGS,
 +    format_args::TO_STRING_IN_FORMAT_ARGS,
 +    formatting::POSSIBLE_MISSING_COMMA,
 +    formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
 +    formatting::SUSPICIOUS_ELSE_FORMATTING,
 +    formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
 +    from_over_into::FROM_OVER_INTO,
 +    from_str_radix_10::FROM_STR_RADIX_10,
 +    functions::DOUBLE_MUST_USE,
 +    functions::MUST_USE_CANDIDATE,
 +    functions::MUST_USE_UNIT,
 +    functions::NOT_UNSAFE_PTR_ARG_DEREF,
 +    functions::RESULT_UNIT_ERR,
 +    functions::TOO_MANY_ARGUMENTS,
 +    functions::TOO_MANY_LINES,
 +    future_not_send::FUTURE_NOT_SEND,
 +    get_last_with_len::GET_LAST_WITH_LEN,
 +    identity_op::IDENTITY_OP,
 +    if_let_mutex::IF_LET_MUTEX,
 +    if_not_else::IF_NOT_ELSE,
 +    if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
 +    implicit_hasher::IMPLICIT_HASHER,
 +    implicit_return::IMPLICIT_RETURN,
 +    implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
 +    inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR,
 +    indexing_slicing::INDEXING_SLICING,
 +    indexing_slicing::OUT_OF_BOUNDS_INDEXING,
 +    infinite_iter::INFINITE_ITER,
 +    infinite_iter::MAYBE_INFINITE_ITER,
 +    inherent_impl::MULTIPLE_INHERENT_IMPL,
 +    inherent_to_string::INHERENT_TO_STRING,
 +    inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY,
 +    inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
 +    int_plus_one::INT_PLUS_ONE,
 +    integer_division::INTEGER_DIVISION,
 +    invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS,
 +    items_after_statements::ITEMS_AFTER_STATEMENTS,
 +    iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR,
 +    large_const_arrays::LARGE_CONST_ARRAYS,
 +    large_enum_variant::LARGE_ENUM_VARIANT,
 +    large_stack_arrays::LARGE_STACK_ARRAYS,
 +    len_zero::COMPARISON_TO_EMPTY,
 +    len_zero::LEN_WITHOUT_IS_EMPTY,
 +    len_zero::LEN_ZERO,
 +    let_if_seq::USELESS_LET_IF_SEQ,
 +    let_underscore::LET_UNDERSCORE_DROP,
 +    let_underscore::LET_UNDERSCORE_LOCK,
 +    let_underscore::LET_UNDERSCORE_MUST_USE,
 +    lifetimes::EXTRA_UNUSED_LIFETIMES,
 +    lifetimes::NEEDLESS_LIFETIMES,
 +    literal_representation::DECIMAL_LITERAL_REPRESENTATION,
 +    literal_representation::INCONSISTENT_DIGIT_GROUPING,
 +    literal_representation::LARGE_DIGIT_GROUPS,
 +    literal_representation::MISTYPED_LITERAL_SUFFIXES,
 +    literal_representation::UNREADABLE_LITERAL,
 +    literal_representation::UNUSUAL_BYTE_GROUPINGS,
 +    loops::EMPTY_LOOP,
 +    loops::EXPLICIT_COUNTER_LOOP,
 +    loops::EXPLICIT_INTO_ITER_LOOP,
 +    loops::EXPLICIT_ITER_LOOP,
 +    loops::FOR_KV_MAP,
 +    loops::FOR_LOOPS_OVER_FALLIBLES,
 +    loops::ITER_NEXT_LOOP,
 +    loops::MANUAL_FLATTEN,
 +    loops::MANUAL_MEMCPY,
 +    loops::MUT_RANGE_BOUND,
 +    loops::NEEDLESS_COLLECT,
 +    loops::NEEDLESS_RANGE_LOOP,
 +    loops::NEVER_LOOP,
 +    loops::SAME_ITEM_PUSH,
 +    loops::SINGLE_ELEMENT_LOOP,
 +    loops::WHILE_IMMUTABLE_CONDITION,
 +    loops::WHILE_LET_LOOP,
 +    loops::WHILE_LET_ON_ITERATOR,
 +    macro_use::MACRO_USE_IMPORTS,
 +    main_recursion::MAIN_RECURSION,
++    manual_assert::MANUAL_ASSERT,
 +    manual_async_fn::MANUAL_ASYNC_FN,
 +    manual_map::MANUAL_MAP,
 +    manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
 +    manual_ok_or::MANUAL_OK_OR,
 +    manual_strip::MANUAL_STRIP,
 +    manual_unwrap_or::MANUAL_UNWRAP_OR,
 +    map_clone::MAP_CLONE,
 +    map_err_ignore::MAP_ERR_IGNORE,
 +    map_unit_fn::OPTION_MAP_UNIT_FN,
 +    map_unit_fn::RESULT_MAP_UNIT_FN,
 +    match_on_vec_items::MATCH_ON_VEC_ITEMS,
 +    match_result_ok::MATCH_RESULT_OK,
 +    match_str_case_mismatch::MATCH_STR_CASE_MISMATCH,
 +    matches::INFALLIBLE_DESTRUCTURING_MATCH,
 +    matches::MATCH_AS_REF,
 +    matches::MATCH_BOOL,
 +    matches::MATCH_LIKE_MATCHES_MACRO,
 +    matches::MATCH_OVERLAPPING_ARM,
 +    matches::MATCH_REF_PATS,
 +    matches::MATCH_SAME_ARMS,
 +    matches::MATCH_SINGLE_BINDING,
 +    matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
 +    matches::MATCH_WILD_ERR_ARM,
 +    matches::REDUNDANT_PATTERN_MATCHING,
 +    matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
 +    matches::SINGLE_MATCH,
 +    matches::SINGLE_MATCH_ELSE,
 +    matches::WILDCARD_ENUM_MATCH_ARM,
 +    matches::WILDCARD_IN_OR_PATTERNS,
 +    mem_forget::MEM_FORGET,
 +    mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
 +    mem_replace::MEM_REPLACE_WITH_DEFAULT,
 +    mem_replace::MEM_REPLACE_WITH_UNINIT,
 +    methods::BIND_INSTEAD_OF_MAP,
 +    methods::BYTES_NTH,
 +    methods::CHARS_LAST_CMP,
 +    methods::CHARS_NEXT_CMP,
 +    methods::CLONED_INSTEAD_OF_COPIED,
 +    methods::CLONE_DOUBLE_REF,
 +    methods::CLONE_ON_COPY,
 +    methods::CLONE_ON_REF_PTR,
 +    methods::EXPECT_FUN_CALL,
 +    methods::EXPECT_USED,
 +    methods::EXTEND_WITH_DRAIN,
 +    methods::FILETYPE_IS_FILE,
 +    methods::FILTER_MAP_IDENTITY,
 +    methods::FILTER_MAP_NEXT,
 +    methods::FILTER_NEXT,
 +    methods::FLAT_MAP_IDENTITY,
 +    methods::FLAT_MAP_OPTION,
 +    methods::FROM_ITER_INSTEAD_OF_COLLECT,
 +    methods::GET_UNWRAP,
 +    methods::IMPLICIT_CLONE,
 +    methods::INEFFICIENT_TO_STRING,
 +    methods::INSPECT_FOR_EACH,
 +    methods::INTO_ITER_ON_REF,
 +    methods::ITERATOR_STEP_BY_ZERO,
 +    methods::ITER_CLONED_COLLECT,
 +    methods::ITER_COUNT,
 +    methods::ITER_NEXT_SLICE,
 +    methods::ITER_NTH,
 +    methods::ITER_NTH_ZERO,
 +    methods::ITER_SKIP_NEXT,
 +    methods::MANUAL_FILTER_MAP,
 +    methods::MANUAL_FIND_MAP,
 +    methods::MANUAL_SATURATING_ARITHMETIC,
 +    methods::MANUAL_SPLIT_ONCE,
 +    methods::MANUAL_STR_REPEAT,
 +    methods::MAP_COLLECT_RESULT_UNIT,
 +    methods::MAP_FLATTEN,
 +    methods::MAP_IDENTITY,
 +    methods::MAP_UNWRAP_OR,
 +    methods::NEW_RET_NO_SELF,
 +    methods::OK_EXPECT,
 +    methods::OPTION_AS_REF_DEREF,
 +    methods::OPTION_FILTER_MAP,
 +    methods::OPTION_MAP_OR_NONE,
 +    methods::OR_FUN_CALL,
 +    methods::RESULT_MAP_OR_INTO_OPTION,
 +    methods::SEARCH_IS_SOME,
 +    methods::SHOULD_IMPLEMENT_TRAIT,
 +    methods::SINGLE_CHAR_ADD_STR,
 +    methods::SINGLE_CHAR_PATTERN,
 +    methods::SKIP_WHILE_NEXT,
 +    methods::STRING_EXTEND_CHARS,
 +    methods::SUSPICIOUS_MAP,
 +    methods::SUSPICIOUS_SPLITN,
 +    methods::UNINIT_ASSUMED_INIT,
 +    methods::UNNECESSARY_FILTER_MAP,
 +    methods::UNNECESSARY_FOLD,
 +    methods::UNNECESSARY_LAZY_EVALUATIONS,
 +    methods::UNWRAP_OR_ELSE_DEFAULT,
 +    methods::UNWRAP_USED,
 +    methods::USELESS_ASREF,
 +    methods::WRONG_SELF_CONVENTION,
 +    methods::ZST_OFFSET,
 +    minmax::MIN_MAX,
 +    misc::CMP_NAN,
 +    misc::CMP_OWNED,
 +    misc::FLOAT_CMP,
 +    misc::FLOAT_CMP_CONST,
 +    misc::MODULO_ONE,
 +    misc::SHORT_CIRCUIT_STATEMENT,
 +    misc::TOPLEVEL_REF_ARG,
 +    misc::USED_UNDERSCORE_BINDING,
 +    misc::ZERO_PTR,
 +    misc_early::BUILTIN_TYPE_SHADOW,
 +    misc_early::DOUBLE_NEG,
 +    misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
 +    misc_early::MIXED_CASE_HEX_LITERALS,
 +    misc_early::REDUNDANT_PATTERN,
++    misc_early::SEPARATED_LITERAL_SUFFIX,
 +    misc_early::UNNEEDED_FIELD_PATTERN,
 +    misc_early::UNNEEDED_WILDCARD_PATTERN,
 +    misc_early::UNSEPARATED_LITERAL_SUFFIX,
 +    misc_early::ZERO_PREFIXED_LITERAL,
 +    missing_const_for_fn::MISSING_CONST_FOR_FN,
 +    missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
 +    missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES,
 +    missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
 +    module_style::MOD_MODULE_FILES,
 +    module_style::SELF_NAMED_MODULE_FILES,
 +    modulo_arithmetic::MODULO_ARITHMETIC,
 +    multiple_crate_versions::MULTIPLE_CRATE_VERSIONS,
 +    mut_key::MUTABLE_KEY_TYPE,
 +    mut_mut::MUT_MUT,
 +    mut_mutex_lock::MUT_MUTEX_LOCK,
 +    mut_reference::UNNECESSARY_MUT_PASSED,
 +    mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL,
 +    mutex_atomic::MUTEX_ATOMIC,
 +    mutex_atomic::MUTEX_INTEGER,
 +    needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE,
 +    needless_bitwise_bool::NEEDLESS_BITWISE_BOOL,
 +    needless_bool::BOOL_COMPARISON,
 +    needless_bool::NEEDLESS_BOOL,
 +    needless_borrow::NEEDLESS_BORROW,
 +    needless_borrow::REF_BINDING_TO_REFERENCE,
 +    needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
 +    needless_continue::NEEDLESS_CONTINUE,
 +    needless_for_each::NEEDLESS_FOR_EACH,
 +    needless_option_as_deref::NEEDLESS_OPTION_AS_DEREF,
 +    needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
 +    needless_question_mark::NEEDLESS_QUESTION_MARK,
 +    needless_update::NEEDLESS_UPDATE,
 +    neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD,
 +    neg_multiply::NEG_MULTIPLY,
 +    new_without_default::NEW_WITHOUT_DEFAULT,
 +    no_effect::NO_EFFECT,
 +    no_effect::NO_EFFECT_UNDERSCORE_BINDING,
 +    no_effect::UNNECESSARY_OPERATION,
 +    non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
 +    non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
 +    non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
 +    non_expressive_names::MANY_SINGLE_CHAR_NAMES,
 +    non_expressive_names::SIMILAR_NAMES,
 +    non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS,
 +    non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY,
 +    nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES,
 +    open_options::NONSENSICAL_OPEN_OPTIONS,
 +    option_env_unwrap::OPTION_ENV_UNWRAP,
 +    option_if_let_else::OPTION_IF_LET_ELSE,
 +    overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
 +    panic_in_result_fn::PANIC_IN_RESULT_FN,
 +    panic_unimplemented::PANIC,
 +    panic_unimplemented::TODO,
 +    panic_unimplemented::UNIMPLEMENTED,
 +    panic_unimplemented::UNREACHABLE,
 +    partialeq_ne_impl::PARTIALEQ_NE_IMPL,
 +    pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
 +    pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
 +    path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
 +    pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
 +    precedence::PRECEDENCE,
 +    ptr::CMP_NULL,
 +    ptr::INVALID_NULL_PTR_USAGE,
 +    ptr::MUT_FROM_REF,
 +    ptr::PTR_ARG,
 +    ptr_eq::PTR_EQ,
 +    ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
 +    question_mark::QUESTION_MARK,
 +    ranges::MANUAL_RANGE_CONTAINS,
 +    ranges::RANGE_MINUS_ONE,
 +    ranges::RANGE_PLUS_ONE,
 +    ranges::RANGE_ZIP_WITH_LEN,
 +    ranges::REVERSED_EMPTY_RANGES,
 +    redundant_clone::REDUNDANT_CLONE,
 +    redundant_closure_call::REDUNDANT_CLOSURE_CALL,
 +    redundant_else::REDUNDANT_ELSE,
 +    redundant_field_names::REDUNDANT_FIELD_NAMES,
 +    redundant_pub_crate::REDUNDANT_PUB_CRATE,
 +    redundant_slicing::REDUNDANT_SLICING,
 +    redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
 +    ref_option_ref::REF_OPTION_REF,
 +    reference::DEREF_ADDROF,
 +    reference::REF_IN_DEREF,
 +    regex::INVALID_REGEX,
 +    regex::TRIVIAL_REGEX,
 +    repeat_once::REPEAT_ONCE,
 +    returns::LET_AND_RETURN,
 +    returns::NEEDLESS_RETURN,
 +    same_name_method::SAME_NAME_METHOD,
 +    self_assignment::SELF_ASSIGNMENT,
 +    self_named_constructors::SELF_NAMED_CONSTRUCTORS,
 +    semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED,
 +    serde_api::SERDE_API_MISUSE,
 +    shadow::SHADOW_REUSE,
 +    shadow::SHADOW_SAME,
 +    shadow::SHADOW_UNRELATED,
 +    single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
 +    size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
 +    slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
 +    stable_sort_primitive::STABLE_SORT_PRIMITIVE,
 +    strings::STRING_ADD,
 +    strings::STRING_ADD_ASSIGN,
 +    strings::STRING_FROM_UTF8_AS_BYTES,
 +    strings::STRING_LIT_AS_BYTES,
++    strings::STRING_SLICE,
 +    strings::STRING_TO_STRING,
 +    strings::STR_TO_STRING,
 +    strlen_on_c_strings::STRLEN_ON_C_STRINGS,
 +    suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS,
 +    suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
 +    suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
 +    swap::ALMOST_SWAPPED,
 +    swap::MANUAL_SWAP,
 +    tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
 +    temporary_assignment::TEMPORARY_ASSIGNMENT,
 +    to_digit_is_some::TO_DIGIT_IS_SOME,
 +    to_string_in_display::TO_STRING_IN_DISPLAY,
 +    trailing_empty_array::TRAILING_EMPTY_ARRAY,
 +    trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
 +    trait_bounds::TYPE_REPETITION_IN_BOUNDS,
 +    transmute::CROSSPOINTER_TRANSMUTE,
 +    transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
 +    transmute::TRANSMUTE_BYTES_TO_STR,
 +    transmute::TRANSMUTE_FLOAT_TO_INT,
 +    transmute::TRANSMUTE_INT_TO_BOOL,
 +    transmute::TRANSMUTE_INT_TO_CHAR,
 +    transmute::TRANSMUTE_INT_TO_FLOAT,
 +    transmute::TRANSMUTE_NUM_TO_BYTES,
 +    transmute::TRANSMUTE_PTR_TO_PTR,
 +    transmute::TRANSMUTE_PTR_TO_REF,
 +    transmute::UNSOUND_COLLECTION_TRANSMUTE,
 +    transmute::USELESS_TRANSMUTE,
 +    transmute::WRONG_TRANSMUTE,
 +    transmuting_null::TRANSMUTING_NULL,
 +    try_err::TRY_ERR,
 +    types::BORROWED_BOX,
 +    types::BOX_COLLECTION,
 +    types::LINKEDLIST,
 +    types::OPTION_OPTION,
 +    types::RC_BUFFER,
 +    types::RC_MUTEX,
 +    types::REDUNDANT_ALLOCATION,
 +    types::TYPE_COMPLEXITY,
 +    types::VEC_BOX,
 +    undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS,
 +    undropped_manually_drops::UNDROPPED_MANUALLY_DROPS,
 +    unicode::INVISIBLE_CHARACTERS,
 +    unicode::NON_ASCII_LITERAL,
 +    unicode::UNICODE_NOT_NFC,
 +    uninit_vec::UNINIT_VEC,
++    unit_hash::UNIT_HASH,
 +    unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
 +    unit_types::LET_UNIT_VALUE,
 +    unit_types::UNIT_ARG,
 +    unit_types::UNIT_CMP,
 +    unnamed_address::FN_ADDRESS_COMPARISONS,
 +    unnamed_address::VTABLE_ADDRESS_COMPARISONS,
 +    unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS,
 +    unnecessary_sort_by::UNNECESSARY_SORT_BY,
 +    unnecessary_wraps::UNNECESSARY_WRAPS,
 +    unnested_or_patterns::UNNESTED_OR_PATTERNS,
 +    unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
 +    unused_async::UNUSED_ASYNC,
 +    unused_io_amount::UNUSED_IO_AMOUNT,
 +    unused_self::UNUSED_SELF,
 +    unused_unit::UNUSED_UNIT,
 +    unwrap::PANICKING_UNWRAP,
 +    unwrap::UNNECESSARY_UNWRAP,
 +    unwrap_in_result::UNWRAP_IN_RESULT,
 +    upper_case_acronyms::UPPER_CASE_ACRONYMS,
 +    use_self::USE_SELF,
 +    useless_conversion::USELESS_CONVERSION,
 +    vec::USELESS_VEC,
 +    vec_init_then_push::VEC_INIT_THEN_PUSH,
 +    vec_resize_to_zero::VEC_RESIZE_TO_ZERO,
 +    verbose_file_reads::VERBOSE_FILE_READS,
 +    wildcard_dependencies::WILDCARD_DEPENDENCIES,
 +    wildcard_imports::ENUM_GLOB_USE,
 +    wildcard_imports::WILDCARD_IMPORTS,
 +    write::PRINTLN_EMPTY_STRING,
 +    write::PRINT_LITERAL,
 +    write::PRINT_STDERR,
 +    write::PRINT_STDOUT,
 +    write::PRINT_WITH_NEWLINE,
 +    write::USE_DEBUG,
 +    write::WRITELN_EMPTY_STRING,
 +    write::WRITE_LITERAL,
 +    write::WRITE_WITH_NEWLINE,
 +    zero_div_zero::ZERO_DIVIDED_BY_ZERO,
 +    zero_sized_map_values::ZERO_SIZED_MAP_VALUES,
 +])
index 1e54482a8dafdc7b5f73d3798f5fd5a04864cc2b,0000000000000000000000000000000000000000..44c75a11eec08111c17db1d2ca03862a17e3a6a3
mode 100644,000000..100644
--- /dev/null
@@@ -1,31 -1,0 +1,30 @@@
-     LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
 +// This file was generated by `cargo dev update_lints`.
 +// Use that command to update this file and do not edit by hand.
 +// Manual edits will be overwritten.
 +
 +store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
 +    LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
 +    LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
 +    LintId::of(copies::BRANCHES_SHARING_CODE),
 +    LintId::of(disallowed_method::DISALLOWED_METHOD),
 +    LintId::of(disallowed_type::DISALLOWED_TYPE),
 +    LintId::of(equatable_if_let::EQUATABLE_IF_LET),
 +    LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
 +    LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
 +    LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),
 +    LintId::of(future_not_send::FUTURE_NOT_SEND),
 +    LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
 +    LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
 +    LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
 +    LintId::of(mutex_atomic::MUTEX_INTEGER),
 +    LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
 +    LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
 +    LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
 +    LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
 +    LintId::of(regex::TRIVIAL_REGEX),
 +    LintId::of(strings::STRING_LIT_AS_BYTES),
 +    LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
 +    LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY),
 +    LintId::of(transmute::USELESS_TRANSMUTE),
 +    LintId::of(use_self::USE_SELF),
 +])
index 268349d28481182fdbac33fe20ba0d0312430fbf,0000000000000000000000000000000000000000..404ca20b5abc62bf05adf9b474a19c0990048e00
mode 100644,000000..100644
--- /dev/null
@@@ -1,101 -1,0 +1,100 @@@
-     LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
 +// This file was generated by `cargo dev update_lints`.
 +// Use that command to update this file and do not edit by hand.
 +// Manual edits will be overwritten.
 +
 +store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
 +    LintId::of(attrs::INLINE_ALWAYS),
 +    LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
 +    LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
 +    LintId::of(bit_mask::VERBOSE_BIT_MASK),
 +    LintId::of(bytecount::NAIVE_BYTECOUNT),
 +    LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
 +    LintId::of(casts::CAST_LOSSLESS),
 +    LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
 +    LintId::of(casts::CAST_POSSIBLE_WRAP),
 +    LintId::of(casts::CAST_PRECISION_LOSS),
 +    LintId::of(casts::CAST_PTR_ALIGNMENT),
 +    LintId::of(casts::CAST_SIGN_LOSS),
 +    LintId::of(casts::PTR_AS_PTR),
 +    LintId::of(checked_conversions::CHECKED_CONVERSIONS),
 +    LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION),
 +    LintId::of(copy_iterator::COPY_ITERATOR),
 +    LintId::of(default::DEFAULT_TRAIT_ACCESS),
 +    LintId::of(dereference::EXPLICIT_DEREF_METHODS),
 +    LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY),
 +    LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE),
 +    LintId::of(doc::DOC_MARKDOWN),
 +    LintId::of(doc::MISSING_ERRORS_DOC),
 +    LintId::of(doc::MISSING_PANICS_DOC),
 +    LintId::of(empty_enum::EMPTY_ENUM),
 +    LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
 +    LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
 +    LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
 +    LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
 +    LintId::of(functions::MUST_USE_CANDIDATE),
 +    LintId::of(functions::TOO_MANY_LINES),
 +    LintId::of(if_not_else::IF_NOT_ELSE),
 +    LintId::of(implicit_hasher::IMPLICIT_HASHER),
 +    LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
 +    LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
 +    LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
 +    LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
 +    LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
 +    LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR),
 +    LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS),
 +    LintId::of(let_underscore::LET_UNDERSCORE_DROP),
 +    LintId::of(literal_representation::LARGE_DIGIT_GROUPS),
 +    LintId::of(literal_representation::UNREADABLE_LITERAL),
 +    LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
 +    LintId::of(loops::EXPLICIT_ITER_LOOP),
 +    LintId::of(macro_use::MACRO_USE_IMPORTS),
++    LintId::of(manual_assert::MANUAL_ASSERT),
 +    LintId::of(manual_ok_or::MANUAL_OK_OR),
 +    LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
 +    LintId::of(matches::MATCH_BOOL),
 +    LintId::of(matches::MATCH_SAME_ARMS),
 +    LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
 +    LintId::of(matches::MATCH_WILD_ERR_ARM),
 +    LintId::of(matches::SINGLE_MATCH_ELSE),
 +    LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
 +    LintId::of(methods::FILTER_MAP_NEXT),
 +    LintId::of(methods::FLAT_MAP_OPTION),
 +    LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT),
 +    LintId::of(methods::IMPLICIT_CLONE),
 +    LintId::of(methods::INEFFICIENT_TO_STRING),
 +    LintId::of(methods::MAP_FLATTEN),
 +    LintId::of(methods::MAP_UNWRAP_OR),
 +    LintId::of(misc::FLOAT_CMP),
 +    LintId::of(misc::USED_UNDERSCORE_BINDING),
-     LintId::of(unicode::NON_ASCII_LITERAL),
 +    LintId::of(mut_mut::MUT_MUT),
 +    LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
 +    LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE),
 +    LintId::of(needless_continue::NEEDLESS_CONTINUE),
 +    LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
 +    LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
 +    LintId::of(no_effect::NO_EFFECT_UNDERSCORE_BINDING),
 +    LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
 +    LintId::of(non_expressive_names::SIMILAR_NAMES),
 +    LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
 +    LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
 +    LintId::of(ranges::RANGE_MINUS_ONE),
 +    LintId::of(ranges::RANGE_PLUS_ONE),
 +    LintId::of(redundant_else::REDUNDANT_ELSE),
 +    LintId::of(ref_option_ref::REF_OPTION_REF),
 +    LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
 +    LintId::of(strings::STRING_ADD_ASSIGN),
 +    LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
 +    LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
 +    LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
 +    LintId::of(types::LINKEDLIST),
 +    LintId::of(types::OPTION_OPTION),
 +    LintId::of(unicode::UNICODE_NOT_NFC),
 +    LintId::of(unit_types::LET_UNIT_VALUE),
 +    LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
 +    LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
 +    LintId::of(unused_async::UNUSED_ASYNC),
 +    LintId::of(unused_self::UNUSED_SELF),
 +    LintId::of(wildcard_imports::ENUM_GLOB_USE),
 +    LintId::of(wildcard_imports::WILDCARD_IMPORTS),
 +    LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
 +])
index 3d68a6e900958fbcfcd886007abc15c468b5ceef,0000000000000000000000000000000000000000..eab389a9bd892089b94a10c749b2837d3916b25c
mode 100644,000000..100644
--- /dev/null
@@@ -1,67 -1,0 +1,71 @@@
 +// This file was generated by `cargo dev update_lints`.
 +// Use that command to update this file and do not edit by hand.
 +// Manual edits will be overwritten.
 +
 +store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
 +    LintId::of(arithmetic::FLOAT_ARITHMETIC),
 +    LintId::of(arithmetic::INTEGER_ARITHMETIC),
 +    LintId::of(as_conversions::AS_CONVERSIONS),
 +    LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
 +    LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
 +    LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
 +    LintId::of(create_dir::CREATE_DIR),
 +    LintId::of(dbg_macro::DBG_MACRO),
 +    LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
 +    LintId::of(disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS),
 +    LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
 +    LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
 +    LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),
 +    LintId::of(exit::EXIT),
 +    LintId::of(float_literal::LOSSY_FLOAT_LITERAL),
 +    LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE),
 +    LintId::of(implicit_return::IMPLICIT_RETURN),
 +    LintId::of(indexing_slicing::INDEXING_SLICING),
 +    LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL),
 +    LintId::of(integer_division::INTEGER_DIVISION),
 +    LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
 +    LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
 +    LintId::of(map_err_ignore::MAP_ERR_IGNORE),
 +    LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
 +    LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
 +    LintId::of(mem_forget::MEM_FORGET),
 +    LintId::of(methods::CLONE_ON_REF_PTR),
 +    LintId::of(methods::EXPECT_USED),
 +    LintId::of(methods::FILETYPE_IS_FILE),
 +    LintId::of(methods::GET_UNWRAP),
 +    LintId::of(methods::UNWRAP_USED),
 +    LintId::of(misc::FLOAT_CMP_CONST),
++    LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX),
 +    LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
++    LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
 +    LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
 +    LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
 +    LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
 +    LintId::of(module_style::MOD_MODULE_FILES),
 +    LintId::of(module_style::SELF_NAMED_MODULE_FILES),
 +    LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),
 +    LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
 +    LintId::of(panic_unimplemented::PANIC),
 +    LintId::of(panic_unimplemented::TODO),
 +    LintId::of(panic_unimplemented::UNIMPLEMENTED),
 +    LintId::of(panic_unimplemented::UNREACHABLE),
 +    LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
 +    LintId::of(same_name_method::SAME_NAME_METHOD),
 +    LintId::of(shadow::SHADOW_REUSE),
 +    LintId::of(shadow::SHADOW_SAME),
 +    LintId::of(shadow::SHADOW_UNRELATED),
 +    LintId::of(strings::STRING_ADD),
++    LintId::of(strings::STRING_SLICE),
 +    LintId::of(strings::STRING_TO_STRING),
 +    LintId::of(strings::STR_TO_STRING),
 +    LintId::of(types::RC_BUFFER),
 +    LintId::of(types::RC_MUTEX),
 +    LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS),
++    LintId::of(unicode::NON_ASCII_LITERAL),
 +    LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
 +    LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
 +    LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
 +    LintId::of(write::PRINT_STDERR),
 +    LintId::of(write::PRINT_STDOUT),
 +    LintId::of(write::USE_DEBUG),
 +])
index a39c111c5742340d1a0d59723da29d722c8271c6,0000000000000000000000000000000000000000..744880bda3e69c2a83763dc5d9b1a38ade7b6ec5
mode 100644,000000..100644
--- /dev/null
@@@ -1,114 -1,0 +1,113 @@@
-     LintId::of(if_then_panic::IF_THEN_PANIC),
 +// This file was generated by `cargo dev update_lints`.
 +// Use that command to update this file and do not edit by hand.
 +// Manual edits will be overwritten.
 +
 +store.register_group(true, "clippy::style", Some("clippy_style"), vec![
 +    LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
 +    LintId::of(assign_ops::ASSIGN_OP_PATTERN),
 +    LintId::of(blacklisted_name::BLACKLISTED_NAME),
 +    LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
 +    LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
 +    LintId::of(casts::FN_TO_NUMERIC_CAST),
 +    LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
 +    LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
 +    LintId::of(collapsible_if::COLLAPSIBLE_IF),
 +    LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
 +    LintId::of(comparison_chain::COMPARISON_CHAIN),
 +    LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
 +    LintId::of(doc::MISSING_SAFETY_DOC),
 +    LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
 +    LintId::of(enum_variants::ENUM_VARIANT_NAMES),
 +    LintId::of(enum_variants::MODULE_INCEPTION),
 +    LintId::of(eq_op::OP_REF),
 +    LintId::of(eta_reduction::REDUNDANT_CLOSURE),
 +    LintId::of(float_literal::EXCESSIVE_PRECISION),
 +    LintId::of(from_over_into::FROM_OVER_INTO),
 +    LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
 +    LintId::of(functions::DOUBLE_MUST_USE),
 +    LintId::of(functions::MUST_USE_UNIT),
 +    LintId::of(functions::RESULT_UNIT_ERR),
 +    LintId::of(inherent_to_string::INHERENT_TO_STRING),
 +    LintId::of(len_zero::COMPARISON_TO_EMPTY),
 +    LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
 +    LintId::of(len_zero::LEN_ZERO),
 +    LintId::of(literal_representation::INCONSISTENT_DIGIT_GROUPING),
 +    LintId::of(literal_representation::UNUSUAL_BYTE_GROUPINGS),
 +    LintId::of(loops::FOR_KV_MAP),
 +    LintId::of(loops::NEEDLESS_RANGE_LOOP),
 +    LintId::of(loops::SAME_ITEM_PUSH),
 +    LintId::of(loops::WHILE_LET_ON_ITERATOR),
 +    LintId::of(main_recursion::MAIN_RECURSION),
 +    LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
 +    LintId::of(manual_map::MANUAL_MAP),
 +    LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
 +    LintId::of(map_clone::MAP_CLONE),
 +    LintId::of(match_result_ok::MATCH_RESULT_OK),
 +    LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
 +    LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
 +    LintId::of(matches::MATCH_OVERLAPPING_ARM),
 +    LintId::of(matches::MATCH_REF_PATS),
 +    LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
 +    LintId::of(matches::SINGLE_MATCH),
 +    LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
 +    LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
 +    LintId::of(methods::BYTES_NTH),
 +    LintId::of(methods::CHARS_LAST_CMP),
 +    LintId::of(methods::CHARS_NEXT_CMP),
 +    LintId::of(methods::INTO_ITER_ON_REF),
 +    LintId::of(methods::ITER_CLONED_COLLECT),
 +    LintId::of(methods::ITER_NEXT_SLICE),
 +    LintId::of(methods::ITER_NTH_ZERO),
 +    LintId::of(methods::ITER_SKIP_NEXT),
 +    LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
 +    LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
 +    LintId::of(methods::NEW_RET_NO_SELF),
 +    LintId::of(methods::OK_EXPECT),
 +    LintId::of(methods::OPTION_MAP_OR_NONE),
 +    LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
 +    LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
 +    LintId::of(methods::SINGLE_CHAR_ADD_STR),
 +    LintId::of(methods::STRING_EXTEND_CHARS),
 +    LintId::of(methods::UNNECESSARY_FOLD),
 +    LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
 +    LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
 +    LintId::of(methods::WRONG_SELF_CONVENTION),
 +    LintId::of(misc::TOPLEVEL_REF_ARG),
 +    LintId::of(misc::ZERO_PTR),
 +    LintId::of(misc_early::BUILTIN_TYPE_SHADOW),
 +    LintId::of(misc_early::DOUBLE_NEG),
 +    LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
 +    LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
 +    LintId::of(misc_early::REDUNDANT_PATTERN),
 +    LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
 +    LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
 +    LintId::of(needless_borrow::NEEDLESS_BORROW),
 +    LintId::of(neg_multiply::NEG_MULTIPLY),
 +    LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
 +    LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
 +    LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
 +    LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
 +    LintId::of(ptr::CMP_NULL),
 +    LintId::of(ptr::PTR_ARG),
 +    LintId::of(ptr_eq::PTR_EQ),
 +    LintId::of(question_mark::QUESTION_MARK),
 +    LintId::of(ranges::MANUAL_RANGE_CONTAINS),
 +    LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
 +    LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
 +    LintId::of(returns::LET_AND_RETURN),
 +    LintId::of(returns::NEEDLESS_RETURN),
 +    LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
 +    LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
 +    LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
 +    LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
 +    LintId::of(try_err::TRY_ERR),
 +    LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
 +    LintId::of(unused_unit::UNUSED_UNIT),
 +    LintId::of(upper_case_acronyms::UPPER_CASE_ACRONYMS),
 +    LintId::of(write::PRINTLN_EMPTY_STRING),
 +    LintId::of(write::PRINT_LITERAL),
 +    LintId::of(write::PRINT_WITH_NEWLINE),
 +    LintId::of(write::WRITELN_EMPTY_STRING),
 +    LintId::of(write::WRITE_LITERAL),
 +    LintId::of(write::WRITE_WITH_NEWLINE),
 +])
index 8859787fbc830c97e7b34a0ee21e053d586bcdcf,0000000000000000000000000000000000000000..a3f964d1580428f92230f26f169586fd86e25504
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,21 @@@
 +// This file was generated by `cargo dev update_lints`.
 +// Use that command to update this file and do not edit by hand.
 +// Manual edits will be overwritten.
 +
 +store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![
 +    LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
 +    LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
 +    LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
 +    LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
 +    LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
 +    LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
 +    LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
 +    LintId::of(loops::EMPTY_LOOP),
 +    LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
 +    LintId::of(loops::MUT_RANGE_BOUND),
 +    LintId::of(methods::SUSPICIOUS_MAP),
 +    LintId::of(mut_key::MUTABLE_KEY_TYPE),
++    LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
 +    LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
 +    LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
 +])
index ed7e827702395dc72336e5f2adaf24709324e6ac,0000000000000000000000000000000000000000..7174d0a082e0f7627f062180d10f5ef47c170a4b
mode 100644,000000..100644
--- /dev/null
@@@ -1,870 -1,0 +1,873 @@@
- mod if_then_panic;
 +// error-pattern:cargo-clippy
 +
 +#![feature(box_patterns)]
 +#![feature(drain_filter)]
 +#![feature(in_band_lifetimes)]
 +#![feature(iter_zip)]
 +#![feature(once_cell)]
 +#![feature(rustc_private)]
 +#![feature(stmt_expr_attributes)]
 +#![feature(control_flow_enum)]
 +#![recursion_limit = "512"]
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]
 +#![warn(trivial_casts, trivial_numeric_casts)]
 +// warn on lints, that are included in `rust-lang/rust`s bootstrap
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +// warn on rustc internal lints
 +#![warn(rustc::internal)]
 +
 +// FIXME: switch to something more ergonomic here, once available.
 +// (Currently there is no way to opt into sysroot crates without `extern crate`.)
 +extern crate rustc_ast;
 +extern crate rustc_ast_pretty;
 +extern crate rustc_data_structures;
 +extern crate rustc_driver;
 +extern crate rustc_errors;
 +extern crate rustc_hir;
 +extern crate rustc_hir_pretty;
 +extern crate rustc_index;
 +extern crate rustc_infer;
 +extern crate rustc_lexer;
 +extern crate rustc_lint;
 +extern crate rustc_middle;
 +extern crate rustc_mir_dataflow;
 +extern crate rustc_parse;
 +extern crate rustc_parse_format;
 +extern crate rustc_session;
 +extern crate rustc_span;
 +extern crate rustc_target;
 +extern crate rustc_trait_selection;
 +extern crate rustc_typeck;
 +
 +#[macro_use]
 +extern crate clippy_utils;
 +
 +use clippy_utils::parse_msrv;
 +use rustc_data_structures::fx::FxHashSet;
 +use rustc_lint::LintId;
 +use rustc_session::Session;
 +
 +/// Macro used to declare a Clippy lint.
 +///
 +/// Every lint declaration consists of 4 parts:
 +///
 +/// 1. The documentation, which is used for the website
 +/// 2. The `LINT_NAME`. See [lint naming][lint_naming] on lint naming conventions.
 +/// 3. The `lint_level`, which is a mapping from *one* of our lint groups to `Allow`, `Warn` or
 +///    `Deny`. The lint level here has nothing to do with what lint groups the lint is a part of.
 +/// 4. The `description` that contains a short explanation on what's wrong with code where the
 +///    lint is triggered.
 +///
 +/// Currently the categories `style`, `correctness`, `suspicious`, `complexity` and `perf` are
 +/// enabled by default. As said in the README.md of this repository, if the lint level mapping
 +/// changes, please update README.md.
 +///
 +/// # Example
 +///
 +/// ```
 +/// #![feature(rustc_private)]
 +/// extern crate rustc_session;
 +/// use rustc_session::declare_tool_lint;
 +/// use clippy_lints::declare_clippy_lint;
 +///
 +/// declare_clippy_lint! {
 +///     /// ### What it does
 +///     /// Checks for ... (describe what the lint matches).
 +///     ///
 +///     /// ### Why is this bad?
 +///     /// Supply the reason for linting the code.
 +///     ///
 +///     /// ### Example
 +///     /// ```rust
 +///     /// // Bad
 +///     /// Insert a short example of code that triggers the lint
 +///     ///
 +///     /// // Good
 +///     /// Insert a short example of improved code that doesn't trigger the lint
 +///     /// ```
 +///     pub LINT_NAME,
 +///     pedantic,
 +///     "description"
 +/// }
 +/// ```
 +/// [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
 +#[macro_export]
 +macro_rules! declare_clippy_lint {
 +    { $(#[$attr:meta])* pub $name:tt, style, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, correctness, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Deny, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, suspicious, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, complexity, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, perf, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, pedantic, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, restriction, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, cargo, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, nursery, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, internal, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Allow, $description, report_in_external_macro: true
 +        }
 +    };
 +    { $(#[$attr:meta])* pub $name:tt, internal_warn, $description:tt } => {
 +        declare_tool_lint! {
 +            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
 +        }
 +    };
 +}
 +
 +#[cfg(feature = "metadata-collector-lint")]
 +mod deprecated_lints;
 +mod utils;
 +
 +// begin lints modules, do not remove this comment, it’s used in `update_lints`
 +mod absurd_extreme_comparisons;
 +mod approx_const;
 +mod arithmetic;
 +mod as_conversions;
 +mod asm_syntax;
 +mod assertions_on_constants;
 +mod assign_ops;
 +mod async_yields_async;
 +mod attrs;
 +mod await_holding_invalid;
 +mod bit_mask;
 +mod blacklisted_name;
 +mod blocks_in_if_conditions;
 +mod bool_assert_comparison;
 +mod booleans;
 +mod bytecount;
 +mod cargo_common_metadata;
 +mod case_sensitive_file_extension_comparisons;
 +mod casts;
 +mod checked_conversions;
 +mod cognitive_complexity;
 +mod collapsible_if;
 +mod collapsible_match;
 +mod comparison_chain;
 +mod copies;
 +mod copy_iterator;
 +mod create_dir;
 +mod dbg_macro;
 +mod default;
 +mod default_numeric_fallback;
 +mod dereference;
 +mod derivable_impls;
 +mod derive;
 +mod disallowed_method;
 +mod disallowed_script_idents;
 +mod disallowed_type;
 +mod doc;
 +mod double_comparison;
 +mod double_parens;
 +mod drop_forget_ref;
 +mod duration_subsec;
 +mod else_if_without_else;
 +mod empty_enum;
 +mod entry;
 +mod enum_clike;
 +mod enum_variants;
 +mod eq_op;
 +mod equatable_if_let;
 +mod erasing_op;
 +mod escape;
 +mod eta_reduction;
 +mod eval_order_dependence;
 +mod excessive_bools;
 +mod exhaustive_items;
 +mod exit;
 +mod explicit_write;
 +mod fallible_impl_from;
 +mod feature_name;
 +mod float_equality_without_abs;
 +mod float_literal;
 +mod floating_point_arithmetic;
 +mod format;
 +mod format_args;
 +mod formatting;
 +mod from_over_into;
 +mod from_str_radix_10;
 +mod functions;
 +mod future_not_send;
 +mod get_last_with_len;
 +mod identity_op;
 +mod if_let_mutex;
 +mod if_not_else;
-     store.register_early_pass(|| Box::new(if_not_else::IfNotElse));
 +mod if_then_some_else_none;
 +mod implicit_hasher;
 +mod implicit_return;
 +mod implicit_saturating_sub;
 +mod inconsistent_struct_constructor;
 +mod indexing_slicing;
 +mod infinite_iter;
 +mod inherent_impl;
 +mod inherent_to_string;
 +mod inline_fn_without_body;
 +mod int_plus_one;
 +mod integer_division;
 +mod invalid_upcast_comparisons;
 +mod items_after_statements;
 +mod iter_not_returning_iterator;
 +mod large_const_arrays;
 +mod large_enum_variant;
 +mod large_stack_arrays;
 +mod len_zero;
 +mod let_if_seq;
 +mod let_underscore;
 +mod lifetimes;
 +mod literal_representation;
 +mod loops;
 +mod macro_use;
 +mod main_recursion;
++mod manual_assert;
 +mod manual_async_fn;
 +mod manual_map;
 +mod manual_non_exhaustive;
 +mod manual_ok_or;
 +mod manual_strip;
 +mod manual_unwrap_or;
 +mod map_clone;
 +mod map_err_ignore;
 +mod map_unit_fn;
 +mod match_on_vec_items;
 +mod match_result_ok;
 +mod match_str_case_mismatch;
 +mod matches;
 +mod mem_forget;
 +mod mem_replace;
 +mod methods;
 +mod minmax;
 +mod misc;
 +mod misc_early;
 +mod missing_const_for_fn;
 +mod missing_doc;
 +mod missing_enforced_import_rename;
 +mod missing_inline;
 +mod module_style;
 +mod modulo_arithmetic;
 +mod multiple_crate_versions;
 +mod mut_key;
 +mod mut_mut;
 +mod mut_mutex_lock;
 +mod mut_reference;
 +mod mutable_debug_assertion;
 +mod mutex_atomic;
 +mod needless_arbitrary_self_type;
 +mod needless_bitwise_bool;
 +mod needless_bool;
 +mod needless_borrow;
 +mod needless_borrowed_ref;
 +mod needless_continue;
 +mod needless_for_each;
 +mod needless_option_as_deref;
 +mod needless_pass_by_value;
 +mod needless_question_mark;
 +mod needless_update;
 +mod neg_cmp_op_on_partial_ord;
 +mod neg_multiply;
 +mod new_without_default;
 +mod no_effect;
 +mod non_copy_const;
 +mod non_expressive_names;
 +mod non_octal_unix_permissions;
 +mod non_send_fields_in_send_ty;
 +mod nonstandard_macro_braces;
 +mod open_options;
 +mod option_env_unwrap;
 +mod option_if_let_else;
 +mod overflow_check_conditional;
 +mod panic_in_result_fn;
 +mod panic_unimplemented;
 +mod partialeq_ne_impl;
 +mod pass_by_ref_or_value;
 +mod path_buf_push_overwrite;
 +mod pattern_type_mismatch;
 +mod precedence;
 +mod ptr;
 +mod ptr_eq;
 +mod ptr_offset_with_cast;
 +mod question_mark;
 +mod ranges;
 +mod redundant_clone;
 +mod redundant_closure_call;
 +mod redundant_else;
 +mod redundant_field_names;
 +mod redundant_pub_crate;
 +mod redundant_slicing;
 +mod redundant_static_lifetimes;
 +mod ref_option_ref;
 +mod reference;
 +mod regex;
 +mod repeat_once;
 +mod returns;
 +mod same_name_method;
 +mod self_assignment;
 +mod self_named_constructors;
 +mod semicolon_if_nothing_returned;
 +mod serde_api;
 +mod shadow;
 +mod single_component_path_imports;
 +mod size_of_in_element_count;
 +mod slow_vector_initialization;
 +mod stable_sort_primitive;
 +mod strings;
 +mod strlen_on_c_strings;
 +mod suspicious_operation_groupings;
 +mod suspicious_trait_impl;
 +mod swap;
 +mod tabs_in_doc_comments;
 +mod temporary_assignment;
 +mod to_digit_is_some;
 +mod to_string_in_display;
 +mod trailing_empty_array;
 +mod trait_bounds;
 +mod transmute;
 +mod transmuting_null;
 +mod try_err;
 +mod types;
 +mod undocumented_unsafe_blocks;
 +mod undropped_manually_drops;
 +mod unicode;
 +mod uninit_vec;
++mod unit_hash;
 +mod unit_return_expecting_ord;
 +mod unit_types;
 +mod unnamed_address;
 +mod unnecessary_self_imports;
 +mod unnecessary_sort_by;
 +mod unnecessary_wraps;
 +mod unnested_or_patterns;
 +mod unsafe_removed_from_name;
 +mod unused_async;
 +mod unused_io_amount;
 +mod unused_self;
 +mod unused_unit;
 +mod unwrap;
 +mod unwrap_in_result;
 +mod upper_case_acronyms;
 +mod use_self;
 +mod useless_conversion;
 +mod vec;
 +mod vec_init_then_push;
 +mod vec_resize_to_zero;
 +mod verbose_file_reads;
 +mod wildcard_dependencies;
 +mod wildcard_imports;
 +mod write;
 +mod zero_div_zero;
 +mod zero_sized_map_values;
 +// end lints modules, do not remove this comment, it’s used in `update_lints`
 +
 +pub use crate::utils::conf::Conf;
 +use crate::utils::conf::TryConf;
 +
 +/// Register all pre expansion lints
 +///
 +/// Pre-expansion lints run before any macro expansion has happened.
 +///
 +/// Note that due to the architecture of the compiler, currently `cfg_attr` attributes on crate
 +/// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass.
 +///
 +/// Used in `./src/driver.rs`.
 +pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) {
 +    // NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
 +    store.register_pre_expansion_pass(|| Box::new(write::Write::default()));
 +    store.register_pre_expansion_pass(|| Box::new(attrs::EarlyAttributes));
 +    store.register_pre_expansion_pass(|| Box::new(dbg_macro::DbgMacro));
 +}
 +
 +#[doc(hidden)]
 +pub fn read_conf(sess: &Session) -> Conf {
 +    let file_name = match utils::conf::lookup_conf_file() {
 +        Ok(Some(path)) => path,
 +        Ok(None) => return Conf::default(),
 +        Err(error) => {
 +            sess.struct_err(&format!("error finding Clippy's configuration file: {}", error))
 +                .emit();
 +            return Conf::default();
 +        },
 +    };
 +
 +    let TryConf { conf, errors } = utils::conf::read(&file_name);
 +    // all conf errors are non-fatal, we just use the default conf in case of error
 +    for error in errors {
 +        sess.struct_err(&format!(
 +            "error reading Clippy's configuration file `{}`: {}",
 +            file_name.display(),
 +            error
 +        ))
 +        .emit();
 +    }
 +
 +    conf
 +}
 +
 +/// Register all lints and lint groups with the rustc plugin registry
 +///
 +/// Used in `./src/driver.rs`.
 +#[allow(clippy::too_many_lines)]
 +#[rustfmt::skip]
 +pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
 +    register_removed_non_tool_lints(store);
 +
 +    include!("lib.deprecated.rs");
 +
 +    include!("lib.register_lints.rs");
 +    include!("lib.register_restriction.rs");
 +    include!("lib.register_pedantic.rs");
 +
 +    #[cfg(feature = "internal-lints")]
 +    include!("lib.register_internal.rs");
 +
 +    include!("lib.register_all.rs");
 +    include!("lib.register_style.rs");
 +    include!("lib.register_complexity.rs");
 +    include!("lib.register_correctness.rs");
 +    include!("lib.register_suspicious.rs");
 +    include!("lib.register_perf.rs");
 +    include!("lib.register_cargo.rs");
 +    include!("lib.register_nursery.rs");
 +
 +    #[cfg(feature = "metadata-collector-lint")]
 +    {
 +        if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
 +            store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
 +            return;
 +        }
 +    }
 +
 +    // all the internal lints
 +    #[cfg(feature = "internal-lints")]
 +    {
 +        store.register_early_pass(|| Box::new(utils::internal_lints::ClippyLintsInternal));
 +        store.register_early_pass(|| Box::new(utils::internal_lints::ProduceIce));
 +        store.register_late_pass(|| Box::new(utils::inspector::DeepCodeInspector));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::CollapsibleCalls));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::CompilerLintFunctions::new()));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::IfChainStyle));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::InvalidPaths));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::InterningDefinedSymbol::default()));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::LintWithoutLintPass::default()));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::MatchTypeOnDiagItem));
 +        store.register_late_pass(|| Box::new(utils::internal_lints::OuterExpnDataPass));
 +    }
 +
 +    store.register_late_pass(|| Box::new(utils::author::Author));
 +    store.register_late_pass(|| Box::new(await_holding_invalid::AwaitHolding));
 +    store.register_late_pass(|| Box::new(serde_api::SerdeApi));
 +    let vec_box_size_threshold = conf.vec_box_size_threshold;
 +    let type_complexity_threshold = conf.type_complexity_threshold;
 +    let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
 +    store.register_late_pass(move || Box::new(types::Types::new(
 +        vec_box_size_threshold,
 +        type_complexity_threshold,
 +        avoid_breaking_exported_api,
 +    )));
 +    store.register_late_pass(|| Box::new(booleans::NonminimalBool));
 +    store.register_late_pass(|| Box::new(needless_bitwise_bool::NeedlessBitwiseBool));
 +    store.register_late_pass(|| Box::new(eq_op::EqOp));
 +    store.register_late_pass(|| Box::new(enum_clike::UnportableVariant));
 +    store.register_late_pass(|| Box::new(float_literal::FloatLiteral));
 +    let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
 +    store.register_late_pass(move || Box::new(bit_mask::BitMask::new(verbose_bit_mask_threshold)));
 +    store.register_late_pass(|| Box::new(ptr::Ptr));
 +    store.register_late_pass(|| Box::new(ptr_eq::PtrEq));
 +    store.register_late_pass(|| Box::new(needless_bool::NeedlessBool));
 +    store.register_late_pass(|| Box::new(needless_option_as_deref::OptionNeedlessDeref));
 +    store.register_late_pass(|| Box::new(needless_bool::BoolComparison));
 +    store.register_late_pass(|| Box::new(needless_for_each::NeedlessForEach));
 +    store.register_late_pass(|| Box::new(misc::MiscLints));
 +    store.register_late_pass(|| Box::new(eta_reduction::EtaReduction));
 +    store.register_late_pass(|| Box::new(identity_op::IdentityOp));
 +    store.register_late_pass(|| Box::new(erasing_op::ErasingOp));
 +    store.register_late_pass(|| Box::new(mut_mut::MutMut));
 +    store.register_late_pass(|| Box::new(mut_reference::UnnecessaryMutPassed));
 +    store.register_late_pass(|| Box::new(len_zero::LenZero));
 +    store.register_late_pass(|| Box::new(attrs::Attributes));
 +    store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
 +    store.register_late_pass(|| Box::new(collapsible_match::CollapsibleMatch));
 +    store.register_late_pass(|| Box::new(unicode::Unicode));
 +    store.register_late_pass(|| Box::new(uninit_vec::UninitVec));
++    store.register_late_pass(|| Box::new(unit_hash::UnitHash));
 +    store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
 +    store.register_late_pass(|| Box::new(strings::StringAdd));
 +    store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn));
 +    store.register_late_pass(|| Box::new(implicit_saturating_sub::ImplicitSaturatingSub));
 +    store.register_late_pass(|| Box::new(default_numeric_fallback::DefaultNumericFallback));
 +    store.register_late_pass(|| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor));
 +    store.register_late_pass(|| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
 +    store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
 +
 +    let msrv = conf.msrv.as_ref().and_then(|s| {
 +        parse_msrv(s, None, None).or_else(|| {
 +            sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
 +            None
 +        })
 +    });
 +
 +    let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
 +    store.register_late_pass(move || Box::new(approx_const::ApproxConstant::new(msrv)));
 +    store.register_late_pass(move || Box::new(methods::Methods::new(avoid_breaking_exported_api, msrv)));
 +    store.register_late_pass(move || Box::new(matches::Matches::new(msrv)));
 +    store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustive::new(msrv)));
 +    store.register_late_pass(move || Box::new(manual_strip::ManualStrip::new(msrv)));
 +    store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv)));
 +    store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv)));
 +    store.register_late_pass(move || Box::new(checked_conversions::CheckedConversions::new(msrv)));
 +    store.register_late_pass(move || Box::new(mem_replace::MemReplace::new(msrv)));
 +    store.register_late_pass(move || Box::new(ranges::Ranges::new(msrv)));
 +    store.register_late_pass(move || Box::new(from_over_into::FromOverInto::new(msrv)));
 +    store.register_late_pass(move || Box::new(use_self::UseSelf::new(msrv)));
 +    store.register_late_pass(move || Box::new(missing_const_for_fn::MissingConstForFn::new(msrv)));
 +    store.register_late_pass(move || Box::new(needless_question_mark::NeedlessQuestionMark));
 +    store.register_late_pass(move || Box::new(casts::Casts::new(msrv)));
 +    store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv)));
 +
 +    store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount));
 +    store.register_late_pass(|| Box::new(same_name_method::SameNameMethod));
 +    store.register_late_pass(|| Box::new(map_clone::MapClone));
 +    store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore));
 +    store.register_late_pass(|| Box::new(shadow::Shadow::default()));
 +    store.register_late_pass(|| Box::new(unit_types::UnitTypes));
 +    store.register_late_pass(|| Box::new(loops::Loops));
 +    store.register_late_pass(|| Box::new(main_recursion::MainRecursion::default()));
 +    store.register_late_pass(|| Box::new(lifetimes::Lifetimes));
 +    store.register_late_pass(|| Box::new(entry::HashMapPass));
 +    store.register_late_pass(|| Box::new(minmax::MinMaxPass));
 +    store.register_late_pass(|| Box::new(open_options::OpenOptions));
 +    store.register_late_pass(|| Box::new(zero_div_zero::ZeroDiv));
 +    store.register_late_pass(|| Box::new(mutex_atomic::Mutex));
 +    store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate));
 +    store.register_late_pass(|| Box::new(needless_borrow::NeedlessBorrow::default()));
 +    store.register_late_pass(|| Box::new(needless_borrowed_ref::NeedlessBorrowedRef));
 +    store.register_late_pass(|| Box::new(no_effect::NoEffect));
 +    store.register_late_pass(|| Box::new(temporary_assignment::TemporaryAssignment));
 +    store.register_late_pass(|| Box::new(transmute::Transmute));
 +    let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
 +    store.register_late_pass(move || Box::new(cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold)));
 +    let too_large_for_stack = conf.too_large_for_stack;
 +    store.register_late_pass(move || Box::new(escape::BoxedLocal{too_large_for_stack}));
 +    store.register_late_pass(move || Box::new(vec::UselessVec{too_large_for_stack}));
 +    store.register_late_pass(|| Box::new(panic_unimplemented::PanicUnimplemented));
 +    store.register_late_pass(|| Box::new(strings::StringLitAsBytes));
 +    store.register_late_pass(|| Box::new(derive::Derive));
 +    store.register_late_pass(|| Box::new(derivable_impls::DerivableImpls));
 +    store.register_late_pass(|| Box::new(get_last_with_len::GetLastWithLen));
 +    store.register_late_pass(|| Box::new(drop_forget_ref::DropForgetRef));
 +    store.register_late_pass(|| Box::new(empty_enum::EmptyEnum));
 +    store.register_late_pass(|| Box::new(absurd_extreme_comparisons::AbsurdExtremeComparisons));
 +    store.register_late_pass(|| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
 +    store.register_late_pass(|| Box::new(regex::Regex));
 +    store.register_late_pass(|| Box::new(copies::CopyAndPaste));
 +    store.register_late_pass(|| Box::new(copy_iterator::CopyIterator));
 +    store.register_late_pass(|| Box::new(format::UselessFormat));
 +    store.register_late_pass(|| Box::new(swap::Swap));
 +    store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional));
 +    store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default()));
 +    let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move || Box::new(blacklisted_name::BlacklistedName::new(blacklisted_names.clone())));
 +    let too_many_arguments_threshold = conf.too_many_arguments_threshold;
 +    let too_many_lines_threshold = conf.too_many_lines_threshold;
 +    store.register_late_pass(move || Box::new(functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold)));
 +    let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_late_pass(move || Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
 +    store.register_late_pass(|| Box::new(neg_multiply::NegMultiply));
 +    store.register_late_pass(|| Box::new(mem_forget::MemForget));
 +    store.register_late_pass(|| Box::new(arithmetic::Arithmetic::default()));
 +    store.register_late_pass(|| Box::new(assign_ops::AssignOps));
 +    store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq));
 +    store.register_late_pass(|| Box::new(eval_order_dependence::EvalOrderDependence));
 +    store.register_late_pass(|| Box::new(missing_doc::MissingDoc::new()));
 +    store.register_late_pass(|| Box::new(missing_inline::MissingInline));
 +    store.register_late_pass(move || Box::new(exhaustive_items::ExhaustiveItems));
 +    store.register_late_pass(|| Box::new(match_result_ok::MatchResultOk));
 +    store.register_late_pass(|| Box::new(partialeq_ne_impl::PartialEqNeImpl));
 +    store.register_late_pass(|| Box::new(unused_io_amount::UnusedIoAmount));
 +    let enum_variant_size_threshold = conf.enum_variant_size_threshold;
 +    store.register_late_pass(move || Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)));
 +    store.register_late_pass(|| Box::new(explicit_write::ExplicitWrite));
 +    store.register_late_pass(|| Box::new(needless_pass_by_value::NeedlessPassByValue));
 +    let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
 +        conf.trivial_copy_size_limit,
 +        conf.pass_by_value_size_limit,
 +        conf.avoid_breaking_exported_api,
 +        &sess.target,
 +    );
 +    store.register_late_pass(move || Box::new(pass_by_ref_or_value));
 +    store.register_late_pass(|| Box::new(ref_option_ref::RefOptionRef));
 +    store.register_late_pass(|| Box::new(try_err::TryErr));
 +    store.register_late_pass(|| Box::new(bytecount::ByteCount));
 +    store.register_late_pass(|| Box::new(infinite_iter::InfiniteIter));
 +    store.register_late_pass(|| Box::new(inline_fn_without_body::InlineFnWithoutBody));
 +    store.register_late_pass(|| Box::new(useless_conversion::UselessConversion::default()));
 +    store.register_late_pass(|| Box::new(implicit_hasher::ImplicitHasher));
 +    store.register_late_pass(|| Box::new(fallible_impl_from::FallibleImplFrom));
 +    store.register_late_pass(|| Box::new(double_comparison::DoubleComparisons));
 +    store.register_late_pass(|| Box::new(question_mark::QuestionMark));
 +    store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
 +    store.register_late_pass(|| Box::new(suspicious_trait_impl::SuspiciousImpl));
 +    store.register_late_pass(|| Box::new(map_unit_fn::MapUnit));
 +    store.register_late_pass(|| Box::new(inherent_impl::MultipleInherentImpl));
 +    store.register_late_pass(|| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
 +    store.register_late_pass(|| Box::new(unwrap::Unwrap));
 +    store.register_late_pass(|| Box::new(duration_subsec::DurationSubsec));
 +    store.register_late_pass(|| Box::new(indexing_slicing::IndexingSlicing));
 +    store.register_late_pass(|| Box::new(non_copy_const::NonCopyConst));
 +    store.register_late_pass(|| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
 +    store.register_late_pass(|| Box::new(redundant_clone::RedundantClone));
 +    store.register_late_pass(|| Box::new(slow_vector_initialization::SlowVectorInit));
 +    store.register_late_pass(|| Box::new(unnecessary_sort_by::UnnecessarySortBy));
 +    store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)));
 +    store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants));
 +    store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull));
 +    store.register_late_pass(|| Box::new(path_buf_push_overwrite::PathBufPushOverwrite));
 +    store.register_late_pass(|| Box::new(integer_division::IntegerDivision));
 +    store.register_late_pass(|| Box::new(inherent_to_string::InherentToString));
 +    let max_trait_bounds = conf.max_trait_bounds;
 +    store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
 +    store.register_late_pass(|| Box::new(comparison_chain::ComparisonChain));
 +    store.register_late_pass(|| Box::new(mut_key::MutableKeyType));
 +    store.register_late_pass(|| Box::new(modulo_arithmetic::ModuloArithmetic));
 +    store.register_early_pass(|| Box::new(reference::DerefAddrOf));
 +    store.register_early_pass(|| Box::new(reference::RefInDeref));
 +    store.register_early_pass(|| Box::new(double_parens::DoubleParens));
 +    store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::new()));
 +    store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
-     store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic));
 +    store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
 +    store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
 +    store.register_early_pass(|| Box::new(formatting::Formatting));
 +    store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints));
 +    store.register_early_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
 +    store.register_late_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
 +    store.register_early_pass(|| Box::new(unused_unit::UnusedUnit));
 +    store.register_late_pass(|| Box::new(returns::Return));
 +    store.register_early_pass(|| Box::new(collapsible_if::CollapsibleIf));
 +    store.register_early_pass(|| Box::new(items_after_statements::ItemsAfterStatements));
 +    store.register_early_pass(|| Box::new(precedence::Precedence));
 +    store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue));
 +    store.register_early_pass(|| Box::new(redundant_else::RedundantElse));
 +    store.register_late_pass(|| Box::new(create_dir::CreateDir));
 +    store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType));
 +    let cargo_ignore_publish = conf.cargo_ignore_publish;
 +    store.register_late_pass(move || Box::new(cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish)));
 +    store.register_late_pass(|| Box::new(multiple_crate_versions::MultipleCrateVersions));
 +    store.register_late_pass(|| Box::new(wildcard_dependencies::WildcardDependencies));
 +    let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
 +    store.register_early_pass(move || Box::new(literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability)));
 +    let literal_representation_threshold = conf.literal_representation_threshold;
 +    store.register_early_pass(move || Box::new(literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold)));
 +    let enum_variant_name_threshold = conf.enum_variant_name_threshold;
 +    store.register_late_pass(move || Box::new(enum_variants::EnumVariantNames::new(enum_variant_name_threshold, avoid_breaking_exported_api)));
 +    store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));
 +    let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
 +    store.register_late_pass(move || Box::new(upper_case_acronyms::UpperCaseAcronyms::new(avoid_breaking_exported_api, upper_case_acronyms_aggressive)));
 +    store.register_late_pass(|| Box::new(default::Default::default()));
 +    store.register_late_pass(|| Box::new(unused_self::UnusedSelf));
 +    store.register_late_pass(|| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
 +    store.register_late_pass(|| Box::new(exit::Exit));
 +    store.register_late_pass(|| Box::new(to_digit_is_some::ToDigitIsSome));
 +    let array_size_threshold = conf.array_size_threshold;
 +    store.register_late_pass(move || Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold)));
 +    store.register_late_pass(move || Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold)));
 +    store.register_late_pass(|| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
 +    store.register_early_pass(|| Box::new(as_conversions::AsConversions));
 +    store.register_late_pass(|| Box::new(let_underscore::LetUnderscore));
 +    store.register_early_pass(|| Box::new(single_component_path_imports::SingleComponentPathImports));
 +    let max_fn_params_bools = conf.max_fn_params_bools;
 +    let max_struct_bools = conf.max_struct_bools;
 +    store.register_early_pass(move || Box::new(excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools)));
 +    store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap));
 +    let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
 +    store.register_late_pass(move || Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
 +    store.register_late_pass(|| Box::new(verbose_file_reads::VerboseFileReads));
 +    store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default()));
 +    store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress));
 +    store.register_late_pass(|| Box::new(dereference::Dereferencing::default()));
 +    store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse));
 +    store.register_late_pass(|| Box::new(future_not_send::FutureNotSend));
 +    store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex));
++    store.register_late_pass(|| Box::new(if_not_else::IfNotElse));
 +    store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality));
 +    store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock));
 +    store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems));
 +    store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn));
 +    store.register_late_pass(|| Box::new(vec_resize_to_zero::VecResizeToZero));
 +    store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn));
 +    let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
 +    store.register_early_pass(move || Box::new(non_expressive_names::NonExpressiveNames {
 +        single_char_binding_names_threshold,
 +    }));
 +    let macro_matcher = conf.standard_macro_braces.iter().cloned().collect::<FxHashSet<_>>();
 +    store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(&macro_matcher)));
 +    store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default()));
 +    store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch));
 +    store.register_late_pass(|| Box::new(stable_sort_primitive::StableSortPrimitive));
 +    store.register_late_pass(|| Box::new(repeat_once::RepeatOnce));
 +    store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult));
 +    store.register_late_pass(|| Box::new(self_assignment::SelfAssignment));
 +    store.register_late_pass(|| Box::new(manual_unwrap_or::ManualUnwrapOr));
 +    store.register_late_pass(|| Box::new(manual_ok_or::ManualOkOr));
 +    store.register_late_pass(|| Box::new(float_equality_without_abs::FloatEqualityWithoutAbs));
 +    store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
 +    store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync));
 +    let disallowed_methods = conf.disallowed_methods.clone();
 +    store.register_late_pass(move || Box::new(disallowed_method::DisallowedMethod::new(disallowed_methods.clone())));
 +    store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
 +    store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
 +    store.register_late_pass(|| Box::new(undropped_manually_drops::UndroppedManuallyDrops));
 +    store.register_late_pass(|| Box::new(strings::StrToString));
 +    store.register_late_pass(|| Box::new(strings::StringToString));
 +    store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues));
 +    store.register_late_pass(|| Box::new(vec_init_then_push::VecInitThenPush::default()));
 +    store.register_late_pass(|| Box::new(case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons));
 +    store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing));
 +    store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10));
 +    store.register_late_pass(|| Box::new(manual_map::ManualMap));
 +    store.register_late_pass(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv)));
 +    store.register_late_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison));
 +    store.register_early_pass(move || Box::new(module_style::ModStyle));
 +    store.register_late_pass(|| Box::new(unused_async::UnusedAsync));
 +    let disallowed_types = conf.disallowed_types.clone();
 +    store.register_late_pass(move || Box::new(disallowed_type::DisallowedType::new(disallowed_types.clone())));
 +    let import_renames = conf.enforced_import_renames.clone();
 +    store.register_late_pass(move || Box::new(missing_enforced_import_rename::ImportRename::new(import_renames.clone())));
 +    let scripts = conf.allowed_scripts.clone();
 +    store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(&scripts)));
 +    store.register_late_pass(|| Box::new(strlen_on_c_strings::StrlenOnCStrings));
 +    store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors));
 +    store.register_late_pass(move || Box::new(feature_name::FeatureName));
 +    store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
++    store.register_late_pass(move || Box::new(manual_assert::ManualAssert));
 +    let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
 +    store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send)));
 +    store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default()));
 +    store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch));
 +    store.register_late_pass(move || Box::new(format_args::FormatArgs));
 +    store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
++    // add lints here, do not remove this comment, it's used in `new_lint`
 +}
 +
 +#[rustfmt::skip]
 +fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
 +    store.register_removed(
 +        "should_assert_eq",
 +        "`assert!()` will be more flexible with RFC 2011",
 +    );
 +    store.register_removed(
 +        "extend_from_slice",
 +        "`.extend_from_slice(_)` is a faster way to extend a Vec by a slice",
 +    );
 +    store.register_removed(
 +        "range_step_by_zero",
 +        "`iterator.step_by(0)` panics nowadays",
 +    );
 +    store.register_removed(
 +        "unstable_as_slice",
 +        "`Vec::as_slice` has been stabilized in 1.7",
 +    );
 +    store.register_removed(
 +        "unstable_as_mut_slice",
 +        "`Vec::as_mut_slice` has been stabilized in 1.7",
 +    );
 +    store.register_removed(
 +        "misaligned_transmute",
 +        "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
 +    );
 +    store.register_removed(
 +        "assign_ops",
 +        "using compound assignment operators (e.g., `+=`) is harmless",
 +    );
 +    store.register_removed(
 +        "if_let_redundant_pattern_matching",
 +        "this lint has been changed to redundant_pattern_matching",
 +    );
 +    store.register_removed(
 +        "unsafe_vector_initialization",
 +        "the replacement suggested by this lint had substantially different behavior",
 +    );
 +    store.register_removed(
 +        "reverse_range_loop",
 +        "this lint is now included in reversed_empty_ranges",
 +    );
 +}
 +
 +/// Register renamed lints.
 +///
 +/// Used in `./src/driver.rs`.
 +pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
++    // NOTE: when renaming a lint, add a corresponding test to tests/ui/rename.rs
 +    ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions");
 +    ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default");
 +    ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");
 +    ls.register_renamed("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes");
 +    ls.register_renamed("clippy::option_and_then_some", "clippy::bind_instead_of_map");
 +    ls.register_renamed("clippy::box_vec", "clippy::box_collection");
 +    ls.register_renamed("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions");
 +    ls.register_renamed("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions");
 +    ls.register_renamed("clippy::option_map_unwrap_or", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or");
 +    ls.register_renamed("clippy::option_unwrap_used", "clippy::unwrap_used");
 +    ls.register_renamed("clippy::result_unwrap_used", "clippy::unwrap_used");
 +    ls.register_renamed("clippy::option_expect_used", "clippy::expect_used");
 +    ls.register_renamed("clippy::result_expect_used", "clippy::expect_used");
 +    ls.register_renamed("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles");
 +    ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles");
 +    ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion");
 +    ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters");
 +    ls.register_renamed("clippy::single_char_push_str", "clippy::single_char_add_str");
 +    ls.register_renamed("clippy::if_let_some_result", "clippy::match_result_ok");
 +
 +    // uplifted lints
 +    ls.register_renamed("clippy::invalid_ref", "invalid_value");
 +    ls.register_renamed("clippy::into_iter_on_array", "array_into_iter");
 +    ls.register_renamed("clippy::unused_label", "unused_labels");
 +    ls.register_renamed("clippy::drop_bounds", "drop_bounds");
 +    ls.register_renamed("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr");
 +    ls.register_renamed("clippy::panic_params", "non_fmt_panics");
 +    ls.register_renamed("clippy::unknown_clippy_lints", "unknown_lints");
 +    ls.register_renamed("clippy::invalid_atomic_ordering", "invalid_atomic_ordering");
 +    ls.register_renamed("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums");
 +}
 +
 +// only exists to let the dogfood integration test works.
 +// Don't run clippy as an executable directly
 +#[allow(dead_code)]
 +fn main() {
 +    panic!("Please use the cargo-clippy executable");
 +}
index e5e6f8d25cc11143878512361a1a9d9f5672cb99,0000000000000000000000000000000000000000..cb0b96e0652e53b1115b238a63713907c8a7fa04
mode 100644,000000..100644
--- /dev/null
@@@ -1,517 -1,0 +1,521 @@@
-             TyKind::OpaqueDef(item, _) => {
 +use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::{in_macro, trait_ref_of_method};
 +use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 +use rustc_hir::intravisit::{
 +    walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty,
 +    NestedVisitorMap, Visitor,
 +};
 +use rustc_hir::FnRetTy::Return;
 +use rustc_hir::{
 +    BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem,
 +    ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier,
 +    TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereClause, WherePredicate,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +use rustc_span::symbol::{kw, Symbol};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for lifetime annotations which can be removed by
 +    /// relying on lifetime elision.
 +    ///
 +    /// ### Why is this bad?
 +    /// The additional lifetimes make the code look more
 +    /// complicated, while there is nothing out of the ordinary going on. Removing
 +    /// them leads to more readable code.
 +    ///
 +    /// ### Known problems
 +    /// - We bail out if the function has a `where` clause where lifetimes
 +    /// are mentioned due to potenial false positives.
 +    /// - Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the
 +    /// placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad: unnecessary lifetime annotations
 +    /// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 {
 +    ///     x
 +    /// }
 +    ///
 +    /// // Good
 +    /// fn elided(x: &u8, y: u8) -> &u8 {
 +    ///     x
 +    /// }
 +    /// ```
 +    pub NEEDLESS_LIFETIMES,
 +    complexity,
 +    "using explicit lifetimes for references in function arguments when elision rules \
 +     would allow omitting them"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for lifetimes in generics that are never used
 +    /// anywhere else.
 +    ///
 +    /// ### Why is this bad?
 +    /// The additional lifetimes make the code look more
 +    /// complicated, while there is nothing out of the ordinary going on. Removing
 +    /// them leads to more readable code.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad: unnecessary lifetimes
 +    /// fn unused_lifetime<'a>(x: u8) {
 +    ///     // ..
 +    /// }
 +    ///
 +    /// // Good
 +    /// fn no_lifetime(x: u8) {
 +    ///     // ...
 +    /// }
 +    /// ```
 +    pub EXTRA_UNUSED_LIFETIMES,
 +    complexity,
 +    "unused lifetimes in function definitions"
 +}
 +
 +declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Lifetimes {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if let ItemKind::Fn(ref sig, ref generics, id) = item.kind {
 +            check_fn_inner(cx, sig.decl, Some(id), generics, item.span, true);
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
 +        if let ImplItemKind::Fn(ref sig, id) = item.kind {
 +            let report_extra_lifetimes = trait_ref_of_method(cx, item.hir_id()).is_none();
 +            check_fn_inner(
 +                cx,
 +                sig.decl,
 +                Some(id),
 +                &item.generics,
 +                item.span,
 +                report_extra_lifetimes,
 +            );
 +        }
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
 +        if let TraitItemKind::Fn(ref sig, ref body) = item.kind {
 +            let body = match *body {
 +                TraitFn::Required(_) => None,
 +                TraitFn::Provided(id) => Some(id),
 +            };
 +            check_fn_inner(cx, sig.decl, body, &item.generics, item.span, true);
 +        }
 +    }
 +}
 +
 +/// The lifetime of a &-reference.
 +#[derive(PartialEq, Eq, Hash, Debug, Clone)]
 +enum RefLt {
 +    Unnamed,
 +    Static,
 +    Named(Symbol),
 +}
 +
 +fn check_fn_inner<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    decl: &'tcx FnDecl<'_>,
 +    body: Option<BodyId>,
 +    generics: &'tcx Generics<'_>,
 +    span: Span,
 +    report_extra_lifetimes: bool,
 +) {
 +    if in_macro(span) || has_where_lifetimes(cx, &generics.where_clause) {
 +        return;
 +    }
 +
 +    let types = generics
 +        .params
 +        .iter()
 +        .filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
 +    for typ in types {
 +        for bound in typ.bounds {
 +            let mut visitor = RefVisitor::new(cx);
 +            walk_param_bound(&mut visitor, bound);
 +            if visitor.lts.iter().any(|lt| matches!(lt, RefLt::Named(_))) {
 +                return;
 +            }
 +            if let GenericBound::Trait(ref trait_ref, _) = *bound {
 +                let params = &trait_ref
 +                    .trait_ref
 +                    .path
 +                    .segments
 +                    .last()
 +                    .expect("a path must have at least one segment")
 +                    .args;
 +                if let Some(params) = *params {
 +                    let lifetimes = params.args.iter().filter_map(|arg| match arg {
 +                        GenericArg::Lifetime(lt) => Some(lt),
 +                        _ => None,
 +                    });
 +                    for bound in lifetimes {
 +                        if bound.name != LifetimeName::Static && !bound.is_elided() {
 +                            return;
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +    if could_use_elision(cx, decl, body, generics.params) {
 +        span_lint(
 +            cx,
 +            NEEDLESS_LIFETIMES,
 +            span.with_hi(decl.output.span().hi()),
 +            "explicit lifetimes given in parameter types where they could be elided \
 +             (or replaced with `'_` if needed by type declaration)",
 +        );
 +    }
 +    if report_extra_lifetimes {
 +        self::report_extra_lifetimes(cx, decl, generics);
 +    }
 +}
 +
 +fn could_use_elision<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    func: &'tcx FnDecl<'_>,
 +    body: Option<BodyId>,
 +    named_generics: &'tcx [GenericParam<'_>],
 +) -> bool {
 +    // There are two scenarios where elision works:
 +    // * no output references, all input references have different LT
 +    // * output references, exactly one input reference with same LT
 +    // All lifetimes must be unnamed, 'static or defined without bounds on the
 +    // level of the current item.
 +
 +    // check named LTs
 +    let allowed_lts = allowed_lts_from(named_generics);
 +
 +    // these will collect all the lifetimes for references in arg/return types
 +    let mut input_visitor = RefVisitor::new(cx);
 +    let mut output_visitor = RefVisitor::new(cx);
 +
 +    // extract lifetimes in input argument types
 +    for arg in func.inputs {
 +        input_visitor.visit_ty(arg);
 +    }
 +    // extract lifetimes in output type
 +    if let Return(ty) = func.output {
 +        output_visitor.visit_ty(ty);
 +    }
 +    for lt in named_generics {
 +        input_visitor.visit_generic_param(lt);
 +    }
 +
 +    if input_visitor.abort() || output_visitor.abort() {
 +        return false;
 +    }
 +
 +    if allowed_lts
 +        .intersection(
 +            &input_visitor
 +                .nested_elision_site_lts
 +                .iter()
 +                .chain(output_visitor.nested_elision_site_lts.iter())
 +                .cloned()
 +                .filter(|v| matches!(v, RefLt::Named(_)))
 +                .collect(),
 +        )
 +        .next()
 +        .is_some()
 +    {
 +        return false;
 +    }
 +
 +    let input_lts = input_visitor.lts;
 +    let output_lts = output_visitor.lts;
 +
 +    if let Some(body_id) = body {
 +        let mut checker = BodyLifetimeChecker {
 +            lifetimes_used_in_body: false,
 +        };
 +        checker.visit_expr(&cx.tcx.hir().body(body_id).value);
 +        if checker.lifetimes_used_in_body {
 +            return false;
 +        }
 +    }
 +
 +    // check for lifetimes from higher scopes
 +    for lt in input_lts.iter().chain(output_lts.iter()) {
 +        if !allowed_lts.contains(lt) {
 +            return false;
 +        }
 +    }
 +
 +    // no input lifetimes? easy case!
 +    if input_lts.is_empty() {
 +        false
 +    } else if output_lts.is_empty() {
 +        // no output lifetimes, check distinctness of input lifetimes
 +
 +        // only unnamed and static, ok
 +        let unnamed_and_static = input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static);
 +        if unnamed_and_static {
 +            return false;
 +        }
 +        // we have no output reference, so we only need all distinct lifetimes
 +        input_lts.len() == unique_lifetimes(&input_lts)
 +    } else {
 +        // we have output references, so we need one input reference,
 +        // and all output lifetimes must be the same
 +        if unique_lifetimes(&output_lts) > 1 {
 +            return false;
 +        }
 +        if input_lts.len() == 1 {
 +            match (&input_lts[0], &output_lts[0]) {
 +                (&RefLt::Named(n1), &RefLt::Named(n2)) if n1 == n2 => true,
 +                (&RefLt::Named(_), &RefLt::Unnamed) => true,
 +                _ => false, /* already elided, different named lifetimes
 +                             * or something static going on */
 +            }
 +        } else {
 +            false
 +        }
 +    }
 +}
 +
 +fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
 +    let mut allowed_lts = FxHashSet::default();
 +    for par in named_generics.iter() {
 +        if let GenericParamKind::Lifetime { .. } = par.kind {
 +            if par.bounds.is_empty() {
 +                allowed_lts.insert(RefLt::Named(par.name.ident().name));
 +            }
 +        }
 +    }
 +    allowed_lts.insert(RefLt::Unnamed);
 +    allowed_lts.insert(RefLt::Static);
 +    allowed_lts
 +}
 +
 +/// Number of unique lifetimes in the given vector.
 +#[must_use]
 +fn unique_lifetimes(lts: &[RefLt]) -> usize {
 +    lts.iter().collect::<FxHashSet<_>>().len()
 +}
 +
 +const CLOSURE_TRAIT_BOUNDS: [LangItem; 3] = [LangItem::Fn, LangItem::FnMut, LangItem::FnOnce];
 +
 +/// A visitor usable for `rustc_front::visit::walk_ty()`.
 +struct RefVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    lts: Vec<RefLt>,
 +    nested_elision_site_lts: Vec<RefLt>,
 +    unelided_trait_object_lifetime: bool,
 +}
 +
 +impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
 +    fn new(cx: &'a LateContext<'tcx>) -> Self {
 +        Self {
 +            cx,
 +            lts: Vec::new(),
 +            nested_elision_site_lts: Vec::new(),
 +            unelided_trait_object_lifetime: false,
 +        }
 +    }
 +
 +    fn record(&mut self, lifetime: &Option<Lifetime>) {
 +        if let Some(ref lt) = *lifetime {
 +            if lt.name == LifetimeName::Static {
 +                self.lts.push(RefLt::Static);
 +            } else if let LifetimeName::Param(ParamName::Fresh(_)) = lt.name {
 +                // Fresh lifetimes generated should be ignored.
 +            } else if lt.is_elided() {
 +                self.lts.push(RefLt::Unnamed);
 +            } else {
 +                self.lts.push(RefLt::Named(lt.name.ident().name));
 +            }
 +        } else {
 +            self.lts.push(RefLt::Unnamed);
 +        }
 +    }
 +
 +    fn all_lts(&self) -> Vec<RefLt> {
 +        self.lts
 +            .iter()
 +            .chain(self.nested_elision_site_lts.iter())
 +            .cloned()
 +            .collect::<Vec<_>>()
 +    }
 +
 +    fn abort(&self) -> bool {
 +        self.unelided_trait_object_lifetime
 +    }
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    // for lifetimes as parameters of generics
 +    fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
 +        self.record(&Some(*lifetime));
 +    }
 +
 +    fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>, tbm: TraitBoundModifier) {
 +        let trait_ref = &poly_tref.trait_ref;
 +        if CLOSURE_TRAIT_BOUNDS.iter().any(|&item| {
 +            self.cx
 +                .tcx
 +                .lang_items()
 +                .require(item)
 +                .map_or(false, |id| Some(id) == trait_ref.trait_def_id())
 +        }) {
 +            let mut sub_visitor = RefVisitor::new(self.cx);
 +            sub_visitor.visit_trait_ref(trait_ref);
 +            self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
 +        } else {
 +            walk_poly_trait_ref(self, poly_tref, tbm);
 +        }
 +    }
 +
 +    fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
 +        match ty.kind {
++            TyKind::OpaqueDef(item, bounds) => {
 +                let map = self.cx.tcx.hir();
 +                let item = map.item(item);
 +                walk_item(self, item);
 +                walk_ty(self, ty);
++                self.lts.extend(bounds.iter().filter_map(|bound| match bound {
++                    GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)),
++                    _ => None,
++                }));
 +            },
 +            TyKind::BareFn(&BareFnTy { decl, .. }) => {
 +                let mut sub_visitor = RefVisitor::new(self.cx);
 +                sub_visitor.visit_fn_decl(decl);
 +                self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
 +                return;
 +            },
 +            TyKind::TraitObject(bounds, ref lt, _) => {
 +                if !lt.is_elided() {
 +                    self.unelided_trait_object_lifetime = true;
 +                }
 +                for bound in bounds {
 +                    self.visit_poly_trait_ref(bound, TraitBoundModifier::None);
 +                }
 +                return;
 +            },
 +            _ => (),
 +        }
 +        walk_ty(self, ty);
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +/// Are any lifetimes mentioned in the `where` clause? If so, we don't try to
 +/// reason about elision.
 +fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, where_clause: &'tcx WhereClause<'_>) -> bool {
 +    for predicate in where_clause.predicates {
 +        match *predicate {
 +            WherePredicate::RegionPredicate(..) => return true,
 +            WherePredicate::BoundPredicate(ref pred) => {
 +                // a predicate like F: Trait or F: for<'a> Trait<'a>
 +                let mut visitor = RefVisitor::new(cx);
 +                // walk the type F, it may not contain LT refs
 +                walk_ty(&mut visitor, pred.bounded_ty);
 +                if !visitor.all_lts().is_empty() {
 +                    return true;
 +                }
 +                // if the bounds define new lifetimes, they are fine to occur
 +                let allowed_lts = allowed_lts_from(pred.bound_generic_params);
 +                // now walk the bounds
 +                for bound in pred.bounds.iter() {
 +                    walk_param_bound(&mut visitor, bound);
 +                }
 +                // and check that all lifetimes are allowed
 +                if visitor.all_lts().iter().any(|it| !allowed_lts.contains(it)) {
 +                    return true;
 +                }
 +            },
 +            WherePredicate::EqPredicate(ref pred) => {
 +                let mut visitor = RefVisitor::new(cx);
 +                walk_ty(&mut visitor, pred.lhs_ty);
 +                walk_ty(&mut visitor, pred.rhs_ty);
 +                if !visitor.lts.is_empty() {
 +                    return true;
 +                }
 +            },
 +        }
 +    }
 +    false
 +}
 +
 +struct LifetimeChecker {
 +    map: FxHashMap<Symbol, Span>,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for LifetimeChecker {
 +    type Map = Map<'tcx>;
 +
 +    // for lifetimes as parameters of generics
 +    fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
 +        self.map.remove(&lifetime.name.ident().name);
 +    }
 +
 +    fn visit_generic_param(&mut self, param: &'tcx GenericParam<'_>) {
 +        // don't actually visit `<'a>` or `<'a: 'b>`
 +        // we've already visited the `'a` declarations and
 +        // don't want to spuriously remove them
 +        // `'b` in `'a: 'b` is useless unless used elsewhere in
 +        // a non-lifetime bound
 +        if let GenericParamKind::Type { .. } = param.kind {
 +            walk_generic_param(self, param);
 +        }
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, generics: &'tcx Generics<'_>) {
 +    let hs = generics
 +        .params
 +        .iter()
 +        .filter_map(|par| match par.kind {
 +            GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)),
 +            _ => None,
 +        })
 +        .collect();
 +    let mut checker = LifetimeChecker { map: hs };
 +
 +    walk_generics(&mut checker, generics);
 +    walk_fn_decl(&mut checker, func);
 +
 +    for &v in checker.map.values() {
 +        span_lint(
 +            cx,
 +            EXTRA_UNUSED_LIFETIMES,
 +            v,
 +            "this lifetime isn't used in the function definition",
 +        );
 +    }
 +}
 +
 +struct BodyLifetimeChecker {
 +    lifetimes_used_in_body: bool,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
 +    type Map = Map<'tcx>;
 +
 +    // for lifetimes as parameters of generics
 +    fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
 +        if lifetime.name.ident().name != kw::Empty && lifetime.name.ident().name != kw::StaticLifetime {
 +            self.lifetimes_used_in_body = true;
 +        }
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
index 2f7360210ba4de7918204c49434a6cf0a5ecd8f3,0000000000000000000000000000000000000000..f9f515cc40a0fbdd120af9de1358d4e92ba66ce7
mode 100644,000000..100644
--- /dev/null
@@@ -1,348 -1,0 +1,348 @@@
-             }
 +use clippy_utils::ty::{has_iter_method, implements_trait};
 +use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::{walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor};
 +use rustc_hir::HirIdMap;
 +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Stmt, StmtKind};
 +use rustc_lint::LateContext;
 +use rustc_middle::hir::map::Map;
 +use rustc_span::source_map::Span;
 +use rustc_span::symbol::{sym, Symbol};
 +use std::iter::Iterator;
 +
 +#[derive(Debug, PartialEq)]
 +enum IncrementVisitorVarState {
 +    Initial,  // Not examined yet
 +    IncrOnce, // Incremented exactly once, may be a loop counter
 +    DontWarn,
 +}
 +
 +/// Scan a for loop for variables that are incremented exactly once and not used after that.
 +pub(super) struct IncrementVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,                  // context reference
 +    states: HirIdMap<IncrementVisitorVarState>, // incremented variables
 +    depth: u32,                                 // depth of conditional expressions
 +    done: bool,
 +}
 +
 +impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
 +    pub(super) fn new(cx: &'a LateContext<'tcx>) -> Self {
 +        Self {
 +            cx,
 +            states: HirIdMap::default(),
 +            depth: 0,
 +            done: false,
 +        }
 +    }
 +
 +    pub(super) fn into_results(self) -> impl Iterator<Item = HirId> {
 +        self.states.into_iter().filter_map(|(id, state)| {
 +            if state == IncrementVisitorVarState::IncrOnce {
 +                Some(id)
 +            } else {
 +                None
 +            }
 +        })
 +    }
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.done {
 +            return;
 +        }
 +
 +        // If node is a variable
 +        if let Some(def_id) = path_to_local(expr) {
 +            if let Some(parent) = get_parent_expr(self.cx, expr) {
 +                let state = self.states.entry(def_id).or_insert(IncrementVisitorVarState::Initial);
 +                if *state == IncrementVisitorVarState::IncrOnce {
 +                    *state = IncrementVisitorVarState::DontWarn;
 +                    return;
 +                }
 +
 +                match parent.kind {
 +                    ExprKind::AssignOp(op, lhs, rhs) => {
 +                        if lhs.hir_id == expr.hir_id {
 +                            *state = if op.node == BinOpKind::Add
 +                                && is_integer_const(self.cx, rhs, 1)
 +                                && *state == IncrementVisitorVarState::Initial
 +                                && self.depth == 0
 +                            {
 +                                IncrementVisitorVarState::IncrOnce
 +                            } else {
 +                                // Assigned some other value or assigned multiple times
 +                                IncrementVisitorVarState::DontWarn
 +                            };
 +                        }
 +                    },
 +                    ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => {
 +                        *state = IncrementVisitorVarState::DontWarn;
 +                    },
 +                    ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
 +                        *state = IncrementVisitorVarState::DontWarn;
 +                    },
 +                    _ => (),
 +                }
 +            }
 +
 +            walk_expr(self, expr);
 +        } else if is_loop(expr) || is_conditional(expr) {
 +            self.depth += 1;
 +            walk_expr(self, expr);
 +            self.depth -= 1;
 +        } else if let ExprKind::Continue(_) = expr.kind {
 +            self.done = true;
 +        } else {
 +            walk_expr(self, expr);
 +        }
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +enum InitializeVisitorState<'hir> {
 +    Initial,          // Not examined yet
 +    Declared(Symbol), // Declared but not (yet) initialized
 +    Initialized {
 +        name: Symbol,
 +        initializer: &'hir Expr<'hir>,
 +    },
 +    DontWarn,
 +}
 +
 +/// Checks whether a variable is initialized at the start of a loop and not modified
 +/// and used after the loop.
 +pub(super) struct InitializeVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,  // context reference
 +    end_expr: &'tcx Expr<'tcx>, // the for loop. Stop scanning here.
 +    var_id: HirId,
 +    state: InitializeVisitorState<'tcx>,
 +    depth: u32, // depth of conditional expressions
 +    past_loop: bool,
 +}
 +
 +impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> {
 +    pub(super) fn new(cx: &'a LateContext<'tcx>, end_expr: &'tcx Expr<'tcx>, var_id: HirId) -> Self {
 +        Self {
 +            cx,
 +            end_expr,
 +            var_id,
 +            state: InitializeVisitorState::Initial,
 +            depth: 0,
 +            past_loop: false,
 +        }
 +    }
 +
 +    pub(super) fn get_result(&self) -> Option<(Symbol, &'tcx Expr<'tcx>)> {
 +        if let InitializeVisitorState::Initialized { name, initializer } = self.state {
 +            Some((name, initializer))
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
 +        // Look for declarations of the variable
 +        if_chain! {
 +            if let StmtKind::Local(local) = stmt.kind;
 +            if local.pat.hir_id == self.var_id;
 +            if let PatKind::Binding(.., ident, _) = local.pat.kind;
 +            then {
 +                self.state = local.init.map_or(InitializeVisitorState::Declared(ident.name), |init| {
 +                    InitializeVisitorState::Initialized {
 +                        initializer: init,
 +                        name: ident.name,
 +                    }
 +                })
 +            }
 +        }
 +        walk_stmt(self, stmt);
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if matches!(self.state, InitializeVisitorState::DontWarn) {
 +            return;
 +        }
 +        if expr.hir_id == self.end_expr.hir_id {
 +            self.past_loop = true;
 +            return;
 +        }
 +        // No need to visit expressions before the variable is
 +        // declared
 +        if matches!(self.state, InitializeVisitorState::Initial) {
 +            return;
 +        }
 +
 +        // If node is the desired variable, see how it's used
 +        if path_to_local_id(expr, self.var_id) {
 +            if self.past_loop {
 +                self.state = InitializeVisitorState::DontWarn;
 +                return;
 +            }
 +
 +            if let Some(parent) = get_parent_expr(self.cx, expr) {
 +                match parent.kind {
 +                    ExprKind::AssignOp(_, lhs, _) if lhs.hir_id == expr.hir_id => {
 +                        self.state = InitializeVisitorState::DontWarn;
 +                    },
 +                    ExprKind::Assign(lhs, rhs, _) if lhs.hir_id == expr.hir_id => {
 +                        self.state = if_chain! {
 +                            if self.depth == 0;
 +                            if let InitializeVisitorState::Declared(name)
 +                                | InitializeVisitorState::Initialized { name, ..} = self.state;
 +                            then {
 +                                InitializeVisitorState::Initialized { initializer: rhs, name }
 +                            } else {
 +                                InitializeVisitorState::DontWarn
 +                            }
 +                        }
 +                    },
 +                    ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
 +                        self.state = InitializeVisitorState::DontWarn;
 +                    },
 +                    _ => (),
 +                }
 +            }
 +
 +            walk_expr(self, expr);
 +        } else if !self.past_loop && is_loop(expr) {
 +            self.state = InitializeVisitorState::DontWarn;
 +        } else if is_conditional(expr) {
 +            self.depth += 1;
 +            walk_expr(self, expr);
 +            self.depth -= 1;
 +        } else {
 +            walk_expr(self, expr);
 +        }
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
 +    }
 +}
 +
 +fn is_loop(expr: &Expr<'_>) -> bool {
 +    matches!(expr.kind, ExprKind::Loop(..))
 +}
 +
 +fn is_conditional(expr: &Expr<'_>) -> bool {
 +    matches!(expr.kind, ExprKind::If(..) | ExprKind::Match(..))
 +}
 +
 +#[derive(PartialEq, Eq)]
 +pub(super) enum Nesting {
 +    Unknown,     // no nesting detected yet
 +    RuledOut,    // the iterator is initialized or assigned within scope
 +    LookFurther, // no nesting detected, no further walk required
 +}
 +
 +use self::Nesting::{LookFurther, RuledOut, Unknown};
 +
 +pub(super) struct LoopNestVisitor {
 +    pub(super) hir_id: HirId,
 +    pub(super) iterator: HirId,
 +    pub(super) nesting: Nesting,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
 +        if stmt.hir_id == self.hir_id {
 +            self.nesting = LookFurther;
 +        } else if self.nesting == Unknown {
 +            walk_stmt(self, stmt);
 +        }
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.nesting != Unknown {
 +            return;
 +        }
 +        if expr.hir_id == self.hir_id {
 +            self.nesting = LookFurther;
 +            return;
 +        }
 +        match expr.kind {
 +            ExprKind::Assign(path, _, _) | ExprKind::AssignOp(_, path, _) => {
 +                if path_to_local_id(path, self.iterator) {
 +                    self.nesting = RuledOut;
 +                }
 +            },
 +            _ => walk_expr(self, expr),
 +        }
 +    }
 +
 +    fn visit_pat(&mut self, pat: &'tcx Pat<'_>) {
 +        if self.nesting != Unknown {
 +            return;
 +        }
 +        if let PatKind::Binding(_, id, ..) = pat.kind {
 +            if id == self.iterator {
 +                self.nesting = RuledOut;
 +                return;
 +            }
 +        }
 +        walk_pat(self, pat);
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +// this function assumes the given expression is a `for` loop.
 +pub(super) fn get_span_of_entire_for_loop(expr: &Expr<'_>) -> Span {
 +    // for some reason this is the only way to get the `Span`
 +    // of the entire `for` loop
 +    if let ExprKind::Match(_, arms, _) = &expr.kind {
 +        arms[0].body.span
 +    } else {
 +        unreachable!()
 +    }
 +}
 +
 +/// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the
 +/// actual `Iterator` that the loop uses.
 +pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String {
 +    let impls_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| {
 +        implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[])
 +    });
 +    if impls_iterator {
 +        format!(
 +            "{}",
 +            sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par()
 +        )
 +    } else {
 +        // (&x).into_iter() ==> x.iter()
 +        // (&mut x).into_iter() ==> x.iter_mut()
 +        match &arg.kind {
 +            ExprKind::AddrOf(BorrowKind::Ref, mutability, arg_inner)
 +                if has_iter_method(cx, cx.typeck_results().expr_ty(arg_inner)).is_some() =>
 +            {
 +                let meth_name = match mutability {
 +                    Mutability::Mut => "iter_mut",
 +                    Mutability::Not => "iter",
 +                };
 +                format!(
 +                    "{}.{}()",
 +                    sugg::Sugg::hir_with_applicability(cx, arg_inner, "_", applic_ref).maybe_par(),
 +                    meth_name,
 +                )
++            },
 +            _ => format!(
 +                "{}.into_iter()",
 +                sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par()
 +            ),
 +        }
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e55aa3f1850fe06a8a6f17b920e6fdcae763267c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,100 @@@
++use clippy_utils::diagnostics::span_lint_and_sugg;
++use clippy_utils::higher::PanicExpn;
++use clippy_utils::source::snippet_with_applicability;
++use clippy_utils::{is_expn_of, sugg};
++use rustc_errors::Applicability;
++use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp};
++use rustc_lint::{LateContext, LateLintPass};
++use rustc_session::{declare_lint_pass, declare_tool_lint};
++
++declare_clippy_lint! {
++    /// ### What it does
++    /// Detects `if`-then-`panic!` that can be replaced with `assert!`.
++    ///
++    /// ### Why is this bad?
++    /// `assert!` is simpler than `if`-then-`panic!`.
++    ///
++    /// ### Example
++    /// ```rust
++    /// let sad_people: Vec<&str> = vec![];
++    /// if !sad_people.is_empty() {
++    ///     panic!("there are sad people: {:?}", sad_people);
++    /// }
++    /// ```
++    /// Use instead:
++    /// ```rust
++    /// let sad_people: Vec<&str> = vec![];
++    /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
++    /// ```
++    pub MANUAL_ASSERT,
++    pedantic,
++    "`panic!` and only a `panic!` in `if`-then statement"
++}
++
++declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]);
++
++impl LateLintPass<'_> for ManualAssert {
++    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
++        if_chain! {
++            if let Expr {
++                kind: ExprKind:: If(cond, Expr {
++                    kind: ExprKind::Block(
++                        Block {
++                            stmts: [stmt],
++                            ..
++                        },
++                        _),
++                    ..
++                }, None),
++                ..
++            } = &expr;
++            if is_expn_of(stmt.span, "panic").is_some();
++            if !matches!(cond.kind, ExprKind::Let(_, _, _));
++            if let StmtKind::Semi(semi) = stmt.kind;
++            if !cx.tcx.sess.source_map().is_multiline(cond.span);
++
++            then {
++                let call = if_chain! {
++                    if let ExprKind::Block(block, _) = semi.kind;
++                    if let Some(init) = block.expr;
++                    then {
++                        init
++                    } else {
++                        semi
++                    }
++                };
++                let span = if let Some(panic_expn) = PanicExpn::parse(call) {
++                    match *panic_expn.format_args.value_args {
++                        [] => panic_expn.format_args.format_string_span,
++                        [.., last] => panic_expn.format_args.format_string_span.to(last.span),
++                    }
++                } else if let ExprKind::Call(_, [format_args]) = call.kind {
++                    format_args.span
++                } else {
++                    return
++                };
++                let mut applicability = Applicability::MachineApplicable;
++                let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
++                let cond_sugg = if let ExprKind::DropTemps(e, ..) = cond.kind {
++                    if let Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..} = e {
++                         sugg::Sugg::hir_with_applicability(cx, not_expr, "..", &mut applicability).maybe_par().to_string()
++                    } else {
++                       format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par())
++                    }
++                } else {
++                   format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par())
++                };
++
++                span_lint_and_sugg(
++                    cx,
++                    MANUAL_ASSERT,
++                    expr.span,
++                    "only a `panic!` in `if`-then statement",
++                    "try",
++                    format!("assert!({}, {});", cond_sugg, sugg),
++                    Applicability::MachineApplicable,
++                );
++            }
++        }
++    }
++}
index a83f38e3d516e5c74c345cc2de119f57468710e2,0000000000000000000000000000000000000000..f501593c5187e36e99b823f0a1a6919df425bc86
mode 100644,000000..100644
--- /dev/null
@@@ -1,171 -1,0 +1,171 @@@
-         CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(char::is_lowercase) },
-         CaseMethod::AsciiLowerCase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'a'..='z')) },
-         CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(char::is_uppercase) },
-         CaseMethod::AsciiUppercase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'A'..='Z')) },
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::ty::is_type_diagnostic_item;
 +use rustc_ast::ast::LitKind;
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 +use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::symbol::SymbolStr;
 +use rustc_span::{sym, Span};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `match` expressions modifying the case of a string with non-compliant arms
 +    ///
 +    /// ### Why is this bad?
 +    /// The arm is unreachable, which is likely a mistake
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let text = "Foo";
 +    ///
 +    /// match &*text.to_ascii_lowercase() {
 +    ///     "foo" => {},
 +    ///     "Bar" => {},
 +    ///     _ => {},
 +    /// }
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// # let text = "Foo";
 +    ///
 +    /// match &*text.to_ascii_lowercase() {
 +    ///     "foo" => {},
 +    ///     "bar" => {},
 +    ///     _ => {},
 +    /// }
 +    /// ```
 +    pub MATCH_STR_CASE_MISMATCH,
 +    correctness,
 +    "creation of a case altering match expression with non-compliant arms"
 +}
 +
 +declare_lint_pass!(MatchStrCaseMismatch => [MATCH_STR_CASE_MISMATCH]);
 +
 +#[derive(Debug)]
 +enum CaseMethod {
 +    LowerCase,
 +    AsciiLowerCase,
 +    UpperCase,
 +    AsciiUppercase,
 +}
 +
 +impl LateLintPass<'_> for MatchStrCaseMismatch {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if_chain! {
 +            if !in_external_macro(cx.tcx.sess, expr.span);
 +            if let ExprKind::Match(match_expr, arms, MatchSource::Normal) = expr.kind;
 +            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(match_expr).kind();
 +            if let ty::Str = ty.kind();
 +            then {
 +                let mut visitor = MatchExprVisitor {
 +                    cx,
 +                    case_method: None,
 +                };
 +
 +                visitor.visit_expr(match_expr);
 +
 +                if let Some(case_method) = visitor.case_method {
 +                    if let Some((bad_case_span, bad_case_str)) = verify_case(&case_method, arms) {
 +                        lint(cx, &case_method, bad_case_span, &bad_case_str);
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +struct MatchExprVisitor<'a, 'tcx> {
 +    cx: &'a LateContext<'tcx>,
 +    case_method: Option<CaseMethod>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +
 +    fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
 +        match ex.kind {
 +            ExprKind::MethodCall(segment, _, [receiver], _)
 +                if self.case_altered(&*segment.ident.as_str(), receiver) => {},
 +            _ => walk_expr(self, ex),
 +        }
 +    }
 +}
 +
 +impl<'a, 'tcx> MatchExprVisitor<'a, 'tcx> {
 +    fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> bool {
 +        if let Some(case_method) = get_case_method(segment_ident) {
 +            let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
 +
 +            if is_type_diagnostic_item(self.cx, ty, sym::String) || ty.kind() == &ty::Str {
 +                self.case_method = Some(case_method);
 +                return true;
 +            }
 +        }
 +
 +        false
 +    }
 +}
 +
 +fn get_case_method(segment_ident_str: &str) -> Option<CaseMethod> {
 +    match segment_ident_str {
 +        "to_lowercase" => Some(CaseMethod::LowerCase),
 +        "to_ascii_lowercase" => Some(CaseMethod::AsciiLowerCase),
 +        "to_uppercase" => Some(CaseMethod::UpperCase),
 +        "to_ascii_uppercase" => Some(CaseMethod::AsciiUppercase),
 +        _ => None,
 +    }
 +}
 +
 +fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(Span, SymbolStr)> {
 +    let case_check = match case_method {
-         CaseMethod::LowerCase => ("to_lower_case", bad_case_str.to_lowercase()),
++        CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(|c| c.to_lowercase().next() == Some(c)) },
++        CaseMethod::AsciiLowerCase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_uppercase()) },
++        CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(|c| c.to_uppercase().next() == Some(c)) },
++        CaseMethod::AsciiUppercase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_lowercase()) },
 +    };
 +
 +    for arm in arms {
 +        if_chain! {
 +            if let PatKind::Lit(Expr {
 +                                kind: ExprKind::Lit(lit),
 +                                ..
 +                            }) = arm.pat.kind;
 +            if let LitKind::Str(symbol, _) = lit.node;
 +            let input = symbol.as_str();
 +            if !case_check(&input);
 +            then {
 +                return Some((lit.span, input));
 +            }
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad_case_str: &str) {
 +    let (method_str, suggestion) = match case_method {
++        CaseMethod::LowerCase => ("to_lowercase", bad_case_str.to_lowercase()),
 +        CaseMethod::AsciiLowerCase => ("to_ascii_lowercase", bad_case_str.to_ascii_lowercase()),
 +        CaseMethod::UpperCase => ("to_uppercase", bad_case_str.to_uppercase()),
 +        CaseMethod::AsciiUppercase => ("to_ascii_uppercase", bad_case_str.to_ascii_uppercase()),
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        MATCH_STR_CASE_MISMATCH,
 +        bad_case_span,
 +        "this `match` arm has a differing case than its expression",
 +        &*format!("consider changing the case of this arm to respect `{}`", method_str),
 +        format!("\"{}\"", suggestion),
 +        Applicability::MachineApplicable,
 +    );
 +}
index b643fba5d328865baded5f1192cca02fa6ae979a,0000000000000000000000000000000000000000..eb311983b29276ebf0b21b35ed9e0dcc46750af3
mode 100644,000000..100644
--- /dev/null
@@@ -1,2373 -1,0 +1,2354 @@@
- use clippy_utils::consts::{constant, miri_to_const, Constant};
++use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt};
 +use clippy_utils::diagnostics::{
 +    multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
 +};
 +use clippy_utils::higher;
 +use clippy_utils::source::{expr_block, indent_of, snippet, snippet_block, snippet_opt, snippet_with_applicability};
 +use clippy_utils::sugg::Sugg;
 +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs};
 +use clippy_utils::visitors::is_local_used;
 +use clippy_utils::{
 +    get_parent_expr, in_macro, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild,
 +    meets_msrv, msrvs, path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns,
 +    remove_blocks, strip_pat_refs,
 +};
 +use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
 +use core::array;
 +use core::iter::{once, ExactSizeIterator};
 +use if_chain::if_chain;
 +use rustc_ast::ast::{Attribute, LitKind};
 +use rustc_errors::Applicability;
 +use rustc_hir::def::{CtorKind, DefKind, Res};
 +use rustc_hir::LangItem::{OptionNone, OptionSome};
 +use rustc_hir::{
 +    self as hir, Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, HirId, Local, MatchSource,
 +    Mutability, Node, Pat, PatKind, PathSegment, QPath, RangeEnd, TyKind,
 +};
 +use rustc_hir::{HirIdMap, HirIdSet};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::{self, Ty, TyS, VariantDef};
 +use rustc_semver::RustcVersion;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::source_map::{Span, Spanned};
 +use rustc_span::sym;
 +use std::cmp::Ordering;
 +use std::collections::hash_map::Entry;
 +use std::iter;
 +use std::ops::Bound;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for matches with a single arm where an `if let`
 +    /// will usually suffice.
 +    ///
 +    /// ### Why is this bad?
 +    /// Just readability – `if let` nests less than a `match`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # fn bar(stool: &str) {}
 +    /// # let x = Some("abc");
 +    /// // Bad
 +    /// match x {
 +    ///     Some(ref foo) => bar(foo),
 +    ///     _ => (),
 +    /// }
 +    ///
 +    /// // Good
 +    /// if let Some(ref foo) = x {
 +    ///     bar(foo);
 +    /// }
 +    /// ```
 +    pub SINGLE_MATCH,
 +    style,
 +    "a `match` statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for matches with two arms where an `if let else` will
 +    /// usually suffice.
 +    ///
 +    /// ### Why is this bad?
 +    /// Just readability – `if let` nests less than a `match`.
 +    ///
 +    /// ### Known problems
 +    /// Personal style preferences may differ.
 +    ///
 +    /// ### Example
 +    /// Using `match`:
 +    ///
 +    /// ```rust
 +    /// # fn bar(foo: &usize) {}
 +    /// # let other_ref: usize = 1;
 +    /// # let x: Option<&usize> = Some(&1);
 +    /// match x {
 +    ///     Some(ref foo) => bar(foo),
 +    ///     _ => bar(&other_ref),
 +    /// }
 +    /// ```
 +    ///
 +    /// Using `if let` with `else`:
 +    ///
 +    /// ```rust
 +    /// # fn bar(foo: &usize) {}
 +    /// # let other_ref: usize = 1;
 +    /// # let x: Option<&usize> = Some(&1);
 +    /// if let Some(ref foo) = x {
 +    ///     bar(foo);
 +    /// } else {
 +    ///     bar(&other_ref);
 +    /// }
 +    /// ```
 +    pub SINGLE_MATCH_ELSE,
 +    pedantic,
 +    "a `match` statement with two arms where the second arm's pattern is a placeholder instead of a specific match pattern"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for matches where all arms match a reference,
 +    /// suggesting to remove the reference and deref the matched expression
 +    /// instead. It also checks for `if let &foo = bar` blocks.
 +    ///
 +    /// ### Why is this bad?
 +    /// It just makes the code less readable. That reference
 +    /// destructuring adds nothing to the code.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// // Bad
 +    /// match x {
 +    ///     &A(ref y) => foo(y),
 +    ///     &B => bar(),
 +    ///     _ => frob(&x),
 +    /// }
 +    ///
 +    /// // Good
 +    /// match *x {
 +    ///     A(ref y) => foo(y),
 +    ///     B => bar(),
 +    ///     _ => frob(x),
 +    /// }
 +    /// ```
 +    pub MATCH_REF_PATS,
 +    style,
 +    "a `match` or `if let` with all arms prefixed with `&` instead of deref-ing the match expression"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for matches where match expression is a `bool`. It
 +    /// suggests to replace the expression with an `if...else` block.
 +    ///
 +    /// ### Why is this bad?
 +    /// It makes the code less readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # fn foo() {}
 +    /// # fn bar() {}
 +    /// let condition: bool = true;
 +    /// match condition {
 +    ///     true => foo(),
 +    ///     false => bar(),
 +    /// }
 +    /// ```
 +    /// Use if/else instead:
 +    /// ```rust
 +    /// # fn foo() {}
 +    /// # fn bar() {}
 +    /// let condition: bool = true;
 +    /// if condition {
 +    ///     foo();
 +    /// } else {
 +    ///     bar();
 +    /// }
 +    /// ```
 +    pub MATCH_BOOL,
 +    pedantic,
 +    "a `match` on a boolean expression instead of an `if..else` block"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for overlapping match arms.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is likely to be an error and if not, makes the code
 +    /// less obvious.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = 5;
 +    /// match x {
 +    ///     1..=10 => println!("1 ... 10"),
 +    ///     5..=15 => println!("5 ... 15"),
 +    ///     _ => (),
 +    /// }
 +    /// ```
 +    pub MATCH_OVERLAPPING_ARM,
 +    style,
 +    "a `match` with overlapping arms"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for arm which matches all errors with `Err(_)`
 +    /// and take drastic actions like `panic!`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It is generally a bad practice, similar to
 +    /// catching all exceptions in java with `catch(Exception)`
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x: Result<i32, &str> = Ok(3);
 +    /// match x {
 +    ///     Ok(_) => println!("ok"),
 +    ///     Err(_) => panic!("err"),
 +    /// }
 +    /// ```
 +    pub MATCH_WILD_ERR_ARM,
 +    pedantic,
 +    "a `match` with `Err(_)` arm and take drastic actions"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for match which is used to add a reference to an
 +    /// `Option` value.
 +    ///
 +    /// ### Why is this bad?
 +    /// Using `as_ref()` or `as_mut()` instead is shorter.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x: Option<()> = None;
 +    ///
 +    /// // Bad
 +    /// let r: Option<&()> = match x {
 +    ///     None => None,
 +    ///     Some(ref v) => Some(v),
 +    /// };
 +    ///
 +    /// // Good
 +    /// let r: Option<&()> = x.as_ref();
 +    /// ```
 +    pub MATCH_AS_REF,
 +    complexity,
 +    "a `match` on an Option value instead of using `as_ref()` or `as_mut`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for wildcard enum matches using `_`.
 +    ///
 +    /// ### Why is this bad?
 +    /// New enum variants added by library updates can be missed.
 +    ///
 +    /// ### Known problems
 +    /// Suggested replacements may be incorrect if guards exhaustively cover some
 +    /// variants, and also may not use correct path to enum if it's not present in the current scope.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # enum Foo { A(usize), B(usize) }
 +    /// # let x = Foo::B(1);
 +    /// // Bad
 +    /// match x {
 +    ///     Foo::A(_) => {},
 +    ///     _ => {},
 +    /// }
 +    ///
 +    /// // Good
 +    /// match x {
 +    ///     Foo::A(_) => {},
 +    ///     Foo::B(_) => {},
 +    /// }
 +    /// ```
 +    pub WILDCARD_ENUM_MATCH_ARM,
 +    restriction,
 +    "a wildcard enum match arm using `_`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for wildcard enum matches for a single variant.
 +    ///
 +    /// ### Why is this bad?
 +    /// New enum variants added by library updates can be missed.
 +    ///
 +    /// ### Known problems
 +    /// Suggested replacements may not use correct path to enum
 +    /// if it's not present in the current scope.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # enum Foo { A, B, C }
 +    /// # let x = Foo::B;
 +    /// // Bad
 +    /// match x {
 +    ///     Foo::A => {},
 +    ///     Foo::B => {},
 +    ///     _ => {},
 +    /// }
 +    ///
 +    /// // Good
 +    /// match x {
 +    ///     Foo::A => {},
 +    ///     Foo::B => {},
 +    ///     Foo::C => {},
 +    /// }
 +    /// ```
 +    pub MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
 +    pedantic,
 +    "a wildcard enum match for a single variant"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for wildcard pattern used with others patterns in same match arm.
 +    ///
 +    /// ### Why is this bad?
 +    /// Wildcard pattern already covers any other pattern as it will match anyway.
 +    /// It makes the code less readable, especially to spot wildcard pattern use in match arm.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// match "foo" {
 +    ///     "a" => {},
 +    ///     "bar" | _ => {},
 +    /// }
 +    ///
 +    /// // Good
 +    /// match "foo" {
 +    ///     "a" => {},
 +    ///     _ => {},
 +    /// }
 +    /// ```
 +    pub WILDCARD_IN_OR_PATTERNS,
 +    complexity,
 +    "a wildcard pattern used with others patterns in same match arm"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for matches being used to destructure a single-variant enum
 +    /// or tuple struct where a `let` will suffice.
 +    ///
 +    /// ### Why is this bad?
 +    /// Just readability – `let` doesn't nest, whereas a `match` does.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// enum Wrapper {
 +    ///     Data(i32),
 +    /// }
 +    ///
 +    /// let wrapper = Wrapper::Data(42);
 +    ///
 +    /// let data = match wrapper {
 +    ///     Wrapper::Data(i) => i,
 +    /// };
 +    /// ```
 +    ///
 +    /// The correct use would be:
 +    /// ```rust
 +    /// enum Wrapper {
 +    ///     Data(i32),
 +    /// }
 +    ///
 +    /// let wrapper = Wrapper::Data(42);
 +    /// let Wrapper::Data(data) = wrapper;
 +    /// ```
 +    pub INFALLIBLE_DESTRUCTURING_MATCH,
 +    style,
 +    "a `match` statement with a single infallible arm instead of a `let`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for useless match that binds to only one value.
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability and needless complexity.
 +    ///
 +    /// ### Known problems
 +    ///  Suggested replacements may be incorrect when `match`
 +    /// is actually binding temporary value, bringing a 'dropped while borrowed' error.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let a = 1;
 +    /// # let b = 2;
 +    ///
 +    /// // Bad
 +    /// match (a, b) {
 +    ///     (c, d) => {
 +    ///         // useless match
 +    ///     }
 +    /// }
 +    ///
 +    /// // Good
 +    /// let (c, d) = (a, b);
 +    /// ```
 +    pub MATCH_SINGLE_BINDING,
 +    complexity,
 +    "a match with a single binding instead of using `let` statement"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched.
 +    ///
 +    /// ### Why is this bad?
 +    /// Correctness and readability. It's like having a wildcard pattern after
 +    /// matching all enum variants explicitly.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # struct A { a: i32 }
 +    /// let a = A { a: 5 };
 +    ///
 +    /// // Bad
 +    /// match a {
 +    ///     A { a: 5, .. } => {},
 +    ///     _ => {},
 +    /// }
 +    ///
 +    /// // Good
 +    /// match a {
 +    ///     A { a: 5 } => {},
 +    ///     _ => {},
 +    /// }
 +    /// ```
 +    pub REST_PAT_IN_FULLY_BOUND_STRUCTS,
 +    restriction,
 +    "a match on a struct that binds all fields but still uses the wildcard pattern"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Lint for redundant pattern matching over `Result`, `Option`,
 +    /// `std::task::Poll` or `std::net::IpAddr`
 +    ///
 +    /// ### Why is this bad?
 +    /// It's more concise and clear to just use the proper
 +    /// utility function
 +    ///
 +    /// ### Known problems
 +    /// This will change the drop order for the matched type. Both `if let` and
 +    /// `while let` will drop the value at the end of the block, both `if` and `while` will drop the
 +    /// value before entering the block. For most types this change will not matter, but for a few
 +    /// types this will not be an acceptable change (e.g. locks). See the
 +    /// [reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about
 +    /// drop order.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # use std::task::Poll;
 +    /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
 +    /// if let Ok(_) = Ok::<i32, i32>(42) {}
 +    /// if let Err(_) = Err::<i32, i32>(42) {}
 +    /// if let None = None::<()> {}
 +    /// if let Some(_) = Some(42) {}
 +    /// if let Poll::Pending = Poll::Pending::<()> {}
 +    /// if let Poll::Ready(_) = Poll::Ready(42) {}
 +    /// if let IpAddr::V4(_) = IpAddr::V4(Ipv4Addr::LOCALHOST) {}
 +    /// if let IpAddr::V6(_) = IpAddr::V6(Ipv6Addr::LOCALHOST) {}
 +    /// match Ok::<i32, i32>(42) {
 +    ///     Ok(_) => true,
 +    ///     Err(_) => false,
 +    /// };
 +    /// ```
 +    ///
 +    /// The more idiomatic use would be:
 +    ///
 +    /// ```rust
 +    /// # use std::task::Poll;
 +    /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
 +    /// if Ok::<i32, i32>(42).is_ok() {}
 +    /// if Err::<i32, i32>(42).is_err() {}
 +    /// if None::<()>.is_none() {}
 +    /// if Some(42).is_some() {}
 +    /// if Poll::Pending::<()>.is_pending() {}
 +    /// if Poll::Ready(42).is_ready() {}
 +    /// if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
 +    /// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
 +    /// Ok::<i32, i32>(42).is_ok();
 +    /// ```
 +    pub REDUNDANT_PATTERN_MATCHING,
 +    style,
 +    "use the proper utility function avoiding an `if let`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `match`  or `if let` expressions producing a
 +    /// `bool` that could be written using `matches!`
 +    ///
 +    /// ### Why is this bad?
 +    /// Readability and needless complexity.
 +    ///
 +    /// ### Known problems
 +    /// This lint falsely triggers, if there are arms with
 +    /// `cfg` attributes that remove an arm evaluating to `false`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = Some(5);
 +    ///
 +    /// // Bad
 +    /// let a = match x {
 +    ///     Some(0) => true,
 +    ///     _ => false,
 +    /// };
 +    ///
 +    /// let a = if let Some(0) = x {
 +    ///     true
 +    /// } else {
 +    ///     false
 +    /// };
 +    ///
 +    /// // Good
 +    /// let a = matches!(x, Some(0));
 +    /// ```
 +    pub MATCH_LIKE_MATCHES_MACRO,
 +    style,
 +    "a match that could be written with the matches! macro"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `match` with identical arm bodies.
 +    ///
 +    /// ### Why is this bad?
 +    /// This is probably a copy & paste error. If arm bodies
 +    /// are the same on purpose, you can factor them
 +    /// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
 +    ///
 +    /// ### Known problems
 +    /// False positive possible with order dependent `match`
 +    /// (see issue
 +    /// [#860](https://github.com/rust-lang/rust-clippy/issues/860)).
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// match foo {
 +    ///     Bar => bar(),
 +    ///     Quz => quz(),
 +    ///     Baz => bar(), // <= oops
 +    /// }
 +    /// ```
 +    ///
 +    /// This should probably be
 +    /// ```rust,ignore
 +    /// match foo {
 +    ///     Bar => bar(),
 +    ///     Quz => quz(),
 +    ///     Baz => baz(), // <= fixed
 +    /// }
 +    /// ```
 +    ///
 +    /// or if the original code was not a typo:
 +    /// ```rust,ignore
 +    /// match foo {
 +    ///     Bar | Baz => bar(), // <= shows the intent better
 +    ///     Quz => quz(),
 +    /// }
 +    /// ```
 +    pub MATCH_SAME_ARMS,
 +    pedantic,
 +    "`match` with identical arm bodies"
 +}
 +
 +#[derive(Default)]
 +pub struct Matches {
 +    msrv: Option<RustcVersion>,
 +    infallible_destructuring_match_linted: bool,
 +}
 +
 +impl Matches {
 +    #[must_use]
 +    pub fn new(msrv: Option<RustcVersion>) -> Self {
 +        Self {
 +            msrv,
 +            ..Matches::default()
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(Matches => [
 +    SINGLE_MATCH,
 +    MATCH_REF_PATS,
 +    MATCH_BOOL,
 +    SINGLE_MATCH_ELSE,
 +    MATCH_OVERLAPPING_ARM,
 +    MATCH_WILD_ERR_ARM,
 +    MATCH_AS_REF,
 +    WILDCARD_ENUM_MATCH_ARM,
 +    MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
 +    WILDCARD_IN_OR_PATTERNS,
 +    MATCH_SINGLE_BINDING,
 +    INFALLIBLE_DESTRUCTURING_MATCH,
 +    REST_PAT_IN_FULLY_BOUND_STRUCTS,
 +    REDUNDANT_PATTERN_MATCHING,
 +    MATCH_LIKE_MATCHES_MACRO,
 +    MATCH_SAME_ARMS,
 +]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Matches {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) {
 +            return;
 +        }
 +
 +        redundant_pattern_match::check(cx, expr);
 +
 +        if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) {
 +            if !check_match_like_matches(cx, expr) {
 +                lint_match_arms(cx, expr);
 +            }
 +        } else {
 +            lint_match_arms(cx, expr);
 +        }
 +
 +        if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind {
 +            check_single_match(cx, ex, arms, expr);
 +            check_match_bool(cx, ex, arms, expr);
 +            check_overlapping_arms(cx, ex, arms);
 +            check_wild_err_arm(cx, ex, arms);
 +            check_wild_enum_match(cx, ex, arms);
 +            check_match_as_ref(cx, ex, arms, expr);
 +            check_wild_in_or_pats(cx, arms);
 +
 +            if self.infallible_destructuring_match_linted {
 +                self.infallible_destructuring_match_linted = false;
 +            } else {
 +                check_match_single_binding(cx, ex, arms, expr);
 +            }
 +        }
 +        if let ExprKind::Match(ex, arms, _) = expr.kind {
 +            check_match_ref_pats(cx, ex, arms.iter().map(|el| el.pat), expr);
 +        }
 +        if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) {
 +            check_match_ref_pats(cx, let_expr, once(let_pat), expr);
 +        }
 +    }
 +
 +    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
 +        if_chain! {
 +            if !in_external_macro(cx.sess(), local.span);
 +            if !in_macro(local.span);
 +            if let Some(expr) = local.init;
 +            if let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind;
 +            if arms.len() == 1 && arms[0].guard.is_none();
 +            if let PatKind::TupleStruct(
 +                QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
 +            if args.len() == 1;
 +            if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind;
 +            let body = remove_blocks(arms[0].body);
 +            if path_to_local_id(body, arg);
 +
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                self.infallible_destructuring_match_linted = true;
 +                span_lint_and_sugg(
 +                    cx,
 +                    INFALLIBLE_DESTRUCTURING_MATCH,
 +                    local.span,
 +                    "you seem to be trying to use `match` to destructure a single infallible pattern. \
 +                    Consider using `let`",
 +                    "try this",
 +                    format!(
 +                        "let {}({}) = {};",
 +                        snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
 +                        snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
 +                        snippet_with_applicability(cx, target.span, "..", &mut applicability),
 +                    ),
 +                    applicability,
 +                );
 +            }
 +        }
 +    }
 +
 +    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
 +        if_chain! {
 +            if !in_external_macro(cx.sess(), pat.span);
 +            if !in_macro(pat.span);
 +            if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind;
 +            if let Some(def_id) = path.res.opt_def_id();
 +            let ty = cx.tcx.type_of(def_id);
 +            if let ty::Adt(def, _) = ty.kind();
 +            if def.is_struct() || def.is_union();
 +            if fields.len() == def.non_enum_variant().fields.len();
 +
 +            then {
 +                span_lint_and_help(
 +                    cx,
 +                    REST_PAT_IN_FULLY_BOUND_STRUCTS,
 +                    pat.span,
 +                    "unnecessary use of `..` pattern in struct binding. All fields were already bound",
 +                    None,
 +                    "consider removing `..` from this binding",
 +                );
 +            }
 +        }
 +    }
 +
 +    extract_msrv_attr!(LateContext);
 +}
 +
 +#[rustfmt::skip]
 +fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
 +    if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
 +        if in_macro(expr.span) {
 +            // Don't lint match expressions present in
 +            // macro_rules! block
 +            return;
 +        }
 +        if let PatKind::Or(..) = arms[0].pat.kind {
 +            // don't lint for or patterns for now, this makes
 +            // the lint noisy in unnecessary situations
 +            return;
 +        }
 +        let els = arms[1].body;
 +        let els = if is_unit_expr(remove_blocks(els)) {
 +            None
 +        } else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind {
 +            if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() {
 +                // single statement/expr "else" block, don't lint
 +                return;
 +            }
 +            // block with 2+ statements or 1 expr and 1+ statement
 +            Some(els)
 +        } else {
 +            // not a block, don't lint
 +            return;
 +        };
 +
 +        let ty = cx.typeck_results().expr_ty(ex);
 +        if *ty.kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id) {
 +            check_single_match_single_pattern(cx, ex, arms, expr, els);
 +            check_single_match_opt_like(cx, ex, arms, expr, ty, els);
 +        }
 +    }
 +}
 +
 +fn check_single_match_single_pattern(
 +    cx: &LateContext<'_>,
 +    ex: &Expr<'_>,
 +    arms: &[Arm<'_>],
 +    expr: &Expr<'_>,
 +    els: Option<&Expr<'_>>,
 +) {
 +    if is_wild(arms[1].pat) {
 +        report_single_match_single_pattern(cx, ex, arms, expr, els);
 +    }
 +}
 +
 +fn report_single_match_single_pattern(
 +    cx: &LateContext<'_>,
 +    ex: &Expr<'_>,
 +    arms: &[Arm<'_>],
 +    expr: &Expr<'_>,
 +    els: Option<&Expr<'_>>,
 +) {
 +    let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
 +    let els_str = els.map_or(String::new(), |els| {
 +        format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span)))
 +    });
 +
 +    let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat);
 +    let (msg, sugg) = if_chain! {
 +        if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind;
 +        let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex));
 +        if let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait();
 +        if let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait();
 +        if ty.is_integral() || ty.is_char() || ty.is_str()
 +            || (implements_trait(cx, ty, spe_trait_id, &[])
 +                && implements_trait(cx, ty, pe_trait_id, &[ty.into()]));
 +        then {
 +            // scrutinee derives PartialEq and the pattern is a constant.
 +            let pat_ref_count = match pat.kind {
 +                // string literals are already a reference.
 +                PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. }) if lit.node.is_str() => pat_ref_count + 1,
 +                _ => pat_ref_count,
 +            };
 +            // References are only implicitly added to the pattern, so no overflow here.
 +            // e.g. will work: match &Some(_) { Some(_) => () }
 +            // will not: match Some(_) { &Some(_) => () }
 +            let ref_count_diff = ty_ref_count - pat_ref_count;
 +
 +            // Try to remove address of expressions first.
 +            let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff);
 +            let ref_count_diff = ref_count_diff - removed;
 +
 +            let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`";
 +            let sugg = format!(
 +                "if {} == {}{} {}{}",
 +                snippet(cx, ex.span, ".."),
 +                // PartialEq for different reference counts may not exist.
 +                "&".repeat(ref_count_diff),
 +                snippet(cx, arms[0].pat.span, ".."),
 +                expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
 +                els_str,
 +            );
 +            (msg, sugg)
 +        } else {
 +            let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`";
 +            let sugg = format!(
 +                "if let {} = {} {}{}",
 +                snippet(cx, arms[0].pat.span, ".."),
 +                snippet(cx, ex.span, ".."),
 +                expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
 +                els_str,
 +            );
 +            (msg, sugg)
 +        }
 +    };
 +
 +    span_lint_and_sugg(
 +        cx,
 +        lint,
 +        expr.span,
 +        msg,
 +        "try this",
 +        sugg,
 +        Applicability::HasPlaceholders,
 +    );
 +}
 +
 +fn check_single_match_opt_like(
 +    cx: &LateContext<'_>,
 +    ex: &Expr<'_>,
 +    arms: &[Arm<'_>],
 +    expr: &Expr<'_>,
 +    ty: Ty<'_>,
 +    els: Option<&Expr<'_>>,
 +) {
 +    // list of candidate `Enum`s we know will never get any more members
 +    let candidates = &[
 +        (&paths::COW, "Borrowed"),
 +        (&paths::COW, "Cow::Borrowed"),
 +        (&paths::COW, "Cow::Owned"),
 +        (&paths::COW, "Owned"),
 +        (&paths::OPTION, "None"),
 +        (&paths::RESULT, "Err"),
 +        (&paths::RESULT, "Ok"),
 +    ];
 +
 +    let path = match arms[1].pat.kind {
 +        PatKind::TupleStruct(ref path, inner, _) => {
 +            // Contains any non wildcard patterns (e.g., `Err(err)`)?
 +            if !inner.iter().all(is_wild) {
 +                return;
 +            }
 +            rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
 +        },
 +        PatKind::Binding(BindingAnnotation::Unannotated, .., ident, None) => ident.to_string(),
 +        PatKind::Path(ref path) => {
 +            rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
 +        },
 +        _ => return,
 +    };
 +
 +    for &(ty_path, pat_path) in candidates {
 +        if path == *pat_path && match_type(cx, ty, ty_path) {
 +            report_single_match_single_pattern(cx, ex, arms, expr, els);
 +        }
 +    }
 +}
 +
 +fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
 +    // Type of expression is `bool`.
 +    if *cx.typeck_results().expr_ty(ex).kind() == ty::Bool {
 +        span_lint_and_then(
 +            cx,
 +            MATCH_BOOL,
 +            expr.span,
 +            "you seem to be trying to match on a boolean expression",
 +            move |diag| {
 +                if arms.len() == 2 {
 +                    // no guards
 +                    let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
 +                        if let ExprKind::Lit(ref lit) = arm_bool.kind {
 +                            match lit.node {
 +                                LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)),
 +                                LitKind::Bool(false) => Some((&*arms[1].body, &*arms[0].body)),
 +                                _ => None,
 +                            }
 +                        } else {
 +                            None
 +                        }
 +                    } else {
 +                        None
 +                    };
 +
 +                    if let Some((true_expr, false_expr)) = exprs {
 +                        let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) {
 +                            (false, false) => Some(format!(
 +                                "if {} {} else {}",
 +                                snippet(cx, ex.span, "b"),
 +                                expr_block(cx, true_expr, None, "..", Some(expr.span)),
 +                                expr_block(cx, false_expr, None, "..", Some(expr.span))
 +                            )),
 +                            (false, true) => Some(format!(
 +                                "if {} {}",
 +                                snippet(cx, ex.span, "b"),
 +                                expr_block(cx, true_expr, None, "..", Some(expr.span))
 +                            )),
 +                            (true, false) => {
 +                                let test = Sugg::hir(cx, ex, "..");
 +                                Some(format!(
 +                                    "if {} {}",
 +                                    !test,
 +                                    expr_block(cx, false_expr, None, "..", Some(expr.span))
 +                                ))
 +                            },
 +                            (true, true) => None,
 +                        };
 +
 +                        if let Some(sugg) = sugg {
 +                            diag.span_suggestion(
 +                                expr.span,
 +                                "consider using an `if`/`else` expression",
 +                                sugg,
 +                                Applicability::HasPlaceholders,
 +                            );
 +                        }
 +                    }
 +                }
 +            },
 +        );
 +    }
 +}
 +
 +fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
 +    if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() {
 +        let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex));
-         let type_ranges = type_ranges(&ranges);
-         if !type_ranges.is_empty() {
-             if let Some((start, end)) = overlapping(&type_ranges) {
++        if !ranges.is_empty() {
++            if let Some((start, end)) = overlapping(&ranges) {
 +                span_lint_and_note(
 +                    cx,
 +                    MATCH_OVERLAPPING_ARM,
 +                    start.span,
 +                    "some ranges overlap",
 +                    Some(end.span),
 +                    "overlaps with this",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) {
 +    let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
 +    if is_type_diagnostic_item(cx, ex_ty, sym::Result) {
 +        for arm in arms {
 +            if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind {
 +                let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
 +                if path_str == "Err" {
 +                    let mut matching_wild = inner.iter().any(is_wild);
 +                    let mut ident_bind_name = String::from("_");
 +                    if !matching_wild {
 +                        // Looking for unused bindings (i.e.: `_e`)
 +                        for pat in inner.iter() {
 +                            if let PatKind::Binding(_, id, ident, None) = pat.kind {
 +                                if ident.as_str().starts_with('_') && !is_local_used(cx, arm.body, id) {
 +                                    ident_bind_name = (&ident.name.as_str()).to_string();
 +                                    matching_wild = true;
 +                                }
 +                            }
 +                        }
 +                    }
 +                    if_chain! {
 +                        if matching_wild;
-                         if let ExprKind::Block(block, _) = arm.body.kind;
-                         if is_panic_block(block);
++                        if is_panic_call(arm.body);
 +                        then {
 +                            // `Err(_)` or `Err(_e)` arm with `panic!` found
 +                            span_lint_and_note(cx,
 +                                MATCH_WILD_ERR_ARM,
 +                                arm.pat.span,
 +                                &format!("`Err({})` matches all errors", &ident_bind_name),
 +                                None,
 +                                "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable",
 +                            );
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +enum CommonPrefixSearcher<'a> {
 +    None,
 +    Path(&'a [PathSegment<'a>]),
 +    Mixed,
 +}
 +impl CommonPrefixSearcher<'a> {
 +    fn with_path(&mut self, path: &'a [PathSegment<'a>]) {
 +        match path {
 +            [path @ .., _] => self.with_prefix(path),
 +            [] => (),
 +        }
 +    }
 +
 +    fn with_prefix(&mut self, path: &'a [PathSegment<'a>]) {
 +        match self {
 +            Self::None => *self = Self::Path(path),
 +            Self::Path(self_path)
 +                if path
 +                    .iter()
 +                    .map(|p| p.ident.name)
 +                    .eq(self_path.iter().map(|p| p.ident.name)) => {},
 +            Self::Path(_) => *self = Self::Mixed,
 +            Self::Mixed => (),
 +        }
 +    }
 +}
 +
 +fn is_hidden(cx: &LateContext<'_>, variant_def: &VariantDef) -> bool {
 +    let attrs = cx.tcx.get_attrs(variant_def.def_id);
 +    clippy_utils::attrs::is_doc_hidden(attrs) || clippy_utils::attrs::is_unstable(attrs)
 +}
 +
 +#[allow(clippy::too_many_lines)]
 +fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
 +    let ty = cx.typeck_results().expr_ty(ex).peel_refs();
 +    let adt_def = match ty.kind() {
 +        ty::Adt(adt_def, _)
 +            if adt_def.is_enum()
 +                && !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) =>
 +        {
 +            adt_def
 +        },
 +        _ => return,
 +    };
 +
 +    // First pass - check for violation, but don't do much book-keeping because this is hopefully
 +    // the uncommon case, and the book-keeping is slightly expensive.
 +    let mut wildcard_span = None;
 +    let mut wildcard_ident = None;
 +    let mut has_non_wild = false;
 +    for arm in arms {
 +        match peel_hir_pat_refs(arm.pat).0.kind {
 +            PatKind::Wild => wildcard_span = Some(arm.pat.span),
 +            PatKind::Binding(_, _, ident, None) => {
 +                wildcard_span = Some(arm.pat.span);
 +                wildcard_ident = Some(ident);
 +            },
 +            _ => has_non_wild = true,
 +        }
 +    }
 +    let wildcard_span = match wildcard_span {
 +        Some(x) if has_non_wild => x,
 +        _ => return,
 +    };
 +
 +    // Accumulate the variants which should be put in place of the wildcard because they're not
 +    // already covered.
 +    let has_hidden = adt_def.variants.iter().any(|x| is_hidden(cx, x));
 +    let mut missing_variants: Vec<_> = adt_def.variants.iter().filter(|x| !is_hidden(cx, x)).collect();
 +
 +    let mut path_prefix = CommonPrefixSearcher::None;
 +    for arm in arms {
 +        // Guards mean that this case probably isn't exhaustively covered. Technically
 +        // this is incorrect, as we should really check whether each variant is exhaustively
 +        // covered by the set of guards that cover it, but that's really hard to do.
 +        recurse_or_patterns(arm.pat, |pat| {
 +            let path = match &peel_hir_pat_refs(pat).0.kind {
 +                PatKind::Path(path) => {
 +                    #[allow(clippy::match_same_arms)]
 +                    let id = match cx.qpath_res(path, pat.hir_id) {
 +                        Res::Def(DefKind::Const | DefKind::ConstParam | DefKind::AnonConst, _) => return,
 +                        Res::Def(_, id) => id,
 +                        _ => return,
 +                    };
 +                    if arm.guard.is_none() {
 +                        missing_variants.retain(|e| e.ctor_def_id != Some(id));
 +                    }
 +                    path
 +                },
 +                PatKind::TupleStruct(path, patterns, ..) => {
 +                    if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
 +                        if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p)) {
 +                            missing_variants.retain(|e| e.ctor_def_id != Some(id));
 +                        }
 +                    }
 +                    path
 +                },
 +                PatKind::Struct(path, patterns, ..) => {
 +                    if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
 +                        if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p.pat)) {
 +                            missing_variants.retain(|e| e.def_id != id);
 +                        }
 +                    }
 +                    path
 +                },
 +                _ => return,
 +            };
 +            match path {
 +                QPath::Resolved(_, path) => path_prefix.with_path(path.segments),
 +                QPath::TypeRelative(
 +                    hir::Ty {
 +                        kind: TyKind::Path(QPath::Resolved(_, path)),
 +                        ..
 +                    },
 +                    _,
 +                ) => path_prefix.with_prefix(path.segments),
 +                _ => (),
 +            }
 +        });
 +    }
 +
 +    let format_suggestion = |variant: &VariantDef| {
 +        format!(
 +            "{}{}{}{}",
 +            if let Some(ident) = wildcard_ident {
 +                format!("{} @ ", ident.name)
 +            } else {
 +                String::new()
 +            },
 +            if let CommonPrefixSearcher::Path(path_prefix) = path_prefix {
 +                let mut s = String::new();
 +                for seg in path_prefix {
 +                    s.push_str(&seg.ident.as_str());
 +                    s.push_str("::");
 +                }
 +                s
 +            } else {
 +                let mut s = cx.tcx.def_path_str(adt_def.did);
 +                s.push_str("::");
 +                s
 +            },
 +            variant.ident.name,
 +            match variant.ctor_kind {
 +                CtorKind::Fn if variant.fields.len() == 1 => "(_)",
 +                CtorKind::Fn => "(..)",
 +                CtorKind::Const => "",
 +                CtorKind::Fictive => "{ .. }",
 +            }
 +        )
 +    };
 +
 +    match missing_variants.as_slice() {
 +        [] => (),
 +        [x] if !adt_def.is_variant_list_non_exhaustive() && !has_hidden => span_lint_and_sugg(
 +            cx,
 +            MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
 +            wildcard_span,
 +            "wildcard matches only a single variant and will also match any future added variants",
 +            "try this",
 +            format_suggestion(x),
 +            Applicability::MaybeIncorrect,
 +        ),
 +        variants => {
 +            let mut suggestions: Vec<_> = variants.iter().copied().map(format_suggestion).collect();
 +            let message = if adt_def.is_variant_list_non_exhaustive() || has_hidden {
 +                suggestions.push("_".into());
 +                "wildcard matches known variants and will also match future added variants"
 +            } else {
 +                "wildcard match will also match any future added variants"
 +            };
 +
 +            span_lint_and_sugg(
 +                cx,
 +                WILDCARD_ENUM_MATCH_ARM,
 +                wildcard_span,
 +                message,
 +                "try this",
 +                suggestions.join(" | "),
 +                Applicability::MaybeIncorrect,
 +            );
 +        },
 +    };
 +}
 +
 +// If the block contains only a `panic!` macro (as expression or statement)
- fn is_panic_block(block: &Block<'_>) -> bool {
-     match (&block.expr, block.stmts.len(), block.stmts.first()) {
-         (&Some(exp), 0, _) => is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none(),
-         (&None, 1, Some(stmt)) => {
-             is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none()
-         },
-         _ => false,
-     }
++fn is_panic_call(expr: &Expr<'_>) -> bool {
++    // Unwrap any wrapping blocks
++    let span = if let ExprKind::Block(block, _) = expr.kind {
++        match (&block.expr, block.stmts.len(), block.stmts.first()) {
++            (&Some(exp), 0, _) => exp.span,
++            (&None, 1, Some(stmt)) => stmt.span,
++            _ => return false,
++        }
++    } else {
++        expr.span
++    };
++
++    is_expn_of(span, "panic").is_some() && is_expn_of(span, "unreachable").is_none()
 +}
 +
 +fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
 +where
 +    'b: 'a,
 +    I: Clone + Iterator<Item = &'a Pat<'b>>,
 +{
 +    if !has_multiple_ref_pats(pats.clone()) {
 +        return;
 +    }
 +
 +    let (first_sugg, msg, title);
 +    let span = ex.span.source_callsite();
 +    if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind {
 +        first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
 +        msg = "try";
 +        title = "you don't need to add `&` to both the expression and the patterns";
 +    } else {
 +        first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
 +        msg = "instead of prefixing all patterns with `&`, you can dereference the expression";
 +        title = "you don't need to add `&` to all patterns";
 +    }
 +
 +    let remaining_suggs = pats.filter_map(|pat| {
 +        if let PatKind::Ref(refp, _) = pat.kind {
 +            Some((pat.span, snippet(cx, refp.span, "..").to_string()))
 +        } else {
 +            None
 +        }
 +    });
 +
 +    span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |diag| {
 +        if !expr.span.from_expansion() {
 +            multispan_sugg(diag, msg, first_sugg.chain(remaining_suggs));
 +        }
 +    });
 +}
 +
 +fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
 +    if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
 +        let arm_ref: Option<BindingAnnotation> = if is_none_arm(cx, &arms[0]) {
 +            is_ref_some_arm(cx, &arms[1])
 +        } else if is_none_arm(cx, &arms[1]) {
 +            is_ref_some_arm(cx, &arms[0])
 +        } else {
 +            None
 +        };
 +        if let Some(rb) = arm_ref {
 +            let suggestion = if rb == BindingAnnotation::Ref {
 +                "as_ref"
 +            } else {
 +                "as_mut"
 +            };
 +
 +            let output_ty = cx.typeck_results().expr_ty(expr);
 +            let input_ty = cx.typeck_results().expr_ty(ex);
 +
 +            let cast = if_chain! {
 +                if let ty::Adt(_, substs) = input_ty.kind();
 +                let input_ty = substs.type_at(0);
 +                if let ty::Adt(_, substs) = output_ty.kind();
 +                let output_ty = substs.type_at(0);
 +                if let ty::Ref(_, output_ty, _) = *output_ty.kind();
 +                if input_ty != output_ty;
 +                then {
 +                    ".map(|x| x as _)"
 +                } else {
 +                    ""
 +                }
 +            };
 +
 +            let mut applicability = Applicability::MachineApplicable;
 +            span_lint_and_sugg(
 +                cx,
 +                MATCH_AS_REF,
 +                expr.span,
 +                &format!("use `{}()` instead", suggestion),
 +                "try this",
 +                format!(
 +                    "{}.{}(){}",
 +                    snippet_with_applicability(cx, ex.span, "_", &mut applicability),
 +                    suggestion,
 +                    cast,
 +                ),
 +                applicability,
 +            );
 +        }
 +    }
 +}
 +
 +fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
 +    for arm in arms {
 +        if let PatKind::Or(fields) = arm.pat.kind {
 +            // look for multiple fields in this arm that contains at least one Wild pattern
 +            if fields.len() > 1 && fields.iter().any(is_wild) {
 +                span_lint_and_help(
 +                    cx,
 +                    WILDCARD_IN_OR_PATTERNS,
 +                    arm.pat.span,
 +                    "wildcard pattern covers any other pattern as it will match anyway",
 +                    None,
 +                    "consider handling `_` separately",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +/// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!`
 +fn check_match_like_matches<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
 +    if let Some(higher::IfLet {
 +        let_pat,
 +        let_expr,
 +        if_then,
 +        if_else: Some(if_else),
 +    }) = higher::IfLet::hir(cx, expr)
 +    {
 +        return find_matches_sugg(
 +            cx,
 +            let_expr,
 +            array::IntoIter::new([(&[][..], Some(let_pat), if_then, None), (&[][..], None, if_else, None)]),
 +            expr,
 +            true,
 +        );
 +    }
 +
 +    if let ExprKind::Match(scrut, arms, MatchSource::Normal) = expr.kind {
 +        return find_matches_sugg(
 +            cx,
 +            scrut,
 +            arms.iter().map(|arm| {
 +                (
 +                    cx.tcx.hir().attrs(arm.hir_id),
 +                    Some(arm.pat),
 +                    arm.body,
 +                    arm.guard.as_ref(),
 +                )
 +            }),
 +            expr,
 +            false,
 +        );
 +    }
 +
 +    false
 +}
 +
 +/// Lint a `match` or `if let` for replacement by `matches!`
 +fn find_matches_sugg<'a, 'b, I>(
 +    cx: &LateContext<'_>,
 +    ex: &Expr<'_>,
 +    mut iter: I,
 +    expr: &Expr<'_>,
 +    is_if_let: bool,
 +) -> bool
 +where
 +    'b: 'a,
 +    I: Clone
 +        + DoubleEndedIterator
 +        + ExactSizeIterator
 +        + Iterator<
 +            Item = (
 +                &'a [Attribute],
 +                Option<&'a Pat<'b>>,
 +                &'a Expr<'b>,
 +                Option<&'a Guard<'b>>,
 +            ),
 +        >,
 +{
 +    if_chain! {
 +        if iter.len() >= 2;
 +        if cx.typeck_results().expr_ty(expr).is_bool();
 +        if let Some((_, last_pat_opt, last_expr, _)) = iter.next_back();
 +        let iter_without_last = iter.clone();
 +        if let Some((first_attrs, _, first_expr, first_guard)) = iter.next();
 +        if let Some(b0) = find_bool_lit(&first_expr.kind, is_if_let);
 +        if let Some(b1) = find_bool_lit(&last_expr.kind, is_if_let);
 +        if b0 != b1;
 +        if first_guard.is_none() || iter.len() == 0;
 +        if first_attrs.is_empty();
 +        if iter
 +            .all(|arm| {
 +                find_bool_lit(&arm.2.kind, is_if_let).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty()
 +            });
 +        then {
 +            if let Some(last_pat) = last_pat_opt {
 +                if !is_wild(last_pat) {
 +                    return false;
 +                }
 +            }
 +
 +            // The suggestion may be incorrect, because some arms can have `cfg` attributes
 +            // evaluated into `false` and so such arms will be stripped before.
 +            let mut applicability = Applicability::MaybeIncorrect;
 +            let pat = {
 +                use itertools::Itertools as _;
 +                iter_without_last
 +                    .filter_map(|arm| {
 +                        let pat_span = arm.1?.span;
 +                        Some(snippet_with_applicability(cx, pat_span, "..", &mut applicability))
 +                    })
 +                    .join(" | ")
 +            };
 +            let pat_and_guard = if let Some(Guard::If(g)) = first_guard {
 +                format!("{} if {}", pat, snippet_with_applicability(cx, g.span, "..", &mut applicability))
 +            } else {
 +                pat
 +            };
 +
 +            // strip potential borrows (#6503), but only if the type is a reference
 +            let mut ex_new = ex;
 +            if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind {
 +                if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() {
 +                    ex_new = ex_inner;
 +                }
 +            };
 +            span_lint_and_sugg(
 +                cx,
 +                MATCH_LIKE_MATCHES_MACRO,
 +                expr.span,
 +                &format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }),
 +                "try this",
 +                format!(
 +                    "{}matches!({}, {})",
 +                    if b0 { "" } else { "!" },
 +                    snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
 +                    pat_and_guard,
 +                ),
 +                applicability,
 +            );
 +            true
 +        } else {
 +            false
 +        }
 +    }
 +}
 +
 +/// Extract a `bool` or `{ bool }`
 +fn find_bool_lit(ex: &ExprKind<'_>, is_if_let: bool) -> Option<bool> {
 +    match ex {
 +        ExprKind::Lit(Spanned {
 +            node: LitKind::Bool(b), ..
 +        }) => Some(*b),
 +        ExprKind::Block(
 +            rustc_hir::Block {
 +                stmts: &[],
 +                expr: Some(exp),
 +                ..
 +            },
 +            _,
 +        ) if is_if_let => {
 +            if let ExprKind::Lit(Spanned {
 +                node: LitKind::Bool(b), ..
 +            }) = exp.kind
 +            {
 +                Some(b)
 +            } else {
 +                None
 +            }
 +        },
 +        _ => None,
 +    }
 +}
 +
 +#[allow(clippy::too_many_lines)]
 +fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
 +    if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
 +        return;
 +    }
 +
 +    // HACK:
 +    // This is a hack to deal with arms that are excluded by macros like `#[cfg]`. It is only used here
 +    // to prevent false positives as there is currently no better way to detect if code was excluded by
 +    // a macro. See PR #6435
 +    if_chain! {
 +        if let Some(match_snippet) = snippet_opt(cx, expr.span);
 +        if let Some(arm_snippet) = snippet_opt(cx, arms[0].span);
 +        if let Some(ex_snippet) = snippet_opt(cx, ex.span);
 +        let rest_snippet = match_snippet.replace(&arm_snippet, "").replace(&ex_snippet, "");
 +        if rest_snippet.contains("=>");
 +        then {
 +            // The code it self contains another thick arrow "=>"
 +            // -> Either another arm or a comment
 +            return;
 +        }
 +    }
 +
 +    let matched_vars = ex.span;
 +    let bind_names = arms[0].pat.span;
 +    let match_body = remove_blocks(arms[0].body);
 +    let mut snippet_body = if match_body.span.from_expansion() {
 +        Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
 +    } else {
 +        snippet_block(cx, match_body.span, "..", Some(expr.span)).to_string()
 +    };
 +
 +    // Do we need to add ';' to suggestion ?
 +    match match_body.kind {
 +        ExprKind::Block(block, _) => {
 +            // macro + expr_ty(body) == ()
 +            if block.span.from_expansion() && cx.typeck_results().expr_ty(match_body).is_unit() {
 +                snippet_body.push(';');
 +            }
 +        },
 +        _ => {
 +            // expr_ty(body) == ()
 +            if cx.typeck_results().expr_ty(match_body).is_unit() {
 +                snippet_body.push(';');
 +            }
 +        },
 +    }
 +
 +    let mut applicability = Applicability::MaybeIncorrect;
 +    match arms[0].pat.kind {
 +        PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => {
 +            // If this match is in a local (`let`) stmt
 +            let (target_span, sugg) = if let Some(parent_let_node) = opt_parent_let(cx, ex) {
 +                (
 +                    parent_let_node.span,
 +                    format!(
 +                        "let {} = {};\n{}let {} = {};",
 +                        snippet_with_applicability(cx, bind_names, "..", &mut applicability),
 +                        snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
 +                        " ".repeat(indent_of(cx, expr.span).unwrap_or(0)),
 +                        snippet_with_applicability(cx, parent_let_node.pat.span, "..", &mut applicability),
 +                        snippet_body
 +                    ),
 +                )
 +            } else {
 +                // If we are in closure, we need curly braces around suggestion
 +                let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
 +                let (mut cbrace_start, mut cbrace_end) = ("".to_string(), "".to_string());
 +                if let Some(parent_expr) = get_parent_expr(cx, expr) {
 +                    if let ExprKind::Closure(..) = parent_expr.kind {
 +                        cbrace_end = format!("\n{}}}", indent);
 +                        // Fix body indent due to the closure
 +                        indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
 +                        cbrace_start = format!("{{\n{}", indent);
 +                    }
 +                }
 +                // If the parent is already an arm, and the body is another match statement,
 +                // we need curly braces around suggestion
 +                let parent_node_id = cx.tcx.hir().get_parent_node(expr.hir_id);
 +                if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) {
 +                    if let ExprKind::Match(..) = arm.body.kind {
 +                        cbrace_end = format!("\n{}}}", indent);
 +                        // Fix body indent due to the match
 +                        indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
 +                        cbrace_start = format!("{{\n{}", indent);
 +                    }
 +                }
 +                (
 +                    expr.span,
 +                    format!(
 +                        "{}let {} = {};\n{}{}{}",
 +                        cbrace_start,
 +                        snippet_with_applicability(cx, bind_names, "..", &mut applicability),
 +                        snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
 +                        indent,
 +                        snippet_body,
 +                        cbrace_end
 +                    ),
 +                )
 +            };
 +            span_lint_and_sugg(
 +                cx,
 +                MATCH_SINGLE_BINDING,
 +                target_span,
 +                "this match could be written as a `let` statement",
 +                "consider using `let` statement",
 +                sugg,
 +                applicability,
 +            );
 +        },
 +        PatKind::Wild => {
 +            if ex.can_have_side_effects() {
 +                let indent = " ".repeat(indent_of(cx, expr.span).unwrap_or(0));
 +                let sugg = format!(
 +                    "{};\n{}{}",
 +                    snippet_with_applicability(cx, ex.span, "..", &mut applicability),
 +                    indent,
 +                    snippet_body
 +                );
 +                span_lint_and_sugg(
 +                    cx,
 +                    MATCH_SINGLE_BINDING,
 +                    expr.span,
 +                    "this match could be replaced by its scrutinee and body",
 +                    "consider using the scrutinee and body instead",
 +                    sugg,
 +                    applicability,
 +                );
 +            } else {
 +                span_lint_and_sugg(
 +                    cx,
 +                    MATCH_SINGLE_BINDING,
 +                    expr.span,
 +                    "this match could be replaced by its body itself",
 +                    "consider using the match body instead",
 +                    snippet_body,
 +                    Applicability::MachineApplicable,
 +                );
 +            }
 +        },
 +        _ => (),
 +    }
 +}
 +
 +/// Returns true if the `ex` match expression is in a local (`let`) statement
 +fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'a>> {
 +    let map = &cx.tcx.hir();
 +    if_chain! {
 +        if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id));
 +        if let Some(Node::Local(parent_let_expr)) = map.find(map.get_parent_node(parent_arm_expr.hir_id));
 +        then {
 +            return Some(parent_let_expr);
 +        }
 +    }
 +    None
 +}
 +
 +/// Gets all arms that are unbounded `PatRange`s.
- fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<Constant>> {
++fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<FullInt>> {
 +    arms.iter()
 +        .filter_map(|arm| {
 +            if let Arm { pat, guard: None, .. } = *arm {
 +                if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
 +                    let lhs = match lhs {
 +                        Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0,
 +                        None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?,
 +                    };
 +                    let rhs = match rhs {
 +                        Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
 +                        None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
 +                    };
-                     let rhs = match range_end {
-                         RangeEnd::Included => Bound::Included(rhs),
-                         RangeEnd::Excluded => Bound::Excluded(rhs),
++
++                    let lhs_val = lhs.int_value(cx, ty)?;
++                    let rhs_val = rhs.int_value(cx, ty)?;
++
++                    let rhs_bound = match range_end {
++                        RangeEnd::Included => Bound::Included(rhs_val),
++                        RangeEnd::Excluded => Bound::Excluded(rhs_val),
 +                    };
 +                    return Some(SpannedRange {
 +                        span: pat.span,
-                         node: (lhs, rhs),
++                        node: (lhs_val, rhs_bound),
 +                    });
 +                }
 +
 +                if let PatKind::Lit(value) = pat.kind {
-                     let value = constant(cx, cx.typeck_results(), value)?.0;
++                    let value = constant_full_int(cx, cx.typeck_results(), value)?;
 +                    return Some(SpannedRange {
 +                        span: pat.span,
-                         node: (value.clone(), Bound::Included(value)),
++                        node: (value, Bound::Included(value)),
 +                    });
 +                }
 +            }
 +            None
 +        })
 +        .collect()
 +}
 +
 +#[derive(Debug, Eq, PartialEq)]
 +pub struct SpannedRange<T> {
 +    pub span: Span,
 +    pub node: (T, Bound<T>),
 +}
 +
- type TypedRanges = Vec<SpannedRange<u128>>;
- /// Gets all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway
- /// and other types than
- /// `Uint` and `Int` probably don't make sense.
- fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
-     ranges
-         .iter()
-         .filter_map(|range| match range.node {
-             (Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange {
-                 span: range.span,
-                 node: (start, Bound::Included(end)),
-             }),
-             (Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange {
-                 span: range.span,
-                 node: (start, Bound::Excluded(end)),
-             }),
-             (Constant::Int(start), Bound::Unbounded) => Some(SpannedRange {
-                 span: range.span,
-                 node: (start, Bound::Unbounded),
-             }),
-             _ => None,
-         })
-         .collect()
- }
 +// Checks if arm has the form `None => None`
 +fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 +    matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
 +}
 +
 +// Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
 +fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotation> {
 +    if_chain! {
 +        if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind;
 +        if is_lang_ctor(cx, qpath, OptionSome);
 +        if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
 +        if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
 +        if let ExprKind::Call(e, args) = remove_blocks(arm.body).kind;
 +        if let ExprKind::Path(ref some_path) = e.kind;
 +        if is_lang_ctor(cx, some_path, OptionSome) && args.len() == 1;
 +        if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind;
 +        if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
 +        then {
 +            return Some(rb)
 +        }
 +    }
 +    None
 +}
 +
 +fn has_multiple_ref_pats<'a, 'b, I>(pats: I) -> bool
 +where
 +    'b: 'a,
 +    I: Iterator<Item = &'a Pat<'b>>,
 +{
 +    let mut ref_count = 0;
 +    for opt in pats.map(|pat| match pat.kind {
 +        PatKind::Ref(..) => Some(true), // &-patterns
 +        PatKind::Wild => Some(false),   // an "anything" wildcard is also fine
 +        _ => None,                      // any other pattern is not fine
 +    }) {
 +        if let Some(inner) = opt {
 +            if inner {
 +                ref_count += 1;
 +            }
 +        } else {
 +            return false;
 +        }
 +    }
 +    ref_count > 1
 +}
 +
 +pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)>
 +where
 +    T: Copy + Ord,
 +{
 +    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 +    enum Kind<'a, T> {
 +        Start(T, &'a SpannedRange<T>),
 +        End(Bound<T>, &'a SpannedRange<T>),
 +    }
 +
 +    impl<'a, T: Copy> Kind<'a, T> {
 +        fn range(&self) -> &'a SpannedRange<T> {
 +            match *self {
 +                Kind::Start(_, r) | Kind::End(_, r) => r,
 +            }
 +        }
 +
 +        fn value(self) -> Bound<T> {
 +            match self {
 +                Kind::Start(t, _) => Bound::Included(t),
 +                Kind::End(t, _) => t,
 +            }
 +        }
 +    }
 +
 +    impl<'a, T: Copy + Ord> PartialOrd for Kind<'a, T> {
 +        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
 +            Some(self.cmp(other))
 +        }
 +    }
 +
 +    impl<'a, T: Copy + Ord> Ord for Kind<'a, T> {
 +        fn cmp(&self, other: &Self) -> Ordering {
 +            match (self.value(), other.value()) {
 +                (Bound::Included(a), Bound::Included(b)) | (Bound::Excluded(a), Bound::Excluded(b)) => a.cmp(&b),
 +                // Range patterns cannot be unbounded (yet)
 +                (Bound::Unbounded, _) | (_, Bound::Unbounded) => unimplemented!(),
 +                (Bound::Included(a), Bound::Excluded(b)) => match a.cmp(&b) {
 +                    Ordering::Equal => Ordering::Greater,
 +                    other => other,
 +                },
 +                (Bound::Excluded(a), Bound::Included(b)) => match a.cmp(&b) {
 +                    Ordering::Equal => Ordering::Less,
 +                    other => other,
 +                },
 +            }
 +        }
 +    }
 +
 +    let mut values = Vec::with_capacity(2 * ranges.len());
 +
 +    for r in ranges {
 +        values.push(Kind::Start(r.node.0, r));
 +        values.push(Kind::End(r.node.1, r));
 +    }
 +
 +    values.sort();
 +
 +    for (a, b) in iter::zip(&values, values.iter().skip(1)) {
 +        match (a, b) {
 +            (&Kind::Start(_, ra), &Kind::End(_, rb)) => {
 +                if ra.node != rb.node {
 +                    return Some((ra, rb));
 +                }
 +            },
 +            (&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (),
 +            _ => {
 +                // skip if the range `a` is completely included into the range `b`
 +                if let Ordering::Equal | Ordering::Less = a.cmp(b) {
 +                    let kind_a = Kind::End(a.range().node.1, a.range());
 +                    let kind_b = Kind::End(b.range().node.1, b.range());
 +                    if let Ordering::Equal | Ordering::Greater = kind_a.cmp(&kind_b) {
 +                        return None;
 +                    }
 +                }
 +                return Some((a.range(), b.range()));
 +            },
 +        }
 +    }
 +
 +    None
 +}
 +
 +mod redundant_pattern_match {
 +    use super::REDUNDANT_PATTERN_MATCHING;
 +    use clippy_utils::diagnostics::span_lint_and_then;
 +    use clippy_utils::higher;
 +    use clippy_utils::source::{snippet, snippet_with_applicability};
 +    use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type};
 +    use clippy_utils::{is_lang_ctor, is_qpath_def_path, is_trait_method, paths};
 +    use if_chain::if_chain;
 +    use rustc_ast::ast::LitKind;
 +    use rustc_data_structures::fx::FxHashSet;
 +    use rustc_errors::Applicability;
 +    use rustc_hir::LangItem::{OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
 +    use rustc_hir::{
 +        intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor},
 +        Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath,
 +    };
 +    use rustc_lint::LateContext;
 +    use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
 +    use rustc_span::sym;
 +
 +    pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if let Some(higher::IfLet {
 +            if_else,
 +            let_pat,
 +            let_expr,
 +            ..
 +        }) = higher::IfLet::hir(cx, expr)
 +        {
 +            find_sugg_for_if_let(cx, expr, let_pat, let_expr, "if", if_else.is_some());
 +        }
 +        if let ExprKind::Match(op, arms, MatchSource::Normal) = &expr.kind {
 +            find_sugg_for_match(cx, expr, op, arms);
 +        }
 +        if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
 +            find_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false);
 +        }
 +    }
 +
 +    /// Checks if the drop order for a type matters. Some std types implement drop solely to
 +    /// deallocate memory. For these types, and composites containing them, changing the drop order
 +    /// won't result in any observable side effects.
 +    fn type_needs_ordered_drop(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 +        type_needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
 +    }
 +
 +    fn type_needs_ordered_drop_inner(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet<Ty<'tcx>>) -> bool {
 +        if !seen.insert(ty) {
 +            return false;
 +        }
 +        if !ty.needs_drop(cx.tcx, cx.param_env) {
 +            false
 +        } else if !cx
 +            .tcx
 +            .lang_items()
 +            .drop_trait()
 +            .map_or(false, |id| implements_trait(cx, ty, id, &[]))
 +        {
 +            // This type doesn't implement drop, so no side effects here.
 +            // Check if any component type has any.
 +            match ty.kind() {
 +                ty::Tuple(_) => ty.tuple_fields().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)),
 +                ty::Array(ty, _) => type_needs_ordered_drop_inner(cx, ty, seen),
 +                ty::Adt(adt, subs) => adt
 +                    .all_fields()
 +                    .map(|f| f.ty(cx.tcx, subs))
 +                    .any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)),
 +                _ => true,
 +            }
 +        }
 +        // Check for std types which implement drop, but only for memory allocation.
 +        else if is_type_diagnostic_item(cx, ty, sym::Vec)
 +            || is_type_lang_item(cx, ty, LangItem::OwnedBox)
 +            || is_type_diagnostic_item(cx, ty, sym::Rc)
 +            || is_type_diagnostic_item(cx, ty, sym::Arc)
 +            || is_type_diagnostic_item(cx, ty, sym::cstring_type)
 +            || is_type_diagnostic_item(cx, ty, sym::BTreeMap)
 +            || is_type_diagnostic_item(cx, ty, sym::LinkedList)
 +            || match_type(cx, ty, &paths::WEAK_RC)
 +            || match_type(cx, ty, &paths::WEAK_ARC)
 +        {
 +            // Check all of the generic arguments.
 +            if let ty::Adt(_, subs) = ty.kind() {
 +                subs.types().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen))
 +            } else {
 +                true
 +            }
 +        } else {
 +            true
 +        }
 +    }
 +
 +    // Extract the generic arguments out of a type
 +    fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
 +        if_chain! {
 +            if let ty::Adt(_, subs) = ty.kind();
 +            if let Some(sub) = subs.get(index);
 +            if let GenericArgKind::Type(sub_ty) = sub.unpack();
 +            then {
 +                Some(sub_ty)
 +            } else {
 +                None
 +            }
 +        }
 +    }
 +
 +    // Checks if there are any temporaries created in the given expression for which drop order
 +    // matters.
 +    fn temporaries_need_ordered_drop(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
 +        struct V<'a, 'tcx> {
 +            cx: &'a LateContext<'tcx>,
 +            res: bool,
 +        }
 +        impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> {
 +            type Map = ErasedMap<'tcx>;
 +            fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +                NestedVisitorMap::None
 +            }
 +
 +            fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
 +                match expr.kind {
 +                    // Taking the reference of a value leaves a temporary
 +                    // e.g. In `&String::new()` the string is a temporary value.
 +                    // Remaining fields are temporary values
 +                    // e.g. In `(String::new(), 0).1` the string is a temporary value.
 +                    ExprKind::AddrOf(_, _, expr) | ExprKind::Field(expr, _) => {
 +                        if !matches!(expr.kind, ExprKind::Path(_)) {
 +                            if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(expr)) {
 +                                self.res = true;
 +                            } else {
 +                                self.visit_expr(expr);
 +                            }
 +                        }
 +                    },
 +                    // the base type is alway taken by reference.
 +                    // e.g. In `(vec![0])[0]` the vector is a temporary value.
 +                    ExprKind::Index(base, index) => {
 +                        if !matches!(base.kind, ExprKind::Path(_)) {
 +                            if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(base)) {
 +                                self.res = true;
 +                            } else {
 +                                self.visit_expr(base);
 +                            }
 +                        }
 +                        self.visit_expr(index);
 +                    },
 +                    // Method calls can take self by reference.
 +                    // e.g. In `String::new().len()` the string is a temporary value.
 +                    ExprKind::MethodCall(_, _, [self_arg, args @ ..], _) => {
 +                        if !matches!(self_arg.kind, ExprKind::Path(_)) {
 +                            let self_by_ref = self
 +                                .cx
 +                                .typeck_results()
 +                                .type_dependent_def_id(expr.hir_id)
 +                                .map_or(false, |id| self.cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref());
 +                            if self_by_ref
 +                                && type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(self_arg))
 +                            {
 +                                self.res = true;
 +                            } else {
 +                                self.visit_expr(self_arg);
 +                            }
 +                        }
 +                        args.iter().for_each(|arg| self.visit_expr(arg));
 +                    },
 +                    // Either explicitly drops values, or changes control flow.
 +                    ExprKind::DropTemps(_)
 +                    | ExprKind::Ret(_)
 +                    | ExprKind::Break(..)
 +                    | ExprKind::Yield(..)
 +                    | ExprKind::Block(Block { expr: None, .. }, _)
 +                    | ExprKind::Loop(..) => (),
 +
 +                    // Only consider the final expression.
 +                    ExprKind::Block(Block { expr: Some(expr), .. }, _) => self.visit_expr(expr),
 +
 +                    _ => walk_expr(self, expr),
 +                }
 +            }
 +        }
 +
 +        let mut v = V { cx, res: false };
 +        v.visit_expr(expr);
 +        v.res
 +    }
 +
 +    fn find_sugg_for_if_let<'tcx>(
 +        cx: &LateContext<'tcx>,
 +        expr: &'tcx Expr<'_>,
 +        let_pat: &Pat<'_>,
 +        let_expr: &'tcx Expr<'_>,
 +        keyword: &'static str,
 +        has_else: bool,
 +    ) {
 +        // also look inside refs
 +        let mut kind = &let_pat.kind;
 +        // if we have &None for example, peel it so we can detect "if let None = x"
 +        if let PatKind::Ref(inner, _mutability) = kind {
 +            kind = &inner.kind;
 +        }
 +        let op_ty = cx.typeck_results().expr_ty(let_expr);
 +        // Determine which function should be used, and the type contained by the corresponding
 +        // variant.
 +        let (good_method, inner_ty) = match kind {
 +            PatKind::TupleStruct(ref path, [sub_pat], _) => {
 +                if let PatKind::Wild = sub_pat.kind {
 +                    if is_lang_ctor(cx, path, ResultOk) {
 +                        ("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty))
 +                    } else if is_lang_ctor(cx, path, ResultErr) {
 +                        ("is_err()", try_get_generic_ty(op_ty, 1).unwrap_or(op_ty))
 +                    } else if is_lang_ctor(cx, path, OptionSome) {
 +                        ("is_some()", op_ty)
 +                    } else if is_lang_ctor(cx, path, PollReady) {
 +                        ("is_ready()", op_ty)
 +                    } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V4) {
 +                        ("is_ipv4()", op_ty)
 +                    } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V6) {
 +                        ("is_ipv6()", op_ty)
 +                    } else {
 +                        return;
 +                    }
 +                } else {
 +                    return;
 +                }
 +            },
 +            PatKind::Path(ref path) => {
 +                let method = if is_lang_ctor(cx, path, OptionNone) {
 +                    "is_none()"
 +                } else if is_lang_ctor(cx, path, PollPending) {
 +                    "is_pending()"
 +                } else {
 +                    return;
 +                };
 +                // `None` and `Pending` don't have an inner type.
 +                (method, cx.tcx.types.unit)
 +            },
 +            _ => return,
 +        };
 +
 +        // If this is the last expression in a block or there is an else clause then the whole
 +        // type needs to be considered, not just the inner type of the branch being matched on.
 +        // Note the last expression in a block is dropped after all local bindings.
 +        let check_ty = if has_else
 +            || (keyword == "if" && matches!(cx.tcx.hir().parent_iter(expr.hir_id).next(), Some((_, Node::Block(..)))))
 +        {
 +            op_ty
 +        } else {
 +            inner_ty
 +        };
 +
 +        // All temporaries created in the scrutinee expression are dropped at the same time as the
 +        // scrutinee would be, so they have to be considered as well.
 +        // e.g. in `if let Some(x) = foo.lock().unwrap().baz.as_ref() { .. }` the lock will be held
 +        // for the duration if body.
 +        let needs_drop = type_needs_ordered_drop(cx, check_ty) || temporaries_need_ordered_drop(cx, let_expr);
 +
 +        // check that `while_let_on_iterator` lint does not trigger
 +        if_chain! {
 +            if keyword == "while";
 +            if let ExprKind::MethodCall(method_path, _, _, _) = let_expr.kind;
 +            if method_path.ident.name == sym::next;
 +            if is_trait_method(cx, let_expr, sym::Iterator);
 +            then {
 +                return;
 +            }
 +        }
 +
 +        let result_expr = match &let_expr.kind {
 +            ExprKind::AddrOf(_, _, borrowed) => borrowed,
 +            _ => let_expr,
 +        };
 +        span_lint_and_then(
 +            cx,
 +            REDUNDANT_PATTERN_MATCHING,
 +            let_pat.span,
 +            &format!("redundant pattern matching, consider using `{}`", good_method),
 +            |diag| {
 +                // if/while let ... = ... { ... }
 +                // ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +                let expr_span = expr.span;
 +
 +                // if/while let ... = ... { ... }
 +                //                 ^^^
 +                let op_span = result_expr.span.source_callsite();
 +
 +                // if/while let ... = ... { ... }
 +                // ^^^^^^^^^^^^^^^^^^^
 +                let span = expr_span.until(op_span.shrink_to_hi());
 +
 +                let mut app = if needs_drop {
 +                    Applicability::MaybeIncorrect
 +                } else {
 +                    Applicability::MachineApplicable
 +                };
 +                let sugg = snippet_with_applicability(cx, op_span, "_", &mut app);
 +
 +                diag.span_suggestion(span, "try this", format!("{} {}.{}", keyword, sugg, good_method), app);
 +
 +                if needs_drop {
 +                    diag.note("this will change drop order of the result, as well as all temporaries");
 +                    diag.note("add `#[allow(clippy::redundant_pattern_matching)]` if this is important");
 +                }
 +            },
 +        );
 +    }
 +
 +    fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
 +        if arms.len() == 2 {
 +            let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
 +
 +            let found_good_method = match node_pair {
 +                (
 +                    PatKind::TupleStruct(ref path_left, patterns_left, _),
 +                    PatKind::TupleStruct(ref path_right, patterns_right, _),
 +                ) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
 +                    if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
 +                        find_good_method_for_match(
 +                            cx,
 +                            arms,
 +                            path_left,
 +                            path_right,
 +                            &paths::RESULT_OK,
 +                            &paths::RESULT_ERR,
 +                            "is_ok()",
 +                            "is_err()",
 +                        )
 +                        .or_else(|| {
 +                            find_good_method_for_match(
 +                                cx,
 +                                arms,
 +                                path_left,
 +                                path_right,
 +                                &paths::IPADDR_V4,
 +                                &paths::IPADDR_V6,
 +                                "is_ipv4()",
 +                                "is_ipv6()",
 +                            )
 +                        })
 +                    } else {
 +                        None
 +                    }
 +                },
 +                (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right))
 +                | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _))
 +                    if patterns.len() == 1 =>
 +                {
 +                    if let PatKind::Wild = patterns[0].kind {
 +                        find_good_method_for_match(
 +                            cx,
 +                            arms,
 +                            path_left,
 +                            path_right,
 +                            &paths::OPTION_SOME,
 +                            &paths::OPTION_NONE,
 +                            "is_some()",
 +                            "is_none()",
 +                        )
 +                        .or_else(|| {
 +                            find_good_method_for_match(
 +                                cx,
 +                                arms,
 +                                path_left,
 +                                path_right,
 +                                &paths::POLL_READY,
 +                                &paths::POLL_PENDING,
 +                                "is_ready()",
 +                                "is_pending()",
 +                            )
 +                        })
 +                    } else {
 +                        None
 +                    }
 +                },
 +                _ => None,
 +            };
 +
 +            if let Some(good_method) = found_good_method {
 +                let span = expr.span.to(op.span);
 +                let result_expr = match &op.kind {
 +                    ExprKind::AddrOf(_, _, borrowed) => borrowed,
 +                    _ => op,
 +                };
 +                span_lint_and_then(
 +                    cx,
 +                    REDUNDANT_PATTERN_MATCHING,
 +                    expr.span,
 +                    &format!("redundant pattern matching, consider using `{}`", good_method),
 +                    |diag| {
 +                        diag.span_suggestion(
 +                            span,
 +                            "try this",
 +                            format!("{}.{}", snippet(cx, result_expr.span, "_"), good_method),
 +                            Applicability::MaybeIncorrect, // snippet
 +                        );
 +                    },
 +                );
 +            }
 +        }
 +    }
 +
 +    #[allow(clippy::too_many_arguments)]
 +    fn find_good_method_for_match<'a>(
 +        cx: &LateContext<'_>,
 +        arms: &[Arm<'_>],
 +        path_left: &QPath<'_>,
 +        path_right: &QPath<'_>,
 +        expected_left: &[&str],
 +        expected_right: &[&str],
 +        should_be_left: &'a str,
 +        should_be_right: &'a str,
 +    ) -> Option<&'a str> {
 +        let body_node_pair = if is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_left)
 +            && is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_right)
 +        {
 +            (&(*arms[0].body).kind, &(*arms[1].body).kind)
 +        } else if is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_left)
 +            && is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_right)
 +        {
 +            (&(*arms[1].body).kind, &(*arms[0].body).kind)
 +        } else {
 +            return None;
 +        };
 +
 +        match body_node_pair {
 +            (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
 +                (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
 +                (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
 +                _ => None,
 +            },
 +            _ => None,
 +        }
 +    }
 +}
 +
 +#[test]
 +fn test_overlapping() {
 +    use rustc_span::source_map::DUMMY_SP;
 +
 +    let sp = |s, e| SpannedRange {
 +        span: DUMMY_SP,
 +        node: (s, e),
 +    };
 +
 +    assert_eq!(None, overlapping::<u8>(&[]));
 +    assert_eq!(None, overlapping(&[sp(1, Bound::Included(4))]));
 +    assert_eq!(
 +        None,
 +        overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6))])
 +    );
 +    assert_eq!(
 +        None,
 +        overlapping(&[
 +            sp(1, Bound::Included(4)),
 +            sp(5, Bound::Included(6)),
 +            sp(10, Bound::Included(11))
 +        ],)
 +    );
 +    assert_eq!(
 +        Some((&sp(1, Bound::Included(4)), &sp(3, Bound::Included(6)))),
 +        overlapping(&[sp(1, Bound::Included(4)), sp(3, Bound::Included(6))])
 +    );
 +    assert_eq!(
 +        Some((&sp(5, Bound::Included(6)), &sp(6, Bound::Included(11)))),
 +        overlapping(&[
 +            sp(1, Bound::Included(4)),
 +            sp(5, Bound::Included(6)),
 +            sp(6, Bound::Included(11))
 +        ],)
 +    );
 +}
 +
 +/// Implementation of `MATCH_SAME_ARMS`.
 +fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) {
 +    if let ExprKind::Match(_, arms, MatchSource::Normal) = expr.kind {
 +        let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 {
 +            let mut h = SpanlessHash::new(cx);
 +            h.hash_expr(arm.body);
 +            h.finish()
 +        };
 +
 +        let eq = |&(lindex, lhs): &(usize, &Arm<'_>), &(rindex, rhs): &(usize, &Arm<'_>)| -> bool {
 +            let min_index = usize::min(lindex, rindex);
 +            let max_index = usize::max(lindex, rindex);
 +
 +            let mut local_map: HirIdMap<HirId> = HirIdMap::default();
 +            let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
 +                if_chain! {
 +                    if let Some(a_id) = path_to_local(a);
 +                    if let Some(b_id) = path_to_local(b);
 +                    let entry = match local_map.entry(a_id) {
 +                        Entry::Vacant(entry) => entry,
 +                        // check if using the same bindings as before
 +                        Entry::Occupied(entry) => return *entry.get() == b_id,
 +                    };
 +                    // the names technically don't have to match; this makes the lint more conservative
 +                    if cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id);
 +                    if TyS::same_type(cx.typeck_results().expr_ty(a), cx.typeck_results().expr_ty(b));
 +                    if pat_contains_local(lhs.pat, a_id);
 +                    if pat_contains_local(rhs.pat, b_id);
 +                    then {
 +                        entry.insert(b_id);
 +                        true
 +                    } else {
 +                        false
 +                    }
 +                }
 +            };
 +            // Arms with a guard are ignored, those can’t always be merged together
 +            // This is also the case for arms in-between each there is an arm with a guard
 +            (min_index..=max_index).all(|index| arms[index].guard.is_none())
 +                && SpanlessEq::new(cx)
 +                    .expr_fallback(eq_fallback)
 +                    .eq_expr(lhs.body, rhs.body)
 +                // these checks could be removed to allow unused bindings
 +                && bindings_eq(lhs.pat, local_map.keys().copied().collect())
 +                && bindings_eq(rhs.pat, local_map.values().copied().collect())
 +        };
 +
 +        let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
 +        for (&(_, i), &(_, j)) in search_same(&indexed_arms, hash, eq) {
 +            span_lint_and_then(
 +                cx,
 +                MATCH_SAME_ARMS,
 +                j.body.span,
 +                "this `match` has identical arm bodies",
 +                |diag| {
 +                    diag.span_note(i.body.span, "same as this");
 +
 +                    // Note: this does not use `span_suggestion` on purpose:
 +                    // there is no clean way
 +                    // to remove the other arm. Building a span and suggest to replace it to ""
 +                    // makes an even more confusing error message. Also in order not to make up a
 +                    // span for the whole pattern, the suggestion is only shown when there is only
 +                    // one pattern. The user should know about `|` if they are already using it…
 +
 +                    let lhs = snippet(cx, i.pat.span, "<pat1>");
 +                    let rhs = snippet(cx, j.pat.span, "<pat2>");
 +
 +                    if let PatKind::Wild = j.pat.kind {
 +                        // if the last arm is _, then i could be integrated into _
 +                        // note that i.pat cannot be _, because that would mean that we're
 +                        // hiding all the subsequent arms, and rust won't compile
 +                        diag.span_note(
 +                            i.body.span,
 +                            &format!(
 +                                "`{}` has the same arm body as the `_` wildcard, consider removing it",
 +                                lhs
 +                            ),
 +                        );
 +                    } else {
 +                        diag.span_help(i.pat.span, &format!("consider refactoring into `{} | {}`", lhs, rhs,))
 +                            .help("...or consider changing the match arm bodies");
 +                    }
 +                },
 +            );
 +        }
 +    }
 +}
 +
 +fn pat_contains_local(pat: &Pat<'_>, id: HirId) -> bool {
 +    let mut result = false;
 +    pat.walk_short(|p| {
 +        result |= matches!(p.kind, PatKind::Binding(_, binding_id, ..) if binding_id == id);
 +        !result
 +    });
 +    result
 +}
 +
 +/// Returns true if all the bindings in the `Pat` are in `ids` and vice versa
 +fn bindings_eq(pat: &Pat<'_>, mut ids: HirIdSet) -> bool {
 +    let mut result = true;
 +    pat.each_binding_or_first(&mut |_, id, _, _| result &= ids.remove(&id));
 +    result && ids.is_empty()
 +}
index 1a32af5dc7a386fdd5e03c3832e8c105d6fc47f8,0000000000000000000000000000000000000000..b4dacb2580c313fbc366aae7b251facfbdda215e
mode 100644,000000..100644
--- /dev/null
@@@ -1,132 -1,0 +1,132 @@@
-                 }
 +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::get_parent_node;
 +use clippy_utils::source::snippet_with_context;
 +use clippy_utils::sugg;
 +use clippy_utils::ty::is_copy;
 +use rustc_errors::Applicability;
 +use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind};
 +use rustc_lint::LateContext;
 +use rustc_middle::ty::{self, adjustment::Adjust};
 +use rustc_span::symbol::{sym, Symbol};
 +
 +use super::CLONE_DOUBLE_REF;
 +use super::CLONE_ON_COPY;
 +
 +/// Checks for the `CLONE_ON_COPY` lint.
 +#[allow(clippy::too_many_lines)]
 +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, args: &[Expr<'_>]) {
 +    let arg = match args {
 +        [arg] if method_name == sym::clone => arg,
 +        _ => return,
 +    };
 +    if cx
 +        .typeck_results()
 +        .type_dependent_def_id(expr.hir_id)
 +        .and_then(|id| cx.tcx.trait_of_item(id))
 +        .zip(cx.tcx.lang_items().clone_trait())
 +        .map_or(true, |(x, y)| x != y)
 +    {
 +        return;
 +    }
 +    let arg_adjustments = cx.typeck_results().expr_adjustments(arg);
 +    let arg_ty = arg_adjustments
 +        .last()
 +        .map_or_else(|| cx.typeck_results().expr_ty(arg), |a| a.target);
 +
 +    let ty = cx.typeck_results().expr_ty(expr);
 +    if let ty::Ref(_, inner, _) = arg_ty.kind() {
 +        if let ty::Ref(_, innermost, _) = inner.kind() {
 +            span_lint_and_then(
 +                cx,
 +                CLONE_DOUBLE_REF,
 +                expr.span,
 +                &format!(
 +                    "using `clone` on a double-reference; \
 +                    this will copy the reference of type `{}` instead of cloning the inner type",
 +                    ty
 +                ),
 +                |diag| {
 +                    if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
 +                        let mut ty = innermost;
 +                        let mut n = 0;
 +                        while let ty::Ref(_, inner, _) = ty.kind() {
 +                            ty = inner;
 +                            n += 1;
 +                        }
 +                        let refs = "&".repeat(n + 1);
 +                        let derefs = "*".repeat(n);
 +                        let explicit = format!("<{}{}>::clone({})", refs, ty, snip);
 +                        diag.span_suggestion(
 +                            expr.span,
 +                            "try dereferencing it",
 +                            format!("{}({}{}).clone()", refs, derefs, snip.deref()),
 +                            Applicability::MaybeIncorrect,
 +                        );
 +                        diag.span_suggestion(
 +                            expr.span,
 +                            "or try being explicit if you are sure, that you want to clone a reference",
 +                            explicit,
 +                            Applicability::MaybeIncorrect,
 +                        );
 +                    }
 +                },
 +            );
 +            return; // don't report clone_on_copy
 +        }
 +    }
 +
 +    if is_copy(cx, ty) {
 +        let parent_is_suffix_expr = match get_parent_node(cx.tcx, expr.hir_id) {
 +            Some(Node::Expr(parent)) => match parent.kind {
 +                // &*x is a nop, &x.clone() is not
 +                ExprKind::AddrOf(..) => return,
 +                // (*x).func() is useless, x.clone().func() can work in case func borrows self
 +                ExprKind::MethodCall(_, _, [self_arg, ..], _)
 +                    if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) =>
 +                {
 +                    return;
-             }
++                },
 +                ExprKind::MethodCall(_, _, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
 +                ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
 +                | ExprKind::Field(..)
 +                | ExprKind::Index(..) => true,
 +                _ => false,
 +            },
 +            // local binding capturing a reference
 +            Some(Node::Local(l))
 +                if matches!(
 +                    l.pat.kind,
 +                    PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..)
 +                ) =>
 +            {
 +                return;
++            },
 +            _ => false,
 +        };
 +
 +        let mut app = Applicability::MachineApplicable;
 +        let snip = snippet_with_context(cx, arg.span, expr.span.ctxt(), "_", &mut app).0;
 +
 +        let deref_count = arg_adjustments
 +            .iter()
 +            .take_while(|adj| matches!(adj.kind, Adjust::Deref(_)))
 +            .count();
 +        let (help, sugg) = if deref_count == 0 {
 +            ("try removing the `clone` call", snip.into())
 +        } else if parent_is_suffix_expr {
 +            ("try dereferencing it", format!("({}{})", "*".repeat(deref_count), snip))
 +        } else {
 +            ("try dereferencing it", format!("{}{}", "*".repeat(deref_count), snip))
 +        };
 +
 +        span_lint_and_sugg(
 +            cx,
 +            CLONE_ON_COPY,
 +            expr.span,
 +            &format!("using `clone` on type `{}` which implements the `Copy` trait", ty),
 +            help,
 +            sugg,
 +            app,
 +        );
 +    }
 +}
index b5bbbb09092af4f12d27c6fc60cc363444796019,0000000000000000000000000000000000000000..fe9ffde0d337c1f15506e73bdca1e0f373c88da5
mode 100644,000000..100644
--- /dev/null
@@@ -1,193 -1,0 +1,193 @@@
-             }
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::eager_or_lazy::is_lazyness_candidate;
 +use clippy_utils::is_trait_item;
 +use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite};
 +use clippy_utils::ty::implements_trait;
 +use clippy_utils::ty::{is_type_diagnostic_item, match_type};
 +use clippy_utils::{contains_return, last_path_segment, paths};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir as hir;
 +use rustc_hir::{BlockCheckMode, UnsafeSource};
 +use rustc_lint::LateContext;
 +use rustc_middle::ty;
 +use rustc_span::source_map::Span;
 +use rustc_span::symbol::{kw, sym};
 +use std::borrow::Cow;
 +
 +use super::OR_FUN_CALL;
 +
 +/// Checks for the `OR_FUN_CALL` lint.
 +#[allow(clippy::too_many_lines)]
 +pub(super) fn check<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &hir::Expr<'_>,
 +    method_span: Span,
 +    name: &str,
 +    args: &'tcx [hir::Expr<'_>],
 +) {
 +    /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
 +    fn check_unwrap_or_default(
 +        cx: &LateContext<'_>,
 +        name: &str,
 +        fun: &hir::Expr<'_>,
 +        self_expr: &hir::Expr<'_>,
 +        arg: &hir::Expr<'_>,
 +        or_has_args: bool,
 +        span: Span,
 +    ) -> bool {
 +        let is_default_default = || is_trait_item(cx, fun, sym::Default);
 +
 +        let implements_default = |arg, default_trait_id| {
 +            let arg_ty = cx.typeck_results().expr_ty(arg);
 +            implements_trait(cx, arg_ty, default_trait_id, &[])
 +        };
 +
 +        if_chain! {
 +            if !or_has_args;
 +            if name == "unwrap_or";
 +            if let hir::ExprKind::Path(ref qpath) = fun.kind;
 +            if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
 +            let path = last_path_segment(qpath).ident.name;
 +            // needs to target Default::default in particular or be *::new and have a Default impl
 +            // available
 +            if (matches!(path, kw::Default) && is_default_default())
 +                || (matches!(path, sym::new) && implements_default(arg, default_trait_id));
 +
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                span_lint_and_sugg(
 +                    cx,
 +                    OR_FUN_CALL,
 +                    span,
 +                    &format!("use of `{}` followed by a call to `{}`", name, path),
 +                    "try this",
 +                    format!(
 +                        "{}.unwrap_or_default()",
 +                        snippet_with_applicability(cx, self_expr.span, "..", &mut applicability)
 +                    ),
 +                    applicability,
 +                );
 +
 +                true
 +            } else {
 +                false
 +            }
 +        }
 +    }
 +
 +    /// Checks for `*or(foo())`.
 +    #[allow(clippy::too_many_arguments)]
 +    fn check_general_case<'tcx>(
 +        cx: &LateContext<'tcx>,
 +        name: &str,
 +        method_span: Span,
 +        self_expr: &hir::Expr<'_>,
 +        arg: &'tcx hir::Expr<'_>,
 +        span: Span,
 +        // None if lambda is required
 +        fun_span: Option<Span>,
 +    ) {
 +        // (path, fn_has_argument, methods, suffix)
 +        static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
 +            (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
 +            (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
 +            (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
 +            (&paths::RESULT, true, &["or", "unwrap_or"], "else"),
 +        ];
 +
 +        if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &arg.kind {
 +            if path.ident.name == sym::len {
 +                let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
 +
 +                match ty.kind() {
 +                    ty::Slice(_) | ty::Array(_, _) | ty::Str => return,
 +                    _ => (),
 +                }
 +
 +                if is_type_diagnostic_item(cx, ty, sym::Vec) {
 +                    return;
 +                }
 +            }
 +        }
 +
 +        if_chain! {
 +            if KNOW_TYPES.iter().any(|k| k.2.contains(&name));
 +
 +            if is_lazyness_candidate(cx, arg);
 +            if !contains_return(arg);
 +
 +            let self_ty = cx.typeck_results().expr_ty(self_expr);
 +
 +            if let Some(&(_, fn_has_arguments, poss, suffix)) =
 +                KNOW_TYPES.iter().find(|&&i| match_type(cx, self_ty, i.0));
 +
 +            if poss.contains(&name);
 +
 +            then {
 +                let macro_expanded_snipped;
 +                let sugg: Cow<'_, str> = {
 +                    let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) {
 +                        (false, Some(fun_span)) => (fun_span, false),
 +                        _ => (arg.span, true),
 +                    };
 +                    let snippet = {
 +                        let not_macro_argument_snippet = snippet_with_macro_callsite(cx, snippet_span, "..");
 +                        if not_macro_argument_snippet == "vec![]" {
 +                            macro_expanded_snipped = snippet(cx, snippet_span, "..");
 +                            match macro_expanded_snipped.strip_prefix("$crate::vec::") {
 +                                Some(stripped) => Cow::from(stripped),
 +                                None => macro_expanded_snipped
 +                            }
 +                        }
 +                        else {
 +                            not_macro_argument_snippet
 +                        }
 +                    };
 +
 +                    if use_lambda {
 +                        let l_arg = if fn_has_arguments { "_" } else { "" };
 +                        format!("|{}| {}", l_arg, snippet).into()
 +                    } else {
 +                        snippet
 +                    }
 +                };
 +                let span_replace_word = method_span.with_hi(span.hi());
 +                span_lint_and_sugg(
 +                    cx,
 +                    OR_FUN_CALL,
 +                    span_replace_word,
 +                    &format!("use of `{}` followed by a function call", name),
 +                    "try this",
 +                    format!("{}_{}({})", name, suffix, sugg),
 +                    Applicability::HasPlaceholders,
 +                );
 +            }
 +        }
 +    }
 +
 +    if args.len() == 2 {
 +        match args[1].kind {
 +            hir::ExprKind::Call(fun, or_args) => {
 +                let or_has_args = !or_args.is_empty();
 +                if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {
 +                    let fun_span = if or_has_args { None } else { Some(fun.span) };
 +                    check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, fun_span);
 +                }
 +            },
 +            hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
 +                check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
 +            },
 +            hir::ExprKind::Block(block, _)
 +                if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) =>
 +            {
 +                if let Some(block_expr) = block.expr {
 +                    if let hir::ExprKind::MethodCall(..) = block_expr.kind {
 +                        check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
 +                    }
 +                }
++            },
 +            _ => (),
 +        }
 +    }
 +}
index 6f65778e1193cfc08d011e0eec606f08e683bf6a,0000000000000000000000000000000000000000..06ba968fa4ed31da1700c3df599ff67badc51359
mode 100644,000000..100644
--- /dev/null
@@@ -1,23 -1,0 +1,18 @@@
- use super::MiscEarlyLints;
 +use clippy_utils::diagnostics::span_lint;
 +use rustc_ast::ast::{Expr, ExprKind, UnOp};
 +use rustc_lint::EarlyContext;
 +
 +use super::DOUBLE_NEG;
 +
 +pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) {
-     match expr.kind {
-         ExprKind::Unary(UnOp::Neg, ref inner) => {
-             if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
-                 span_lint(
-                     cx,
-                     DOUBLE_NEG,
-                     expr.span,
-                     "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
-                 );
-             }
-         },
-         ExprKind::Lit(ref lit) => MiscEarlyLints::check_lit(cx, lit),
-         _ => (),
++    if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind {
++        if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
++            span_lint(
++                cx,
++                DOUBLE_NEG,
++                expr.span,
++                "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
++            );
++        }
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1165c19a0cf0b442fbee3d8622e1637dff722849
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,38 @@@
++use clippy_utils::diagnostics::span_lint_and_sugg;
++use rustc_ast::ast::Lit;
++use rustc_errors::Applicability;
++use rustc_lint::EarlyContext;
++
++use super::{SEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX};
++
++pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
++    let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
++        val
++    } else {
++        return; // It's useless so shouldn't lint.
++    };
++    // Do not lint when literal is unsuffixed.
++    if !suffix.is_empty() {
++        if lit_snip.as_bytes()[maybe_last_sep_idx] == b'_' {
++            span_lint_and_sugg(
++                cx,
++                SEPARATED_LITERAL_SUFFIX,
++                lit.span,
++                &format!("{} type suffix should not be separated by an underscore", sugg_type),
++                "remove the underscore",
++                format!("{}{}", &lit_snip[..maybe_last_sep_idx], suffix),
++                Applicability::MachineApplicable,
++            );
++        } else {
++            span_lint_and_sugg(
++                cx,
++                UNSEPARATED_LITERAL_SUFFIX,
++                lit.span,
++                &format!("{} type suffix should be separated by an underscore", sugg_type),
++                "add an underscore",
++                format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
++                Applicability::MachineApplicable,
++            );
++        }
++    }
++}
index b32feab4ee3e7e5506b23875170ca01d6d4920b6,0000000000000000000000000000000000000000..7c3f5f22ade0f9ba447d1dc583791b092f1abf80
mode 100644,000000..100644
--- /dev/null
@@@ -1,348 -1,0 +1,377 @@@
- mod unseparated_literal_suffix;
 +mod builtin_type_shadow;
 +mod double_neg;
++mod literal_suffix;
 +mod mixed_case_hex_literals;
 +mod redundant_pattern;
 +mod unneeded_field_pattern;
 +mod unneeded_wildcard_pattern;
- use rustc_ast::ast::{Expr, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
 +mod zero_prefixed_literal;
 +
 +use clippy_utils::diagnostics::span_lint;
 +use clippy_utils::source::snippet_opt;
-     /// It is much less readable.
++use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
 +use rustc_ast::visit::FnKind;
 +use rustc_data_structures::fx::FxHashMap;
 +use rustc_lint::{EarlyContext, EarlyLintPass};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for structure field patterns bound to wildcards.
 +    ///
 +    /// ### Why is this bad?
 +    /// Using `..` instead is shorter and leaves the focus on
 +    /// the fields that are actually bound.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # struct Foo {
 +    /// #     a: i32,
 +    /// #     b: i32,
 +    /// #     c: i32,
 +    /// # }
 +    /// let f = Foo { a: 0, b: 0, c: 0 };
 +    ///
 +    /// // Bad
 +    /// match f {
 +    ///     Foo { a: _, b: 0, .. } => {},
 +    ///     Foo { a: _, b: _, c: _ } => {},
 +    /// }
 +    ///
 +    /// // Good
 +    /// match f {
 +    ///     Foo { b: 0, .. } => {},
 +    ///     Foo { .. } => {},
 +    /// }
 +    /// ```
 +    pub UNNEEDED_FIELD_PATTERN,
 +    restriction,
 +    "struct fields bound to a wildcard instead of using `..`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for function arguments having the similar names
 +    /// differing by an underscore.
 +    ///
 +    /// ### Why is this bad?
 +    /// It affects code readability.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// fn foo(a: i32, _a: i32) {}
 +    ///
 +    /// // Good
 +    /// fn bar(a: i32, _b: i32) {}
 +    /// ```
 +    pub DUPLICATE_UNDERSCORE_ARGUMENT,
 +    style,
 +    "function arguments having names which only differ by an underscore"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Detects expressions of the form `--x`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It can mislead C/C++ programmers to think `x` was
 +    /// decremented.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let mut x = 3;
 +    /// --x;
 +    /// ```
 +    pub DOUBLE_NEG,
 +    style,
 +    "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Warns on hexadecimal literals with mixed-case letter
 +    /// digits.
 +    ///
 +    /// ### Why is this bad?
 +    /// It looks confusing.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let y = 0x1a9BAcD;
 +    ///
 +    /// // Good
 +    /// let y = 0x1A9BACD;
 +    /// ```
 +    pub MIXED_CASE_HEX_LITERALS,
 +    style,
 +    "hex literals whose letter digits are not consistently upper- or lowercased"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Warns if literal suffixes are not separated by an
 +    /// underscore.
++    /// To enforce unseparated literal suffix style,
++    /// see the `separated_literal_suffix` lint.
 +    ///
 +    /// ### Why is this bad?
-     pedantic,
++    /// Suffix style should be consistent.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let y = 123832i32;
 +    ///
 +    /// // Good
 +    /// let y = 123832_i32;
 +    /// ```
 +    pub UNSEPARATED_LITERAL_SUFFIX,
-             unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
++    restriction,
 +    "literals whose suffix is not separated by an underscore"
 +}
 +
++declare_clippy_lint! {
++    /// ### What it does
++    /// Warns if literal suffixes are separated by an underscore.
++    /// To enforce separated literal suffix style,
++    /// see the `unseparated_literal_suffix` lint.
++    ///
++    /// ### Why is this bad?
++    /// Suffix style should be consistent.
++    ///
++    /// ### Example
++    /// ```rust
++    /// // Bad
++    /// let y = 123832_i32;
++    ///
++    /// // Good
++    /// let y = 123832i32;
++    /// ```
++    pub SEPARATED_LITERAL_SUFFIX,
++    restriction,
++    "literals whose suffix is separated by an underscore"
++}
++
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Warns if an integral constant literal starts with `0`.
 +    ///
 +    /// ### Why is this bad?
 +    /// In some languages (including the infamous C language
 +    /// and most of its
 +    /// family), this marks an octal constant. In Rust however, this is a decimal
 +    /// constant. This could
 +    /// be confusing for both the writer and a reader of the constant.
 +    ///
 +    /// ### Example
 +    ///
 +    /// In Rust:
 +    /// ```rust
 +    /// fn main() {
 +    ///     let a = 0123;
 +    ///     println!("{}", a);
 +    /// }
 +    /// ```
 +    ///
 +    /// prints `123`, while in C:
 +    ///
 +    /// ```c
 +    /// #include <stdio.h>
 +    ///
 +    /// int main() {
 +    ///     int a = 0123;
 +    ///     printf("%d\n", a);
 +    /// }
 +    /// ```
 +    ///
 +    /// prints `83` (as `83 == 0o123` while `123 == 0o173`).
 +    pub ZERO_PREFIXED_LITERAL,
 +    complexity,
 +    "integer literals starting with `0`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Warns if a generic shadows a built-in type.
 +    ///
 +    /// ### Why is this bad?
 +    /// This gives surprising type errors.
 +    ///
 +    /// ### Example
 +    ///
 +    /// ```ignore
 +    /// impl<u32> Foo<u32> {
 +    ///     fn impl_func(&self) -> u32 {
 +    ///         42
 +    ///     }
 +    /// }
 +    /// ```
 +    pub BUILTIN_TYPE_SHADOW,
 +    style,
 +    "shadowing a builtin type"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for patterns in the form `name @ _`.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's almost always more readable to just use direct
 +    /// bindings.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let v = Some("abc");
 +    ///
 +    /// // Bad
 +    /// match v {
 +    ///     Some(x) => (),
 +    ///     y @ _ => (),
 +    /// }
 +    ///
 +    /// // Good
 +    /// match v {
 +    ///     Some(x) => (),
 +    ///     y => (),
 +    /// }
 +    /// ```
 +    pub REDUNDANT_PATTERN,
 +    style,
 +    "using `name @ _` in a pattern"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for tuple patterns with a wildcard
 +    /// pattern (`_`) is next to a rest pattern (`..`).
 +    ///
 +    /// _NOTE_: While `_, ..` means there is at least one element left, `..`
 +    /// means there are 0 or more elements left. This can make a difference
 +    /// when refactoring, but shouldn't result in errors in the refactored code,
 +    /// since the wildcard pattern isn't used anyway.
 +    /// ### Why is this bad?
 +    /// The wildcard pattern is unneeded as the rest pattern
 +    /// can match that element as well.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # struct TupleStruct(u32, u32, u32);
 +    /// # let t = TupleStruct(1, 2, 3);
 +    /// // Bad
 +    /// match t {
 +    ///     TupleStruct(0, .., _) => (),
 +    ///     _ => (),
 +    /// }
 +    ///
 +    /// // Good
 +    /// match t {
 +    ///     TupleStruct(0, ..) => (),
 +    ///     _ => (),
 +    /// }
 +    /// ```
 +    pub UNNEEDED_WILDCARD_PATTERN,
 +    complexity,
 +    "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)"
 +}
 +
 +declare_lint_pass!(MiscEarlyLints => [
 +    UNNEEDED_FIELD_PATTERN,
 +    DUPLICATE_UNDERSCORE_ARGUMENT,
 +    DOUBLE_NEG,
 +    MIXED_CASE_HEX_LITERALS,
 +    UNSEPARATED_LITERAL_SUFFIX,
++    SEPARATED_LITERAL_SUFFIX,
 +    ZERO_PREFIXED_LITERAL,
 +    BUILTIN_TYPE_SHADOW,
 +    REDUNDANT_PATTERN,
 +    UNNEEDED_WILDCARD_PATTERN,
 +]);
 +
 +impl EarlyLintPass for MiscEarlyLints {
 +    fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) {
 +        for param in &gen.params {
 +            builtin_type_shadow::check(cx, param);
 +        }
 +    }
 +
 +    fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
 +        unneeded_field_pattern::check(cx, pat);
 +        redundant_pattern::check(cx, pat);
 +        unneeded_wildcard_pattern::check(cx, pat);
 +    }
 +
 +    fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
 +        let mut registered_names: FxHashMap<String, Span> = FxHashMap::default();
 +
 +        for arg in &fn_kind.decl().inputs {
 +            if let PatKind::Ident(_, ident, None) = arg.pat.kind {
 +                let arg_name = ident.to_string();
 +
 +                if let Some(arg_name) = arg_name.strip_prefix('_') {
 +                    if let Some(correspondence) = registered_names.get(arg_name) {
 +                        span_lint(
 +                            cx,
 +                            DUPLICATE_UNDERSCORE_ARGUMENT,
 +                            *correspondence,
 +                            &format!(
 +                                "`{}` already exists, having another argument having almost the same \
 +                                 name makes code comprehension and documentation more difficult",
 +                                arg_name
 +                            ),
 +                        );
 +                    }
 +                } else {
 +                    registered_names.insert(arg_name, arg.pat.span);
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
 +        if in_external_macro(cx.sess, expr.span) {
 +            return;
 +        }
++
++        if let ExprKind::Lit(ref lit) = expr.kind {
++            MiscEarlyLints::check_lit(cx, lit);
++        }
 +        double_neg::check(cx, expr);
 +    }
 +}
 +
 +impl MiscEarlyLints {
 +    fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
 +        // We test if first character in snippet is a number, because the snippet could be an expansion
 +        // from a built-in macro like `line!()` or a proc-macro like `#[wasm_bindgen]`.
 +        // Note that this check also covers special case that `line!()` is eagerly expanded by compiler.
 +        // See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression.
 +        // FIXME: Find a better way to detect those cases.
 +        let lit_snip = match snippet_opt(cx, lit.span) {
 +            Some(snip) if snip.chars().next().map_or(false, |c| c.is_digit(10)) => snip,
 +            _ => return,
 +        };
 +
 +        if let LitKind::Int(value, lit_int_type) = lit.kind {
 +            let suffix = match lit_int_type {
 +                LitIntType::Signed(ty) => ty.name_str(),
 +                LitIntType::Unsigned(ty) => ty.name_str(),
 +                LitIntType::Unsuffixed => "",
 +            };
-             unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
++            literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
 +            if lit_snip.starts_with("0x") {
 +                mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
 +            } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
 +                // nothing to do
 +            } else if value != 0 && lit_snip.starts_with('0') {
 +                zero_prefixed_literal::check(cx, lit, &lit_snip);
 +            }
 +        } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
 +            let suffix = float_ty.name_str();
++            literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
 +        }
 +    }
 +}
index f351d0098b7509cf6abdddfef53c21a29cc7a663,0000000000000000000000000000000000000000..d41b54745649958de717e61f6d395bfbce0e62e5
mode 100644,000000..100644
--- /dev/null
@@@ -1,178 -1,0 +1,178 @@@
-                 }
 +use std::{
 +    ffi::OsString,
 +    path::{Component, Path},
 +};
 +
 +use rustc_ast::ast;
 +use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 +use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::{FileName, RealFileName, SourceFile, Span, SyntaxContext};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks that module layout uses only self named module files, bans mod.rs files.
 +    ///
 +    /// ### Why is this bad?
 +    /// Having multiple module layout styles in a project can be confusing.
 +    ///
 +    /// ### Example
 +    /// ```text
 +    /// src/
 +    ///   stuff/
 +    ///     stuff_files.rs
 +    ///     mod.rs
 +    ///   lib.rs
 +    /// ```
 +    /// Use instead:
 +    /// ```text
 +    /// src/
 +    ///   stuff/
 +    ///     stuff_files.rs
 +    ///   stuff.rs
 +    ///   lib.rs
 +    /// ```
 +    pub MOD_MODULE_FILES,
 +    restriction,
 +    "checks that module layout is consistent"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks that module layout uses only mod.rs files.
 +    ///
 +    /// ### Why is this bad?
 +    /// Having multiple module layout styles in a project can be confusing.
 +    ///
 +    /// ### Example
 +    /// ```text
 +    /// src/
 +    ///   stuff/
 +    ///     stuff_files.rs
 +    ///   stuff.rs
 +    ///   lib.rs
 +    /// ```
 +    /// Use instead:
 +    /// ```text
 +    /// src/
 +    ///   stuff/
 +    ///     stuff_files.rs
 +    ///     mod.rs
 +    ///   lib.rs
 +    /// ```
 +
 +    pub SELF_NAMED_MODULE_FILES,
 +    restriction,
 +    "checks that module layout is consistent"
 +}
 +
 +pub struct ModStyle;
 +
 +impl_lint_pass!(ModStyle => [MOD_MODULE_FILES, SELF_NAMED_MODULE_FILES]);
 +
 +impl EarlyLintPass for ModStyle {
 +    fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
 +        if cx.builder.lint_level(MOD_MODULE_FILES).0 == Level::Allow
 +            && cx.builder.lint_level(SELF_NAMED_MODULE_FILES).0 == Level::Allow
 +        {
 +            return;
 +        }
 +
 +        let files = cx.sess.source_map().files();
 +
 +        let trim_to_src = if let RealFileName::LocalPath(p) = &cx.sess.opts.working_dir {
 +            p.to_string_lossy()
 +        } else {
 +            return;
 +        };
 +
 +        // `folder_segments` is all unique folder path segments `path/to/foo.rs` gives
 +        // `[path, to]` but not foo
 +        let mut folder_segments = FxHashSet::default();
 +        // `mod_folders` is all the unique folder names that contain a mod.rs file
 +        let mut mod_folders = FxHashSet::default();
 +        // `file_map` maps file names to the full path including the file name
 +        // `{ foo => path/to/foo.rs, .. }
 +        let mut file_map = FxHashMap::default();
 +        for file in files.iter() {
 +            match &file.name {
 +                FileName::Real(RealFileName::LocalPath(lp))
 +                    if lp.to_string_lossy().starts_with(trim_to_src.as_ref()) =>
 +                {
 +                    let p = lp.to_string_lossy();
 +                    let path = Path::new(p.trim_start_matches(trim_to_src.as_ref()));
 +                    if let Some(stem) = path.file_stem() {
 +                        file_map.insert(stem.to_os_string(), (file, path.to_owned()));
 +                    }
 +                    process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders);
 +                    check_self_named_mod_exists(cx, path, file);
++                },
 +                _ => {},
 +            }
 +        }
 +
 +        for folder in &folder_segments {
 +            if !mod_folders.contains(folder) {
 +                if let Some((file, path)) = file_map.get(folder) {
 +                    let mut correct = path.clone();
 +                    correct.pop();
 +                    correct.push(folder);
 +                    correct.push("mod.rs");
 +                    cx.struct_span_lint(
 +                        SELF_NAMED_MODULE_FILES,
 +                        Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
 +                        |build| {
 +                            let mut lint =
 +                                build.build(&format!("`mod.rs` files are required, found `{}`", path.display()));
 +                            lint.help(&format!("move `{}` to `{}`", path.display(), correct.display(),));
 +                            lint.emit();
 +                        },
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +/// For each `path` we add each folder component to `folder_segments` and if the file name
 +/// is `mod.rs` we add it's parent folder to `mod_folders`.
 +fn process_paths_for_mod_files(
 +    path: &Path,
 +    folder_segments: &mut FxHashSet<OsString>,
 +    mod_folders: &mut FxHashSet<OsString>,
 +) {
 +    let mut comp = path.components().rev().peekable();
 +    let _ = comp.next();
 +    if path.ends_with("mod.rs") {
 +        mod_folders.insert(comp.peek().map(|c| c.as_os_str().to_owned()).unwrap_or_default());
 +    }
 +    let folders = comp
 +        .filter_map(|c| {
 +            if let Component::Normal(s) = c {
 +                Some(s.to_os_string())
 +            } else {
 +                None
 +            }
 +        })
 +        .collect::<Vec<_>>();
 +    folder_segments.extend(folders);
 +}
 +
 +/// Checks every path for the presence of `mod.rs` files and emits the lint if found.
 +fn check_self_named_mod_exists(cx: &EarlyContext<'_>, path: &Path, file: &SourceFile) {
 +    if path.ends_with("mod.rs") {
 +        let mut mod_file = path.to_path_buf();
 +        mod_file.pop();
 +        mod_file.set_extension("rs");
 +
 +        cx.struct_span_lint(
 +            MOD_MODULE_FILES,
 +            Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
 +            |build| {
 +                let mut lint = build.build(&format!("`mod.rs` files are not allowed, found `{}`", path.display()));
 +                lint.help(&format!("move `{}` to `{}`", path.display(), mod_file.display(),));
 +                lint.emit();
 +            },
 +        );
 +    }
 +}
index 1b2495d764d2a0c650f9f866a153252fa5288b5a,0000000000000000000000000000000000000000..f1be90c44f98b998901e0f4b2462722466c99d69
mode 100644,000000..100644
--- /dev/null
@@@ -1,278 -1,0 +1,282 @@@
-                     if let [Adjustment {
-                         kind: Adjust::Deref(_), ..
-                     }, Adjustment {
-                         kind: Adjust::Deref(_), ..
-                     }, Adjustment {
-                         kind: Adjust::Borrow(_),
-                         ..
-                     }] = *adj3
 +//! Checks for needless address of operations (`&`)
 +//!
 +//! This lint is **warn** by default
 +
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::source::{snippet_opt, snippet_with_applicability, snippet_with_context};
 +use clippy_utils::{get_parent_expr, in_macro, path_to_local};
 +use if_chain::if_chain;
 +use rustc_ast::util::parser::PREC_POSTFIX;
 +use rustc_data_structures::fx::FxIndexMap;
 +use rustc_errors::Applicability;
 +use rustc_hir::{BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty;
 +use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::Span;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for address of operations (`&`) that are going to
 +    /// be dereferenced immediately by the compiler.
 +    ///
 +    /// ### Why is this bad?
 +    /// Suggests that the receiver of the expression borrows
 +    /// the expression.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// fn fun(_a: &i32) {}
 +    ///
 +    /// // Bad
 +    /// let x: &i32 = &&&&&&5;
 +    /// fun(&x);
 +    ///
 +    /// // Good
 +    /// let x: &i32 = &5;
 +    /// fun(x);
 +    /// ```
 +    pub NEEDLESS_BORROW,
 +    style,
 +    "taking a reference that is going to be automatically dereferenced"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `ref` bindings which create a reference to a reference.
 +    ///
 +    /// ### Why is this bad?
 +    /// The address-of operator at the use site is clearer about the need for a reference.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let x = Some("");
 +    /// if let Some(ref x) = x {
 +    ///     // use `x` here
 +    /// }
 +    ///
 +    /// // Good
 +    /// let x = Some("");
 +    /// if let Some(x) = x {
 +    ///     // use `&x` here
 +    /// }
 +    /// ```
 +    pub REF_BINDING_TO_REFERENCE,
 +    pedantic,
 +    "`ref` binding to a reference"
 +}
 +
 +impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW, REF_BINDING_TO_REFERENCE]);
 +#[derive(Default)]
 +pub struct NeedlessBorrow {
 +    /// The body the first local was found in. Used to emit lints when the traversal of the body has
 +    /// been finished. Note we can't lint at the end of every body as they can be nested within each
 +    /// other.
 +    current_body: Option<BodyId>,
 +    /// The list of locals currently being checked by the lint.
 +    /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted.
 +    /// This is needed for or patterns where one of the branches can be linted, but another can not
 +    /// be.
 +    ///
 +    /// e.g. `m!(x) | Foo::Bar(ref x)`
 +    ref_locals: FxIndexMap<HirId, Option<RefPat>>,
 +}
 +
 +struct RefPat {
 +    /// Whether every usage of the binding is dereferenced.
 +    always_deref: bool,
 +    /// The spans of all the ref bindings for this local.
 +    spans: Vec<Span>,
 +    /// The applicability of this suggestion.
 +    app: Applicability,
 +    /// All the replacements which need to be made.
 +    replacements: Vec<(Span, String)>,
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if let Some(local) = path_to_local(e) {
 +            self.check_local_usage(cx, e, local);
 +        }
 +
 +        if e.span.from_expansion() {
 +            return;
 +        }
 +        if let ExprKind::AddrOf(BorrowKind::Ref, mutability, inner) = e.kind {
 +            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() {
 +                for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
++                    if let [
++                        Adjustment {
++                            kind: Adjust::Deref(_), ..
++                        },
++                        Adjustment {
++                            kind: Adjust::Deref(_), ..
++                        },
++                        Adjustment {
++                            kind: Adjust::Borrow(_),
++                            ..
++                        },
++                    ] = *adj3
 +                    {
 +                        let help_msg_ty = if matches!(mutability, Mutability::Not) {
 +                            format!("&{}", ty)
 +                        } else {
 +                            format!("&mut {}", ty)
 +                        };
 +
 +                        span_lint_and_then(
 +                            cx,
 +                            NEEDLESS_BORROW,
 +                            e.span,
 +                            &format!(
 +                                "this expression borrows a reference (`{}`) that is immediately dereferenced \
 +                             by the compiler",
 +                                help_msg_ty
 +                            ),
 +                            |diag| {
 +                                if let Some(snippet) = snippet_opt(cx, inner.span) {
 +                                    diag.span_suggestion(
 +                                        e.span,
 +                                        "change this to",
 +                                        snippet,
 +                                        Applicability::MachineApplicable,
 +                                    );
 +                                }
 +                            },
 +                        );
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
 +        if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind {
 +            if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) {
 +                // This binding id has been seen before. Add this pattern to the list of changes.
 +                if let Some(prev_pat) = opt_prev_pat {
 +                    if in_macro(pat.span) {
 +                        // Doesn't match the context of the previous pattern. Can't lint here.
 +                        *opt_prev_pat = None;
 +                    } else {
 +                        prev_pat.spans.push(pat.span);
 +                        prev_pat.replacements.push((
 +                            pat.span,
 +                            snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut prev_pat.app)
 +                                .0
 +                                .into(),
 +                        ));
 +                    }
 +                }
 +                return;
 +            }
 +
 +            if_chain! {
 +                if !in_macro(pat.span);
 +                if let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind();
 +                // only lint immutable refs, because borrowed `&mut T` cannot be moved out
 +                if let ty::Ref(_, _, Mutability::Not) = *tam.kind();
 +                then {
 +                    let mut app = Applicability::MachineApplicable;
 +                    let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0;
 +                    self.current_body = self.current_body.or(cx.enclosing_body);
 +                    self.ref_locals.insert(
 +                        id,
 +                        Some(RefPat {
 +                            always_deref: true,
 +                            spans: vec![pat.span],
 +                            app,
 +                            replacements: vec![(pat.span, snip.into())],
 +                        }),
 +                    );
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
 +        if Some(body.id()) == self.current_body {
 +            for pat in self.ref_locals.drain(..).filter_map(|(_, x)| x) {
 +                let replacements = pat.replacements;
 +                let app = pat.app;
 +                span_lint_and_then(
 +                    cx,
 +                    if pat.always_deref {
 +                        NEEDLESS_BORROW
 +                    } else {
 +                        REF_BINDING_TO_REFERENCE
 +                    },
 +                    pat.spans,
 +                    "this pattern creates a reference to a reference",
 +                    |diag| {
 +                        diag.multipart_suggestion("try this", replacements, app);
 +                    },
 +                );
 +            }
 +            self.current_body = None;
 +        }
 +    }
 +}
 +impl NeedlessBorrow {
 +    fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, local: HirId) {
 +        if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
 +            if let Some(pat) = outer_pat {
 +                // Check for auto-deref
 +                if !matches!(
 +                    cx.typeck_results().expr_adjustments(e),
 +                    [
 +                        Adjustment {
 +                            kind: Adjust::Deref(_),
 +                            ..
 +                        },
 +                        Adjustment {
 +                            kind: Adjust::Deref(_),
 +                            ..
 +                        },
 +                        ..
 +                    ]
 +                ) {
 +                    match get_parent_expr(cx, e) {
 +                        // Field accesses are the same no matter the number of references.
 +                        Some(Expr {
 +                            kind: ExprKind::Field(..),
 +                            ..
 +                        }) => (),
 +                        Some(&Expr {
 +                            span,
 +                            kind: ExprKind::Unary(UnOp::Deref, _),
 +                            ..
 +                        }) if !in_macro(span) => {
 +                            // Remove explicit deref.
 +                            let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0;
 +                            pat.replacements.push((span, snip.into()));
 +                        },
 +                        Some(parent) if !in_macro(parent.span) => {
 +                            // Double reference might be needed at this point.
 +                            if parent.precedence().order() == PREC_POSTFIX {
 +                                // Parentheses would be needed here, don't lint.
 +                                *outer_pat = None;
 +                            } else {
 +                                pat.always_deref = false;
 +                                let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0;
 +                                pat.replacements.push((e.span, format!("&{}", snip)));
 +                            }
 +                        },
 +                        _ if !in_macro(e.span) => {
 +                            // Double reference might be needed at this point.
 +                            pat.always_deref = false;
 +                            let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app);
 +                            pat.replacements.push((e.span, format!("&{}", snip)));
 +                        },
 +                        // Edge case for macros. The span of the identifier will usually match the context of the
 +                        // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc
 +                        // macros
 +                        _ => *outer_pat = None,
 +                    }
 +                }
 +            }
 +        }
 +    }
 +}
index 374b7bd59649e87db0f8ffbbdb22f1ae0b015309,0000000000000000000000000000000000000000..7ebf84d400f569c3f891bc7d417afeeb2d741167
mode 100644,000000..100644
--- /dev/null
@@@ -1,238 -1,0 +1,238 @@@
-     nursery,
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::is_lint_allowed;
 +use clippy_utils::source::snippet;
 +use clippy_utils::ty::{implements_trait, is_copy};
 +use rustc_ast::ImplPolarity;
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::{FieldDef, Item, ItemKind, Node};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Warns about fields in struct implementing `Send` that are neither `Send` nor `Copy`.
 +    ///
 +    /// ### Why is this bad?
 +    /// Sending the struct to another thread will transfer the ownership to
 +    /// the new thread by dropping in the current thread during the transfer.
 +    /// This causes soundness issues for non-`Send` fields, as they are also
 +    /// dropped and might not be set up to handle this.
 +    ///
 +    /// See:
 +    /// * [*The Rustonomicon* about *Send and Sync*](https://doc.rust-lang.org/nomicon/send-and-sync.html)
 +    /// * [The documentation of `Send`](https://doc.rust-lang.org/std/marker/trait.Send.html)
 +    ///
 +    /// ### Known Problems
 +    /// Data structures that contain raw pointers may cause false positives.
 +    /// They are sometimes safe to be sent across threads but do not implement
 +    /// the `Send` trait. This lint has a heuristic to filter out basic cases
 +    /// such as `Vec<*const T>`, but it's not perfect. Feel free to create an
 +    /// issue if you have a suggestion on how this heuristic can be improved.
 +    ///
 +    /// ### Example
 +    /// ```rust,ignore
 +    /// struct ExampleStruct<T> {
 +    ///     rc_is_not_send: Rc<String>,
 +    ///     unbounded_generic_field: T,
 +    /// }
 +    ///
 +    /// // This impl is unsound because it allows sending `!Send` types through `ExampleStruct`
 +    /// unsafe impl<T> Send for ExampleStruct<T> {}
 +    /// ```
 +    /// Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html)
 +    /// or specify correct bounds on generic type parameters (`T: Send`).
 +    pub NON_SEND_FIELDS_IN_SEND_TY,
++    suspicious,
 +    "there is field that does not implement `Send` in a `Send` struct"
 +}
 +
 +#[derive(Copy, Clone)]
 +pub struct NonSendFieldInSendTy {
 +    enable_raw_pointer_heuristic: bool,
 +}
 +
 +impl NonSendFieldInSendTy {
 +    pub fn new(enable_raw_pointer_heuristic: bool) -> Self {
 +        Self {
 +            enable_raw_pointer_heuristic,
 +        }
 +    }
 +}
 +
 +impl_lint_pass!(NonSendFieldInSendTy => [NON_SEND_FIELDS_IN_SEND_TY]);
 +
 +impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        let ty_allowed_in_send = if self.enable_raw_pointer_heuristic {
 +            ty_allowed_with_raw_pointer_heuristic
 +        } else {
 +            ty_allowed_without_raw_pointer_heuristic
 +        };
 +
 +        // Checks if we are in `Send` impl item.
 +        // We start from `Send` impl instead of `check_field_def()` because
 +        // single `AdtDef` may have multiple `Send` impls due to generic
 +        // parameters, and the lint is much easier to implement in this way.
 +        if_chain! {
 +            if let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send);
 +            if let ItemKind::Impl(hir_impl) = &item.kind;
 +            if let Some(trait_ref) = &hir_impl.of_trait;
 +            if let Some(trait_id) = trait_ref.trait_def_id();
 +            if send_trait == trait_id;
 +            if hir_impl.polarity == ImplPolarity::Positive;
 +            if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.def_id);
 +            if let self_ty = ty_trait_ref.self_ty();
 +            if let ty::Adt(adt_def, impl_trait_substs) = self_ty.kind();
 +            then {
 +                let mut non_send_fields = Vec::new();
 +
 +                let hir_map = cx.tcx.hir();
 +                for variant in &adt_def.variants {
 +                    for field in &variant.fields {
 +                        if_chain! {
 +                            if let Some(field_hir_id) = field
 +                                .did
 +                                .as_local()
 +                                .map(|local_def_id| hir_map.local_def_id_to_hir_id(local_def_id));
 +                            if !is_lint_allowed(cx, NON_SEND_FIELDS_IN_SEND_TY, field_hir_id);
 +                            if let field_ty = field.ty(cx.tcx, impl_trait_substs);
 +                            if !ty_allowed_in_send(cx, field_ty, send_trait);
 +                            if let Node::Field(field_def) = hir_map.get(field_hir_id);
 +                            then {
 +                                non_send_fields.push(NonSendField {
 +                                    def: field_def,
 +                                    ty: field_ty,
 +                                    generic_params: collect_generic_params(cx, field_ty),
 +                                })
 +                            }
 +                        }
 +                    }
 +                }
 +
 +                if !non_send_fields.is_empty() {
 +                    span_lint_and_then(
 +                        cx,
 +                        NON_SEND_FIELDS_IN_SEND_TY,
 +                        item.span,
 +                        &format!(
 +                            "this implementation is unsound, as some fields in `{}` are `!Send`",
 +                            snippet(cx, hir_impl.self_ty.span, "Unknown")
 +                        ),
 +                        |diag| {
 +                            for field in non_send_fields {
 +                                diag.span_note(
 +                                    field.def.span,
 +                                    &format!("the type of field `{}` is `!Send`", field.def.ident.name),
 +                                );
 +
 +                                match field.generic_params.len() {
 +                                    0 => diag.help("use a thread-safe type that implements `Send`"),
 +                                    1 if is_ty_param(field.ty) => diag.help(&format!("add `{}: Send` bound in `Send` impl", field.ty)),
 +                                    _ => diag.help(&format!(
 +                                        "add bounds on type parameter{} `{}` that satisfy `{}: Send`",
 +                                        if field.generic_params.len() > 1 { "s" } else { "" },
 +                                        field.generic_params_string(),
 +                                        snippet(cx, field.def.ty.span, "Unknown"),
 +                                    )),
 +                                };
 +                            }
 +                        },
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +struct NonSendField<'tcx> {
 +    def: &'tcx FieldDef<'tcx>,
 +    ty: Ty<'tcx>,
 +    generic_params: Vec<Ty<'tcx>>,
 +}
 +
 +impl<'tcx> NonSendField<'tcx> {
 +    fn generic_params_string(&self) -> String {
 +        self.generic_params
 +            .iter()
 +            .map(ToString::to_string)
 +            .collect::<Vec<_>>()
 +            .join(", ")
 +    }
 +}
 +
 +/// Given a type, collect all of its generic parameters.
 +/// Example: `MyStruct<P, Box<Q, R>>` => `vec![P, Q, R]`
 +fn collect_generic_params<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Vec<Ty<'tcx>> {
 +    ty.walk(cx.tcx)
 +        .filter_map(|inner| match inner.unpack() {
 +            GenericArgKind::Type(inner_ty) => Some(inner_ty),
 +            _ => None,
 +        })
 +        .filter(|&inner_ty| is_ty_param(inner_ty))
 +        .collect()
 +}
 +
 +/// Be more strict when the heuristic is disabled
 +fn ty_allowed_without_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, send_trait: DefId) -> bool {
 +    if implements_trait(cx, ty, send_trait, &[]) {
 +        return true;
 +    }
 +
 +    if is_copy(cx, ty) && !contains_raw_pointer(cx, ty) {
 +        return true;
 +    }
 +
 +    false
 +}
 +
 +/// Heuristic to allow cases like `Vec<*const u8>`
 +fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, send_trait: DefId) -> bool {
 +    if implements_trait(cx, ty, send_trait, &[]) || is_copy(cx, ty) {
 +        return true;
 +    }
 +
 +    // The type is known to be `!Send` and `!Copy`
 +    match ty.kind() {
 +        ty::Tuple(_) => ty
 +            .tuple_fields()
 +            .all(|ty| ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait)),
 +        ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
 +        ty::Adt(_, substs) => {
 +            if contains_raw_pointer(cx, ty) {
 +                // descends only if ADT contains any raw pointers
 +                substs.iter().all(|generic_arg| match generic_arg.unpack() {
 +                    GenericArgKind::Type(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
 +                    // Lifetimes and const generics are not solid part of ADT and ignored
 +                    GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => true,
 +                })
 +            } else {
 +                false
 +            }
 +        },
 +        // Raw pointers are `!Send` but allowed by the heuristic
 +        ty::RawPtr(_) => true,
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the type contains any raw pointers in substs (including nested ones).
 +fn contains_raw_pointer<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> bool {
 +    for ty_node in target_ty.walk(cx.tcx) {
 +        if_chain! {
 +            if let GenericArgKind::Type(inner_ty) = ty_node.unpack();
 +            if let ty::RawPtr(_) = inner_ty.kind();
 +            then {
 +                return true;
 +            }
 +        }
 +    }
 +
 +    false
 +}
 +
 +/// Returns `true` if the type is a type parameter such as `T`.
 +fn is_ty_param(target_ty: Ty<'_>) -> bool {
 +    matches!(target_ty.kind(), ty::Param(_))
 +}
index a62eb0699891bf583fc94e13a6e38629b533f877,0000000000000000000000000000000000000000..cbe1c5d44d513044d745718518c69876f69a10f3
mode 100644,000000..100644
--- /dev/null
@@@ -1,212 -1,0 +1,212 @@@
-     /// Using the dedicated functions of the Option type is clearer and
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::higher;
 +use clippy_utils::sugg::Sugg;
 +use clippy_utils::ty::is_type_diagnostic_item;
 +use clippy_utils::{
 +    can_move_expr_to_closure, eager_or_lazy, in_constant, in_macro, is_else_clause, is_lang_ctor, peel_hir_expr_while,
 +    CaptureKind,
 +};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::LangItem::OptionSome;
 +use rustc_hir::{def::Res, BindingAnnotation, Block, Expr, ExprKind, Mutability, PatKind, Path, QPath, UnOp};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Lints usage of `if let Some(v) = ... { y } else { x }` which is more
 +    /// idiomatically done with `Option::map_or` (if the else bit is a pure
 +    /// expression) or `Option::map_or_else` (if the else bit is an impure
 +    /// expression).
 +    ///
 +    /// ### Why is this bad?
++    /// Using the dedicated functions of the `Option` type is clearer and
 +    /// more concise than an `if let` expression.
 +    ///
 +    /// ### Known problems
 +    /// This lint uses a deliberately conservative metric for checking
 +    /// if the inside of either body contains breaks or continues which will
 +    /// cause it to not suggest a fix if either block contains a loop with
 +    /// continues or breaks contained within the loop.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// # let optional: Option<u32> = Some(0);
 +    /// # fn do_complicated_function() -> u32 { 5 };
 +    /// let _ = if let Some(foo) = optional {
 +    ///     foo
 +    /// } else {
 +    ///     5
 +    /// };
 +    /// let _ = if let Some(foo) = optional {
 +    ///     foo
 +    /// } else {
 +    ///     let y = do_complicated_function();
 +    ///     y*y
 +    /// };
 +    /// ```
 +    ///
 +    /// should be
 +    ///
 +    /// ```rust
 +    /// # let optional: Option<u32> = Some(0);
 +    /// # fn do_complicated_function() -> u32 { 5 };
 +    /// let _ = optional.map_or(5, |foo| foo);
 +    /// let _ = optional.map_or_else(||{
 +    ///     let y = do_complicated_function();
 +    ///     y*y
 +    /// }, |foo| foo);
 +    /// ```
 +    pub OPTION_IF_LET_ELSE,
 +    nursery,
 +    "reimplementation of Option::map_or"
 +}
 +
 +declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]);
 +
 +/// Returns true iff the given expression is the result of calling `Result::ok`
 +fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
 +    if let ExprKind::MethodCall(path, _, &[ref receiver], _) = &expr.kind {
 +        path.ident.name.as_str() == "ok"
 +            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::Result)
 +    } else {
 +        false
 +    }
 +}
 +
 +/// A struct containing information about occurrences of the
 +/// `if let Some(..) = .. else` construct that this lint detects.
 +struct OptionIfLetElseOccurence {
 +    option: String,
 +    method_sugg: String,
 +    some_expr: String,
 +    none_expr: String,
 +}
 +
 +/// Extracts the body of a given arm. If the arm contains only an expression,
 +/// then it returns the expression. Otherwise, it returns the entire block
 +fn extract_body_from_expr<'a>(expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
 +    if let ExprKind::Block(
 +        Block {
 +            stmts: block_stmts,
 +            expr: Some(block_expr),
 +            ..
 +        },
 +        _,
 +    ) = expr.kind
 +    {
 +        if let [] = block_stmts {
 +            Some(block_expr)
 +        } else {
 +            Some(expr)
 +        }
 +    } else {
 +        None
 +    }
 +}
 +
 +fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String {
 +    format!(
 +        "{}{}",
 +        Sugg::hir(cx, cond_expr, "..").maybe_par(),
 +        if as_mut {
 +            ".as_mut()"
 +        } else if as_ref {
 +            ".as_ref()"
 +        } else {
 +            ""
 +        }
 +    )
 +}
 +
 +/// If this expression is the option if let/else construct we're detecting, then
 +/// this function returns an `OptionIfLetElseOccurence` struct with details if
 +/// this construct is found, or None if this construct is not found.
 +fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionIfLetElseOccurence> {
 +    if_chain! {
 +        if !in_macro(expr.span); // Don't lint macros, because it behaves weirdly
 +        if !in_constant(cx, expr.hir_id);
 +        if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) })
 +            = higher::IfLet::hir(cx, expr);
 +        if !is_else_clause(cx.tcx, expr);
 +        if !is_result_ok(cx, let_expr); // Don't lint on Result::ok because a different lint does it already
 +        if let PatKind::TupleStruct(struct_qpath, [inner_pat], _) = &let_pat.kind;
 +        if is_lang_ctor(cx, struct_qpath, OptionSome);
 +        if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind;
 +        if let Some(some_captures) = can_move_expr_to_closure(cx, if_then);
 +        if let Some(none_captures) = can_move_expr_to_closure(cx, if_else);
 +        if some_captures
 +            .iter()
 +            .filter_map(|(id, &c)| none_captures.get(id).map(|&c2| (c, c2)))
 +            .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref());
 +
 +        then {
 +            let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
 +            let some_body = extract_body_from_expr(if_then)?;
 +            let none_body = extract_body_from_expr(if_else)?;
 +            let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) {
 +                "map_or"
 +            } else {
 +                "map_or_else"
 +            };
 +            let capture_name = id.name.to_ident_string();
 +            let (as_ref, as_mut) = match &let_expr.kind {
 +                ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
 +                ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true),
 +                _ => (bind_annotation == &BindingAnnotation::Ref, bind_annotation == &BindingAnnotation::RefMut),
 +            };
 +            let cond_expr = match let_expr.kind {
 +                // Pointer dereferencing happens automatically, so we can omit it in the suggestion
 +                ExprKind::Unary(UnOp::Deref, expr) | ExprKind::AddrOf(_, _, expr) => expr,
 +                _ => let_expr,
 +            };
 +            // Check if captures the closure will need conflict with borrows made in the scrutinee.
 +            // TODO: check all the references made in the scrutinee expression. This will require interacting
 +            // with the borrow checker. Currently only `<local>[.<field>]*` is checked for.
 +            if as_ref || as_mut {
 +                let e = peel_hir_expr_while(cond_expr, |e| match e.kind {
 +                    ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e),
 +                    _ => None,
 +                });
 +                if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(local_id), .. })) = e.kind {
 +                    match some_captures.get(local_id)
 +                        .or_else(|| (method_sugg == "map_or_else").then(|| ()).and_then(|_| none_captures.get(local_id)))
 +                    {
 +                        Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None,
 +                        Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None,
 +                        Some(CaptureKind::Ref(Mutability::Not)) | None => (),
 +                    }
 +                }
 +            }
 +            Some(OptionIfLetElseOccurence {
 +                option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut),
 +                method_sugg: method_sugg.to_string(),
 +                some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir(cx, some_body, "..")),
 +                none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir(cx, none_body, "..")),
 +            })
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
 +        if let Some(detection) = detect_option_if_let_else(cx, expr) {
 +            span_lint_and_sugg(
 +                cx,
 +                OPTION_IF_LET_ELSE,
 +                expr.span,
 +                format!("use Option::{} instead of an if let/else", detection.method_sugg).as_str(),
 +                "try",
 +                format!(
 +                    "{}.{}({}, {})",
 +                    detection.option, detection.method_sugg, detection.none_expr, detection.some_expr,
 +                ),
 +                Applicability::MaybeIncorrect,
 +            );
 +        }
 +    }
 +}
index 92a4801a8468ae3d3e592212280e8dd7959c9bc5,0000000000000000000000000000000000000000..8a36e20fc973d678297d14718039e8913af8acc7
mode 100644,000000..100644
--- /dev/null
@@@ -1,434 -1,0 +1,445 @@@
- use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty};
 +//! Checks for usage of  `&Vec[_]` and `&String`.
 +
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 +use clippy_utils::ptr::get_spans;
 +use clippy_utils::source::snippet_opt;
-     BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, Impl, ImplItem, ImplItemKind, Item,
-     ItemKind, Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
++use clippy_utils::ty::walk_ptrs_hir_ty;
 +use clippy_utils::{expr_path_res, is_lint_allowed, match_any_diagnostic_items, paths};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
++use rustc_hir::def::Res;
 +use rustc_hir::{
- use rustc_middle::ty;
++    BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, Impl, ImplItem, ImplItemKind, Item, ItemKind,
++    Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
 +};
 +use rustc_lint::{LateContext, LateLintPass};
-             check_fn(cx, sig.decl, item.hir_id(), Some(body_id));
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +use rustc_span::symbol::Symbol;
 +use rustc_span::{sym, MultiSpan};
 +use std::borrow::Cow;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// This lint checks for function arguments of type `&String`
 +    /// or `&Vec` unless the references are mutable. It will also suggest you
 +    /// replace `.clone()` calls with the appropriate `.to_owned()`/`to_string()`
 +    /// calls.
 +    ///
 +    /// ### Why is this bad?
 +    /// Requiring the argument to be of the specific size
 +    /// makes the function less useful for no benefit; slices in the form of `&[T]`
 +    /// or `&str` usually suffice and can be obtained from other types, too.
 +    ///
 +    /// ### Known problems
 +    /// The lint does not follow data. So if you have an
 +    /// argument `x` and write `let y = x; y.clone()` the lint will not suggest
 +    /// changing that `.clone()` to `.to_owned()`.
 +    ///
 +    /// Other functions called from this function taking a `&String` or `&Vec`
 +    /// argument may also fail to compile if you change the argument. Applying
 +    /// this lint on them will fix the problem, but they may be in other crates.
 +    ///
 +    /// One notable example of a function that may cause issues, and which cannot
 +    /// easily be changed due to being in the standard library is `Vec::contains`.
 +    /// when called on a `Vec<Vec<T>>`. If a `&Vec` is passed to that method then
 +    /// it will compile, but if a `&[T]` is passed then it will not compile.
 +    ///
 +    /// ```ignore
 +    /// fn cannot_take_a_slice(v: &Vec<u8>) -> bool {
 +    ///     let vec_of_vecs: Vec<Vec<u8>> = some_other_fn();
 +    ///
 +    ///     vec_of_vecs.contains(v)
 +    /// }
 +    /// ```
 +    ///
 +    /// Also there may be `fn(&Vec)`-typed references pointing to your function.
 +    /// If you have them, you will get a compiler error after applying this lint's
 +    /// suggestions. You then have the choice to undo your changes or change the
 +    /// type of the reference.
 +    ///
 +    /// Note that if the function is part of your public interface, there may be
 +    /// other crates referencing it, of which you may not be aware. Carefully
 +    /// deprecate the function before applying the lint suggestions in this case.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// // Bad
 +    /// fn foo(&Vec<u32>) { .. }
 +    ///
 +    /// // Good
 +    /// fn foo(&[u32]) { .. }
 +    /// ```
 +    pub PTR_ARG,
 +    style,
 +    "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// This lint checks for equality comparisons with `ptr::null`
 +    ///
 +    /// ### Why is this bad?
 +    /// It's easier and more readable to use the inherent
 +    /// `.is_null()`
 +    /// method instead
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// // Bad
 +    /// if x == ptr::null {
 +    ///     ..
 +    /// }
 +    ///
 +    /// // Good
 +    /// if x.is_null() {
 +    ///     ..
 +    /// }
 +    /// ```
 +    pub CMP_NULL,
 +    style,
 +    "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// This lint checks for functions that take immutable
 +    /// references and return mutable ones.
 +    ///
 +    /// ### Why is this bad?
 +    /// This is trivially unsound, as one can create two
 +    /// mutable references from the same (immutable!) source.
 +    /// This [error](https://github.com/rust-lang/rust/issues/39465)
 +    /// actually lead to an interim Rust release 1.15.1.
 +    ///
 +    /// ### Known problems
 +    /// To be on the conservative side, if there's at least one
 +    /// mutable reference with the output lifetime, this lint will not trigger.
 +    /// In practice, this case is unlikely anyway.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// fn foo(&Foo) -> &mut Bar { .. }
 +    /// ```
 +    pub MUT_FROM_REF,
 +    correctness,
 +    "fns that create mutable refs from immutable ref args"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// This lint checks for invalid usages of `ptr::null`.
 +    ///
 +    /// ### Why is this bad?
 +    /// This causes undefined behavior.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// // Bad. Undefined behavior
 +    /// unsafe { std::slice::from_raw_parts(ptr::null(), 0); }
 +    /// ```
 +    ///
 +    /// ```ignore
 +    /// // Good
 +    /// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); }
 +    /// ```
 +    pub INVALID_NULL_PTR_USAGE,
 +    correctness,
 +    "invalid usage of a null pointer, suggesting `NonNull::dangling()` instead"
 +}
 +
 +declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, INVALID_NULL_PTR_USAGE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for Ptr {
 +    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 +        if let ItemKind::Fn(ref sig, _, body_id) = item.kind {
-             check_fn(cx, sig.decl, item.hir_id(), Some(body_id));
++            check_fn(cx, sig.decl, Some(body_id));
 +        }
 +    }
 +
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
 +        if let ImplItemKind::Fn(ref sig, body_id) = item.kind {
 +            let parent_item = cx.tcx.hir().get_parent_item(item.hir_id());
 +            if let Some(Node::Item(it)) = cx.tcx.hir().find(parent_item) {
 +                if let ItemKind::Impl(Impl { of_trait: Some(_), .. }) = it.kind {
 +                    return; // ignore trait impls
 +                }
 +            }
-             check_fn(cx, sig.decl, item.hir_id(), body_id);
++            check_fn(cx, sig.decl, Some(body_id));
 +        }
 +    }
 +
 +    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
 +        if let TraitItemKind::Fn(ref sig, ref trait_method) = item.kind {
 +            let body_id = if let TraitFn::Provided(b) = *trait_method {
 +                Some(b)
 +            } else {
 +                None
 +            };
- fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: Option<BodyId>) {
-     let fn_def_id = cx.tcx.hir().local_def_id(fn_id);
-     let sig = cx.tcx.fn_sig(fn_def_id);
-     let fn_ty = sig.skip_binder();
++            check_fn(cx, sig.decl, body_id);
 +        }
 +    }
 +
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        if let ExprKind::Binary(ref op, l, r) = expr.kind {
 +            if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(cx, l) || is_null_path(cx, r)) {
 +                span_lint(
 +                    cx,
 +                    CMP_NULL,
 +                    expr.span,
 +                    "comparing with null is better expressed by the `.is_null()` method",
 +                );
 +            }
 +        } else {
 +            check_invalid_ptr_usage(cx, expr);
 +        }
 +    }
 +}
 +
 +fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +    // (fn_path, arg_indices) - `arg_indices` are the `arg` positions where null would cause U.B.
 +    const INVALID_NULL_PTR_USAGE_TABLE: [(&[&str], &[usize]); 16] = [
 +        (&paths::SLICE_FROM_RAW_PARTS, &[0]),
 +        (&paths::SLICE_FROM_RAW_PARTS_MUT, &[0]),
 +        (&paths::PTR_COPY, &[0, 1]),
 +        (&paths::PTR_COPY_NONOVERLAPPING, &[0, 1]),
 +        (&paths::PTR_READ, &[0]),
 +        (&paths::PTR_READ_UNALIGNED, &[0]),
 +        (&paths::PTR_READ_VOLATILE, &[0]),
 +        (&paths::PTR_REPLACE, &[0]),
 +        (&paths::PTR_SLICE_FROM_RAW_PARTS, &[0]),
 +        (&paths::PTR_SLICE_FROM_RAW_PARTS_MUT, &[0]),
 +        (&paths::PTR_SWAP, &[0, 1]),
 +        (&paths::PTR_SWAP_NONOVERLAPPING, &[0, 1]),
 +        (&paths::PTR_WRITE, &[0]),
 +        (&paths::PTR_WRITE_UNALIGNED, &[0]),
 +        (&paths::PTR_WRITE_VOLATILE, &[0]),
 +        (&paths::PTR_WRITE_BYTES, &[0]),
 +    ];
 +
 +    if_chain! {
 +        if let ExprKind::Call(fun, args) = expr.kind;
 +        if let ExprKind::Path(ref qpath) = fun.kind;
 +        if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
 +        let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::<Vec<_>>();
 +        if let Some(&(_, arg_indices)) = INVALID_NULL_PTR_USAGE_TABLE
 +            .iter()
 +            .find(|&&(fn_path, _)| fn_path == fun_def_path);
 +        then {
 +            for &arg_idx in arg_indices {
 +                if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        INVALID_NULL_PTR_USAGE,
 +                        arg.span,
 +                        "pointer must be non-null",
 +                        "change this to",
 +                        "core::ptr::NonNull::dangling().as_ptr()".to_string(),
 +                        Applicability::MachineApplicable,
 +                    );
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +#[allow(clippy::too_many_lines)]
-     for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() {
++fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option<BodyId>) {
 +    let body = opt_body_id.map(|id| cx.tcx.hir().body(id));
 +
-         if let ty::Ref(_, ty, Mutability::Not) = ty.kind() {
-             if is_type_diagnostic_item(cx, ty, sym::Vec) {
++    for (idx, arg) in decl.inputs.iter().enumerate() {
 +        // Honor the allow attribute on parameters. See issue 5644.
 +        if let Some(body) = &body {
 +            if is_lint_allowed(cx, PTR_ARG, body.params[idx].hir_id) {
 +                continue;
 +            }
 +        }
 +
-             } else if is_type_diagnostic_item(cx, ty, sym::String) {
++        let (item_name, path) = if_chain! {
++            if let TyKind::Rptr(_, MutTy { ty, mutbl: Mutability::Not }) = arg.kind;
++            if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
++            if let Res::Def(_, did) = path.res;
++            if let Some(item_name) = cx.tcx.get_diagnostic_name(did);
++            then {
++                (item_name, path)
++            } else {
++                continue
++            }
++        };
++
++        match item_name {
++            sym::Vec => {
 +                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
 +                    span_lint_and_then(
 +                        cx,
 +                        PTR_ARG,
 +                        arg.span,
 +                        "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
 +                         with non-Vec-based slices",
 +                        |diag| {
 +                            if let Some(ref snippet) = get_only_generic_arg_snippet(cx, arg) {
 +                                diag.span_suggestion(
 +                                    arg.span,
 +                                    "change this to",
 +                                    format!("&[{}]", snippet),
 +                                    Applicability::Unspecified,
 +                                );
 +                            }
 +                            for (clonespan, suggestion) in spans {
 +                                diag.span_suggestion(
 +                                    clonespan,
 +                                    &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
 +                                        Cow::Owned(format!("change `{}` to", x))
 +                                    }),
 +                                    suggestion.into(),
 +                                    Applicability::Unspecified,
 +                                );
 +                            }
 +                        },
 +                    );
 +                }
-             } else if is_type_diagnostic_item(cx, ty, sym::PathBuf) {
++            },
++            sym::String => {
 +                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
 +                    span_lint_and_then(
 +                        cx,
 +                        PTR_ARG,
 +                        arg.span,
 +                        "writing `&String` instead of `&str` involves a new object where a slice will do",
 +                        |diag| {
 +                            diag.span_suggestion(arg.span, "change this to", "&str".into(), Applicability::Unspecified);
 +                            for (clonespan, suggestion) in spans {
 +                                diag.span_suggestion_short(
 +                                    clonespan,
 +                                    &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
 +                                        Cow::Owned(format!("change `{}` to", x))
 +                                    }),
 +                                    suggestion.into(),
 +                                    Applicability::Unspecified,
 +                                );
 +                            }
 +                        },
 +                    );
 +                }
-             } else if match_type(cx, ty, &paths::COW) {
++            },
++            sym::PathBuf => {
 +                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) {
 +                    span_lint_and_then(
 +                        cx,
 +                        PTR_ARG,
 +                        arg.span,
 +                        "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do",
 +                        |diag| {
 +                            diag.span_suggestion(
 +                                arg.span,
 +                                "change this to",
 +                                "&Path".into(),
 +                                Applicability::Unspecified,
 +                            );
 +                            for (clonespan, suggestion) in spans {
 +                                diag.span_suggestion_short(
 +                                    clonespan,
 +                                    &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
 +                                        Cow::Owned(format!("change `{}` to", x))
 +                                    }),
 +                                    suggestion.into(),
 +                                    Applicability::Unspecified,
 +                                );
 +                            }
 +                        },
 +                    );
 +                }
-                     if let TyKind::Rptr(_, MutTy { ty, ..} ) = arg.kind;
-                     if let TyKind::Path(QPath::Resolved(None, pp)) = ty.kind;
-                     if let [ref bx] = *pp.segments;
++            },
++            sym::Cow => {
 +                if_chain! {
-             }
++                    if let [ref bx] = *path.segments;
 +                    if let Some(params) = bx.args;
 +                    if !params.parenthesized;
 +                    if let Some(inner) = params.args.iter().find_map(|arg| match arg {
 +                        GenericArg::Type(ty) => Some(ty),
 +                        _ => None,
 +                    });
 +                    let replacement = snippet_opt(cx, inner.span);
 +                    if let Some(r) = replacement;
 +                    then {
 +                        span_lint_and_sugg(
 +                            cx,
 +                            PTR_ARG,
 +                            arg.span,
 +                            "using a reference to `Cow` is not recommended",
 +                            "change this to",
 +                            "&".to_owned() + &r,
 +                            Applicability::Unspecified,
 +                        );
 +                    }
 +                }
++            },
++            _ => {},
 +        }
 +    }
 +
 +    if let FnRetTy::Return(ty) = decl.output {
 +        if let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty) {
 +            let mut immutables = vec![];
 +            for (_, ref mutbl, ref argspan) in decl
 +                .inputs
 +                .iter()
 +                .filter_map(get_rptr_lm)
 +                .filter(|&(lt, _, _)| lt.name == out.name)
 +            {
 +                if *mutbl == Mutability::Mut {
 +                    return;
 +                }
 +                immutables.push(*argspan);
 +            }
 +            if immutables.is_empty() {
 +                return;
 +            }
 +            span_lint_and_then(
 +                cx,
 +                MUT_FROM_REF,
 +                ty.span,
 +                "mutable borrow from immutable input(s)",
 +                |diag| {
 +                    let ms = MultiSpan::from_spans(immutables);
 +                    diag.span_note(ms, "immutable borrow here");
 +                },
 +            );
 +        }
 +    }
 +}
 +
 +fn get_only_generic_arg_snippet(cx: &LateContext<'_>, arg: &Ty<'_>) -> Option<String> {
 +    if_chain! {
 +        if let TyKind::Path(QPath::Resolved(_, path)) = walk_ptrs_hir_ty(arg).kind;
 +        if let Some(&PathSegment{args: Some(parameters), ..}) = path.segments.last();
 +        let types: Vec<_> = parameters.args.iter().filter_map(|arg| match arg {
 +            GenericArg::Type(ty) => Some(ty),
 +            _ => None,
 +        }).collect();
 +        if types.len() == 1;
 +        then {
 +            snippet_opt(cx, types[0].span)
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
 +    if let TyKind::Rptr(ref lt, ref m) = ty.kind {
 +        Some((lt, m.mutbl, ty.span))
 +    } else {
 +        None
 +    }
 +}
 +
 +fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    if let ExprKind::Call(pathexp, []) = expr.kind {
 +        expr_path_res(cx, pathexp).opt_def_id().map_or(false, |id| {
 +            match_any_diagnostic_items(cx, id, &[sym::ptr_null, sym::ptr_null_mut]).is_some()
 +        })
 +    } else {
 +        false
 +    }
 +}
index 4d616e26bfc1da1dab23a26aaaf0dcbc3b009cf5,0000000000000000000000000000000000000000..f63ef163bcbd0f1b76ddfd92fcac4d38b50a48bc
mode 100644,000000..100644
--- /dev/null
@@@ -1,227 -1,0 +1,221 @@@
-     fn expression_returns_unmodified_err(
-         cx: &LateContext<'_>,
-         expression: &Expr<'_>,
-         origin_hir_id: &Expr<'_>,
-     ) -> bool {
-         match expression.kind {
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::higher;
 +use clippy_utils::is_lang_ctor;
 +use clippy_utils::source::snippet_with_applicability;
 +use clippy_utils::sugg::Sugg;
 +use clippy_utils::ty::is_type_diagnostic_item;
 +use clippy_utils::{eq_expr_value, path_to_local, path_to_local_id};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::LangItem::{OptionNone, OptionSome, ResultOk};
 +use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, PatKind, StmtKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for expressions that could be replaced by the question mark operator.
 +    ///
 +    /// ### Why is this bad?
 +    /// Question mark usage is more idiomatic.
 +    ///
 +    /// ### Example
 +    /// ```ignore
 +    /// if option.is_none() {
 +    ///     return None;
 +    /// }
 +    /// ```
 +    ///
 +    /// Could be written:
 +    ///
 +    /// ```ignore
 +    /// option?;
 +    /// ```
 +    pub QUESTION_MARK,
 +    style,
 +    "checks for expressions that could be replaced by the question mark operator"
 +}
 +
 +declare_lint_pass!(QuestionMark => [QUESTION_MARK]);
 +
 +impl QuestionMark {
 +    /// Checks if the given expression on the given context matches the following structure:
 +    ///
 +    /// ```ignore
 +    /// if option.is_none() {
 +    ///    return None;
 +    /// }
 +    /// ```
 +    ///
 +    /// ```ignore
 +    /// if result.is_err() {
 +    ///     return result;
 +    /// }
 +    /// ```
 +    ///
 +    /// If it matches, it will suggest to use the question mark operator instead
 +    fn check_is_none_or_err_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>) {
 +        if_chain! {
 +            if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
 +            if let ExprKind::MethodCall(segment, _, args, _) = &cond.kind;
 +            if let Some(subject) = args.get(0);
 +            if (Self::option_check_and_early_return(cx, subject, then) && segment.ident.name == sym!(is_none)) ||
 +                (Self::result_check_and_early_return(cx, subject, then) && segment.ident.name == sym!(is_err));
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                let receiver_str = &Sugg::hir_with_applicability(cx, subject, "..", &mut applicability);
 +                let mut replacement: Option<String> = None;
 +                if let Some(else_inner) = r#else {
 +                    if_chain! {
 +                        if let ExprKind::Block(block, None) = &else_inner.kind;
 +                        if block.stmts.is_empty();
 +                        if let Some(block_expr) = &block.expr;
 +                        if eq_expr_value(cx, subject, block_expr);
 +                        then {
 +                            replacement = Some(format!("Some({}?)", receiver_str));
 +                        }
 +                    }
 +                } else if Self::moves_by_default(cx, subject)
 +                    && !matches!(subject.kind, ExprKind::Call(..) | ExprKind::MethodCall(..))
 +                {
 +                    replacement = Some(format!("{}.as_ref()?;", receiver_str));
 +                } else {
 +                    replacement = Some(format!("{}?;", receiver_str));
 +                }
 +
 +                if let Some(replacement_str) = replacement {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        QUESTION_MARK,
 +                        expr.span,
 +                        "this block may be rewritten with the `?` operator",
 +                        "replace it with",
 +                        replacement_str,
 +                        applicability,
 +                    );
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_if_let_some_or_err_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>) {
 +        if_chain! {
 +            if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) })
 +                = higher::IfLet::hir(cx, expr);
 +            if let PatKind::TupleStruct(ref path1, fields, None) = let_pat.kind;
 +            if (Self::option_check_and_early_return(cx, let_expr, if_else) && is_lang_ctor(cx, path1, OptionSome)) ||
 +                (Self::result_check_and_early_return(cx, let_expr, if_else) && is_lang_ctor(cx, path1, ResultOk));
 +
 +            if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind;
 +            let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
 +            if let ExprKind::Block(block, None) = if_then.kind;
 +            if block.stmts.is_empty();
 +            if let Some(trailing_expr) = &block.expr;
 +            if path_to_local_id(trailing_expr, bind_id);
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
 +                let replacement = format!("{}{}?", receiver_str, if by_ref { ".as_ref()" } else { "" },);
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    QUESTION_MARK,
 +                    expr.span,
 +                    "this if-let-else may be rewritten with the `?` operator",
 +                    "replace it with",
 +                    replacement,
 +                    applicability,
 +                );
 +            }
 +        }
 +    }
 +
 +    fn result_check_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>, nested_expr: &Expr<'_>) -> bool {
 +        Self::is_result(cx, expr) && Self::expression_returns_unmodified_err(cx, nested_expr, expr)
 +    }
 +
 +    fn option_check_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>, nested_expr: &Expr<'_>) -> bool {
 +        Self::is_option(cx, expr) && Self::expression_returns_none(cx, nested_expr)
 +    }
 +
 +    fn moves_by_default(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
 +        let expr_ty = cx.typeck_results().expr_ty(expression);
 +
 +        !expr_ty.is_copy_modulo_regions(cx.tcx.at(expression.span), cx.param_env)
 +    }
 +
 +    fn is_option(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
 +        let expr_ty = cx.typeck_results().expr_ty(expression);
 +
 +        is_type_diagnostic_item(cx, expr_ty, sym::Option)
 +    }
 +
 +    fn is_result(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
 +        let expr_ty = cx.typeck_results().expr_ty(expression);
 +
 +        is_type_diagnostic_item(cx, expr_ty, sym::Result)
 +    }
 +
 +    fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
 +        match expression.kind {
 +            ExprKind::Block(block, _) => {
 +                if let Some(return_expression) = Self::return_expression(block) {
 +                    return Self::expression_returns_none(cx, return_expression);
 +                }
 +
 +                false
 +            },
 +            ExprKind::Ret(Some(expr)) => Self::expression_returns_none(cx, expr),
 +            ExprKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
 +            _ => false,
 +        }
 +    }
 +
-                     return Self::expression_returns_unmodified_err(cx, return_expression, origin_hir_id);
++    fn expression_returns_unmodified_err(cx: &LateContext<'_>, expr: &Expr<'_>, cond_expr: &Expr<'_>) -> bool {
++        match expr.kind {
 +            ExprKind::Block(block, _) => {
 +                if let Some(return_expression) = Self::return_expression(block) {
-             ExprKind::Ret(Some(expr)) | ExprKind::Call(expr, _) => {
-                 Self::expression_returns_unmodified_err(cx, expr, origin_hir_id)
-             },
-             ExprKind::Path(_) => path_to_local(expression) == path_to_local(origin_hir_id),
++                    return Self::expression_returns_unmodified_err(cx, return_expression, cond_expr);
 +                }
 +
 +                false
 +            },
++            ExprKind::Ret(Some(ret_expr)) => Self::expression_returns_unmodified_err(cx, ret_expr, cond_expr),
++            ExprKind::Path(_) => path_to_local(expr) == path_to_local(cond_expr),
 +            _ => false,
 +        }
 +    }
 +
 +    fn return_expression<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 +        // Check if last expression is a return statement. Then, return the expression
 +        if_chain! {
 +            if block.stmts.len() == 1;
 +            if let Some(expr) = block.stmts.iter().last();
 +            if let StmtKind::Semi(expr) = expr.kind;
 +            if let ExprKind::Ret(Some(ret_expr)) = expr.kind;
 +
 +            then {
 +                return Some(ret_expr);
 +            }
 +        }
 +
 +        // Check for `return` without a semicolon.
 +        if_chain! {
 +            if block.stmts.is_empty();
 +            if let Some(ExprKind::Ret(Some(ret_expr))) = block.expr.as_ref().map(|e| &e.kind);
 +            then {
 +                return Some(ret_expr);
 +            }
 +        }
 +
 +        None
 +    }
 +}
 +
 +impl<'tcx> LateLintPass<'tcx> for QuestionMark {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 +        Self::check_is_none_or_err_and_early_return(cx, expr);
 +        Self::check_if_let_some_or_err_and_early_return(cx, expr);
 +    }
 +}
index 35b6bde56964c17f64c1f711dae4ed77fe9839d0,0000000000000000000000000000000000000000..6435107b8b4643f02f94078b7fe0c70802458d56
mode 100644,000000..100644
--- /dev/null
@@@ -1,413 -1,0 +1,449 @@@
- declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]);
 +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
 +use clippy_utils::source::{snippet, snippet_with_applicability};
 +use clippy_utils::ty::is_type_diagnostic_item;
 +use clippy_utils::SpanlessEq;
 +use clippy_utils::{get_parent_expr, is_lint_allowed, match_function_call, method_calls, paths};
 +use if_chain::if_chain;
 +use rustc_errors::Applicability;
 +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath};
 +use rustc_lint::{LateContext, LateLintPass, LintContext};
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Spanned;
 +use rustc_span::sym;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for string appends of the form `x = x + y` (without
 +    /// `let`!).
 +    ///
 +    /// ### Why is this bad?
 +    /// It's not really bad, but some people think that the
 +    /// `.push_str(_)` method is more readable.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let mut x = "Hello".to_owned();
 +    /// x = x + ", World";
 +    ///
 +    /// // More readable
 +    /// x += ", World";
 +    /// x.push_str(", World");
 +    /// ```
 +    pub STRING_ADD_ASSIGN,
 +    pedantic,
 +    "using `x = x + ..` where x is a `String` instead of `push_str()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for all instances of `x + _` where `x` is of type
 +    /// `String`, but only if [`string_add_assign`](#string_add_assign) does *not*
 +    /// match.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's not bad in and of itself. However, this particular
 +    /// `Add` implementation is asymmetric (the other operand need not be `String`,
 +    /// but `x` does), while addition as mathematically defined is symmetric, also
 +    /// the `String::push_str(_)` function is a perfectly good replacement.
 +    /// Therefore, some dislike it and wish not to have it in their code.
 +    ///
 +    /// That said, other people think that string addition, having a long tradition
 +    /// in other languages is actually fine, which is why we decided to make this
 +    /// particular lint `allow` by default.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = "Hello".to_owned();
 +    /// x + ", World";
 +    /// ```
 +    pub STRING_ADD,
 +    restriction,
 +    "using `x + ..` where x is a `String` instead of `push_str()`"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for the `as_bytes` method called on string literals
 +    /// that contain only ASCII characters.
 +    ///
 +    /// ### Why is this bad?
 +    /// Byte string literals (e.g., `b"foo"`) can be used
 +    /// instead. They are shorter but less discoverable than `as_bytes()`.
 +    ///
 +    /// ### Known problems
 +    /// `"str".as_bytes()` and the suggested replacement of `b"str"` are not
 +    /// equivalent because they have different types. The former is `&[u8]`
 +    /// while the latter is `&[u8; 3]`. That means in general they will have a
 +    /// different set of methods and different trait implementations.
 +    ///
 +    /// ```compile_fail
 +    /// fn f(v: Vec<u8>) {}
 +    ///
 +    /// f("...".as_bytes().to_owned()); // works
 +    /// f(b"...".to_owned()); // does not work, because arg is [u8; 3] not Vec<u8>
 +    ///
 +    /// fn g(r: impl std::io::Read) {}
 +    ///
 +    /// g("...".as_bytes()); // works
 +    /// g(b"..."); // does not work
 +    /// ```
 +    ///
 +    /// The actual equivalent of `"str".as_bytes()` with the same type is not
 +    /// `b"str"` but `&b"str"[..]`, which is a great deal of punctuation and not
 +    /// more readable than a function call.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // Bad
 +    /// let bs = "a byte string".as_bytes();
 +    ///
 +    /// // Good
 +    /// let bs = b"a byte string";
 +    /// ```
 +    pub STRING_LIT_AS_BYTES,
 +    nursery,
 +    "calling `as_bytes` on a string literal instead of using a byte string literal"
 +}
 +
-         if let ExprKind::Binary(
-             Spanned {
-                 node: BinOpKind::Add, ..
-             },
-             left,
-             _,
-         ) = e.kind
-         {
-             if is_string(cx, left) {
-                 if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
-                     let parent = get_parent_expr(cx, e);
-                     if let Some(p) = parent {
-                         if let ExprKind::Assign(target, _, _) = p.kind {
-                             // avoid duplicate matches
-                             if SpanlessEq::new(cx).eq_expr(target, left) {
-                                 return;
++declare_clippy_lint! {
++    /// ### What it does
++    /// Checks for slice operations on strings
++    ///
++    /// ### Why is this bad?
++    /// UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character
++    /// counts and string indices. This may lead to panics, and should warrant some test cases
++    /// containing wide UTF-8 characters. This lint is most useful in code that should avoid
++    /// panics at all costs.
++    ///
++    /// ### Known problems
++    /// Probably lots of false positives. If an index comes from a known valid position (e.g.
++    /// obtained via `char_indices` over the same string), it is totally OK.
++    ///
++    /// # Example
++    /// ```rust,should_panic
++    /// &"Ölkanne"[1..];
++    /// ```
++    pub STRING_SLICE,
++    restriction,
++    "slicing a string"
++}
++
++declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN, STRING_SLICE]);
 +
 +impl<'tcx> LateLintPass<'tcx> for StringAdd {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        if in_external_macro(cx.sess(), e.span) {
 +            return;
 +        }
-                 span_lint(
-                     cx,
-                     STRING_ADD,
-                     e.span,
-                     "you added something to a string. Consider using `String::push_str()` instead",
-                 );
-             }
-         } else if let ExprKind::Assign(target, src, _) = e.kind {
-             if is_string(cx, target) && is_add(cx, src, target) {
-                 span_lint(
-                     cx,
-                     STRING_ADD_ASSIGN,
-                     e.span,
-                     "you assigned the result of adding something to this string. Consider using \
-                      `String::push_str()` instead",
-                 );
-             }
++        match e.kind {
++            ExprKind::Binary(
++                Spanned {
++                    node: BinOpKind::Add, ..
++                },
++                left,
++                _,
++            ) => {
++                if is_string(cx, left) {
++                    if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
++                        let parent = get_parent_expr(cx, e);
++                        if let Some(p) = parent {
++                            if let ExprKind::Assign(target, _, _) = p.kind {
++                                // avoid duplicate matches
++                                if SpanlessEq::new(cx).eq_expr(target, left) {
++                                    return;
++                                }
 +                            }
 +                        }
 +                    }
++                    span_lint(
++                        cx,
++                        STRING_ADD,
++                        e.span,
++                        "you added something to a string. Consider using `String::push_str()` instead",
++                    );
 +                }
++            },
++            ExprKind::Assign(target, src, _) => {
++                if is_string(cx, target) && is_add(cx, src, target) {
++                    span_lint(
++                        cx,
++                        STRING_ADD_ASSIGN,
++                        e.span,
++                        "you assigned the result of adding something to this string. Consider using \
++                         `String::push_str()` instead",
++                    );
++                }
++            },
++            ExprKind::Index(target, _idx) => {
++                let e_ty = cx.typeck_results().expr_ty(target).peel_refs();
++                if matches!(e_ty.kind(), ty::Str) || is_type_diagnostic_item(cx, e_ty, sym::String) {
++                    span_lint(
++                        cx,
++                        STRING_SLICE,
++                        e.span,
++                        "indexing into a string may panic if the index is within a UTF-8 character",
++                    );
++                }
++            },
++            _ => {},
 +        }
 +    }
 +}
 +
 +fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym::String)
 +}
 +
 +fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
 +    match src.kind {
 +        ExprKind::Binary(
 +            Spanned {
 +                node: BinOpKind::Add, ..
 +            },
 +            left,
 +            _,
 +        ) => SpanlessEq::new(cx).eq_expr(target, left),
 +        ExprKind::Block(block, _) => {
 +            block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
 +        },
 +        _ => false,
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Check if the string is transformed to byte array and casted back to string.
 +    ///
 +    /// ### Why is this bad?
 +    /// It's unnecessary, the string can be used directly.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap();
 +    /// ```
 +    /// could be written as
 +    /// ```rust
 +    /// let _ = &"Hello World!"[6..11];
 +    /// ```
 +    pub STRING_FROM_UTF8_AS_BYTES,
 +    complexity,
 +    "casting string slices to byte slices and back"
 +}
 +
 +// Max length a b"foo" string can take
 +const MAX_LENGTH_BYTE_STRING_LIT: usize = 32;
 +
 +declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS_BYTES]);
 +
 +impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 +        use rustc_ast::LitKind;
 +
 +        if_chain! {
 +            // Find std::str::converts::from_utf8
 +            if let Some(args) = match_function_call(cx, e, &paths::STR_FROM_UTF8);
 +
 +            // Find string::as_bytes
 +            if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args[0].kind;
 +            if let ExprKind::Index(left, right) = args.kind;
 +            let (method_names, expressions, _) = method_calls(left, 1);
 +            if method_names.len() == 1;
 +            if expressions.len() == 1;
 +            if expressions[0].len() == 1;
 +            if method_names[0] == sym!(as_bytes);
 +
 +            // Check for slicer
 +            if let ExprKind::Struct(QPath::LangItem(LangItem::Range, _), _, _) = right.kind;
 +
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +                let string_expression = &expressions[0][0];
 +
 +                let snippet_app = snippet_with_applicability(
 +                    cx,
 +                    string_expression.span, "..",
 +                    &mut applicability,
 +                );
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    STRING_FROM_UTF8_AS_BYTES,
 +                    e.span,
 +                    "calling a slice of `as_bytes()` with `from_utf8` should be not necessary",
 +                    "try",
 +                    format!("Some(&{}[{}])", snippet_app, snippet(cx, right.span, "..")),
 +                    applicability
 +                )
 +            }
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::MethodCall(path, _, args, _) = &e.kind;
 +            if path.ident.name == sym!(as_bytes);
 +            if let ExprKind::Lit(lit) = &args[0].kind;
 +            if let LitKind::Str(lit_content, _) = &lit.node;
 +            then {
 +                let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#);
 +                let mut applicability = Applicability::MachineApplicable;
 +                if callsite.starts_with("include_str!") {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        STRING_LIT_AS_BYTES,
 +                        e.span,
 +                        "calling `as_bytes()` on `include_str!(..)`",
 +                        "consider using `include_bytes!(..)` instead",
 +                        snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen(
 +                            "include_str",
 +                            "include_bytes",
 +                            1,
 +                        ),
 +                        applicability,
 +                    );
 +                } else if lit_content.as_str().is_ascii()
 +                    && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
 +                    && !args[0].span.from_expansion()
 +                {
 +                    span_lint_and_sugg(
 +                        cx,
 +                        STRING_LIT_AS_BYTES,
 +                        e.span,
 +                        "calling `as_bytes()` on a string literal",
 +                        "consider using a byte string literal instead",
 +                        format!(
 +                            "b{}",
 +                            snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability)
 +                        ),
 +                        applicability,
 +                    );
 +                }
 +            }
 +        }
 +
 +        if_chain! {
 +            if let ExprKind::MethodCall(path, _, [recv], _) = &e.kind;
 +            if path.ident.name == sym!(into_bytes);
 +            if let ExprKind::MethodCall(path, _, [recv], _) = &recv.kind;
 +            if matches!(&*path.ident.name.as_str(), "to_owned" | "to_string");
 +            if let ExprKind::Lit(lit) = &recv.kind;
 +            if let LitKind::Str(lit_content, _) = &lit.node;
 +
 +            if lit_content.as_str().is_ascii();
 +            if lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT;
 +            if !recv.span.from_expansion();
 +            then {
 +                let mut applicability = Applicability::MachineApplicable;
 +
 +                span_lint_and_sugg(
 +                    cx,
 +                    STRING_LIT_AS_BYTES,
 +                    e.span,
 +                    "calling `into_bytes()` on a string literal",
 +                    "consider using a byte string literal instead",
 +                    format!(
 +                        "b{}.to_vec()",
 +                        snippet_with_applicability(cx, recv.span, r#""..""#, &mut applicability)
 +                    ),
 +                    applicability,
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// This lint checks for `.to_string()` method calls on values of type `&str`.
 +    ///
 +    /// ### Why is this bad?
 +    /// The `to_string` method is also used on other types to convert them to a string.
 +    /// When called on a `&str` it turns the `&str` into the owned variant `String`, which can be better
 +    /// expressed with `.to_owned()`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // example code where clippy issues a warning
 +    /// let _ = "str".to_string();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// // example code which does not raise clippy warning
 +    /// let _ = "str".to_owned();
 +    /// ```
 +    pub STR_TO_STRING,
 +    restriction,
 +    "using `to_string()` on a `&str`, which should be `to_owned()`"
 +}
 +
 +declare_lint_pass!(StrToString => [STR_TO_STRING]);
 +
 +impl LateLintPass<'_> for StrToString {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind;
 +            if path.ident.name == sym!(to_string);
 +            let ty = cx.typeck_results().expr_ty(self_arg);
 +            if let ty::Ref(_, ty, ..) = ty.kind();
 +            if *ty.kind() == ty::Str;
 +            then {
 +                span_lint_and_help(
 +                    cx,
 +                    STR_TO_STRING,
 +                    expr.span,
 +                    "`to_string()` called on a `&str`",
 +                    None,
 +                    "consider using `.to_owned()`",
 +                );
 +            }
 +        }
 +    }
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// This lint checks for `.to_string()` method calls on values of type `String`.
 +    ///
 +    /// ### Why is this bad?
 +    /// The `to_string` method is also used on other types to convert them to a string.
 +    /// When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// // example code where clippy issues a warning
 +    /// let msg = String::from("Hello World");
 +    /// let _ = msg.to_string();
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// // example code which does not raise clippy warning
 +    /// let msg = String::from("Hello World");
 +    /// let _ = msg.clone();
 +    /// ```
 +    pub STRING_TO_STRING,
 +    restriction,
 +    "using `to_string()` on a `String`, which should be `clone()`"
 +}
 +
 +declare_lint_pass!(StringToString => [STRING_TO_STRING]);
 +
 +impl LateLintPass<'_> for StringToString {
 +    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
 +        if_chain! {
 +            if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind;
 +            if path.ident.name == sym!(to_string);
 +            let ty = cx.typeck_results().expr_ty(self_arg);
 +            if is_type_diagnostic_item(cx, ty, sym::String);
 +            then {
 +                span_lint_and_help(
 +                    cx,
 +                    STRING_TO_STRING,
 +                    expr.span,
 +                    "`to_string()` called on a `String`",
 +                    None,
 +                    "consider using `.clone()`",
 +                );
 +            }
 +        }
 +    }
 +}
index e08e4d03c7efef5c651cdd46fcfb4ada153400d3,0000000000000000000000000000000000000000..11aef50991b0a1415a12dc83077de7246fe53d03
mode 100644,000000..100644
--- /dev/null
@@@ -1,225 -1,0 +1,226 @@@
-         let lex_start = (between_span.lo().0 + 1) as usize;
-         let src_str = source_file.src.as_ref()?[lex_start..between_span.hi().0 as usize].to_string();
 +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
 +use clippy_utils::source::{indent_of, reindent_multiline, snippet};
 +use clippy_utils::{in_macro, is_lint_allowed};
 +use rustc_errors::Applicability;
 +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 +use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, HirId, Local, UnsafeSource};
 +use rustc_lexer::TokenKind;
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::lint::in_external_macro;
 +use rustc_middle::ty::TyCtxt;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::{BytePos, Span};
 +use std::borrow::Cow;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for `unsafe` blocks without a `// Safety: ` comment
 +    /// explaining why the unsafe operations performed inside
 +    /// the block are safe.
 +    ///
 +    /// ### Why is this bad?
 +    /// Undocumented unsafe blocks can make it difficult to
 +    /// read and maintain code, as well as uncover unsoundness
 +    /// and bugs.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// use std::ptr::NonNull;
 +    /// let a = &mut 42;
 +    ///
 +    /// let ptr = unsafe { NonNull::new_unchecked(a) };
 +    /// ```
 +    /// Use instead:
 +    /// ```rust
 +    /// use std::ptr::NonNull;
 +    /// let a = &mut 42;
 +    ///
 +    /// // Safety: references are guaranteed to be non-null.
 +    /// let ptr = unsafe { NonNull::new_unchecked(a) };
 +    /// ```
 +    pub UNDOCUMENTED_UNSAFE_BLOCKS,
 +    restriction,
 +    "creating an unsafe block without explaining why it is safe"
 +}
 +
 +impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS]);
 +
 +#[derive(Default)]
 +pub struct UndocumentedUnsafeBlocks {
 +    pub local_level: u32,
 +    pub local_span: Option<Span>,
 +    // The local was already checked for an overall safety comment
 +    // There is no need to continue checking the blocks in the local
 +    pub local_checked: bool,
 +    // Since we can only check the blocks from expanded macros
 +    // We have to omit the suggestion due to the actual definition
 +    // Not being available to us
 +    pub macro_expansion: bool,
 +}
 +
 +impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
 +    fn check_block(&mut self, cx: &LateContext<'_>, block: &'_ Block<'_>) {
 +        if_chain! {
 +            if !self.local_checked;
 +            if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id);
 +            if !in_external_macro(cx.tcx.sess, block.span);
 +            if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules;
 +            if let Some(enclosing_scope_hir_id) = cx.tcx.hir().get_enclosing_scope(block.hir_id);
 +            if self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, block.span) == Some(false);
 +            then {
 +                let mut span = block.span;
 +
 +                if let Some(local_span) = self.local_span {
 +                    span = local_span;
 +
 +                    let result = self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, span);
 +
 +                    if result.unwrap_or(true) {
 +                        self.local_checked = true;
 +                        return;
 +                    }
 +                }
 +
 +                self.lint(cx, span);
 +            }
 +        }
 +    }
 +
 +    fn check_local(&mut self, cx: &LateContext<'_>, local: &'_ Local<'_>) {
 +        if_chain! {
 +            if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, local.hir_id);
 +            if !in_external_macro(cx.tcx.sess, local.span);
 +            if let Some(init) = local.init;
 +            then {
 +                self.visit_expr(init);
 +
 +                if self.local_level > 0 {
 +                    self.local_span = Some(local.span);
 +                }
 +            }
 +        }
 +    }
 +
 +    fn check_block_post(&mut self, _: &LateContext<'_>, _: &'_ Block<'_>) {
 +        self.local_level = self.local_level.saturating_sub(1);
 +
 +        if self.local_level == 0 {
 +            self.local_checked = false;
 +            self.local_span = None;
 +        }
 +    }
 +}
 +
 +impl<'hir> Visitor<'hir> for UndocumentedUnsafeBlocks {
 +    type Map = Map<'hir>;
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +
 +    fn visit_expr(&mut self, ex: &'v Expr<'v>) {
 +        match ex.kind {
 +            ExprKind::Block(_, _) => self.local_level = self.local_level.saturating_add(1),
 +            _ => walk_expr(self, ex),
 +        }
 +    }
 +}
 +
 +impl UndocumentedUnsafeBlocks {
 +    fn block_has_safety_comment(&mut self, tcx: TyCtxt<'_>, enclosing_hir_id: HirId, block_span: Span) -> Option<bool> {
 +        let map = tcx.hir();
 +        let source_map = tcx.sess.source_map();
 +
 +        let enclosing_scope_span = map.opt_span(enclosing_hir_id)?;
 +
 +        let between_span = if in_macro(block_span) {
 +            self.macro_expansion = true;
 +            enclosing_scope_span.with_hi(block_span.hi())
 +        } else {
 +            self.macro_expansion = false;
 +            enclosing_scope_span.to(block_span)
 +        };
 +
 +        let file_name = source_map.span_to_filename(between_span);
 +        let source_file = source_map.get_source_file(&file_name)?;
 +
++        let lex_start = (between_span.lo().0 - source_file.start_pos.0 + 1) as usize;
++        let lex_end = (between_span.hi().0 - source_file.start_pos.0) as usize;
++        let src_str = source_file.src.as_ref()?[lex_start..lex_end].to_string();
 +
 +        let mut pos = 0;
 +        let mut comment = false;
 +
 +        for token in rustc_lexer::tokenize(&src_str) {
 +            match token.kind {
 +                TokenKind::LineComment { doc_style: None }
 +                | TokenKind::BlockComment {
 +                    doc_style: None,
 +                    terminated: true,
 +                } => {
 +                    let comment_str = src_str[pos + 2..pos + token.len].to_ascii_uppercase();
 +
 +                    if comment_str.contains("SAFETY:") {
 +                        comment = true;
 +                    }
 +                },
 +                // We need to add all whitespace to `pos` before checking the comment's line number
 +                TokenKind::Whitespace => {},
 +                _ => {
 +                    if comment {
 +                        // Get the line number of the "comment" (really wherever the trailing whitespace ended)
 +                        let comment_line_num = source_file
 +                            .lookup_file_pos_with_col_display(BytePos((lex_start + pos).try_into().unwrap()))
 +                            .0;
 +                        // Find the block/local's line number
 +                        let block_line_num = tcx.sess.source_map().lookup_char_pos(block_span.lo()).line;
 +
 +                        // Check the comment is immediately followed by the block/local
 +                        if block_line_num == comment_line_num + 1 || block_line_num == comment_line_num {
 +                            return Some(true);
 +                        }
 +
 +                        comment = false;
 +                    }
 +                },
 +            }
 +
 +            pos += token.len;
 +        }
 +
 +        Some(false)
 +    }
 +
 +    fn lint(&self, cx: &LateContext<'_>, mut span: Span) {
 +        let source_map = cx.tcx.sess.source_map();
 +
 +        if source_map.is_multiline(span) {
 +            span = source_map.span_until_char(span, '\n');
 +        }
 +
 +        if self.macro_expansion {
 +            span_lint_and_help(
 +                cx,
 +                UNDOCUMENTED_UNSAFE_BLOCKS,
 +                span,
 +                "unsafe block in macro expansion missing a safety comment",
 +                None,
 +                "consider adding a safety comment in the macro definition",
 +            );
 +        } else {
 +            let block_indent = indent_of(cx, span);
 +            let suggestion = format!("// Safety: ...\n{}", snippet(cx, span, ".."));
 +
 +            span_lint_and_sugg(
 +                cx,
 +                UNDOCUMENTED_UNSAFE_BLOCKS,
 +                span,
 +                "unsafe block missing a safety comment",
 +                "consider adding a safety comment",
 +                reindent_multiline(Cow::Borrowed(&suggestion), true, block_indent).to_string(),
 +                Applicability::HasPlaceholders,
 +            );
 +        }
 +    }
 +}
index f337dec8f2b9663faf88299154394ba35e8c49ba,0000000000000000000000000000000000000000..f49ce696a04b77d4832cca91d62f78b12964f72d
mode 100644,000000..100644
--- /dev/null
@@@ -1,138 -1,0 +1,138 @@@
-     pedantic,
 +use clippy_utils::diagnostics::span_lint_and_sugg;
 +use clippy_utils::is_lint_allowed;
 +use clippy_utils::source::snippet;
 +use rustc_ast::ast::LitKind;
 +use rustc_errors::Applicability;
 +use rustc_hir::{Expr, ExprKind, HirId};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::source_map::Span;
 +use unicode_normalization::UnicodeNormalization;
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for invisible Unicode characters in the code.
 +    ///
 +    /// ### Why is this bad?
 +    /// Having an invisible character in the code makes for all
 +    /// sorts of April fools, but otherwise is very much frowned upon.
 +    ///
 +    /// ### Example
 +    /// You don't see it, but there may be a zero-width space or soft hyphen
 +    /// some­where in this text.
 +    pub INVISIBLE_CHARACTERS,
 +    correctness,
 +    "using an invisible character in a string literal, which is confusing"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for non-ASCII characters in string literals.
 +    ///
 +    /// ### Why is this bad?
 +    /// Yeah, we know, the 90's called and wanted their charset
 +    /// back. Even so, there still are editors and other programs out there that
 +    /// don't work well with Unicode. So if the code is meant to be used
 +    /// internationally, on multiple operating systems, or has other portability
 +    /// requirements, activating this lint could be useful.
 +    ///
 +    /// ### Example
 +    /// ```rust
 +    /// let x = String::from("€");
 +    /// ```
 +    /// Could be written as:
 +    /// ```rust
 +    /// let x = String::from("\u{20ac}");
 +    /// ```
 +    pub NON_ASCII_LITERAL,
++    restriction,
 +    "using any literal non-ASCII chars in a string literal instead of using the `\\u` escape"
 +}
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Checks for string literals that contain Unicode in a form
 +    /// that is not equal to its
 +    /// [NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms).
 +    ///
 +    /// ### Why is this bad?
 +    /// If such a string is compared to another, the results
 +    /// may be surprising.
 +    ///
 +    /// ### Example
 +    /// You may not see it, but "à"" and "à"" aren't the same string. The
 +    /// former when escaped is actually `"a\u{300}"` while the latter is `"\u{e0}"`.
 +    pub UNICODE_NOT_NFC,
 +    pedantic,
 +    "using a Unicode literal not in NFC normal form (see [Unicode tr15](http://www.unicode.org/reports/tr15/) for further information)"
 +}
 +
 +declare_lint_pass!(Unicode => [INVISIBLE_CHARACTERS, NON_ASCII_LITERAL, UNICODE_NOT_NFC]);
 +
 +impl LateLintPass<'_> for Unicode {
 +    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
 +        if let ExprKind::Lit(ref lit) = expr.kind {
 +            if let LitKind::Str(_, _) = lit.node {
 +                check_str(cx, lit.span, expr.hir_id);
 +            }
 +        }
 +    }
 +}
 +
 +fn escape<T: Iterator<Item = char>>(s: T) -> String {
 +    let mut result = String::new();
 +    for c in s {
 +        if c as u32 > 0x7F {
 +            for d in c.escape_unicode() {
 +                result.push(d);
 +            }
 +        } else {
 +            result.push(c);
 +        }
 +    }
 +    result
 +}
 +
 +fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
 +    let string = snippet(cx, span, "");
 +    if string.chars().any(|c| ['\u{200B}', '\u{ad}', '\u{2060}'].contains(&c)) {
 +        span_lint_and_sugg(
 +            cx,
 +            INVISIBLE_CHARACTERS,
 +            span,
 +            "invisible character detected",
 +            "consider replacing the string with",
 +            string
 +                .replace("\u{200B}", "\\u{200B}")
 +                .replace("\u{ad}", "\\u{AD}")
 +                .replace("\u{2060}", "\\u{2060}"),
 +            Applicability::MachineApplicable,
 +        );
 +    }
 +    if string.chars().any(|c| c as u32 > 0x7F) {
 +        span_lint_and_sugg(
 +            cx,
 +            NON_ASCII_LITERAL,
 +            span,
 +            "literal non-ASCII character detected",
 +            "consider replacing the string with",
 +            if is_lint_allowed(cx, UNICODE_NOT_NFC, id) {
 +                escape(string.chars())
 +            } else {
 +                escape(string.nfc())
 +            },
 +            Applicability::MachineApplicable,
 +        );
 +    }
 +    if is_lint_allowed(cx, NON_ASCII_LITERAL, id) && string.chars().zip(string.nfc()).any(|(a, b)| a != b) {
 +        span_lint_and_sugg(
 +            cx,
 +            UNICODE_NOT_NFC,
 +            span,
 +            "non-NFC Unicode sequence detected",
 +            "consider replacing the string with",
 +            string.nfc().collect::<String>(),
 +            Applicability::MachineApplicable,
 +        );
 +    }
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a3a3f2d41c7323354af7c50b4b7b46ffecd32879
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,77 @@@
++use clippy_utils::diagnostics::span_lint_and_then;
++use clippy_utils::source::snippet;
++use rustc_errors::Applicability;
++use rustc_hir::{Expr, ExprKind};
++use rustc_lint::{LateContext, LateLintPass};
++use rustc_session::{declare_lint_pass, declare_tool_lint};
++use rustc_span::sym;
++
++declare_clippy_lint! {
++    /// ### What it does
++    /// Detects `().hash(_)`.
++    ///
++    /// ### Why is this bad?
++    /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
++    ///
++    /// ### Example
++    /// ```rust
++    /// # use std::hash::Hash;
++    /// # use std::collections::hash_map::DefaultHasher;
++    /// # enum Foo { Empty, WithValue(u8) }
++    /// # use Foo::*;
++    /// # let mut state = DefaultHasher::new();
++    /// # let my_enum = Foo::Empty;
++    /// match my_enum {
++    ///       Empty => ().hash(&mut state),
++    ///       WithValue(x) => x.hash(&mut state),
++    /// }
++    /// ```
++    /// Use instead:
++    /// ```rust
++    /// # use std::hash::Hash;
++    /// # use std::collections::hash_map::DefaultHasher;
++    /// # enum Foo { Empty, WithValue(u8) }
++    /// # use Foo::*;
++    /// # let mut state = DefaultHasher::new();
++    /// # let my_enum = Foo::Empty;
++    /// match my_enum {
++    ///       Empty => 0_u8.hash(&mut state),
++    ///       WithValue(x) => x.hash(&mut state),
++    /// }
++    /// ```
++    pub UNIT_HASH,
++    correctness,
++    "hashing a unit value, which does nothing"
++}
++declare_lint_pass!(UnitHash => [UNIT_HASH]);
++
++impl LateLintPass<'tcx> for UnitHash {
++    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
++        if_chain! {
++            if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
++            if name_ident.ident.name == sym::hash;
++            if let [recv, state_param] = args;
++            if cx.typeck_results().expr_ty(recv).is_unit();
++            then {
++                span_lint_and_then(
++                    cx,
++                    UNIT_HASH,
++                    expr.span,
++                    "this call to `hash` on the unit type will do nothing",
++                    |diag| {
++                        diag.span_suggestion(
++                            expr.span,
++                            "remove the call to `hash` or consider using",
++                            format!(
++                                "0_u8.hash({})",
++                                snippet(cx, state_param.span, ".."),
++                            ),
++                            Applicability::MaybeIncorrect,
++                        );
++                        diag.note("the implementation of `Hash` for `()` is a no-op");
++                    }
++                );
++            }
++        }
++    }
++}
index a4680ae137b3254e13f3c318448194a10211c8f9,0000000000000000000000000000000000000000..6447e3fa2ca08a85d04716b6bd1f955ba8f5b931
mode 100644,000000..100644
--- /dev/null
@@@ -1,139 -1,0 +1,139 @@@
-     /// Checks for functions of type Result that contain `expect()` or `unwrap()`
 +use clippy_utils::diagnostics::span_lint_and_then;
 +use clippy_utils::ty::is_type_diagnostic_item;
 +use clippy_utils::{method_chain_args, return_ty};
 +use if_chain::if_chain;
 +use rustc_hir as hir;
 +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 +use rustc_hir::{Expr, ImplItemKind};
 +use rustc_lint::{LateContext, LateLintPass};
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::ty;
 +use rustc_session::{declare_lint_pass, declare_tool_lint};
 +use rustc_span::{sym, Span};
 +
 +declare_clippy_lint! {
 +    /// ### What it does
++    /// Checks for functions of type `Result` that contain `expect()` or `unwrap()`
 +    ///
 +    /// ### Why is this bad?
 +    /// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics.
 +    ///
 +    /// ### Known problems
 +    /// This can cause false positives in functions that handle both recoverable and non recoverable errors.
 +    ///
 +    /// ### Example
 +    /// Before:
 +    /// ```rust
 +    /// fn divisible_by_3(i_str: String) -> Result<(), String> {
 +    ///     let i = i_str
 +    ///         .parse::<i32>()
 +    ///         .expect("cannot divide the input by three");
 +    ///
 +    ///     if i % 3 != 0 {
 +    ///         Err("Number is not divisible by 3")?
 +    ///     }
 +    ///
 +    ///     Ok(())
 +    /// }
 +    /// ```
 +    ///
 +    /// After:
 +    /// ```rust
 +    /// fn divisible_by_3(i_str: String) -> Result<(), String> {
 +    ///     let i = i_str
 +    ///         .parse::<i32>()
 +    ///         .map_err(|e| format!("cannot divide the input by three: {}", e))?;
 +    ///
 +    ///     if i % 3 != 0 {
 +    ///         Err("Number is not divisible by 3")?
 +    ///     }
 +    ///
 +    ///     Ok(())
 +    /// }
 +    /// ```
 +    pub UNWRAP_IN_RESULT,
 +    restriction,
 +    "functions of type `Result<..>` or `Option`<...> that contain `expect()` or `unwrap()`"
 +}
 +
 +declare_lint_pass!(UnwrapInResult=> [UNWRAP_IN_RESULT]);
 +
 +impl<'tcx> LateLintPass<'tcx> for UnwrapInResult {
 +    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
 +        if_chain! {
 +            // first check if it's a method or function
 +            if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind;
 +            // checking if its return type is `result` or `option`
 +            if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::Result)
 +                || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::Option);
 +            then {
 +                lint_impl_body(cx, impl_item.span, impl_item);
 +            }
 +        }
 +    }
 +}
 +
 +struct FindExpectUnwrap<'a, 'tcx> {
 +    lcx: &'a LateContext<'tcx>,
 +    typeck_results: &'tcx ty::TypeckResults<'tcx>,
 +    result: Vec<Span>,
 +}
 +
 +impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        // check for `expect`
 +        if let Some(arglists) = method_chain_args(expr, &["expect"]) {
 +            let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
 +            if is_type_diagnostic_item(self.lcx, reciever_ty, sym::Option)
 +                || is_type_diagnostic_item(self.lcx, reciever_ty, sym::Result)
 +            {
 +                self.result.push(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.lcx, reciever_ty, sym::Option)
 +                || is_type_diagnostic_item(self.lcx, reciever_ty, sym::Result)
 +            {
 +                self.result.push(expr.span);
 +            }
 +        }
 +
 +        // and check sub-expressions
 +        intravisit::walk_expr(self, expr);
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) {
 +    if let ImplItemKind::Fn(_, body_id) = impl_item.kind {
 +        let body = cx.tcx.hir().body(body_id);
 +        let mut fpu = FindExpectUnwrap {
 +            lcx: cx,
 +            typeck_results: cx.tcx.typeck(impl_item.def_id),
 +            result: Vec::new(),
 +        };
 +        fpu.visit_expr(&body.value);
 +
 +        // if we've found one, lint
 +        if !fpu.result.is_empty() {
 +            span_lint_and_then(
 +                cx,
 +                UNWRAP_IN_RESULT,
 +                impl_span,
 +                "used unwrap or expect in a function that returns result or option",
 +                move |diag| {
 +                    diag.help("unwrap and expect should not be used in a function that returns result or option");
 +                    diag.span_note(fpu.result, "potential non-recoverable error(s)");
 +                },
 +            );
 +        }
 +    }
 +}
index d05c52122d5ee518ab1d00f0349851909026151b,0000000000000000000000000000000000000000..122a5ce3fc8f12d19fd8d0ce877ff2a672c01537
mode 100644,000000..100644
--- /dev/null
@@@ -1,339 -1,0 +1,339 @@@
-     /// Lint: RESTRICTED_SCRIPTS.
 +//! Read configurations files.
 +
 +#![allow(clippy::module_name_repetitions)]
 +
 +use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor};
 +use serde::Deserialize;
 +use std::error::Error;
 +use std::path::{Path, PathBuf};
 +use std::{env, fmt, fs, io};
 +
 +/// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint.
 +#[derive(Clone, Debug, Deserialize)]
 +pub struct Rename {
 +    pub path: String,
 +    pub rename: String,
 +}
 +
 +/// A single disallowed method, used by the `DISALLOWED_METHOD` lint.
 +#[derive(Clone, Debug, Deserialize)]
 +#[serde(untagged)]
 +pub enum DisallowedMethod {
 +    Simple(String),
 +    WithReason { path: String, reason: Option<String> },
 +}
 +
 +/// A single disallowed type, used by the `DISALLOWED_TYPE` lint.
 +#[derive(Clone, Debug, Deserialize)]
 +#[serde(untagged)]
 +pub enum DisallowedType {
 +    Simple(String),
 +    WithReason { path: String, reason: Option<String> },
 +}
 +
 +/// Conf with parse errors
 +#[derive(Default)]
 +pub struct TryConf {
 +    pub conf: Conf,
 +    pub errors: Vec<String>,
 +}
 +
 +impl TryConf {
 +    fn from_error(error: impl Error) -> Self {
 +        Self {
 +            conf: Conf::default(),
 +            errors: vec![error.to_string()],
 +        }
 +    }
 +}
 +
 +macro_rules! define_Conf {
 +    ($(
 +        $(#[doc = $doc:literal])+
 +        $(#[conf_deprecated($dep:literal)])?
 +        ($name:ident: $ty:ty = $default:expr),
 +    )*) => {
 +        /// Clippy lint configuration
 +        pub struct Conf {
 +            $($(#[doc = $doc])+ pub $name: $ty,)*
 +        }
 +
 +        mod defaults {
 +            $(pub fn $name() -> $ty { $default })*
 +        }
 +
 +        impl Default for Conf {
 +            fn default() -> Self {
 +                Self { $($name: defaults::$name(),)* }
 +            }
 +        }
 +
 +        impl<'de> Deserialize<'de> for TryConf {
 +            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
 +                deserializer.deserialize_map(ConfVisitor)
 +            }
 +        }
 +
 +        #[derive(Deserialize)]
 +        #[serde(field_identifier, rename_all = "kebab-case")]
 +        #[allow(non_camel_case_types)]
 +        enum Field { $($name,)* third_party, }
 +
 +        struct ConfVisitor;
 +
 +        impl<'de> Visitor<'de> for ConfVisitor {
 +            type Value = TryConf;
 +
 +            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
 +                formatter.write_str("Conf")
 +            }
 +
 +            fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapAccess<'de> {
 +                let mut errors = Vec::new();
 +                $(let mut $name = None;)*
 +                // could get `Field` here directly, but get `str` first for diagnostics
 +                while let Some(name) = map.next_key::<&str>()? {
 +                    match Field::deserialize(name.into_deserializer())? {
 +                        $(Field::$name => {
 +                            $(errors.push(format!("deprecated field `{}`. {}", name, $dep));)?
 +                            match map.next_value() {
 +                                Err(e) => errors.push(e.to_string()),
 +                                Ok(value) => match $name {
 +                                    Some(_) => errors.push(format!("duplicate field `{}`", name)),
 +                                    None => $name = Some(value),
 +                                }
 +                            }
 +                        })*
 +                        // white-listed; ignore
 +                        Field::third_party => drop(map.next_value::<IgnoredAny>())
 +                    }
 +                }
 +                let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* };
 +                Ok(TryConf { conf, errors })
 +            }
 +        }
 +
 +        #[cfg(feature = "metadata-collector-lint")]
 +        pub mod metadata {
 +            use crate::utils::internal_lints::metadata_collector::ClippyConfiguration;
 +
 +            macro_rules! wrap_option {
 +                () => (None);
 +                ($x:literal) => (Some($x));
 +            }
 +
 +            pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
 +                vec![
 +                    $(
 +                        {
 +                            let deprecation_reason = wrap_option!($($dep)?);
 +
 +                            ClippyConfiguration::new(
 +                                stringify!($name),
 +                                stringify!($ty),
 +                                format!("{:?}", super::defaults::$name()),
 +                                concat!($($doc, '\n',)*),
 +                                deprecation_reason,
 +                            )
 +                        },
 +                    )+
 +                ]
 +            }
 +        }
 +    };
 +}
 +
 +define_Conf! {
 +    /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX.
 +    ///
 +    /// Suppress lints whenever the suggested change would cause breakage for other crates.
 +    (avoid_breaking_exported_api: bool = true),
 +    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT.
 +    ///
 +    /// The minimum rust version that the project supports
 +    (msrv: Option<String> = None),
 +    /// Lint: BLACKLISTED_NAME.
 +    ///
 +    /// The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
 +    (blacklisted_names: Vec<String> = ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
 +    /// Lint: COGNITIVE_COMPLEXITY.
 +    ///
 +    /// The maximum cognitive complexity a function can have
 +    (cognitive_complexity_threshold: u64 = 25),
 +    /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
 +    ///
 +    /// Use the Cognitive Complexity lint instead.
 +    #[conf_deprecated("Please use `cognitive-complexity-threshold` instead")]
 +    (cyclomatic_complexity_threshold: Option<u64> = None),
 +    /// Lint: DOC_MARKDOWN.
 +    ///
 +    /// The list of words this lint should not consider as identifiers needing ticks
 +    (doc_valid_idents: Vec<String> = [
 +        "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
 +        "DirectX",
 +        "ECMAScript",
 +        "GPLv2", "GPLv3",
 +        "GitHub", "GitLab",
 +        "IPv4", "IPv6",
 +        "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript",
 +        "NaN", "NaNs",
 +        "OAuth", "GraphQL",
 +        "OCaml",
 +        "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS",
 +        "WebGL",
 +        "TensorFlow",
 +        "TrueType",
 +        "iOS", "macOS", "FreeBSD",
 +        "TeX", "LaTeX", "BibTeX", "BibLaTeX",
 +        "MinGW",
 +        "CamelCase",
 +    ].iter().map(ToString::to_string).collect()),
 +    /// Lint: TOO_MANY_ARGUMENTS.
 +    ///
 +    /// The maximum number of argument a function or method can have
 +    (too_many_arguments_threshold: u64 = 7),
 +    /// Lint: TYPE_COMPLEXITY.
 +    ///
 +    /// The maximum complexity a type can have
 +    (type_complexity_threshold: u64 = 250),
 +    /// Lint: MANY_SINGLE_CHAR_NAMES.
 +    ///
 +    /// The maximum number of single char bindings a scope may have
 +    (single_char_binding_names_threshold: u64 = 4),
 +    /// Lint: BOXED_LOCAL, USELESS_VEC.
 +    ///
 +    /// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
 +    (too_large_for_stack: u64 = 200),
 +    /// Lint: ENUM_VARIANT_NAMES.
 +    ///
 +    /// The minimum number of enum variants for the lints about variant names to trigger
 +    (enum_variant_name_threshold: u64 = 3),
 +    /// Lint: LARGE_ENUM_VARIANT.
 +    ///
 +    /// The maximum size of an enum's variant to avoid box suggestion
 +    (enum_variant_size_threshold: u64 = 200),
 +    /// Lint: VERBOSE_BIT_MASK.
 +    ///
 +    /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
 +    (verbose_bit_mask_threshold: u64 = 1),
 +    /// Lint: DECIMAL_LITERAL_REPRESENTATION.
 +    ///
 +    /// The lower bound for linting decimal literals
 +    (literal_representation_threshold: u64 = 16384),
 +    /// Lint: TRIVIALLY_COPY_PASS_BY_REF.
 +    ///
 +    /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
 +    (trivial_copy_size_limit: Option<u64> = None),
 +    /// Lint: LARGE_TYPE_PASS_BY_MOVE.
 +    ///
 +    /// The minimum size (in bytes) to consider a type for passing by reference instead of by value.
 +    (pass_by_value_size_limit: u64 = 256),
 +    /// Lint: TOO_MANY_LINES.
 +    ///
 +    /// The maximum number of lines a function or method can have
 +    (too_many_lines_threshold: u64 = 100),
 +    /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS.
 +    ///
 +    /// The maximum allowed size for arrays on the stack
 +    (array_size_threshold: u64 = 512_000),
 +    /// Lint: VEC_BOX.
 +    ///
 +    /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed
 +    (vec_box_size_threshold: u64 = 4096),
 +    /// Lint: TYPE_REPETITION_IN_BOUNDS.
 +    ///
 +    /// The maximum number of bounds a trait can have to be linted
 +    (max_trait_bounds: u64 = 3),
 +    /// Lint: STRUCT_EXCESSIVE_BOOLS.
 +    ///
 +    /// The maximum number of bool fields a struct can have
 +    (max_struct_bools: u64 = 3),
 +    /// Lint: FN_PARAMS_EXCESSIVE_BOOLS.
 +    ///
 +    /// The maximum number of bool parameters a function can have
 +    (max_fn_params_bools: u64 = 3),
 +    /// Lint: WILDCARD_IMPORTS.
 +    ///
 +    /// Whether to allow certain wildcard imports (prelude, super in tests).
 +    (warn_on_all_wildcard_imports: bool = false),
 +    /// Lint: DISALLOWED_METHOD.
 +    ///
 +    /// The list of disallowed methods, written as fully qualified paths.
 +    (disallowed_methods: Vec<crate::utils::conf::DisallowedMethod> = Vec::new()),
 +    /// Lint: DISALLOWED_TYPE.
 +    ///
 +    /// The list of disallowed types, written as fully qualified paths.
 +    (disallowed_types: Vec<crate::utils::conf::DisallowedType> = Vec::new()),
 +    /// Lint: UNREADABLE_LITERAL.
 +    ///
 +    /// Should the fraction of a decimal be linted to include separators.
 +    (unreadable_literal_lint_fractions: bool = true),
 +    /// Lint: UPPER_CASE_ACRONYMS.
 +    ///
 +    /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other
 +    (upper_case_acronyms_aggressive: bool = false),
 +    /// Lint: _CARGO_COMMON_METADATA.
 +    ///
 +    /// For internal testing only, ignores the current `publish` settings in the Cargo manifest.
 +    (cargo_ignore_publish: bool = false),
 +    /// Lint: NONSTANDARD_MACRO_BRACES.
 +    ///
 +    /// Enforce the named macros always use the braces specified.
 +    ///
 +    /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
 +    /// is could be used with a full path two `MacroMatcher`s have to be added one with the full path
 +    /// `crate_name::macro_name` and one with just the macro name.
 +    (standard_macro_braces: Vec<crate::nonstandard_macro_braces::MacroMatcher> = Vec::new()),
 +    /// Lint: MISSING_ENFORCED_IMPORT_RENAMES.
 +    ///
 +    /// The list of imports to always rename, a fully qualified path followed by the rename.
 +    (enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()),
-     (allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
++    /// Lint: DISALLOWED_SCRIPT_IDENTS.
 +    ///
 +    /// The list of unicode scripts allowed to be used in the scope.
++    (allowed_scripts: Vec<String> = ["Latin"].iter().map(ToString::to_string).collect()),
 +    /// Lint: NON_SEND_FIELDS_IN_SEND_TY.
 +    ///
 +    /// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
 +    (enable_raw_pointer_heuristic_for_send: bool = true),
 +}
 +
 +/// Search for the configuration file.
 +pub fn lookup_conf_file() -> io::Result<Option<PathBuf>> {
 +    /// Possible filename to search for.
 +    const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];
 +
 +    // Start looking for a config file in CLIPPY_CONF_DIR, or failing that, CARGO_MANIFEST_DIR.
 +    // If neither of those exist, use ".".
 +    let mut current = env::var_os("CLIPPY_CONF_DIR")
 +        .or_else(|| env::var_os("CARGO_MANIFEST_DIR"))
 +        .map_or_else(|| PathBuf::from("."), PathBuf::from);
 +    loop {
 +        for config_file_name in &CONFIG_FILE_NAMES {
 +            if let Ok(config_file) = current.join(config_file_name).canonicalize() {
 +                match fs::metadata(&config_file) {
 +                    Err(e) if e.kind() == io::ErrorKind::NotFound => {},
 +                    Err(e) => return Err(e),
 +                    Ok(md) if md.is_dir() => {},
 +                    Ok(_) => return Ok(Some(config_file)),
 +                }
 +            }
 +        }
 +
 +        // If the current directory has no parent, we're done searching.
 +        if !current.pop() {
 +            return Ok(None);
 +        }
 +    }
 +}
 +
 +/// Read the `toml` configuration file.
 +///
 +/// In case of error, the function tries to continue as much as possible.
 +pub fn read(path: &Path) -> TryConf {
 +    let content = match fs::read_to_string(path) {
 +        Err(e) => return TryConf::from_error(e),
 +        Ok(content) => content,
 +    };
 +    toml::from_str(&content).unwrap_or_else(TryConf::from_error)
 +}
index 0d27874b7affb88d7a4dc16f119469919cbf23ef,0000000000000000000000000000000000000000..99cf4c1ed40fbcbd0a52105176f455b05f230995
mode 100644,000000..100644
--- /dev/null
@@@ -1,889 -1,0 +1,900 @@@
-         docs.push('\n');
 +//! This lint is used to collect metadata about clippy lints. This metadata is exported as a json
 +//! file and then used to generate the [clippy lint list](https://rust-lang.github.io/rust-clippy/master/index.html)
 +//!
 +//! This module and therefor the entire lint is guarded by a feature flag called
 +//! `metadata-collector-lint`
 +//!
 +//! The module transforms all lint names to ascii lowercase to ensure that we don't have mismatches
 +//! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such
 +//! a simple mistake)
 +
 +use if_chain::if_chain;
 +use rustc_ast as ast;
 +use rustc_data_structures::fx::FxHashMap;
 +use rustc_hir::{
 +    self as hir, def::DefKind, intravisit, intravisit::Visitor, ExprKind, Item, ItemKind, Mutability, QPath,
 +};
 +use rustc_lint::{CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId};
 +use rustc_middle::hir::map::Map;
 +use rustc_session::{declare_tool_lint, impl_lint_pass};
 +use rustc_span::{sym, Loc, Span, Symbol};
 +use serde::{ser::SerializeStruct, Serialize, Serializer};
 +use std::collections::BinaryHeap;
 +use std::fmt;
 +use std::fs::{self, OpenOptions};
 +use std::io::prelude::*;
 +use std::path::Path;
 +
 +use crate::utils::internal_lints::is_lint_ref_type;
 +use clippy_utils::{
 +    diagnostics::span_lint, last_path_segment, match_def_path, match_function_call, match_path, paths, ty::match_type,
 +    ty::walk_ptrs_ty_depth,
 +};
 +
 +/// This is the output file of the lint collector.
 +const OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
 +/// These lints are excluded from the export.
 +const BLACK_LISTED_LINTS: [&str; 3] = ["lint_author", "deep_code_inspection", "internal_metadata_collector"];
 +/// These groups will be ignored by the lint group matcher. This is useful for collections like
 +/// `clippy::all`
 +const IGNORED_LINT_GROUPS: [&str; 1] = ["clippy::all"];
 +/// Lints within this group will be excluded from the collection. These groups
 +/// have to be defined without the `clippy::` prefix.
 +const EXCLUDED_LINT_GROUPS: [&str; 1] = ["internal"];
 +/// Collected deprecated lint will be assigned to this group in the JSON output
 +const DEPRECATED_LINT_GROUP_STR: &str = "deprecated";
 +/// This is the lint level for deprecated lints that will be displayed in the lint list
 +const DEPRECATED_LINT_LEVEL: &str = "none";
 +/// This array holds Clippy's lint groups with their corresponding default lint level. The
 +/// lint level for deprecated lints is set in `DEPRECATED_LINT_LEVEL`.
 +const DEFAULT_LINT_LEVELS: &[(&str, &str)] = &[
 +    ("correctness", "deny"),
 +    ("suspicious", "warn"),
 +    ("restriction", "allow"),
 +    ("style", "warn"),
 +    ("pedantic", "allow"),
 +    ("complexity", "warn"),
 +    ("perf", "warn"),
 +    ("cargo", "allow"),
 +    ("nursery", "allow"),
 +];
 +/// This prefix is in front of the lint groups in the lint store. The prefix will be trimmed
 +/// to only keep the actual lint group in the output.
 +const CLIPPY_LINT_GROUP_PREFIX: &str = "clippy::";
 +
 +/// This template will be used to format the configuration section in the lint documentation.
 +/// The `configurations` parameter will be replaced with one or multiple formatted
 +/// `ClippyConfiguration` instances. See `CONFIGURATION_VALUE_TEMPLATE` for further customizations
 +macro_rules! CONFIGURATION_SECTION_TEMPLATE {
 +    () => {
 +        r#"
 +### Configuration
 +This lint has the following configuration variables:
 +
 +{configurations}
 +"#
 +    };
 +}
 +/// This template will be used to format an individual `ClippyConfiguration` instance in the
 +/// lint documentation.
 +///
 +/// The format function will provide strings for the following parameters: `name`, `ty`, `doc` and
 +/// `default`
 +macro_rules! CONFIGURATION_VALUE_TEMPLATE {
 +    () => {
 +        "* `{name}`: `{ty}`: {doc} (defaults to `{default}`)\n"
 +    };
 +}
 +
 +const LINT_EMISSION_FUNCTIONS: [&[&str]; 7] = [
 +    &["clippy_utils", "diagnostics", "span_lint"],
 +    &["clippy_utils", "diagnostics", "span_lint_and_help"],
 +    &["clippy_utils", "diagnostics", "span_lint_and_note"],
 +    &["clippy_utils", "diagnostics", "span_lint_hir"],
 +    &["clippy_utils", "diagnostics", "span_lint_and_sugg"],
 +    &["clippy_utils", "diagnostics", "span_lint_and_then"],
 +    &["clippy_utils", "diagnostics", "span_lint_hir_and_then"],
 +];
 +const SUGGESTION_DIAGNOSTIC_BUILDER_METHODS: [(&str, bool); 9] = [
 +    ("span_suggestion", false),
 +    ("span_suggestion_short", false),
 +    ("span_suggestion_verbose", false),
 +    ("span_suggestion_hidden", false),
 +    ("tool_only_span_suggestion", false),
 +    ("multipart_suggestion", true),
 +    ("multipart_suggestions", true),
 +    ("tool_only_multipart_suggestion", true),
 +    ("span_suggestions", true),
 +];
 +const SUGGESTION_FUNCTIONS: [&[&str]; 2] = [
 +    &["clippy_utils", "diagnostics", "multispan_sugg"],
 +    &["clippy_utils", "diagnostics", "multispan_sugg_with_applicability"],
 +];
 +const DEPRECATED_LINT_TYPE: [&str; 3] = ["clippy_lints", "deprecated_lints", "ClippyDeprecatedLint"];
 +
 +/// The index of the applicability name of `paths::APPLICABILITY_VALUES`
 +const APPLICABILITY_NAME_INDEX: usize = 2;
 +/// This applicability will be set for unresolved applicability values.
 +const APPLICABILITY_UNRESOLVED_STR: &str = "Unresolved";
 +
 +declare_clippy_lint! {
 +    /// ### What it does
 +    /// Collects metadata about clippy lints for the website.
 +    ///
 +    /// This lint will be used to report problems of syntax parsing. You should hopefully never
 +    /// see this but never say never I guess ^^
 +    ///
 +    /// ### Why is this bad?
 +    /// This is not a bad thing but definitely a hacky way to do it. See
 +    /// issue [#4310](https://github.com/rust-lang/rust-clippy/issues/4310) for a discussion
 +    /// about the implementation.
 +    ///
 +    /// ### Known problems
 +    /// Hopefully none. It would be pretty uncool to have a problem here :)
 +    ///
 +    /// ### Example output
 +    /// ```json,ignore
 +    /// {
 +    ///     "id": "internal_metadata_collector",
 +    ///     "id_span": {
 +    ///         "path": "clippy_lints/src/utils/internal_lints/metadata_collector.rs",
 +    ///         "line": 1
 +    ///     },
 +    ///     "group": "clippy::internal",
 +    ///     "docs": " ### What it does\nCollects metadata about clippy lints for the website. [...] "
 +    /// }
 +    /// ```
 +    pub INTERNAL_METADATA_COLLECTOR,
 +    internal_warn,
 +    "A busy bee collection metadata about lints"
 +}
 +
 +impl_lint_pass!(MetadataCollector => [INTERNAL_METADATA_COLLECTOR]);
 +
 +#[allow(clippy::module_name_repetitions)]
 +#[derive(Debug, Clone)]
 +pub struct MetadataCollector {
 +    /// All collected lints
 +    ///
 +    /// We use a Heap here to have the lints added in alphabetic order in the export
 +    lints: BinaryHeap<LintMetadata>,
 +    applicability_info: FxHashMap<String, ApplicabilityInfo>,
 +    config: Vec<ClippyConfiguration>,
 +}
 +
 +impl MetadataCollector {
 +    pub fn new() -> Self {
 +        Self {
 +            lints: BinaryHeap::<LintMetadata>::default(),
 +            applicability_info: FxHashMap::<String, ApplicabilityInfo>::default(),
 +            config: collect_configs(),
 +        }
 +    }
 +
 +    fn get_lint_configs(&self, lint_name: &str) -> Option<String> {
 +        self.config
 +            .iter()
 +            .filter(|config| config.lints.iter().any(|lint| lint == lint_name))
 +            .map(ToString::to_string)
 +            .reduce(|acc, x| acc + &x)
 +            .map(|configurations| format!(CONFIGURATION_SECTION_TEMPLATE!(), configurations = configurations))
 +    }
 +}
 +
 +impl Drop for MetadataCollector {
 +    /// You might ask: How hacky is this?
 +    /// My answer:     YES
 +    fn drop(&mut self) {
 +        // The metadata collector gets dropped twice, this makes sure that we only write
 +        // when the list is full
 +        if self.lints.is_empty() {
 +            return;
 +        }
 +
 +        let mut applicability_info = std::mem::take(&mut self.applicability_info);
 +
 +        // Mapping the final data
 +        let mut lints = std::mem::take(&mut self.lints).into_sorted_vec();
 +        lints
 +            .iter_mut()
 +            .for_each(|x| x.applicability = Some(applicability_info.remove(&x.id).unwrap_or_default()));
 +
 +        // Outputting
 +        if Path::new(OUTPUT_FILE).exists() {
 +            fs::remove_file(OUTPUT_FILE).unwrap();
 +        }
 +        let mut file = OpenOptions::new().write(true).create(true).open(OUTPUT_FILE).unwrap();
 +        writeln!(file, "{}", serde_json::to_string_pretty(&lints).unwrap()).unwrap();
 +    }
 +}
 +
 +#[derive(Debug, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord)]
 +struct LintMetadata {
 +    id: String,
 +    id_span: SerializableSpan,
 +    group: String,
 +    level: String,
 +    docs: String,
 +    /// This field is only used in the output and will only be
 +    /// mapped shortly before the actual output.
 +    applicability: Option<ApplicabilityInfo>,
 +}
 +
 +impl LintMetadata {
 +    fn new(id: String, id_span: SerializableSpan, group: String, level: &'static str, docs: String) -> Self {
 +        Self {
 +            id,
 +            id_span,
 +            group,
 +            level: level.to_string(),
 +            docs,
 +            applicability: None,
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord)]
 +struct SerializableSpan {
 +    path: String,
 +    line: usize,
 +}
 +
 +impl std::fmt::Display for SerializableSpan {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        write!(f, "{}:{}", self.path.rsplit('/').next().unwrap_or_default(), self.line)
 +    }
 +}
 +
 +impl SerializableSpan {
 +    fn from_item(cx: &LateContext<'_>, item: &Item<'_>) -> Self {
 +        Self::from_span(cx, item.ident.span)
 +    }
 +
 +    fn from_span(cx: &LateContext<'_>, span: Span) -> Self {
 +        let loc: Loc = cx.sess().source_map().lookup_char_pos(span.lo());
 +
 +        Self {
 +            path: format!("{}", loc.file.name.prefer_remapped()),
 +            line: loc.line,
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
 +struct ApplicabilityInfo {
 +    /// Indicates if any of the lint emissions uses multiple spans. This is related to
 +    /// [rustfix#141](https://github.com/rust-lang/rustfix/issues/141) as such suggestions can
 +    /// currently not be applied automatically.
 +    is_multi_part_suggestion: bool,
 +    applicability: Option<usize>,
 +}
 +
 +impl Serialize for ApplicabilityInfo {
 +    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 +    where
 +        S: Serializer,
 +    {
 +        let mut s = serializer.serialize_struct("ApplicabilityInfo", 2)?;
 +        s.serialize_field("is_multi_part_suggestion", &self.is_multi_part_suggestion)?;
 +        if let Some(index) = self.applicability {
 +            s.serialize_field(
 +                "applicability",
 +                &paths::APPLICABILITY_VALUES[index][APPLICABILITY_NAME_INDEX],
 +            )?;
 +        } else {
 +            s.serialize_field("applicability", APPLICABILITY_UNRESOLVED_STR)?;
 +        }
 +        s.end()
 +    }
 +}
 +
 +// ==================================================================
 +// Configuration
 +// ==================================================================
 +#[derive(Debug, Clone, Default)]
 +pub struct ClippyConfiguration {
 +    name: String,
 +    config_type: &'static str,
 +    default: String,
 +    lints: Vec<String>,
 +    doc: String,
 +    #[allow(dead_code)]
 +    deprecation_reason: Option<&'static str>,
 +}
 +
 +impl ClippyConfiguration {
 +    pub fn new(
 +        name: &'static str,
 +        config_type: &'static str,
 +        default: String,
 +        doc_comment: &'static str,
 +        deprecation_reason: Option<&'static str>,
 +    ) -> Self {
 +        let (lints, doc) = parse_config_field_doc(doc_comment)
 +            .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string()));
 +
 +        Self {
 +            name: to_kebab(name),
 +            lints,
 +            doc,
 +            config_type,
 +            default,
 +            deprecation_reason,
 +        }
 +    }
 +}
 +
 +fn collect_configs() -> Vec<ClippyConfiguration> {
 +    crate::utils::conf::metadata::get_configuration_metadata()
 +}
 +
 +/// This parses the field documentation of the config struct.
 +///
 +/// ```rust, ignore
 +/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin")
 +/// ```
 +///
 +/// Would yield:
 +/// ```rust, ignore
 +/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin")
 +/// ```
 +fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
 +    const DOC_START: &str = " Lint: ";
 +    if_chain! {
 +        if doc_comment.starts_with(DOC_START);
 +        if let Some(split_pos) = doc_comment.find('.');
 +        then {
 +            let mut doc_comment = doc_comment.to_string();
 +            let mut documentation = doc_comment.split_off(split_pos);
 +
 +            // Extract lints
 +            doc_comment.make_ascii_lowercase();
 +            let lints: Vec<String> = doc_comment.split_off(DOC_START.len()).split(", ").map(str::to_string).collect();
 +
 +            // Format documentation correctly
 +            // split off leading `.` from lint name list and indent for correct formatting
 +            documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n    ");
 +
 +            Some((lints, documentation))
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +/// Transforms a given `snake_case_string` to a tasty `kebab-case-string`
 +fn to_kebab(config_name: &str) -> String {
 +    config_name.replace('_', "-")
 +}
 +
 +impl fmt::Display for ClippyConfiguration {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
 +        write!(
 +            f,
 +            CONFIGURATION_VALUE_TEMPLATE!(),
 +            name = self.name,
 +            ty = self.config_type,
 +            doc = self.doc,
 +            default = self.default
 +        )
 +    }
 +}
 +
 +// ==================================================================
 +// Lint pass
 +// ==================================================================
 +impl<'hir> LateLintPass<'hir> for MetadataCollector {
 +    /// Collecting lint declarations like:
 +    /// ```rust, ignore
 +    /// declare_clippy_lint! {
 +    ///     /// ### What it does
 +    ///     /// Something IDK.
 +    ///     pub SOME_LINT,
 +    ///     internal,
 +    ///     "Who am I?"
 +    /// }
 +    /// ```
 +    fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) {
 +        if let ItemKind::Static(ty, Mutability::Not, _) = item.kind {
 +            // Normal lint
 +            if_chain! {
 +                // item validation
 +                if is_lint_ref_type(cx, ty);
 +                // blacklist check
 +                let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
 +                if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
 +                // metadata extraction
 +                if let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item);
 +                if let Some(mut docs) = extract_attr_docs_or_lint(cx, item);
 +                then {
 +                    if let Some(configuration_section) = self.get_lint_configs(&lint_name) {
 +                        docs.push_str(&configuration_section);
 +                    }
 +
 +                    self.lints.push(LintMetadata::new(
 +                        lint_name,
 +                        SerializableSpan::from_item(cx, item),
 +                        group,
 +                        level,
 +                        docs,
 +                    ));
 +                }
 +            }
 +
 +            if_chain! {
 +                if is_deprecated_lint(cx, ty);
 +                // blacklist check
 +                let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
 +                if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
 +                // Metadata the little we can get from a deprecated lint
 +                if let Some(docs) = extract_attr_docs_or_lint(cx, item);
 +                then {
 +                    self.lints.push(LintMetadata::new(
 +                        lint_name,
 +                        SerializableSpan::from_item(cx, item),
 +                        DEPRECATED_LINT_GROUP_STR.to_string(),
 +                        DEPRECATED_LINT_LEVEL,
 +                        docs,
 +                    ));
 +                }
 +            }
 +        }
 +    }
 +
 +    /// Collecting constant applicability from the actual lint emissions
 +    ///
 +    /// Example:
 +    /// ```rust, ignore
 +    /// span_lint_and_sugg(
 +    ///     cx,
 +    ///     SOME_LINT,
 +    ///     item.span,
 +    ///     "Le lint message",
 +    ///     "Here comes help:",
 +    ///     "#![allow(clippy::all)]",
 +    ///     Applicability::MachineApplicable, // <-- Extracts this constant value
 +    /// );
 +    /// ```
 +    fn check_expr(&mut self, cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>) {
 +        if let Some(args) = match_lint_emission(cx, expr) {
 +            let mut emission_info = extract_emission_info(cx, args);
 +            if emission_info.is_empty() {
 +                // See:
 +                // - src/misc.rs:734:9
 +                // - src/methods/mod.rs:3545:13
 +                // - src/methods/mod.rs:3496:13
 +                // We are basically unable to resolve the lint name itself.
 +                return;
 +            }
 +
 +            for (lint_name, applicability, is_multi_part) in emission_info.drain(..) {
 +                let app_info = self.applicability_info.entry(lint_name).or_default();
 +                app_info.applicability = applicability;
 +                app_info.is_multi_part_suggestion = is_multi_part;
 +            }
 +        }
 +    }
 +}
 +
 +// ==================================================================
 +// Lint definition extraction
 +// ==================================================================
 +fn sym_to_string(sym: Symbol) -> String {
 +    sym.as_str().to_string()
 +}
 +
 +fn extract_attr_docs_or_lint(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
 +    extract_attr_docs(cx, item).or_else(|| {
 +        lint_collection_error_item(cx, item, "could not collect the lint documentation");
 +        None
 +    })
 +}
 +
 +/// This function collects all documentation that has been added to an item using
 +/// `#[doc = r""]` attributes. Several attributes are aggravated using line breaks
 +///
 +/// ```ignore
 +/// #[doc = r"Hello world!"]
 +/// #[doc = r"=^.^="]
 +/// struct SomeItem {}
 +/// ```
 +///
 +/// Would result in `Hello world!\n=^.^=\n`
 +///
 +/// ---
 +///
 +/// This function may modify the doc comment to ensure that the string can be displayed using a
 +/// markdown viewer in Clippy's lint list. The following modifications could be applied:
 +/// * Removal of leading space after a new line. (Important to display tables)
 +/// * Ensures that code blocks only contain language information
 +fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
 +    let attrs = cx.tcx.hir().attrs(item.hir_id());
 +    let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str);
 +    let mut docs = String::from(&*lines.next()?.as_str());
 +    let mut in_code_block = false;
++    let mut is_code_block_rust = false;
 +    for line in lines {
 +        let line = line.as_str();
 +        let line = &*line;
++
++        // Rustdoc hides code lines starting with `# ` and this removes them from Clippy's lint list :)
++        if is_code_block_rust && line.trim_start().starts_with("# ") {
++            continue;
++        }
++
++        // The line should be represented in the lint list, even if it's just an empty line
++        docs.push('\n');
 +        if let Some(info) = line.trim_start().strip_prefix("```") {
 +            in_code_block = !in_code_block;
++            is_code_block_rust = false;
 +            if in_code_block {
 +                let lang = info
 +                    .trim()
 +                    .split(',')
 +                    // remove rustdoc directives
 +                    .find(|&s| !matches!(s, "" | "ignore" | "no_run" | "should_panic"))
 +                    // if no language is present, fill in "rust"
 +                    .unwrap_or("rust");
 +                docs.push_str("```");
 +                docs.push_str(lang);
++
++                is_code_block_rust = lang == "rust";
 +                continue;
 +            }
 +        }
 +        // This removes the leading space that the macro translation introduces
 +        if let Some(stripped_doc) = line.strip_prefix(' ') {
 +            docs.push_str(stripped_doc);
 +        } else if !line.is_empty() {
 +            docs.push_str(line);
 +        }
 +    }
 +    Some(docs)
 +}
 +
 +fn get_lint_group_and_level_or_lint(
 +    cx: &LateContext<'_>,
 +    lint_name: &str,
 +    item: &'hir Item<'_>,
 +) -> Option<(String, &'static str)> {
 +    let result = cx
 +        .lint_store
 +        .check_lint_name(cx.sess(), lint_name, Some(sym::clippy), &[]);
 +    if let CheckLintNameResult::Tool(Ok(lint_lst)) = result {
 +        if let Some(group) = get_lint_group(cx, lint_lst[0]) {
 +            if EXCLUDED_LINT_GROUPS.contains(&group.as_str()) {
 +                return None;
 +            }
 +
 +            if let Some(level) = get_lint_level_from_group(&group) {
 +                Some((group, level))
 +            } else {
 +                lint_collection_error_item(
 +                    cx,
 +                    item,
 +                    &format!("Unable to determine lint level for found group `{}`", group),
 +                );
 +                None
 +            }
 +        } else {
 +            lint_collection_error_item(cx, item, "Unable to determine lint group");
 +            None
 +        }
 +    } else {
 +        lint_collection_error_item(cx, item, "Unable to find lint in lint_store");
 +        None
 +    }
 +}
 +
 +fn get_lint_group(cx: &LateContext<'_>, lint_id: LintId) -> Option<String> {
 +    for (group_name, lints, _) in &cx.lint_store.get_lint_groups() {
 +        if IGNORED_LINT_GROUPS.contains(group_name) {
 +            continue;
 +        }
 +
 +        if lints.iter().any(|group_lint| *group_lint == lint_id) {
 +            let group = group_name.strip_prefix(CLIPPY_LINT_GROUP_PREFIX).unwrap_or(group_name);
 +            return Some((*group).to_string());
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn get_lint_level_from_group(lint_group: &str) -> Option<&'static str> {
 +    DEFAULT_LINT_LEVELS
 +        .iter()
 +        .find_map(|(group_name, group_level)| (*group_name == lint_group).then(|| *group_level))
 +}
 +
 +fn is_deprecated_lint(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
 +    if let hir::TyKind::Path(ref path) = ty.kind {
 +        if let hir::def::Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, ty.hir_id) {
 +            return match_def_path(cx, def_id, &DEPRECATED_LINT_TYPE);
 +        }
 +    }
 +
 +    false
 +}
 +
 +// ==================================================================
 +// Lint emission
 +// ==================================================================
 +fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &str) {
 +    span_lint(
 +        cx,
 +        INTERNAL_METADATA_COLLECTOR,
 +        item.ident.span,
 +        &format!("metadata collection error for `{}`: {}", item.ident.name, message),
 +    );
 +}
 +
 +// ==================================================================
 +// Applicability
 +// ==================================================================
 +/// This function checks if a given expression is equal to a simple lint emission function call.
 +/// It will return the function arguments if the emission matched any function.
 +fn match_lint_emission<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>) -> Option<&'hir [hir::Expr<'hir>]> {
 +    LINT_EMISSION_FUNCTIONS
 +        .iter()
 +        .find_map(|emission_fn| match_function_call(cx, expr, emission_fn))
 +}
 +
 +fn take_higher_applicability(a: Option<usize>, b: Option<usize>) -> Option<usize> {
 +    a.map_or(b, |a| a.max(b.unwrap_or_default()).into())
 +}
 +
 +fn extract_emission_info<'hir>(
 +    cx: &LateContext<'hir>,
 +    args: &'hir [hir::Expr<'hir>],
 +) -> Vec<(String, Option<usize>, bool)> {
 +    let mut lints = Vec::new();
 +    let mut applicability = None;
 +    let mut multi_part = false;
 +
 +    for arg in args {
 +        let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(arg));
 +
 +        if match_type(cx, arg_ty, &paths::LINT) {
 +            // If we found the lint arg, extract the lint name
 +            let mut resolved_lints = resolve_lints(cx, arg);
 +            lints.append(&mut resolved_lints);
 +        } else if match_type(cx, arg_ty, &paths::APPLICABILITY) {
 +            applicability = resolve_applicability(cx, arg);
 +        } else if arg_ty.is_closure() {
 +            multi_part |= check_is_multi_part(cx, arg);
 +            // TODO xFrednet 2021-03-01: don't use or_else but rather a comparison
 +            applicability = applicability.or_else(|| resolve_applicability(cx, arg));
 +        }
 +    }
 +
 +    lints
 +        .drain(..)
 +        .map(|lint_name| (lint_name, applicability, multi_part))
 +        .collect()
 +}
 +
 +/// Resolves the possible lints that this expression could reference
 +fn resolve_lints(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Vec<String> {
 +    let mut resolver = LintResolver::new(cx);
 +    resolver.visit_expr(expr);
 +    resolver.lints
 +}
 +
 +/// This function tries to resolve the linked applicability to the given expression.
 +fn resolve_applicability(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<usize> {
 +    let mut resolver = ApplicabilityResolver::new(cx);
 +    resolver.visit_expr(expr);
 +    resolver.complete()
 +}
 +
 +fn check_is_multi_part(cx: &LateContext<'hir>, closure_expr: &'hir hir::Expr<'hir>) -> bool {
 +    if let ExprKind::Closure(_, _, body_id, _, _) = closure_expr.kind {
 +        let mut scanner = IsMultiSpanScanner::new(cx);
 +        intravisit::walk_body(&mut scanner, cx.tcx.hir().body(body_id));
 +        return scanner.is_multi_part();
 +    } else if let Some(local) = get_parent_local(cx, closure_expr) {
 +        if let Some(local_init) = local.init {
 +            return check_is_multi_part(cx, local_init);
 +        }
 +    }
 +
 +    false
 +}
 +
 +struct LintResolver<'a, 'hir> {
 +    cx: &'a LateContext<'hir>,
 +    lints: Vec<String>,
 +}
 +
 +impl<'a, 'hir> LintResolver<'a, 'hir> {
 +    fn new(cx: &'a LateContext<'hir>) -> Self {
 +        Self {
 +            cx,
 +            lints: Vec::<String>::default(),
 +        }
 +    }
 +}
 +
 +impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> {
 +    type Map = Map<'hir>;
 +
 +    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
 +        intravisit::NestedVisitorMap::All(self.cx.tcx.hir())
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
 +        if_chain! {
 +            if let ExprKind::Path(qpath) = &expr.kind;
 +            if let QPath::Resolved(_, path) = qpath;
 +
 +            let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
 +            if match_type(self.cx, expr_ty, &paths::LINT);
 +            then {
 +                if let hir::def::Res::Def(DefKind::Static, _) = path.res {
 +                    let lint_name = last_path_segment(qpath).ident.name;
 +                    self.lints.push(sym_to_string(lint_name).to_ascii_lowercase());
 +                } else if let Some(local) = get_parent_local(self.cx, expr) {
 +                    if let Some(local_init) = local.init {
 +                        intravisit::walk_expr(self, local_init);
 +                    }
 +                }
 +            }
 +        }
 +
 +        intravisit::walk_expr(self, expr);
 +    }
 +}
 +
 +/// This visitor finds the highest applicability value in the visited expressions
 +struct ApplicabilityResolver<'a, 'hir> {
 +    cx: &'a LateContext<'hir>,
 +    /// This is the index of hightest `Applicability` for `paths::APPLICABILITY_VALUES`
 +    applicability_index: Option<usize>,
 +}
 +
 +impl<'a, 'hir> ApplicabilityResolver<'a, 'hir> {
 +    fn new(cx: &'a LateContext<'hir>) -> Self {
 +        Self {
 +            cx,
 +            applicability_index: None,
 +        }
 +    }
 +
 +    fn add_new_index(&mut self, new_index: usize) {
 +        self.applicability_index = take_higher_applicability(self.applicability_index, Some(new_index));
 +    }
 +
 +    fn complete(self) -> Option<usize> {
 +        self.applicability_index
 +    }
 +}
 +
 +impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> {
 +    type Map = Map<'hir>;
 +
 +    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
 +        intravisit::NestedVisitorMap::All(self.cx.tcx.hir())
 +    }
 +
 +    fn visit_path(&mut self, path: &'hir hir::Path<'hir>, _id: hir::HirId) {
 +        for (index, enum_value) in paths::APPLICABILITY_VALUES.iter().enumerate() {
 +            if match_path(path, enum_value) {
 +                self.add_new_index(index);
 +                return;
 +            }
 +        }
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
 +        let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
 +
 +        if_chain! {
 +            if match_type(self.cx, expr_ty, &paths::APPLICABILITY);
 +            if let Some(local) = get_parent_local(self.cx, expr);
 +            if let Some(local_init) = local.init;
 +            then {
 +                intravisit::walk_expr(self, local_init);
 +            }
 +        };
 +
 +        intravisit::walk_expr(self, expr);
 +    }
 +}
 +
 +/// This returns the parent local node if the expression is a reference one
 +fn get_parent_local(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::Local<'hir>> {
 +    if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind {
 +        if let hir::def::Res::Local(local_hir) = path.res {
 +            return get_parent_local_hir_id(cx, local_hir);
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn get_parent_local_hir_id(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
 +    let map = cx.tcx.hir();
 +
 +    match map.find(map.get_parent_node(hir_id)) {
 +        Some(hir::Node::Local(local)) => Some(local),
 +        Some(hir::Node::Pat(pattern)) => get_parent_local_hir_id(cx, pattern.hir_id),
 +        _ => None,
 +    }
 +}
 +
 +/// This visitor finds the highest applicability value in the visited expressions
 +struct IsMultiSpanScanner<'a, 'hir> {
 +    cx: &'a LateContext<'hir>,
 +    suggestion_count: usize,
 +}
 +
 +impl<'a, 'hir> IsMultiSpanScanner<'a, 'hir> {
 +    fn new(cx: &'a LateContext<'hir>) -> Self {
 +        Self {
 +            cx,
 +            suggestion_count: 0,
 +        }
 +    }
 +
 +    /// Add a new single expression suggestion to the counter
 +    fn add_single_span_suggestion(&mut self) {
 +        self.suggestion_count += 1;
 +    }
 +
 +    /// Signals that a suggestion with possible multiple spans was found
 +    fn add_multi_part_suggestion(&mut self) {
 +        self.suggestion_count += 2;
 +    }
 +
 +    /// Checks if the suggestions include multiple spanns
 +    fn is_multi_part(&self) -> bool {
 +        self.suggestion_count > 1
 +    }
 +}
 +
 +impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> {
 +    type Map = Map<'hir>;
 +
 +    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
 +        intravisit::NestedVisitorMap::All(self.cx.tcx.hir())
 +    }
 +
 +    fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
 +        // Early return if the lint is already multi span
 +        if self.is_multi_part() {
 +            return;
 +        }
 +
 +        match &expr.kind {
 +            ExprKind::Call(fn_expr, _args) => {
 +                let found_function = SUGGESTION_FUNCTIONS
 +                    .iter()
 +                    .any(|func_path| match_function_call(self.cx, fn_expr, func_path).is_some());
 +                if found_function {
 +                    // These functions are all multi part suggestions
 +                    self.add_single_span_suggestion();
 +                }
 +            },
 +            ExprKind::MethodCall(path, _path_span, arg, _arg_span) => {
 +                let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&arg[0]));
 +                if match_type(self.cx, self_ty, &paths::DIAGNOSTIC_BUILDER) {
 +                    let called_method = path.ident.name.as_str().to_string();
 +                    for (method_name, is_multi_part) in &SUGGESTION_DIAGNOSTIC_BUILDER_METHODS {
 +                        if *method_name == called_method {
 +                            if *is_multi_part {
 +                                self.add_multi_part_suggestion();
 +                            } else {
 +                                self.add_single_span_suggestion();
 +                            }
 +                            break;
 +                        }
 +                    }
 +                }
 +            },
 +            _ => {},
 +        }
 +
 +        intravisit::walk_expr(self, expr);
 +    }
 +}
index 8bf31807d55d1441d74e503a42e29334aee365f0,0000000000000000000000000000000000000000..04347672e0fbb35e12241580aacfeac22de28fbc
mode 100644,000000..100644
--- /dev/null
@@@ -1,577 -1,0 +1,636 @@@
 +#![allow(clippy::float_cmp)]
 +
 +use crate::{clip, is_direct_expn_of, sext, unsext};
 +use if_chain::if_chain;
 +use rustc_ast::ast::{self, LitFloatType, LitKind};
 +use rustc_data_structures::sync::Lrc;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, QPath, UnOp};
 +use rustc_lint::LateContext;
 +use rustc_middle::mir::interpret::Scalar;
 +use rustc_middle::ty::subst::{Subst, SubstsRef};
 +use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty, TyCtxt};
 +use rustc_middle::{bug, span_bug};
 +use rustc_span::symbol::Symbol;
 +use std::cmp::Ordering::{self, Equal};
 +use std::convert::TryInto;
 +use std::hash::{Hash, Hasher};
 +use std::iter;
 +
 +/// A `LitKind`-like enum to fold constant `Expr`s into.
 +#[derive(Debug, Clone)]
 +pub enum Constant {
 +    /// A `String` (e.g., "abc").
 +    Str(String),
 +    /// A binary string (e.g., `b"abc"`).
 +    Binary(Lrc<[u8]>),
 +    /// A single `char` (e.g., `'a'`).
 +    Char(char),
 +    /// An integer's bit representation.
 +    Int(u128),
 +    /// An `f32`.
 +    F32(f32),
 +    /// An `f64`.
 +    F64(f64),
 +    /// `true` or `false`.
 +    Bool(bool),
 +    /// An array of constants.
 +    Vec(Vec<Constant>),
 +    /// Also an array, but with only one constant, repeated N times.
 +    Repeat(Box<Constant>, u64),
 +    /// A tuple of constants.
 +    Tuple(Vec<Constant>),
 +    /// A raw pointer.
 +    RawPtr(u128),
 +    /// A reference
 +    Ref(Box<Constant>),
 +    /// A literal with syntax error.
 +    Err(Symbol),
 +}
 +
 +impl PartialEq for Constant {
 +    fn eq(&self, other: &Self) -> bool {
 +        match (self, other) {
 +            (&Self::Str(ref ls), &Self::Str(ref rs)) => ls == rs,
 +            (&Self::Binary(ref l), &Self::Binary(ref r)) => l == r,
 +            (&Self::Char(l), &Self::Char(r)) => l == r,
 +            (&Self::Int(l), &Self::Int(r)) => l == r,
 +            (&Self::F64(l), &Self::F64(r)) => {
 +                // We want `Fw32 == FwAny` and `FwAny == Fw64`, and by transitivity we must have
 +                // `Fw32 == Fw64`, so don’t compare them.
 +                // `to_bits` is required to catch non-matching 0.0, -0.0, and NaNs.
 +                l.to_bits() == r.to_bits()
 +            },
 +            (&Self::F32(l), &Self::F32(r)) => {
 +                // We want `Fw32 == FwAny` and `FwAny == Fw64`, and by transitivity we must have
 +                // `Fw32 == Fw64`, so don’t compare them.
 +                // `to_bits` is required to catch non-matching 0.0, -0.0, and NaNs.
 +                f64::from(l).to_bits() == f64::from(r).to_bits()
 +            },
 +            (&Self::Bool(l), &Self::Bool(r)) => l == r,
 +            (&Self::Vec(ref l), &Self::Vec(ref r)) | (&Self::Tuple(ref l), &Self::Tuple(ref r)) => l == r,
 +            (&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => ls == rs && lv == rv,
 +            (&Self::Ref(ref lb), &Self::Ref(ref rb)) => *lb == *rb,
 +            // TODO: are there inter-type equalities?
 +            _ => false,
 +        }
 +    }
 +}
 +
 +impl Hash for Constant {
 +    fn hash<H>(&self, state: &mut H)
 +    where
 +        H: Hasher,
 +    {
 +        std::mem::discriminant(self).hash(state);
 +        match *self {
 +            Self::Str(ref s) => {
 +                s.hash(state);
 +            },
 +            Self::Binary(ref b) => {
 +                b.hash(state);
 +            },
 +            Self::Char(c) => {
 +                c.hash(state);
 +            },
 +            Self::Int(i) => {
 +                i.hash(state);
 +            },
 +            Self::F32(f) => {
 +                f64::from(f).to_bits().hash(state);
 +            },
 +            Self::F64(f) => {
 +                f.to_bits().hash(state);
 +            },
 +            Self::Bool(b) => {
 +                b.hash(state);
 +            },
 +            Self::Vec(ref v) | Self::Tuple(ref v) => {
 +                v.hash(state);
 +            },
 +            Self::Repeat(ref c, l) => {
 +                c.hash(state);
 +                l.hash(state);
 +            },
 +            Self::RawPtr(u) => {
 +                u.hash(state);
 +            },
 +            Self::Ref(ref r) => {
 +                r.hash(state);
 +            },
 +            Self::Err(ref s) => {
 +                s.hash(state);
 +            },
 +        }
 +    }
 +}
 +
 +impl Constant {
 +    pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option<Ordering> {
 +        match (left, right) {
 +            (&Self::Str(ref ls), &Self::Str(ref rs)) => Some(ls.cmp(rs)),
 +            (&Self::Char(ref l), &Self::Char(ref r)) => Some(l.cmp(r)),
 +            (&Self::Int(l), &Self::Int(r)) => {
 +                if let ty::Int(int_ty) = *cmp_type.kind() {
 +                    Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty)))
 +                } else {
 +                    Some(l.cmp(&r))
 +                }
 +            },
 +            (&Self::F64(l), &Self::F64(r)) => l.partial_cmp(&r),
 +            (&Self::F32(l), &Self::F32(r)) => l.partial_cmp(&r),
 +            (&Self::Bool(ref l), &Self::Bool(ref r)) => Some(l.cmp(r)),
 +            (&Self::Tuple(ref l), &Self::Tuple(ref r)) | (&Self::Vec(ref l), &Self::Vec(ref r)) => iter::zip(l, r)
 +                .map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri))
 +                .find(|r| r.map_or(true, |o| o != Ordering::Equal))
 +                .unwrap_or_else(|| Some(l.len().cmp(&r.len()))),
 +            (&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => {
 +                match Self::partial_cmp(tcx, cmp_type, lv, rv) {
 +                    Some(Equal) => Some(ls.cmp(rs)),
 +                    x => x,
 +                }
 +            },
 +            (&Self::Ref(ref lb), &Self::Ref(ref rb)) => Self::partial_cmp(tcx, cmp_type, lb, rb),
 +            // TODO: are there any useful inter-type orderings?
 +            _ => None,
 +        }
 +    }
++
++    /// Returns the integer value or `None` if `self` or `val_type` is not integer type.
++    pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option<FullInt> {
++        if let Constant::Int(const_int) = *self {
++            match *val_type.kind() {
++                ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
++                ty::Uint(_) => Some(FullInt::U(const_int)),
++                _ => None,
++            }
++        } else {
++            None
++        }
++    }
 +}
 +
 +/// Parses a `LitKind` to a `Constant`.
 +pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
 +    match *lit {
 +        LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
 +        LitKind::Byte(b) => Constant::Int(u128::from(b)),
 +        LitKind::ByteStr(ref s) => Constant::Binary(Lrc::clone(s)),
 +        LitKind::Char(c) => Constant::Char(c),
 +        LitKind::Int(n, _) => Constant::Int(n),
 +        LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
 +            ast::FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()),
 +            ast::FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()),
 +        },
 +        LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind() {
 +            ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
 +            ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()),
 +            _ => bug!(),
 +        },
 +        LitKind::Bool(b) => Constant::Bool(b),
 +        LitKind::Err(s) => Constant::Err(s),
 +    }
 +}
 +
 +pub fn constant<'tcx>(
 +    lcx: &LateContext<'tcx>,
 +    typeck_results: &ty::TypeckResults<'tcx>,
 +    e: &Expr<'_>,
 +) -> Option<(Constant, bool)> {
 +    let mut cx = ConstEvalLateContext {
 +        lcx,
 +        typeck_results,
 +        param_env: lcx.param_env,
 +        needed_resolution: false,
 +        substs: lcx.tcx.intern_substs(&[]),
 +    };
 +    cx.expr(e).map(|cst| (cst, cx.needed_resolution))
 +}
 +
 +pub fn constant_simple<'tcx>(
 +    lcx: &LateContext<'tcx>,
 +    typeck_results: &ty::TypeckResults<'tcx>,
 +    e: &Expr<'_>,
 +) -> Option<Constant> {
 +    constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
 +}
 +
++pub fn constant_full_int(
++    lcx: &LateContext<'tcx>,
++    typeck_results: &ty::TypeckResults<'tcx>,
++    e: &Expr<'_>,
++) -> Option<FullInt> {
++    constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e))
++}
++
++#[derive(Copy, Clone, Debug, Eq)]
++pub enum FullInt {
++    S(i128),
++    U(u128),
++}
++
++impl PartialEq for FullInt {
++    #[must_use]
++    fn eq(&self, other: &Self) -> bool {
++        self.cmp(other) == Ordering::Equal
++    }
++}
++
++impl PartialOrd for FullInt {
++    #[must_use]
++    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
++        Some(self.cmp(other))
++    }
++}
++
++impl Ord for FullInt {
++    #[must_use]
++    fn cmp(&self, other: &Self) -> Ordering {
++        use FullInt::{S, U};
++
++        fn cmp_s_u(s: i128, u: u128) -> Ordering {
++            u128::try_from(s).map_or(Ordering::Less, |x| x.cmp(&u))
++        }
++
++        match (*self, *other) {
++            (S(s), S(o)) => s.cmp(&o),
++            (U(s), U(o)) => s.cmp(&o),
++            (S(s), U(o)) => cmp_s_u(s, o),
++            (U(s), S(o)) => cmp_s_u(o, s).reverse(),
++        }
++    }
++}
++
 +/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`.
 +pub fn constant_context<'a, 'tcx>(
 +    lcx: &'a LateContext<'tcx>,
 +    typeck_results: &'a ty::TypeckResults<'tcx>,
 +) -> ConstEvalLateContext<'a, 'tcx> {
 +    ConstEvalLateContext {
 +        lcx,
 +        typeck_results,
 +        param_env: lcx.param_env,
 +        needed_resolution: false,
 +        substs: lcx.tcx.intern_substs(&[]),
 +    }
 +}
 +
 +pub struct ConstEvalLateContext<'a, 'tcx> {
 +    lcx: &'a LateContext<'tcx>,
 +    typeck_results: &'a ty::TypeckResults<'tcx>,
 +    param_env: ty::ParamEnv<'tcx>,
 +    needed_resolution: bool,
 +    substs: SubstsRef<'tcx>,
 +}
 +
 +impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
 +    /// Simple constant folding: Insert an expression, get a constant or none.
 +    pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
 +        match e.kind {
 +            ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
 +            ExprKind::Block(block, _) => self.block(block),
 +            ExprKind::Lit(ref lit) => {
 +                if is_direct_expn_of(e.span, "cfg").is_some() {
 +                    None
 +                } else {
 +                    Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e)))
 +                }
 +            },
 +            ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec),
 +            ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
 +            ExprKind::Repeat(value, _) => {
 +                let n = match self.typeck_results.expr_ty(e).kind() {
 +                    ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?,
 +                    _ => span_bug!(e.span, "typeck error"),
 +                };
 +                self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
 +            },
 +            ExprKind::Unary(op, operand) => self.expr(operand).and_then(|o| match op {
 +                UnOp::Not => self.constant_not(&o, self.typeck_results.expr_ty(e)),
 +                UnOp::Neg => self.constant_negate(&o, self.typeck_results.expr_ty(e)),
 +                UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }),
 +            }),
 +            ExprKind::If(cond, then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
 +            ExprKind::Binary(op, left, right) => self.binop(op, left, right),
 +            ExprKind::Call(callee, args) => {
 +                // We only handle a few const functions for now.
 +                if_chain! {
 +                    if args.is_empty();
 +                    if let ExprKind::Path(qpath) = &callee.kind;
 +                    let res = self.typeck_results.qpath_res(qpath, callee.hir_id);
 +                    if let Some(def_id) = res.opt_def_id();
 +                    let def_path: Vec<_> = self.lcx.get_def_path(def_id).into_iter().map(Symbol::as_str).collect();
 +                    let def_path: Vec<&str> = def_path.iter().take(4).map(|s| &**s).collect();
 +                    if let ["core", "num", int_impl, "max_value"] = *def_path;
 +                    then {
 +                       let value = match int_impl {
 +                           "<impl i8>" => i8::MAX as u128,
 +                           "<impl i16>" => i16::MAX as u128,
 +                           "<impl i32>" => i32::MAX as u128,
 +                           "<impl i64>" => i64::MAX as u128,
 +                           "<impl i128>" => i128::MAX as u128,
 +                           _ => return None,
 +                       };
 +                       Some(Constant::Int(value))
 +                    }
 +                    else {
 +                        None
 +                    }
 +                }
 +            },
 +            ExprKind::Index(arr, index) => self.index(arr, index),
 +            ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
 +            // TODO: add other expressions.
 +            _ => None,
 +        }
 +    }
 +
 +    #[allow(clippy::cast_possible_wrap)]
 +    fn constant_not(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
 +        use self::Constant::{Bool, Int};
 +        match *o {
 +            Bool(b) => Some(Bool(!b)),
 +            Int(value) => {
 +                let value = !value;
 +                match *ty.kind() {
 +                    ty::Int(ity) => Some(Int(unsext(self.lcx.tcx, value as i128, ity))),
 +                    ty::Uint(ity) => Some(Int(clip(self.lcx.tcx, value, ity))),
 +                    _ => None,
 +                }
 +            },
 +            _ => None,
 +        }
 +    }
 +
 +    fn constant_negate(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
 +        use self::Constant::{Int, F32, F64};
 +        match *o {
 +            Int(value) => {
 +                let ity = match *ty.kind() {
 +                    ty::Int(ity) => ity,
 +                    _ => return None,
 +                };
 +                // sign extend
 +                let value = sext(self.lcx.tcx, value, ity);
 +                let value = value.checked_neg()?;
 +                // clear unused bits
 +                Some(Int(unsext(self.lcx.tcx, value, ity)))
 +            },
 +            F32(f) => Some(F32(-f)),
 +            F64(f) => Some(F64(-f)),
 +            _ => None,
 +        }
 +    }
 +
 +    /// Create `Some(Vec![..])` of all constants, unless there is any
 +    /// non-constant part.
 +    fn multi(&mut self, vec: &[Expr<'_>]) -> Option<Vec<Constant>> {
 +        vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
 +    }
 +
 +    /// Lookup a possibly constant expression from an `ExprKind::Path`.
 +    fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<Constant> {
 +        let res = self.typeck_results.qpath_res(qpath, id);
 +        match res {
 +            Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
 +                let substs = self.typeck_results.node_substs(id);
 +                let substs = if self.substs.is_empty() {
 +                    substs
 +                } else {
 +                    substs.subst(self.lcx.tcx, self.substs)
 +                };
 +
 +                let result = self
 +                    .lcx
 +                    .tcx
 +                    .const_eval_resolve(
 +                        self.param_env,
 +                        ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs),
 +                        None,
 +                    )
 +                    .ok()
 +                    .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
 +                let result = miri_to_const(result);
 +                if result.is_some() {
 +                    self.needed_resolution = true;
 +                }
 +                result
 +            },
 +            // FIXME: cover all usable cases.
 +            _ => None,
 +        }
 +    }
 +
 +    fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant> {
 +        let lhs = self.expr(lhs);
 +        let index = self.expr(index);
 +
 +        match (lhs, index) {
 +            (Some(Constant::Vec(vec)), Some(Constant::Int(index))) => match vec.get(index as usize) {
 +                Some(Constant::F32(x)) => Some(Constant::F32(*x)),
 +                Some(Constant::F64(x)) => Some(Constant::F64(*x)),
 +                _ => None,
 +            },
 +            (Some(Constant::Vec(vec)), _) => {
 +                if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) {
 +                    match vec.get(0) {
 +                        Some(Constant::F32(x)) => Some(Constant::F32(*x)),
 +                        Some(Constant::F64(x)) => Some(Constant::F64(*x)),
 +                        _ => None,
 +                    }
 +                } else {
 +                    None
 +                }
 +            },
 +            _ => None,
 +        }
 +    }
 +
 +    /// A block can only yield a constant if it only has one constant expression.
 +    fn block(&mut self, block: &Block<'_>) -> Option<Constant> {
 +        if block.stmts.is_empty() {
 +            block.expr.as_ref().and_then(|b| self.expr(b))
 +        } else {
 +            None
 +        }
 +    }
 +
 +    fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant> {
 +        if let Some(Constant::Bool(b)) = self.expr(cond) {
 +            if b {
 +                self.expr(&*then)
 +            } else {
 +                otherwise.as_ref().and_then(|expr| self.expr(expr))
 +            }
 +        } else {
 +            None
 +        }
 +    }
 +
 +    fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant> {
 +        let l = self.expr(left)?;
 +        let r = self.expr(right);
 +        match (l, r) {
 +            (Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck_results.expr_ty_opt(left)?.kind() {
 +                ty::Int(ity) => {
 +                    let l = sext(self.lcx.tcx, l, ity);
 +                    let r = sext(self.lcx.tcx, r, ity);
 +                    let zext = |n: i128| Constant::Int(unsext(self.lcx.tcx, n, ity));
 +                    match op.node {
 +                        BinOpKind::Add => l.checked_add(r).map(zext),
 +                        BinOpKind::Sub => l.checked_sub(r).map(zext),
 +                        BinOpKind::Mul => l.checked_mul(r).map(zext),
 +                        BinOpKind::Div if r != 0 => l.checked_div(r).map(zext),
 +                        BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext),
 +                        BinOpKind::Shr => l.checked_shr(r.try_into().expect("invalid shift")).map(zext),
 +                        BinOpKind::Shl => l.checked_shl(r.try_into().expect("invalid shift")).map(zext),
 +                        BinOpKind::BitXor => Some(zext(l ^ r)),
 +                        BinOpKind::BitOr => Some(zext(l | r)),
 +                        BinOpKind::BitAnd => Some(zext(l & r)),
 +                        BinOpKind::Eq => Some(Constant::Bool(l == r)),
 +                        BinOpKind::Ne => Some(Constant::Bool(l != r)),
 +                        BinOpKind::Lt => Some(Constant::Bool(l < r)),
 +                        BinOpKind::Le => Some(Constant::Bool(l <= r)),
 +                        BinOpKind::Ge => Some(Constant::Bool(l >= r)),
 +                        BinOpKind::Gt => Some(Constant::Bool(l > r)),
 +                        _ => None,
 +                    }
 +                },
 +                ty::Uint(_) => match op.node {
 +                    BinOpKind::Add => l.checked_add(r).map(Constant::Int),
 +                    BinOpKind::Sub => l.checked_sub(r).map(Constant::Int),
 +                    BinOpKind::Mul => l.checked_mul(r).map(Constant::Int),
 +                    BinOpKind::Div => l.checked_div(r).map(Constant::Int),
 +                    BinOpKind::Rem => l.checked_rem(r).map(Constant::Int),
 +                    BinOpKind::Shr => l.checked_shr(r.try_into().expect("shift too large")).map(Constant::Int),
 +                    BinOpKind::Shl => l.checked_shl(r.try_into().expect("shift too large")).map(Constant::Int),
 +                    BinOpKind::BitXor => Some(Constant::Int(l ^ r)),
 +                    BinOpKind::BitOr => Some(Constant::Int(l | r)),
 +                    BinOpKind::BitAnd => Some(Constant::Int(l & r)),
 +                    BinOpKind::Eq => Some(Constant::Bool(l == r)),
 +                    BinOpKind::Ne => Some(Constant::Bool(l != r)),
 +                    BinOpKind::Lt => Some(Constant::Bool(l < r)),
 +                    BinOpKind::Le => Some(Constant::Bool(l <= r)),
 +                    BinOpKind::Ge => Some(Constant::Bool(l >= r)),
 +                    BinOpKind::Gt => Some(Constant::Bool(l > r)),
 +                    _ => None,
 +                },
 +                _ => None,
 +            },
 +            (Constant::F32(l), Some(Constant::F32(r))) => match op.node {
 +                BinOpKind::Add => Some(Constant::F32(l + r)),
 +                BinOpKind::Sub => Some(Constant::F32(l - r)),
 +                BinOpKind::Mul => Some(Constant::F32(l * r)),
 +                BinOpKind::Div => Some(Constant::F32(l / r)),
 +                BinOpKind::Rem => Some(Constant::F32(l % r)),
 +                BinOpKind::Eq => Some(Constant::Bool(l == r)),
 +                BinOpKind::Ne => Some(Constant::Bool(l != r)),
 +                BinOpKind::Lt => Some(Constant::Bool(l < r)),
 +                BinOpKind::Le => Some(Constant::Bool(l <= r)),
 +                BinOpKind::Ge => Some(Constant::Bool(l >= r)),
 +                BinOpKind::Gt => Some(Constant::Bool(l > r)),
 +                _ => None,
 +            },
 +            (Constant::F64(l), Some(Constant::F64(r))) => match op.node {
 +                BinOpKind::Add => Some(Constant::F64(l + r)),
 +                BinOpKind::Sub => Some(Constant::F64(l - r)),
 +                BinOpKind::Mul => Some(Constant::F64(l * r)),
 +                BinOpKind::Div => Some(Constant::F64(l / r)),
 +                BinOpKind::Rem => Some(Constant::F64(l % r)),
 +                BinOpKind::Eq => Some(Constant::Bool(l == r)),
 +                BinOpKind::Ne => Some(Constant::Bool(l != r)),
 +                BinOpKind::Lt => Some(Constant::Bool(l < r)),
 +                BinOpKind::Le => Some(Constant::Bool(l <= r)),
 +                BinOpKind::Ge => Some(Constant::Bool(l >= r)),
 +                BinOpKind::Gt => Some(Constant::Bool(l > r)),
 +                _ => None,
 +            },
 +            (l, r) => match (op.node, l, r) {
 +                (BinOpKind::And, Constant::Bool(false), _) => Some(Constant::Bool(false)),
 +                (BinOpKind::Or, Constant::Bool(true), _) => Some(Constant::Bool(true)),
 +                (BinOpKind::And, Constant::Bool(true), Some(r)) | (BinOpKind::Or, Constant::Bool(false), Some(r)) => {
 +                    Some(r)
 +                },
 +                (BinOpKind::BitXor, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l ^ r)),
 +                (BinOpKind::BitAnd, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l & r)),
 +                (BinOpKind::BitOr, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l | r)),
 +                _ => None,
 +            },
 +        }
 +    }
 +}
 +
 +pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
 +    use rustc_middle::mir::interpret::ConstValue;
 +    match result.val {
 +        ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(int))) => {
 +            match result.ty.kind() {
 +                ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
 +                ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
 +                ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
 +                    int.try_into().expect("invalid f32 bit representation"),
 +                ))),
 +                ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
 +                    int.try_into().expect("invalid f64 bit representation"),
 +                ))),
 +                ty::RawPtr(type_and_mut) => {
 +                    if let ty::Uint(_) = type_and_mut.ty.kind() {
 +                        return Some(Constant::RawPtr(int.assert_bits(int.size())));
 +                    }
 +                    None
 +                },
 +                // FIXME: implement other conversions.
 +                _ => None,
 +            }
 +        },
 +        ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind() {
 +            ty::Ref(_, tam, _) => match tam.kind() {
 +                ty::Str => String::from_utf8(
 +                    data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)
 +                        .to_owned(),
 +                )
 +                .ok()
 +                .map(Constant::Str),
 +                _ => None,
 +            },
 +            _ => None,
 +        },
 +        ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind() {
 +            ty::Array(sub_type, len) => match sub_type.kind() {
 +                ty::Float(FloatTy::F32) => match miri_to_const(len) {
 +                    Some(Constant::Int(len)) => alloc
 +                        .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
 +                        .to_owned()
 +                        .chunks(4)
 +                        .map(|chunk| {
 +                            Some(Constant::F32(f32::from_le_bytes(
 +                                chunk.try_into().expect("this shouldn't happen"),
 +                            )))
 +                        })
 +                        .collect::<Option<Vec<Constant>>>()
 +                        .map(Constant::Vec),
 +                    _ => None,
 +                },
 +                ty::Float(FloatTy::F64) => match miri_to_const(len) {
 +                    Some(Constant::Int(len)) => alloc
 +                        .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize))
 +                        .to_owned()
 +                        .chunks(8)
 +                        .map(|chunk| {
 +                            Some(Constant::F64(f64::from_le_bytes(
 +                                chunk.try_into().expect("this shouldn't happen"),
 +                            )))
 +                        })
 +                        .collect::<Option<Vec<Constant>>>()
 +                        .map(Constant::Vec),
 +                    _ => None,
 +                },
 +                // FIXME: implement other array type conversions.
 +                _ => None,
 +            },
 +            _ => None,
 +        },
 +        // FIXME: implement other conversions.
 +        _ => None,
 +    }
 +}
index 9302e5c21faa4f7606d485726bcbf256aba1cfb8,0000000000000000000000000000000000000000..d47b002ad7aca95a94336ac60e6b6f511913d3b4
mode 100644,000000..100644
--- /dev/null
@@@ -1,243 -1,0 +1,243 @@@
- ///    = help: Consider using `f64::NAN` if you would like a constant representing NaN
 +//! Clippy wrappers around rustc's diagnostic functions.
 +//!
 +//! These functions are used by the `INTERNAL_METADATA_COLLECTOR` lint to collect the corresponding
 +//! lint applicability. Please make sure that you update the `LINT_EMISSION_FUNCTIONS` variable in
 +//! `clippy_lints::utils::internal_lints::metadata_collector` when a new function is added
 +//! or renamed.
 +//!
 +//! Thank you!
 +//! ~The `INTERNAL_METADATA_COLLECTOR` lint
 +
 +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() {
 +        if let Some(lint) = lint.name_lower().strip_prefix("clippy::") {
 +            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.rsplit_once('.').unwrap().1)
 +                }),
 +                lint
 +            ));
 +        }
 +    }
 +}
 +
 +/// 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
 +///
 +/// ```text
 +/// 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
 +///
 +/// ```text
 +/// 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<C, S, F>(cx: &C, lint: &'static Lint, sp: S, msg: &str, f: F)
 +where
 +    C: LintContext,
 +    S: Into<MultiSpan>,
 +    F: FnOnce(&mut DiagnosticBuilder<'_>),
 +{
 +    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: impl Into<MultiSpan>,
 +    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
 +///
 +/// ```text
 +/// 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);
 +}
 +
 +/// Create a suggestion made from several `span → replacement`.
 +///
 +/// rustfix currently doesn't support the automatic application of suggestions with
 +/// multiple spans. This is tracked in issue [rustfix#141](https://github.com/rust-lang/rustfix/issues/141).
 +/// Suggestions with multiple spans will be silently ignored.
 +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 60c4cb361aa6c0dfbc2d9ff534ca2569d9e7db18,0000000000000000000000000000000000000000..b3a9a1de2ec93daa57b44eace9a0d66d1781f6d3
mode 100644,000000..100644
--- /dev/null
@@@ -1,784 -1,0 +1,792 @@@
- //! This module contains functions that retrieves specifiec elements.
++//! This module contains functions that retrieve specific elements.
 +
 +#![deny(clippy::missing_docs_in_private_items)]
 +
 +use crate::ty::is_type_diagnostic_item;
- use crate::{is_expn_of, last_path_segment, match_def_path, paths};
++use crate::{is_expn_of, last_path_segment, match_def_path, path_to_local_id, paths};
 +use if_chain::if_chain;
 +use rustc_ast::ast::{self, LitKind};
 +use rustc_hir as hir;
 +use rustc_hir::{
-     Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StmtKind, UnOp,
++    Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, PatKind, QPath, StmtKind, UnOp,
 +};
 +use rustc_lint::LateContext;
 +use rustc_span::{sym, symbol, ExpnKind, Span, Symbol};
 +
 +/// The essential nodes of a desugared for loop as well as the entire span:
 +/// `for pat in arg { body }` becomes `(pat, arg, body)`. Return `(pat, arg, body, span)`.
 +pub struct ForLoop<'tcx> {
 +    /// `for` loop item
 +    pub pat: &'tcx hir::Pat<'tcx>,
 +    /// `IntoIterator` argument
 +    pub arg: &'tcx hir::Expr<'tcx>,
 +    /// `for` loop body
 +    pub body: &'tcx hir::Expr<'tcx>,
 +    /// entire `for` loop span
 +    pub span: Span,
 +}
 +
 +impl<'tcx> ForLoop<'tcx> {
 +    #[inline]
 +    /// Parses a desugared `for` loop
 +    pub fn hir(expr: &Expr<'tcx>) -> Option<Self> {
 +        if_chain! {
 +            if let hir::ExprKind::Match(iterexpr, arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
 +            if let Some(first_arm) = arms.get(0);
 +            if let hir::ExprKind::Call(_, iterargs) = iterexpr.kind;
 +            if let Some(first_arg) = iterargs.get(0);
 +            if iterargs.len() == 1 && arms.len() == 1 && first_arm.guard.is_none();
 +            if let hir::ExprKind::Loop(block, ..) = first_arm.body.kind;
 +            if block.expr.is_none();
 +            if let [ _, _, ref let_stmt, ref body ] = *block.stmts;
 +            if let hir::StmtKind::Local(local) = let_stmt.kind;
 +            if let hir::StmtKind::Expr(body_expr) = body.kind;
 +            then {
 +                return Some(Self {
 +                    pat: &*local.pat,
 +                    arg: first_arg,
 +                    body: body_expr,
 +                    span: first_arm.span
 +                });
 +            }
 +        }
 +        None
 +    }
 +}
 +
 +/// An `if` expression without `DropTemps`
 +pub struct If<'hir> {
 +    /// `if` condition
 +    pub cond: &'hir Expr<'hir>,
 +    /// `if` then expression
 +    pub then: &'hir Expr<'hir>,
 +    /// `else` expression
 +    pub r#else: Option<&'hir Expr<'hir>>,
 +}
 +
 +impl<'hir> If<'hir> {
 +    #[inline]
 +    /// Parses an `if` expression
 +    pub const fn hir(expr: &Expr<'hir>) -> Option<Self> {
 +        if let ExprKind::If(
 +            Expr {
 +                kind: ExprKind::DropTemps(cond),
 +                ..
 +            },
 +            then,
 +            r#else,
 +        ) = expr.kind
 +        {
 +            Some(Self { cond, then, r#else })
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +/// An `if let` expression
 +pub struct IfLet<'hir> {
 +    /// `if let` pattern
 +    pub let_pat: &'hir Pat<'hir>,
 +    /// `if let` scrutinee
 +    pub let_expr: &'hir Expr<'hir>,
 +    /// `if let` then expression
 +    pub if_then: &'hir Expr<'hir>,
 +    /// `if let` else expression
 +    pub if_else: Option<&'hir Expr<'hir>>,
 +}
 +
 +impl<'hir> IfLet<'hir> {
 +    /// Parses an `if let` expression
 +    pub fn hir(cx: &LateContext<'_>, expr: &Expr<'hir>) -> Option<Self> {
 +        if let ExprKind::If(
 +            Expr {
 +                kind: ExprKind::Let(let_pat, let_expr, _),
 +                ..
 +            },
 +            if_then,
 +            if_else,
 +        ) = expr.kind
 +        {
 +            let mut iter = cx.tcx.hir().parent_iter(expr.hir_id);
 +            if let Some((_, Node::Block(Block { stmts: [], .. }))) = iter.next() {
 +                if let Some((
 +                    _,
 +                    Node::Expr(Expr {
 +                        kind: ExprKind::Loop(_, _, LoopSource::While, _),
 +                        ..
 +                    }),
 +                )) = iter.next()
 +                {
 +                    // while loop desugar
 +                    return None;
 +                }
 +            }
 +            return Some(Self {
 +                let_pat,
 +                let_expr,
 +                if_then,
 +                if_else,
 +            });
 +        }
 +        None
 +    }
 +}
 +
 +/// An `if let` or `match` expression. Useful for lints that trigger on one or the other.
 +pub enum IfLetOrMatch<'hir> {
 +    /// Any `match` expression
 +    Match(&'hir Expr<'hir>, &'hir [Arm<'hir>], MatchSource),
 +    /// scrutinee, pattern, then block, else block
 +    IfLet(
 +        &'hir Expr<'hir>,
 +        &'hir Pat<'hir>,
 +        &'hir Expr<'hir>,
 +        Option<&'hir Expr<'hir>>,
 +    ),
 +}
 +
 +impl<'hir> IfLetOrMatch<'hir> {
 +    /// Parses an `if let` or `match` expression
 +    pub fn parse(cx: &LateContext<'_>, expr: &Expr<'hir>) -> Option<Self> {
 +        match expr.kind {
 +            ExprKind::Match(expr, arms, source) => Some(Self::Match(expr, arms, source)),
 +            _ => IfLet::hir(cx, expr).map(
 +                |IfLet {
 +                     let_expr,
 +                     let_pat,
 +                     if_then,
 +                     if_else,
 +                 }| { Self::IfLet(let_expr, let_pat, if_then, if_else) },
 +            ),
 +        }
 +    }
 +}
 +
 +/// An `if` or `if let` expression
 +pub struct IfOrIfLet<'hir> {
 +    /// `if` condition that is maybe a `let` expression
 +    pub cond: &'hir Expr<'hir>,
 +    /// `if` then expression
 +    pub then: &'hir Expr<'hir>,
 +    /// `else` expression
 +    pub r#else: Option<&'hir Expr<'hir>>,
 +}
 +
 +impl<'hir> IfOrIfLet<'hir> {
 +    #[inline]
 +    /// Parses an `if` or `if let` expression
 +    pub const fn hir(expr: &Expr<'hir>) -> Option<Self> {
 +        if let ExprKind::If(cond, then, r#else) = expr.kind {
 +            if let ExprKind::DropTemps(new_cond) = cond.kind {
 +                return Some(Self {
 +                    cond: new_cond,
 +                    r#else,
 +                    then,
 +                });
 +            }
 +            if let ExprKind::Let(..) = cond.kind {
 +                return Some(Self { cond, then, r#else });
 +            }
 +        }
 +        None
 +    }
 +}
 +
 +/// Represent a range akin to `ast::ExprKind::Range`.
 +#[derive(Debug, Copy, Clone)]
 +pub struct Range<'a> {
 +    /// The lower bound of the range, or `None` for ranges such as `..X`.
 +    pub start: Option<&'a hir::Expr<'a>>,
 +    /// The upper bound of the range, or `None` for ranges such as `X..`.
 +    pub end: Option<&'a hir::Expr<'a>>,
 +    /// Whether the interval is open or closed.
 +    pub limits: ast::RangeLimits,
 +}
 +
 +impl<'a> Range<'a> {
 +    /// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
 +    pub fn hir(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> {
 +        /// Finds the field named `name` in the field. Always return `Some` for
 +        /// convenience.
 +        fn get_field<'c>(name: &str, fields: &'c [hir::ExprField<'_>]) -> Option<&'c hir::Expr<'c>> {
 +            let expr = &fields.iter().find(|field| field.ident.name.as_str() == name)?.expr;
 +            Some(expr)
 +        }
 +
 +        match expr.kind {
 +            hir::ExprKind::Call(path, args)
 +                if matches!(
 +                    path.kind,
 +                    hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
 +                ) =>
 +            {
 +                Some(Range {
 +                    start: Some(&args[0]),
 +                    end: Some(&args[1]),
 +                    limits: ast::RangeLimits::Closed,
 +                })
 +            },
 +            hir::ExprKind::Struct(path, fields, None) => match &path {
 +                hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
 +                    start: None,
 +                    end: None,
 +                    limits: ast::RangeLimits::HalfOpen,
 +                }),
 +                hir::QPath::LangItem(hir::LangItem::RangeFrom, _) => Some(Range {
 +                    start: Some(get_field("start", fields)?),
 +                    end: None,
 +                    limits: ast::RangeLimits::HalfOpen,
 +                }),
 +                hir::QPath::LangItem(hir::LangItem::Range, _) => Some(Range {
 +                    start: Some(get_field("start", fields)?),
 +                    end: Some(get_field("end", fields)?),
 +                    limits: ast::RangeLimits::HalfOpen,
 +                }),
 +                hir::QPath::LangItem(hir::LangItem::RangeToInclusive, _) => Some(Range {
 +                    start: None,
 +                    end: Some(get_field("end", fields)?),
 +                    limits: ast::RangeLimits::Closed,
 +                }),
 +                hir::QPath::LangItem(hir::LangItem::RangeTo, _) => Some(Range {
 +                    start: None,
 +                    end: Some(get_field("end", fields)?),
 +                    limits: ast::RangeLimits::HalfOpen,
 +                }),
 +                _ => None,
 +            },
 +            _ => None,
 +        }
 +    }
 +}
 +
 +/// Represent the pre-expansion arguments of a `vec!` invocation.
 +pub enum VecArgs<'a> {
 +    /// `vec![elem; len]`
 +    Repeat(&'a hir::Expr<'a>, &'a hir::Expr<'a>),
 +    /// `vec![a, b, c]`
 +    Vec(&'a [hir::Expr<'a>]),
 +}
 +
 +impl<'a> VecArgs<'a> {
 +    /// Returns the arguments of the `vec!` macro if this expression was expanded
 +    /// from `vec!`.
 +    pub fn hir(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> Option<VecArgs<'a>> {
 +        if_chain! {
 +            if let hir::ExprKind::Call(fun, args) = expr.kind;
 +            if let hir::ExprKind::Path(ref qpath) = fun.kind;
 +            if is_expn_of(fun.span, "vec").is_some();
 +            if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
 +            then {
 +                return if match_def_path(cx, fun_def_id, &paths::VEC_FROM_ELEM) && args.len() == 2 {
 +                    // `vec![elem; size]` case
 +                    Some(VecArgs::Repeat(&args[0], &args[1]))
 +                }
 +                else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
 +                    // `vec![a, b, c]` case
 +                    if_chain! {
 +                        if let hir::ExprKind::Box(boxed) = args[0].kind;
 +                        if let hir::ExprKind::Array(args) = boxed.kind;
 +                        then {
 +                            return Some(VecArgs::Vec(args));
 +                        }
 +                    }
 +
 +                    None
 +                }
 +                else if match_def_path(cx, fun_def_id, &paths::VEC_NEW) && args.is_empty() {
 +                    Some(VecArgs::Vec(&[]))
 +                }
 +                else {
 +                    None
 +                };
 +            }
 +        }
 +
 +        None
 +    }
 +}
 +
 +/// A desugared `while` loop
 +pub struct While<'hir> {
 +    /// `while` loop condition
 +    pub condition: &'hir Expr<'hir>,
 +    /// `while` loop body
 +    pub body: &'hir Expr<'hir>,
 +}
 +
 +impl<'hir> While<'hir> {
 +    #[inline]
 +    /// Parses a desugared `while` loop
 +    pub const fn hir(expr: &Expr<'hir>) -> Option<Self> {
 +        if let ExprKind::Loop(
 +            Block {
 +                expr:
 +                    Some(Expr {
 +                        kind:
 +                            ExprKind::If(
 +                                Expr {
 +                                    kind: ExprKind::DropTemps(condition),
 +                                    ..
 +                                },
 +                                body,
 +                                _,
 +                            ),
 +                        ..
 +                    }),
 +                ..
 +            },
 +            _,
 +            LoopSource::While,
 +            _,
 +        ) = expr.kind
 +        {
 +            return Some(Self { condition, body });
 +        }
 +        None
 +    }
 +}
 +
 +/// A desugared `while let` loop
 +pub struct WhileLet<'hir> {
 +    /// `while let` loop item pattern
 +    pub let_pat: &'hir Pat<'hir>,
 +    /// `while let` loop scrutinee
 +    pub let_expr: &'hir Expr<'hir>,
 +    /// `while let` loop body
 +    pub if_then: &'hir Expr<'hir>,
 +}
 +
 +impl<'hir> WhileLet<'hir> {
 +    #[inline]
 +    /// Parses a desugared `while let` loop
 +    pub const fn hir(expr: &Expr<'hir>) -> Option<Self> {
 +        if let ExprKind::Loop(
 +            Block {
 +                expr:
 +                    Some(Expr {
 +                        kind:
 +                            ExprKind::If(
 +                                Expr {
 +                                    kind: ExprKind::Let(let_pat, let_expr, _),
 +                                    ..
 +                                },
 +                                if_then,
 +                                _,
 +                            ),
 +                        ..
 +                    }),
 +                ..
 +            },
 +            _,
 +            LoopSource::While,
 +            _,
 +        ) = expr.kind
 +        {
 +            return Some(Self {
 +                let_pat,
 +                let_expr,
 +                if_then,
 +            });
 +        }
 +        None
 +    }
 +}
 +
 +/// Converts a hir binary operator to the corresponding `ast` type.
 +#[must_use]
 +pub fn binop(op: hir::BinOpKind) -> ast::BinOpKind {
 +    match op {
 +        hir::BinOpKind::Eq => ast::BinOpKind::Eq,
 +        hir::BinOpKind::Ge => ast::BinOpKind::Ge,
 +        hir::BinOpKind::Gt => ast::BinOpKind::Gt,
 +        hir::BinOpKind::Le => ast::BinOpKind::Le,
 +        hir::BinOpKind::Lt => ast::BinOpKind::Lt,
 +        hir::BinOpKind::Ne => ast::BinOpKind::Ne,
 +        hir::BinOpKind::Or => ast::BinOpKind::Or,
 +        hir::BinOpKind::Add => ast::BinOpKind::Add,
 +        hir::BinOpKind::And => ast::BinOpKind::And,
 +        hir::BinOpKind::BitAnd => ast::BinOpKind::BitAnd,
 +        hir::BinOpKind::BitOr => ast::BinOpKind::BitOr,
 +        hir::BinOpKind::BitXor => ast::BinOpKind::BitXor,
 +        hir::BinOpKind::Div => ast::BinOpKind::Div,
 +        hir::BinOpKind::Mul => ast::BinOpKind::Mul,
 +        hir::BinOpKind::Rem => ast::BinOpKind::Rem,
 +        hir::BinOpKind::Shl => ast::BinOpKind::Shl,
 +        hir::BinOpKind::Shr => ast::BinOpKind::Shr,
 +        hir::BinOpKind::Sub => ast::BinOpKind::Sub,
 +    }
 +}
 +
 +/// Extract args from an assert-like macro.
 +/// Currently working with:
 +/// - `assert!`, `assert_eq!` and `assert_ne!`
 +/// - `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!`
 +/// For example:
 +/// `assert!(expr)` will return `Some([expr])`
 +/// `debug_assert_eq!(a, b)` will return `Some([a, b])`
 +pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx Expr<'tcx>>> {
 +    /// Try to match the AST for a pattern that contains a match, for example when two args are
 +    /// compared
 +    fn ast_matchblock(matchblock_expr: &'tcx Expr<'tcx>) -> Option<Vec<&Expr<'_>>> {
 +        if_chain! {
 +            if let ExprKind::Match(headerexpr, _, _) = &matchblock_expr.kind;
 +            if let ExprKind::Tup([lhs, rhs]) = &headerexpr.kind;
 +            if let ExprKind::AddrOf(BorrowKind::Ref, _, lhs) = lhs.kind;
 +            if let ExprKind::AddrOf(BorrowKind::Ref, _, rhs) = rhs.kind;
 +            then {
 +                return Some(vec![lhs, rhs]);
 +            }
 +        }
 +        None
 +    }
 +
 +    if let ExprKind::Block(block, _) = e.kind {
 +        if block.stmts.len() == 1 {
 +            if let StmtKind::Semi(matchexpr) = block.stmts.get(0)?.kind {
 +                // macros with unique arg: `{debug_}assert!` (e.g., `debug_assert!(some_condition)`)
 +                if_chain! {
 +                    if let Some(If { cond, .. }) = If::hir(matchexpr);
 +                    if let ExprKind::Unary(UnOp::Not, condition) = cond.kind;
 +                    then {
 +                        return Some(vec![condition]);
 +                    }
 +                }
 +
 +                // debug macros with two args: `debug_assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
 +                if_chain! {
 +                    if let ExprKind::Block(matchblock,_) = matchexpr.kind;
 +                    if let Some(matchblock_expr) = matchblock.expr;
 +                    then {
 +                        return ast_matchblock(matchblock_expr);
 +                    }
 +                }
 +            }
 +        } else if let Some(matchblock_expr) = block.expr {
 +            // macros with two args: `assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
 +            return ast_matchblock(matchblock_expr);
 +        }
 +    }
 +    None
 +}
 +
 +/// A parsed `format!` expansion
 +pub struct FormatExpn<'tcx> {
 +    /// Span of `format!(..)`
 +    pub call_site: Span,
 +    /// Inner `format_args!` expansion
 +    pub format_args: FormatArgsExpn<'tcx>,
 +}
 +
 +impl FormatExpn<'tcx> {
 +    /// Parses an expanded `format!` invocation
 +    pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
 +        if_chain! {
 +            if let ExprKind::Block(block, _) = expr.kind;
 +            if let [stmt] = block.stmts;
 +            if let StmtKind::Local(local) = stmt.kind;
 +            if let Some(init) = local.init;
 +            if let ExprKind::Call(_, [format_args]) = init.kind;
 +            let expn_data = expr.span.ctxt().outer_expn_data();
 +            if let ExpnKind::Macro(_, sym::format) = expn_data.kind;
 +            if let Some(format_args) = FormatArgsExpn::parse(format_args);
 +            then {
 +                Some(FormatExpn {
 +                    call_site: expn_data.call_site,
 +                    format_args,
 +                })
 +            } else {
 +                None
 +            }
 +        }
 +    }
 +}
 +
 +/// A parsed `format_args!` expansion
 +pub struct FormatArgsExpn<'tcx> {
 +    /// Span of the first argument, the format string
 +    pub format_string_span: Span,
 +    /// Values passed after the format string
 +    pub value_args: Vec<&'tcx Expr<'tcx>>,
 +
 +    /// String literal expressions which represent the format string split by "{}"
 +    pub format_string_parts: &'tcx [Expr<'tcx>],
 +    /// Symbols corresponding to [`Self::format_string_parts`]
 +    pub format_string_symbols: Vec<Symbol>,
++    /// Match arm patterns, the `arg0`, etc. from the next field `args`
++    pub arg_names: &'tcx [Pat<'tcx>],
 +    /// Expressions like `ArgumentV1::new(arg0, Debug::fmt)`
 +    pub args: &'tcx [Expr<'tcx>],
 +    /// The final argument passed to `Arguments::new_v1_formatted`, if applicable
 +    pub fmt_expr: Option<&'tcx Expr<'tcx>>,
 +}
 +
 +impl FormatArgsExpn<'tcx> {
 +    /// Parses an expanded `format_args!` or `format_args_nl!` invocation
 +    pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
 +        if_chain! {
 +            if let ExpnKind::Macro(_, name) = expr.span.ctxt().outer_expn_data().kind;
 +            let name = name.as_str();
 +            if name.ends_with("format_args") || name.ends_with("format_args_nl");
 +            if let ExprKind::Call(_, args) = expr.kind;
 +            if let Some((strs_ref, args, fmt_expr)) = match args {
 +                // Arguments::new_v1
 +                [strs_ref, args] => Some((strs_ref, args, None)),
 +                // Arguments::new_v1_formatted
 +                [strs_ref, args, fmt_expr, _unsafe_arg] => Some((strs_ref, args, Some(fmt_expr))),
 +                _ => None,
 +            };
 +            if let ExprKind::AddrOf(BorrowKind::Ref, _, strs_arr) = strs_ref.kind;
 +            if let ExprKind::Array(format_string_parts) = strs_arr.kind;
 +            if let Some(format_string_symbols) = format_string_parts
 +                .iter()
 +                .map(|e| {
 +                    if let ExprKind::Lit(lit) = &e.kind {
 +                        if let LitKind::Str(symbol, _style) = lit.node {
 +                            return Some(symbol);
 +                        }
 +                    }
 +                    None
 +                })
 +                .collect();
 +            if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args.kind;
 +            if let ExprKind::Match(args, [arm], _) = args.kind;
 +            if let ExprKind::Tup(value_args) = args.kind;
 +            if let Some(value_args) = value_args
 +                .iter()
 +                .map(|e| match e.kind {
 +                    ExprKind::AddrOf(_, _, e) => Some(e),
 +                    _ => None,
 +                })
 +                .collect();
++            if let PatKind::Tuple(arg_names, None) = arm.pat.kind;
 +            if let ExprKind::Array(args) = arm.body.kind;
 +            then {
 +                Some(FormatArgsExpn {
 +                    format_string_span: strs_ref.span,
 +                    value_args,
 +                    format_string_parts,
 +                    format_string_symbols,
++                    arg_names,
 +                    args,
 +                    fmt_expr,
 +                })
 +            } else {
 +                None
 +            }
 +        }
 +    }
 +
 +    /// Returns a vector of `FormatArgsArg`.
 +    pub fn args(&self) -> Option<Vec<FormatArgsArg<'tcx>>> {
 +        if let Some(expr) = self.fmt_expr {
 +            if_chain! {
 +                if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind;
 +                if let ExprKind::Array(exprs) = expr.kind;
 +                then {
 +                    exprs.iter().map(|fmt| {
 +                        if_chain! {
 +                            // struct `core::fmt::rt::v1::Argument`
 +                            if let ExprKind::Struct(_, fields, _) = fmt.kind;
 +                            if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position);
 +                            if let ExprKind::Lit(lit) = &position_field.expr.kind;
 +                            if let LitKind::Int(position, _) = lit.node;
++                            if let Ok(i) = usize::try_from(position);
++                            let arg = &self.args[i];
++                            if let ExprKind::Call(_, [arg_name, _]) = arg.kind;
++                            if let Some(j) = self
++                                .arg_names
++                                .iter()
++                                .position(|pat| path_to_local_id(arg_name, pat.hir_id));
 +                            then {
-                                 let i = usize::try_from(position).unwrap();
-                                 Some(FormatArgsArg { value: self.value_args[i], arg: &self.args[i], fmt: Some(fmt) })
++                                Some(FormatArgsArg { value: self.value_args[j], arg, fmt: Some(fmt) })
 +                            } else {
 +                                None
 +                            }
 +                        }
 +                    }).collect()
 +                } else {
 +                    None
 +                }
 +            }
 +        } else {
 +            Some(
 +                self.value_args
 +                    .iter()
 +                    .zip(self.args.iter())
 +                    .map(|(value, arg)| FormatArgsArg { value, arg, fmt: None })
 +                    .collect(),
 +            )
 +        }
 +    }
 +}
 +
 +/// Type representing a `FormatArgsExpn`'s format arguments
 +pub struct FormatArgsArg<'tcx> {
 +    /// An element of `value_args` according to `position`
 +    pub value: &'tcx Expr<'tcx>,
 +    /// An element of `args` according to `position`
 +    pub arg: &'tcx Expr<'tcx>,
 +    /// An element of `fmt_expn`
 +    pub fmt: Option<&'tcx Expr<'tcx>>,
 +}
 +
 +impl<'tcx> FormatArgsArg<'tcx> {
 +    /// Returns true if any formatting parameters are used that would have an effect on strings,
 +    /// like `{:+2}` instead of just `{}`.
 +    pub fn has_string_formatting(&self) -> bool {
 +        self.fmt.map_or(false, |fmt| {
 +            // `!` because these conditions check that `self` is unformatted.
 +            !if_chain! {
 +                // struct `core::fmt::rt::v1::Argument`
 +                if let ExprKind::Struct(_, fields, _) = fmt.kind;
 +                if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format);
 +                // struct `core::fmt::rt::v1::FormatSpec`
 +                if let ExprKind::Struct(_, subfields, _) = format_field.expr.kind;
 +                let mut precision_found = false;
 +                let mut width_found = false;
 +                if subfields.iter().all(|field| {
 +                    match field.ident.name {
 +                        sym::precision => {
 +                            precision_found = true;
 +                            if let ExprKind::Path(ref precision_path) = field.expr.kind {
 +                                last_path_segment(precision_path).ident.name == sym::Implied
 +                            } else {
 +                                false
 +                            }
 +                        }
 +                        sym::width => {
 +                            width_found = true;
 +                            if let ExprKind::Path(ref width_qpath) = field.expr.kind {
 +                                last_path_segment(width_qpath).ident.name == sym::Implied
 +                            } else {
 +                                false
 +                            }
 +                        }
 +                        _ => true,
 +                    }
 +                });
 +                if precision_found && width_found;
 +                then { true } else { false }
 +            }
 +        })
 +    }
 +
 +    /// Returns true if the argument is formatted using `Display::fmt`.
 +    pub fn is_display(&self) -> bool {
 +        if_chain! {
 +            if let ExprKind::Call(_, [_, format_field]) = self.arg.kind;
 +            if let ExprKind::Path(QPath::Resolved(_, path)) = format_field.kind;
 +            if let [.., t, _] = path.segments;
 +            if t.ident.name == sym::Display;
 +            then { true } else { false }
 +        }
 +    }
 +}
 +
 +/// Checks if a `let` statement is from a `for` loop desugaring.
 +pub fn is_from_for_desugar(local: &hir::Local<'_>) -> bool {
 +    // This will detect plain for-loops without an actual variable binding:
 +    //
 +    // ```
 +    // for x in some_vec {
 +    //     // do stuff
 +    // }
 +    // ```
 +    if_chain! {
 +        if let Some(expr) = local.init;
 +        if let hir::ExprKind::Match(_, _, hir::MatchSource::ForLoopDesugar) = expr.kind;
 +        then {
 +            return true;
 +        }
 +    }
 +
 +    // This detects a variable binding in for loop to avoid `let_unit_value`
 +    // lint (see issue #1964).
 +    //
 +    // ```
 +    // for _ in vec![()] {
 +    //     // anything
 +    // }
 +    // ```
 +    if let hir::LocalSource::ForLoopDesugar = local.source {
 +        return true;
 +    }
 +
 +    false
 +}
 +
 +/// A parsed `panic!` expansion
 +pub struct PanicExpn<'tcx> {
 +    /// Span of `panic!(..)`
 +    pub call_site: Span,
 +    /// Inner `format_args!` expansion
 +    pub format_args: FormatArgsExpn<'tcx>,
 +}
 +
 +impl PanicExpn<'tcx> {
 +    /// Parses an expanded `panic!` invocation
 +    pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
 +        if_chain! {
-             if let ExprKind::Block(block, _) = expr.kind;
-             if let Some(init) = block.expr;
-             if let ExprKind::Call(_, [format_args]) = init.kind;
++            if let ExprKind::Call(_, [format_args]) = expr.kind;
 +            let expn_data = expr.span.ctxt().outer_expn_data();
 +            if let Some(format_args) = FormatArgsExpn::parse(format_args);
 +            then {
 +                Some(PanicExpn {
 +                    call_site: expn_data.call_site,
 +                    format_args,
 +                })
 +            } else {
 +                None
 +            }
 +        }
 +    }
 +}
 +
 +/// A parsed `Vec` initialization expression
 +#[derive(Clone, Copy)]
 +pub enum VecInitKind {
 +    /// `Vec::new()`
 +    New,
 +    /// `Vec::default()` or `Default::default()`
 +    Default,
 +    /// `Vec::with_capacity(123)`
 +    WithLiteralCapacity(u64),
 +    /// `Vec::with_capacity(slice.len())`
 +    WithExprCapacity(HirId),
 +}
 +
 +/// Checks if given expression is an initialization of `Vec` and returns its kind.
 +pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<VecInitKind> {
 +    if let ExprKind::Call(func, args) = expr.kind {
 +        match func.kind {
 +            ExprKind::Path(QPath::TypeRelative(ty, name))
 +                if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec) =>
 +            {
 +                if name.ident.name == sym::new {
 +                    return Some(VecInitKind::New);
 +                } else if name.ident.name == symbol::kw::Default {
 +                    return Some(VecInitKind::Default);
 +                } else if name.ident.name.as_str() == "with_capacity" {
 +                    let arg = args.get(0)?;
 +                    if_chain! {
 +                        if let ExprKind::Lit(lit) = &arg.kind;
 +                        if let LitKind::Int(num, _) = lit.node;
 +                        then {
 +                            return Some(VecInitKind::WithLiteralCapacity(num.try_into().ok()?))
 +                        }
 +                    }
 +                    return Some(VecInitKind::WithExprCapacity(arg.hir_id));
 +                }
-             }
++            },
 +            ExprKind::Path(QPath::Resolved(_, path))
 +                if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD)
 +                    && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) =>
 +            {
 +                return Some(VecInitKind::Default);
-             }
++            },
 +            _ => (),
 +        }
 +    }
 +    None
 +}
index 9bc380ca6caa6501c526c4edd18b2faa11df4a5c,0000000000000000000000000000000000000000..086fbc9d3ddddcfba357846e45e897f806118814
mode 100644,000000..100644
--- /dev/null
@@@ -1,2165 -1,0 +1,2168 @@@
- pub mod camel_case;
 +#![feature(box_patterns)]
 +#![feature(in_band_lifetimes)]
 +#![feature(iter_zip)]
 +#![feature(rustc_private)]
 +#![feature(control_flow_enum)]
 +#![recursion_limit = "512"]
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)]
 +// warn on the same lints as `clippy_lints`
 +#![warn(trivial_casts, trivial_numeric_casts)]
 +// warn on lints, that are included in `rust-lang/rust`s bootstrap
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +// warn on rustc internal lints
 +#![warn(rustc::internal)]
 +
 +// FIXME: switch to something more ergonomic here, once available.
 +// (Currently there is no way to opt into sysroot crates without `extern crate`.)
 +extern crate rustc_ast;
 +extern crate rustc_ast_pretty;
 +extern crate rustc_attr;
 +extern crate rustc_data_structures;
 +extern crate rustc_errors;
 +extern crate rustc_hir;
 +extern crate rustc_infer;
 +extern crate rustc_lexer;
 +extern crate rustc_lint;
 +extern crate rustc_middle;
 +extern crate rustc_session;
 +extern crate rustc_span;
 +extern crate rustc_target;
 +extern crate rustc_trait_selection;
 +extern crate rustc_typeck;
 +
 +#[macro_use]
 +pub mod sym_helper;
 +
 +#[allow(clippy::module_name_repetitions)]
 +pub mod ast_utils;
 +pub mod attrs;
- /// * Yield/Return statments.
 +pub mod comparisons;
 +pub mod consts;
 +pub mod diagnostics;
 +pub mod eager_or_lazy;
 +pub mod higher;
 +mod hir_utils;
 +pub mod msrvs;
 +pub mod numeric_literal;
 +pub mod paths;
 +pub mod ptr;
 +pub mod qualify_min_const_fn;
 +pub mod source;
++pub mod str_utils;
 +pub mod sugg;
 +pub mod ty;
 +pub mod usage;
 +pub mod visitors;
 +
 +pub use self::attrs::*;
 +pub use self::hir_utils::{both, count_eq, eq_expr_value, over, SpanlessEq, SpanlessHash};
 +
 +use std::collections::hash_map::Entry;
 +use std::hash::BuildHasherDefault;
 +
 +use if_chain::if_chain;
 +use rustc_ast::ast::{self, Attribute, LitKind};
 +use rustc_data_structures::unhash::UnhashMap;
 +use rustc_hir as hir;
 +use rustc_hir::def::{DefKind, Res};
 +use rustc_hir::def_id::DefId;
 +use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 +use rustc_hir::intravisit::{self, walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
 +use rustc_hir::itemlikevisit::ItemLikeVisitor;
 +use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
 +use rustc_hir::{
 +    def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, ForeignItem, GenericArgs,
 +    HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node,
 +    Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind,
 +    UnOp,
 +};
 +use rustc_lint::{LateContext, Level, Lint, LintContext};
 +use rustc_middle::hir::exports::Export;
 +use rustc_middle::hir::map::Map;
 +use rustc_middle::hir::place::PlaceBase;
 +use rustc_middle::ty as rustc_ty;
 +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 +use rustc_middle::ty::binding::BindingMode;
 +use rustc_middle::ty::{layout::IntegerExt, BorrowKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeFoldable, UpvarCapture};
 +use rustc_semver::RustcVersion;
 +use rustc_session::Session;
 +use rustc_span::hygiene::{ExpnKind, MacroKind};
 +use rustc_span::source_map::original_sp;
 +use rustc_span::sym;
 +use rustc_span::symbol::{kw, Symbol};
 +use rustc_span::{Span, DUMMY_SP};
 +use rustc_target::abi::Integer;
 +
 +use crate::consts::{constant, Constant};
 +use crate::ty::{can_partially_move_ty, is_copy, is_recursively_primitive_type};
 +
 +pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
 +    if let Ok(version) = RustcVersion::parse(msrv) {
 +        return Some(version);
 +    } else if let Some(sess) = sess {
 +        if let Some(span) = span {
 +            sess.span_err(span, &format!("`{}` is not a valid Rust version", msrv));
 +        }
 +    }
 +    None
 +}
 +
 +pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool {
 +    msrv.map_or(true, |msrv| msrv.meets(*lint_msrv))
 +}
 +
 +#[macro_export]
 +macro_rules! extract_msrv_attr {
 +    (LateContext) => {
 +        extract_msrv_attr!(@LateContext, ());
 +    };
 +    (EarlyContext) => {
 +        extract_msrv_attr!(@EarlyContext);
 +    };
 +    (@$context:ident$(, $call:tt)?) => {
 +        fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'tcx>, attrs: &'tcx [rustc_ast::ast::Attribute]) {
 +            use $crate::get_unique_inner_attr;
 +            match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") {
 +                Some(msrv_attr) => {
 +                    if let Some(msrv) = msrv_attr.value_str() {
 +                        self.msrv = $crate::parse_msrv(
 +                            &msrv.to_string(),
 +                            Some(cx.sess$($call)?),
 +                            Some(msrv_attr.span),
 +                        );
 +                    } else {
 +                        cx.sess$($call)?.span_err(msrv_attr.span, "bad clippy attribute");
 +                    }
 +                },
 +                _ => (),
 +            }
 +        }
 +    };
 +}
 +
 +/// Returns `true` if the two spans come from differing expansions (i.e., one is
 +/// from a macro and one isn't).
 +#[must_use]
 +pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
 +    rhs.ctxt() != lhs.ctxt()
 +}
 +
 +/// If the given expression is a local binding, find the initializer expression.
 +/// If that initializer expression is another local binding, find its initializer again.
 +/// This process repeats as long as possible (but usually no more than once). Initializer
 +/// expressions with adjustments are ignored. If this is not desired, use [`find_binding_init`]
 +/// instead.
 +///
 +/// Examples:
 +/// ```ignore
 +/// let abc = 1;
 +/// //        ^ output
 +/// let def = abc;
 +/// dbg!(def)
 +/// //   ^^^ input
 +///
 +/// // or...
 +/// let abc = 1;
 +/// let def = abc + 2;
 +/// //        ^^^^^^^ output
 +/// dbg!(def)
 +/// //   ^^^ input
 +/// ```
 +pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> {
 +    while let Some(init) = path_to_local(expr)
 +        .and_then(|id| find_binding_init(cx, id))
 +        .filter(|init| cx.typeck_results().expr_adjustments(init).is_empty())
 +    {
 +        expr = init;
 +    }
 +    expr
 +}
 +
 +/// Finds the initializer expression for a local binding. Returns `None` if the binding is mutable.
 +/// By only considering immutable bindings, we guarantee that the returned expression represents the
 +/// value of the binding wherever it is referenced.
 +///
 +/// Example: For `let x = 1`, if the `HirId` of `x` is provided, the `Expr` `1` is returned.
 +/// Note: If you have an expression that references a binding `x`, use `path_to_local` to get the
 +/// canonical binding `HirId`.
 +pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
 +    let hir = cx.tcx.hir();
 +    if_chain! {
 +        if let Some(Node::Binding(pat)) = hir.find(hir_id);
 +        if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..));
 +        let parent = hir.get_parent_node(hir_id);
 +        if let Some(Node::Local(local)) = hir.find(parent);
 +        then {
 +            return local.init;
 +        }
 +    }
 +    None
 +}
 +
 +/// Returns `true` if the given `NodeId` is inside a constant context
 +///
 +/// # Example
 +///
 +/// ```rust,ignore
 +/// if in_constant(cx, expr.hir_id) {
 +///     // Do something
 +/// }
 +/// ```
 +pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
 +    let parent_id = cx.tcx.hir().get_parent_item(id);
 +    match cx.tcx.hir().get(parent_id) {
 +        Node::Item(&Item {
 +            kind: ItemKind::Const(..) | ItemKind::Static(..),
 +            ..
 +        })
 +        | Node::TraitItem(&TraitItem {
 +            kind: TraitItemKind::Const(..),
 +            ..
 +        })
 +        | Node::ImplItem(&ImplItem {
 +            kind: ImplItemKind::Const(..),
 +            ..
 +        })
 +        | Node::AnonConst(_) => true,
 +        Node::Item(&Item {
 +            kind: ItemKind::Fn(ref sig, ..),
 +            ..
 +        })
 +        | Node::ImplItem(&ImplItem {
 +            kind: ImplItemKind::Fn(ref sig, _),
 +            ..
 +        }) => sig.header.constness == Constness::Const,
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if a `QPath` resolves to a constructor of a `LangItem`.
 +/// For example, use this to check whether a function call or a pattern is `Some(..)`.
 +pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem) -> bool {
 +    if let QPath::Resolved(_, path) = qpath {
 +        if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res {
 +            if let Ok(item_id) = cx.tcx.lang_items().require(lang_item) {
 +                return cx.tcx.parent(ctor_id) == Some(item_id);
 +            }
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns `true` if this `span` was expanded by any macro.
 +#[must_use]
 +pub fn in_macro(span: Span) -> bool {
 +    span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
 +}
 +
 +pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
 +    matches!(
 +        expr.kind,
 +        ExprKind::Block(
 +            Block {
 +                stmts: [],
 +                expr: None,
 +                ..
 +            },
 +            _
 +        ) | ExprKind::Tup([])
 +    )
 +}
 +
 +/// Checks if given pattern is a wildcard (`_`)
 +pub fn is_wild(pat: &Pat<'_>) -> bool {
 +    matches!(pat.kind, PatKind::Wild)
 +}
 +
 +/// Checks if the first type parameter is a lang item.
 +pub fn is_ty_param_lang_item(cx: &LateContext<'_>, qpath: &QPath<'tcx>, item: LangItem) -> Option<&'tcx hir::Ty<'tcx>> {
 +    let ty = get_qpath_generic_tys(qpath).next()?;
 +
 +    if let TyKind::Path(qpath) = &ty.kind {
 +        cx.qpath_res(qpath, ty.hir_id)
 +            .opt_def_id()
 +            .map_or(false, |id| {
 +                cx.tcx.lang_items().require(item).map_or(false, |lang_id| id == lang_id)
 +            })
 +            .then(|| ty)
 +    } else {
 +        None
 +    }
 +}
 +
 +/// Checks if the first type parameter is a diagnostic item.
 +pub fn is_ty_param_diagnostic_item(
 +    cx: &LateContext<'_>,
 +    qpath: &QPath<'tcx>,
 +    item: Symbol,
 +) -> Option<&'tcx hir::Ty<'tcx>> {
 +    let ty = get_qpath_generic_tys(qpath).next()?;
 +
 +    if let TyKind::Path(qpath) = &ty.kind {
 +        cx.qpath_res(qpath, ty.hir_id)
 +            .opt_def_id()
 +            .map_or(false, |id| cx.tcx.is_diagnostic_item(item, id))
 +            .then(|| ty)
 +    } else {
 +        None
 +    }
 +}
 +
 +/// Checks if the method call given in `expr` belongs to the given trait.
 +/// This is a deprecated function, consider using [`is_trait_method`].
 +pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
 +    let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
 +    let trt_id = cx.tcx.trait_of_item(def_id);
 +    trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path))
 +}
 +
 +/// Checks if a method is defined in an impl of a diagnostic item
 +pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
 +    if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
 +        if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() {
 +            return cx.tcx.is_diagnostic_item(diag_item, adt.did);
 +        }
 +    }
 +    false
 +}
 +
 +/// Checks if a method is in a diagnostic item trait
 +pub fn is_diag_trait_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
 +    if let Some(trait_did) = cx.tcx.trait_of_item(def_id) {
 +        return cx.tcx.is_diagnostic_item(diag_item, trait_did);
 +    }
 +    false
 +}
 +
 +/// Checks if the method call given in `expr` belongs to the given trait.
 +pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
 +    cx.typeck_results()
 +        .type_dependent_def_id(expr.hir_id)
 +        .map_or(false, |did| is_diag_trait_item(cx, did, diag_item))
 +}
 +
 +/// Checks if the given expression is a path referring an item on the trait
 +/// that is marked with the given diagnostic item.
 +///
 +/// For checking method call expressions instead of path expressions, use
 +/// [`is_trait_method`].
 +///
 +/// For example, this can be used to find if an expression like `u64::default`
 +/// refers to an item of the trait `Default`, which is associated with the
 +/// `diag_item` of `sym::Default`.
 +pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
 +    if let hir::ExprKind::Path(ref qpath) = expr.kind {
 +        cx.qpath_res(qpath, expr.hir_id)
 +            .opt_def_id()
 +            .map_or(false, |def_id| is_diag_trait_item(cx, def_id, diag_item))
 +    } else {
 +        false
 +    }
 +}
 +
 +pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
 +    match *path {
 +        QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
 +        QPath::TypeRelative(_, seg) => seg,
 +        QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
 +    }
 +}
 +
 +pub fn get_qpath_generics(path: &QPath<'tcx>) -> Option<&'tcx GenericArgs<'tcx>> {
 +    match path {
 +        QPath::Resolved(_, p) => p.segments.last().and_then(|s| s.args),
 +        QPath::TypeRelative(_, s) => s.args,
 +        QPath::LangItem(..) => None,
 +    }
 +}
 +
 +pub fn get_qpath_generic_tys(path: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>> {
 +    get_qpath_generics(path)
 +        .map_or([].as_ref(), |a| a.args)
 +        .iter()
 +        .filter_map(|a| {
 +            if let hir::GenericArg::Type(ty) = a {
 +                Some(ty)
 +            } else {
 +                None
 +            }
 +        })
 +}
 +
 +pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
 +    match *path {
 +        QPath::Resolved(_, path) => path.segments.get(0),
 +        QPath::TypeRelative(_, seg) => Some(seg),
 +        QPath::LangItem(..) => None,
 +    }
 +}
 +
 +/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
 +/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
 +/// `QPath::Resolved.1.res.opt_def_id()`.
 +///
 +/// Matches a `QPath` against a slice of segment string literals.
 +///
 +/// There is also `match_path` if you are dealing with a `rustc_hir::Path` instead of a
 +/// `rustc_hir::QPath`.
 +///
 +/// # Examples
 +/// ```rust,ignore
 +/// match_qpath(path, &["std", "rt", "begin_unwind"])
 +/// ```
 +pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
 +    match *path {
 +        QPath::Resolved(_, path) => match_path(path, segments),
 +        QPath::TypeRelative(ty, segment) => match ty.kind {
 +            TyKind::Path(ref inner_path) => {
 +                if let [prefix @ .., end] = segments {
 +                    if match_qpath(inner_path, prefix) {
 +                        return segment.ident.name.as_str() == *end;
 +                    }
 +                }
 +                false
 +            },
 +            _ => false,
 +        },
 +        QPath::LangItem(..) => false,
 +    }
 +}
 +
 +/// If the expression is a path, resolve it. Otherwise, return `Res::Err`.
 +pub fn expr_path_res(cx: &LateContext<'_>, expr: &Expr<'_>) -> Res {
 +    if let ExprKind::Path(p) = &expr.kind {
 +        cx.qpath_res(p, expr.hir_id)
 +    } else {
 +        Res::Err
 +    }
 +}
 +
 +/// Resolves the path to a `DefId` and checks if it matches the given path.
 +pub fn is_qpath_def_path(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, segments: &[&str]) -> bool {
 +    cx.qpath_res(path, hir_id)
 +        .opt_def_id()
 +        .map_or(false, |id| match_def_path(cx, id, segments))
 +}
 +
 +/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path.
 +///
 +/// Please use `is_expr_diagnostic_item` if the target is a diagnostic item.
 +pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
 +    expr_path_res(cx, expr)
 +        .opt_def_id()
 +        .map_or(false, |id| match_def_path(cx, id, segments))
 +}
 +
 +/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given
 +/// diagnostic item.
 +pub fn is_expr_diagnostic_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
 +    expr_path_res(cx, expr)
 +        .opt_def_id()
 +        .map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
 +}
 +
 +/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
 +/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
 +/// `QPath::Resolved.1.res.opt_def_id()`.
 +///
 +/// Matches a `Path` against a slice of segment string literals.
 +///
 +/// There is also `match_qpath` if you are dealing with a `rustc_hir::QPath` instead of a
 +/// `rustc_hir::Path`.
 +///
 +/// # Examples
 +///
 +/// ```rust,ignore
 +/// if match_path(&trait_ref.path, &paths::HASH) {
 +///     // This is the `std::hash::Hash` trait.
 +/// }
 +///
 +/// if match_path(ty_path, &["rustc", "lint", "Lint"]) {
 +///     // This is a `rustc_middle::lint::Lint`.
 +/// }
 +/// ```
 +pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool {
 +    path.segments
 +        .iter()
 +        .rev()
 +        .zip(segments.iter().rev())
 +        .all(|(a, b)| a.ident.name.as_str() == *b)
 +}
 +
 +/// If the expression is a path to a local, returns the canonical `HirId` of the local.
 +pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
 +    if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
 +        if let Res::Local(id) = path.res {
 +            return Some(id);
 +        }
 +    }
 +    None
 +}
 +
 +/// Returns true if the expression is a path to a local with the specified `HirId`.
 +/// Use this function to see if an expression matches a function argument or a match binding.
 +pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool {
 +    path_to_local(expr) == Some(id)
 +}
 +
 +/// Gets the definition associated to a path.
 +pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
 +    macro_rules! try_res {
 +        ($e:expr) => {
 +            match $e {
 +                Some(e) => e,
 +                None => return Res::Err,
 +            }
 +        };
 +    }
 +    fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export> {
 +        tcx.item_children(def_id)
 +            .iter()
 +            .find(|item| item.ident.name.as_str() == name)
 +    }
 +
 +    let (krate, first, path) = match *path {
 +        [krate, first, ref path @ ..] => (krate, first, path),
 +        [primitive] => {
 +            return PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy);
 +        },
 +        _ => return Res::Err,
 +    };
 +    let tcx = cx.tcx;
 +    let crates = tcx.crates(());
 +    let krate = try_res!(crates.iter().find(|&&num| tcx.crate_name(num).as_str() == krate));
 +    let first = try_res!(item_child_by_name(tcx, krate.as_def_id(), first));
 +    let last = path
 +        .iter()
 +        .copied()
 +        // `get_def_path` seems to generate these empty segments for extern blocks.
 +        // We can just ignore them.
 +        .filter(|segment| !segment.is_empty())
 +        // for each segment, find the child item
 +        .try_fold(first, |item, segment| {
 +            let def_id = item.res.def_id();
 +            if let Some(item) = item_child_by_name(tcx, def_id, segment) {
 +                Some(item)
 +            } else if matches!(item.res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
 +                // it is not a child item so check inherent impl items
 +                tcx.inherent_impls(def_id)
 +                    .iter()
 +                    .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment))
 +            } else {
 +                None
 +            }
 +        });
 +    try_res!(last).res.expect_non_local()
 +}
 +
 +/// Convenience function to get the `DefId` of a trait by path.
 +/// It could be a trait or trait alias.
 +pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
 +    match path_to_res(cx, path) {
 +        Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
 +        _ => None,
 +    }
 +}
 +
 +/// Gets the `hir::TraitRef` of the trait the given method is implemented for.
 +///
 +/// Use this if you want to find the `TraitRef` of the `Add` trait in this example:
 +///
 +/// ```rust
 +/// struct Point(isize, isize);
 +///
 +/// impl std::ops::Add for Point {
 +///     type Output = Self;
 +///
 +///     fn add(self, other: Self) -> Self {
 +///         Point(0, 0)
 +///     }
 +/// }
 +/// ```
 +pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx TraitRef<'tcx>> {
 +    // Get the implemented trait for the current function
 +    let parent_impl = cx.tcx.hir().get_parent_item(hir_id);
 +    if_chain! {
 +        if parent_impl != hir::CRATE_HIR_ID;
 +        if let hir::Node::Item(item) = cx.tcx.hir().get(parent_impl);
 +        if let hir::ItemKind::Impl(impl_) = &item.kind;
 +        then { return impl_.of_trait.as_ref(); }
 +    }
 +    None
 +}
 +
 +/// This method will return tuple of projection stack and root of the expression,
 +/// used in `can_mut_borrow_both`.
 +///
 +/// For example, if `e` represents the `v[0].a.b[x]`
 +/// this method will return a tuple, composed of a `Vec`
 +/// containing the `Expr`s for `v[0], v[0].a, v[0].a.b, v[0].a.b[x]`
 +/// and an `Expr` for root of them, `v`
 +fn projection_stack<'a, 'hir>(mut e: &'a Expr<'hir>) -> (Vec<&'a Expr<'hir>>, &'a Expr<'hir>) {
 +    let mut result = vec![];
 +    let root = loop {
 +        match e.kind {
 +            ExprKind::Index(ep, _) | ExprKind::Field(ep, _) => {
 +                result.push(e);
 +                e = ep;
 +            },
 +            _ => break e,
 +        };
 +    };
 +    result.reverse();
 +    (result, root)
 +}
 +
 +/// Checks if two expressions can be mutably borrowed simultaneously
 +/// and they aren't dependent on borrowing same thing twice
 +pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) -> bool {
 +    let (s1, r1) = projection_stack(e1);
 +    let (s2, r2) = projection_stack(e2);
 +    if !eq_expr_value(cx, r1, r2) {
 +        return true;
 +    }
 +    for (x1, x2) in s1.iter().zip(s2.iter()) {
 +        match (&x1.kind, &x2.kind) {
 +            (ExprKind::Field(_, i1), ExprKind::Field(_, i2)) => {
 +                if i1 != i2 {
 +                    return true;
 +                }
 +            },
 +            (ExprKind::Index(_, i1), ExprKind::Index(_, i2)) => {
 +                if !eq_expr_value(cx, i1, i2) {
 +                    return false;
 +                }
 +            },
 +            _ => return false,
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns true if the `def_id` associated with the `path` is recognized as a "default-equivalent"
 +/// constructor from the std library
 +fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool {
 +    let std_types_symbols = &[
 +        sym::String,
 +        sym::Vec,
 +        sym::VecDeque,
 +        sym::LinkedList,
 +        sym::HashMap,
 +        sym::BTreeMap,
 +        sym::HashSet,
 +        sym::BTreeSet,
 +        sym::BinaryHeap,
 +    ];
 +
 +    if let QPath::TypeRelative(_, method) = path {
 +        if method.ident.name == sym::new {
 +            if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
 +                if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() {
 +                    return std_types_symbols
 +                        .iter()
 +                        .any(|&symbol| cx.tcx.is_diagnostic_item(symbol, adt.did));
 +                }
 +            }
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns true if the expr is equal to `Default::default()` of it's type when evaluated.
 +/// It doesn't cover all cases, for example indirect function calls (some of std
 +/// functions are supported) but it is the best we have.
 +pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    match &e.kind {
 +        ExprKind::Lit(lit) => match lit.node {
 +            LitKind::Bool(false) | LitKind::Int(0, _) => true,
 +            LitKind::Str(s, _) => s.is_empty(),
 +            _ => false,
 +        },
 +        ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
 +        ExprKind::Repeat(x, y) => if_chain! {
 +            if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(y.body).value.kind;
 +            if let LitKind::Int(v, _) = const_lit.node;
 +            if v <= 32 && is_default_equivalent(cx, x);
 +            then {
 +                true
 +            }
 +            else {
 +                false
 +            }
 +        },
 +        ExprKind::Call(repl_func, _) => if_chain! {
 +            if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
 +            if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
 +            if is_diag_trait_item(cx, repl_def_id, sym::Default)
 +                || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath);
 +            then {
 +                true
 +            }
 +            else {
 +                false
 +            }
 +        },
 +        ExprKind::Path(qpath) => is_lang_ctor(cx, qpath, OptionNone),
 +        ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])),
 +        _ => false,
 +    }
 +}
 +
 +/// Checks if the top level expression can be moved into a closure as is.
 +/// Currently checks for:
 +/// * Break/Continue outside the given loop HIR ids.
-         if let [Adjustment {
-             kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
-             target,
-         }, ref adjust @ ..] = *cx
++/// * Yield/Return statements.
 +/// * Inline assembly.
 +/// * Usages of a field of a local where the type of the local can be partially moved.
 +///
 +/// For example, given the following function:
 +///
 +/// ```
 +/// fn f<'a>(iter: &mut impl Iterator<Item = (usize, &'a mut String)>) {
 +///     for item in iter {
 +///         let s = item.1;
 +///         if item.0 > 10 {
 +///             continue;
 +///         } else {
 +///             s.clear();
 +///         }
 +///     }
 +/// }
 +/// ```
 +///
 +/// When called on the expression `item.0` this will return false unless the local `item` is in the
 +/// `ignore_locals` set. The type `(usize, &mut String)` can have the second element moved, so it
 +/// isn't always safe to move into a closure when only a single field is needed.
 +///
 +/// When called on the `continue` expression this will return false unless the outer loop expression
 +/// is in the `loop_ids` set.
 +///
 +/// Note that this check is not recursive, so passing the `if` expression will always return true
 +/// even though sub-expressions might return false.
 +pub fn can_move_expr_to_closure_no_visit(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +    loop_ids: &[HirId],
 +    ignore_locals: &HirIdSet,
 +) -> bool {
 +    match expr.kind {
 +        ExprKind::Break(Destination { target_id: Ok(id), .. }, _)
 +        | ExprKind::Continue(Destination { target_id: Ok(id), .. })
 +            if loop_ids.contains(&id) =>
 +        {
 +            true
 +        },
 +        ExprKind::Break(..)
 +        | ExprKind::Continue(_)
 +        | ExprKind::Ret(_)
 +        | ExprKind::Yield(..)
 +        | ExprKind::InlineAsm(_)
 +        | ExprKind::LlvmInlineAsm(_) => false,
 +        // Accessing a field of a local value can only be done if the type isn't
 +        // partially moved.
 +        ExprKind::Field(
 +            &Expr {
 +                hir_id,
 +                kind:
 +                    ExprKind::Path(QPath::Resolved(
 +                        _,
 +                        Path {
 +                            res: Res::Local(local_id),
 +                            ..
 +                        },
 +                    )),
 +                ..
 +            },
 +            _,
 +        ) if !ignore_locals.contains(local_id) && can_partially_move_ty(cx, cx.typeck_results().node_type(hir_id)) => {
 +            // TODO: check if the local has been partially moved. Assume it has for now.
 +            false
 +        },
 +        _ => true,
 +    }
 +}
 +
 +/// How a local is captured by a closure
 +#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 +pub enum CaptureKind {
 +    Value,
 +    Ref(Mutability),
 +}
 +impl CaptureKind {
 +    pub fn is_imm_ref(self) -> bool {
 +        self == Self::Ref(Mutability::Not)
 +    }
 +}
 +impl std::ops::BitOr for CaptureKind {
 +    type Output = Self;
 +    fn bitor(self, rhs: Self) -> Self::Output {
 +        match (self, rhs) {
 +            (CaptureKind::Value, _) | (_, CaptureKind::Value) => CaptureKind::Value,
 +            (CaptureKind::Ref(Mutability::Mut), CaptureKind::Ref(_))
 +            | (CaptureKind::Ref(_), CaptureKind::Ref(Mutability::Mut)) => CaptureKind::Ref(Mutability::Mut),
 +            (CaptureKind::Ref(Mutability::Not), CaptureKind::Ref(Mutability::Not)) => CaptureKind::Ref(Mutability::Not),
 +        }
 +    }
 +}
 +impl std::ops::BitOrAssign for CaptureKind {
 +    fn bitor_assign(&mut self, rhs: Self) {
 +        *self = *self | rhs;
 +    }
 +}
 +
 +/// Given an expression referencing a local, determines how it would be captured in a closure.
 +/// Note as this will walk up to parent expressions until the capture can be determined it should
 +/// only be used while making a closure somewhere a value is consumed. e.g. a block, match arm, or
 +/// function argument (other than a receiver).
 +pub fn capture_local_usage(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind {
 +    fn pat_capture_kind(cx: &LateContext<'_>, pat: &Pat<'_>) -> CaptureKind {
 +        let mut capture = CaptureKind::Ref(Mutability::Not);
 +        pat.each_binding_or_first(&mut |_, id, span, _| match cx
 +            .typeck_results()
 +            .extract_binding_mode(cx.sess(), id, span)
 +            .unwrap()
 +        {
 +            BindingMode::BindByValue(_) if !is_copy(cx, cx.typeck_results().node_type(id)) => {
 +                capture = CaptureKind::Value;
 +            },
 +            BindingMode::BindByReference(Mutability::Mut) if capture != CaptureKind::Value => {
 +                capture = CaptureKind::Ref(Mutability::Mut);
 +            },
 +            _ => (),
 +        });
 +        capture
 +    }
 +
 +    debug_assert!(matches!(
 +        e.kind,
 +        ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(_), .. }))
 +    ));
 +
 +    let mut child_id = e.hir_id;
 +    let mut capture = CaptureKind::Value;
 +    let mut capture_expr_ty = e;
 +
 +    for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) {
-                 e
-                 @
-                 Expr {
++        if let [
++            Adjustment {
++                kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
++                target,
++            },
++            ref adjust @ ..,
++        ] = *cx
 +            .typeck_results()
 +            .adjustments()
 +            .get(child_id)
 +            .map_or(&[][..], |x| &**x)
 +        {
 +            if let rustc_ty::RawPtr(TypeAndMut { mutbl: mutability, .. }) | rustc_ty::Ref(_, _, mutability) =
 +                *adjust.last().map_or(target, |a| a.target).kind()
 +            {
 +                return CaptureKind::Ref(mutability);
 +            }
 +        }
 +
 +        match parent {
 +            Node::Expr(e) => match e.kind {
 +                ExprKind::AddrOf(_, mutability, _) => return CaptureKind::Ref(mutability),
 +                ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, _) => capture = CaptureKind::Ref(Mutability::Not),
 +                ExprKind::Assign(lhs, ..) | ExprKind::Assign(_, lhs, _) if lhs.hir_id == child_id => {
 +                    return CaptureKind::Ref(Mutability::Mut);
 +                },
 +                ExprKind::Field(..) => {
 +                    if capture == CaptureKind::Value {
 +                        capture_expr_ty = e;
 +                    }
 +                },
 +                ExprKind::Let(pat, ..) => {
 +                    let mutability = match pat_capture_kind(cx, pat) {
 +                        CaptureKind::Value => Mutability::Not,
 +                        CaptureKind::Ref(m) => m,
 +                    };
 +                    return CaptureKind::Ref(mutability);
 +                },
 +                ExprKind::Match(_, arms, _) => {
 +                    let mut mutability = Mutability::Not;
 +                    for capture in arms.iter().map(|arm| pat_capture_kind(cx, arm.pat)) {
 +                        match capture {
 +                            CaptureKind::Value => break,
 +                            CaptureKind::Ref(Mutability::Mut) => mutability = Mutability::Mut,
 +                            CaptureKind::Ref(Mutability::Not) => (),
 +                        }
 +                    }
 +                    return CaptureKind::Ref(mutability);
 +                },
 +                _ => break,
 +            },
 +            Node::Local(l) => match pat_capture_kind(cx, l.pat) {
 +                CaptureKind::Value => break,
 +                capture @ CaptureKind::Ref(_) => return capture,
 +            },
 +            _ => break,
 +        }
 +
 +        child_id = parent_id;
 +    }
 +
 +    if capture == CaptureKind::Value && is_copy(cx, cx.typeck_results().expr_ty(capture_expr_ty)) {
 +        // Copy types are never automatically captured by value.
 +        CaptureKind::Ref(Mutability::Not)
 +    } else {
 +        capture
 +    }
 +}
 +
 +/// Checks if the expression can be moved into a closure as is. This will return a list of captures
 +/// if so, otherwise, `None`.
 +pub fn can_move_expr_to_closure(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<HirIdMap<CaptureKind>> {
 +    struct V<'cx, 'tcx> {
 +        cx: &'cx LateContext<'tcx>,
 +        // Stack of potential break targets contained in the expression.
 +        loops: Vec<HirId>,
 +        /// Local variables created in the expression. These don't need to be captured.
 +        locals: HirIdSet,
 +        /// Whether this expression can be turned into a closure.
 +        allow_closure: bool,
 +        /// Locals which need to be captured, and whether they need to be by value, reference, or
 +        /// mutable reference.
 +        captures: HirIdMap<CaptureKind>,
 +    }
 +    impl Visitor<'tcx> for V<'_, 'tcx> {
 +        type Map = ErasedMap<'tcx>;
 +        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +            NestedVisitorMap::None
 +        }
 +
 +        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
 +            if !self.allow_closure {
 +                return;
 +            }
 +
 +            match e.kind {
 +                ExprKind::Path(QPath::Resolved(None, &Path { res: Res::Local(l), .. })) => {
 +                    if !self.locals.contains(&l) {
 +                        let cap = capture_local_usage(self.cx, e);
 +                        self.captures.entry(l).and_modify(|e| *e |= cap).or_insert(cap);
 +                    }
 +                },
 +                ExprKind::Closure(..) => {
 +                    let closure_id = self.cx.tcx.hir().local_def_id(e.hir_id).to_def_id();
 +                    for capture in self.cx.typeck_results().closure_min_captures_flattened(closure_id) {
 +                        let local_id = match capture.place.base {
 +                            PlaceBase::Local(id) => id,
 +                            PlaceBase::Upvar(var) => var.var_path.hir_id,
 +                            _ => continue,
 +                        };
 +                        if !self.locals.contains(&local_id) {
 +                            let capture = match capture.info.capture_kind {
 +                                UpvarCapture::ByValue(_) => CaptureKind::Value,
 +                                UpvarCapture::ByRef(borrow) => match borrow.kind {
 +                                    BorrowKind::ImmBorrow => CaptureKind::Ref(Mutability::Not),
 +                                    BorrowKind::UniqueImmBorrow | BorrowKind::MutBorrow => {
 +                                        CaptureKind::Ref(Mutability::Mut)
 +                                    },
 +                                },
 +                            };
 +                            self.captures
 +                                .entry(local_id)
 +                                .and_modify(|e| *e |= capture)
 +                                .or_insert(capture);
 +                        }
 +                    }
 +                },
 +                ExprKind::Loop(b, ..) => {
 +                    self.loops.push(e.hir_id);
 +                    self.visit_block(b);
 +                    self.loops.pop();
 +                },
 +                _ => {
 +                    self.allow_closure &= can_move_expr_to_closure_no_visit(self.cx, e, &self.loops, &self.locals);
 +                    walk_expr(self, e);
 +                },
 +            }
 +        }
 +
 +        fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) {
 +            p.each_binding_or_first(&mut |_, id, _, _| {
 +                self.locals.insert(id);
 +            });
 +        }
 +    }
 +
 +    let mut v = V {
 +        cx,
 +        allow_closure: true,
 +        loops: Vec::new(),
 +        locals: HirIdSet::default(),
 +        captures: HirIdMap::default(),
 +    };
 +    v.visit_expr(expr);
 +    v.allow_closure.then(|| v.captures)
 +}
 +
 +/// Returns the method names and argument list of nested method call expressions that make up
 +/// `expr`. method/span lists are sorted with the most recent call first.
 +pub fn method_calls<'tcx>(
 +    expr: &'tcx Expr<'tcx>,
 +    max_depth: usize,
 +) -> (Vec<Symbol>, Vec<&'tcx [Expr<'tcx>]>, Vec<Span>) {
 +    let mut method_names = Vec::with_capacity(max_depth);
 +    let mut arg_lists = Vec::with_capacity(max_depth);
 +    let mut spans = Vec::with_capacity(max_depth);
 +
 +    let mut current = expr;
 +    for _ in 0..max_depth {
 +        if let ExprKind::MethodCall(path, span, args, _) = &current.kind {
 +            if args.iter().any(|e| e.span.from_expansion()) {
 +                break;
 +            }
 +            method_names.push(path.ident.name);
 +            arg_lists.push(&**args);
 +            spans.push(*span);
 +            current = &args[0];
 +        } else {
 +            break;
 +        }
 +    }
 +
 +    (method_names, arg_lists, spans)
 +}
 +
 +/// Matches an `Expr` against a chain of methods, and return the matched `Expr`s.
 +///
 +/// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`,
 +/// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
 +/// containing the `Expr`s for
 +/// `.bar()` and `.baz()`
 +pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<&'a [Expr<'a>]>> {
 +    let mut current = expr;
 +    let mut matched = Vec::with_capacity(methods.len());
 +    for method_name in methods.iter().rev() {
 +        // method chains are stored last -> first
 +        if let ExprKind::MethodCall(path, _, args, _) = current.kind {
 +            if path.ident.name.as_str() == *method_name {
 +                if args.iter().any(|e| e.span.from_expansion()) {
 +                    return None;
 +                }
 +                matched.push(args); // build up `matched` backwards
 +                current = &args[0]; // go to parent expression
 +            } else {
 +                return None;
 +            }
 +        } else {
 +            return None;
 +        }
 +    }
 +    // Reverse `matched` so that it is in the same order as `methods`.
 +    matched.reverse();
 +    Some(matched)
 +}
 +
 +/// Returns `true` if the provided `def_id` is an entrypoint to a program.
 +pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
 +    cx.tcx
 +        .entry_fn(())
 +        .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id)
 +}
 +
 +/// Returns `true` if the expression is in the program's `#[panic_handler]`.
 +pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    let parent = cx.tcx.hir().get_parent_item(e.hir_id);
 +    let def_id = cx.tcx.hir().local_def_id(parent).to_def_id();
 +    Some(def_id) == cx.tcx.lang_items().panic_impl()
 +}
 +
 +/// Gets the name of the item the expression is in, if available.
 +pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
 +    let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
 +    match cx.tcx.hir().find(parent_id) {
 +        Some(
 +            Node::Item(Item { ident, .. })
 +            | Node::TraitItem(TraitItem { ident, .. })
 +            | Node::ImplItem(ImplItem { ident, .. }),
 +        ) => Some(ident.name),
 +        _ => None,
 +    }
 +}
 +
 +pub struct ContainsName {
 +    pub name: Symbol,
 +    pub result: bool,
 +}
 +
 +impl<'tcx> Visitor<'tcx> for ContainsName {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_name(&mut self, _: Span, name: Symbol) {
 +        if self.name == name {
 +            self.result = true;
 +        }
 +    }
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +/// Checks if an `Expr` contains a certain name.
 +pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool {
 +    let mut cn = ContainsName { name, result: false };
 +    cn.visit_expr(expr);
 +    cn.result
 +}
 +
 +/// Returns `true` if `expr` contains a return expression
 +pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
 +    struct RetCallFinder {
 +        found: bool,
 +    }
 +
 +    impl<'tcx> hir::intravisit::Visitor<'tcx> for RetCallFinder {
 +        type Map = Map<'tcx>;
 +
 +        fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
 +            if self.found {
 +                return;
 +            }
 +            if let hir::ExprKind::Ret(..) = &expr.kind {
 +                self.found = true;
 +            } else {
 +                hir::intravisit::walk_expr(self, expr);
 +            }
 +        }
 +
 +        fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
 +            hir::intravisit::NestedVisitorMap::None
 +        }
 +    }
 +
 +    let mut visitor = RetCallFinder { found: false };
 +    visitor.visit_expr(expr);
 +    visitor.found
 +}
 +
 +struct FindMacroCalls<'a, 'b> {
 +    names: &'a [&'b str],
 +    result: Vec<Span>,
 +}
 +
 +impl<'a, 'b, 'tcx> Visitor<'tcx> for FindMacroCalls<'a, 'b> {
 +    type Map = Map<'tcx>;
 +
 +    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 +        if self.names.iter().any(|fun| is_expn_of(expr.span, fun).is_some()) {
 +            self.result.push(expr.span);
 +        }
 +        // and check sub-expressions
 +        intravisit::walk_expr(self, expr);
 +    }
 +
 +    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 +        NestedVisitorMap::None
 +    }
 +}
 +
 +/// Finds calls of the specified macros in a function body.
 +pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec<Span> {
 +    let mut fmc = FindMacroCalls {
 +        names,
 +        result: Vec::new(),
 +    };
 +    fmc.visit_expr(&body.value);
 +    fmc.result
 +}
 +
 +/// Extends the span to the beginning of the spans line, incl. whitespaces.
 +///
 +/// ```rust,ignore
 +///        let x = ();
 +/// //             ^^
 +/// // will be converted to
 +///        let x = ();
 +/// // ^^^^^^^^^^^^^^
 +/// ```
 +fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
 +    let span = original_sp(span, DUMMY_SP);
 +    let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap();
 +    let line_no = source_map_and_line.line;
 +    let line_start = source_map_and_line.sf.lines[line_no];
 +    span.with_lo(line_start)
 +}
 +
 +/// Gets the parent node, if any.
 +pub fn get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option<Node<'_>> {
 +    tcx.hir().parent_iter(id).next().map(|(_, node)| node)
 +}
 +
 +/// Gets the parent expression, if any –- this is useful to constrain a lint.
 +pub fn get_parent_expr<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    get_parent_expr_for_hir(cx, e.hir_id)
 +}
 +
 +/// This retrieves the parent for the given `HirId` if it's an expression. This is useful for
 +/// constraint lints
 +pub fn get_parent_expr_for_hir<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::HirId) -> Option<&'tcx Expr<'tcx>> {
 +    match get_parent_node(cx.tcx, hir_id) {
 +        Some(Node::Expr(parent)) => Some(parent),
 +        _ => None,
 +    }
 +}
 +
 +pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Block<'tcx>> {
 +    let map = &cx.tcx.hir();
 +    let enclosing_node = map
 +        .get_enclosing_scope(hir_id)
 +        .and_then(|enclosing_id| map.find(enclosing_id));
 +    enclosing_node.and_then(|node| match node {
 +        Node::Block(block) => Some(block),
 +        Node::Item(&Item {
 +            kind: ItemKind::Fn(_, _, eid),
 +            ..
 +        })
 +        | Node::ImplItem(&ImplItem {
 +            kind: ImplItemKind::Fn(_, eid),
 +            ..
 +        }) => match cx.tcx.hir().body(eid).value.kind {
 +            ExprKind::Block(block, _) => Some(block),
 +            _ => None,
 +        },
 +        _ => None,
 +    })
 +}
 +
 +/// Gets the loop or closure enclosing the given expression, if any.
 +pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    for (_, node) in tcx.hir().parent_iter(expr.hir_id) {
 +        match node {
 +            Node::Expr(
-         &[Expr {
-             kind: ExprKind::Closure(_, _, body, _, _),
-             ..
-         }],
++                e @ Expr {
 +                    kind: ExprKind::Loop(..) | ExprKind::Closure(..),
 +                    ..
 +                },
 +            ) => return Some(e),
 +            Node::Expr(_) | Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),
 +            _ => break,
 +        }
 +    }
 +    None
 +}
 +
 +/// Gets the parent node if it's an impl block.
 +pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> {
 +    match tcx.hir().parent_iter(id).next() {
 +        Some((
 +            _,
 +            Node::Item(Item {
 +                kind: ItemKind::Impl(imp),
 +                ..
 +            }),
 +        )) => Some(imp),
 +        _ => None,
 +    }
 +}
 +
 +/// Checks if the given expression is the else clause of either an `if` or `if let` expression.
 +pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 +    let mut iter = tcx.hir().parent_iter(expr.hir_id);
 +    match iter.next() {
 +        Some((
 +            _,
 +            Node::Expr(Expr {
 +                kind: ExprKind::If(_, _, Some(else_expr)),
 +                ..
 +            }),
 +        )) => else_expr.hir_id == expr.hir_id,
 +        _ => false,
 +    }
 +}
 +
 +/// Checks whether the given expression is a constant integer of the given value.
 +/// unlike `is_integer_literal`, this version does const folding
 +pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool {
 +    if is_integer_literal(e, value) {
 +        return true;
 +    }
 +    let enclosing_body = cx.tcx.hir().local_def_id(cx.tcx.hir().enclosing_body_owner(e.hir_id));
 +    if let Some((Constant::Int(v), _)) = constant(cx, cx.tcx.typeck(enclosing_body), e) {
 +        return value == v;
 +    }
 +    false
 +}
 +
 +/// Checks whether the given expression is a constant literal of the given value.
 +pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
 +    // FIXME: use constant folding
 +    if let ExprKind::Lit(ref spanned) = expr.kind {
 +        if let LitKind::Int(v, _) = spanned.node {
 +            return v == value;
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns `true` if the given `Expr` has been coerced before.
 +///
 +/// Examples of coercions can be found in the Nomicon at
 +/// <https://doc.rust-lang.org/nomicon/coercions.html>.
 +///
 +/// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_typeck::check::coercion` for more
 +/// information on adjustments and coercions.
 +pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 +    cx.typeck_results().adjustments().get(e.hir_id).is_some()
 +}
 +
 +/// Returns the pre-expansion span if 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
 +/// # macro_rules! foo { ($e:tt) => { $e } }; macro_rules! bar { ($e:expr) => { $e } }
 +/// foo!(bar!(42));
 +/// ```
 +/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
 +/// from `bar!` by `is_direct_expn_of`.
 +#[must_use]
 +pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
 +    if span.from_expansion() {
 +        let data = span.ctxt().outer_expn_data();
 +        let new_span = data.call_site;
 +
 +        if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
 +            if mac_name.as_str() == name {
 +                return Some(new_span);
 +            }
 +        }
 +    }
 +
 +    None
 +}
 +
 +/// Convenience function to get the return type of a function.
 +pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> {
 +    let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
 +    let ret_ty = cx.tcx.fn_sig(fn_def_id).output();
 +    cx.tcx.erase_late_bound_regions(ret_ty)
 +}
 +
 +/// Checks if an expression is constructing a tuple-like enum variant or struct
 +pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    if let ExprKind::Call(fun, _) = expr.kind {
 +        if let ExprKind::Path(ref qp) = fun.kind {
 +            let res = cx.qpath_res(qp, fun.hir_id);
 +            return match res {
 +                def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
 +                def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
 +                _ => false,
 +            };
 +        }
 +    }
 +    false
 +}
 +
 +/// Returns `true` if a pattern is refutable.
 +// TODO: should be implemented using rustc/mir_build/thir machinery
 +pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
 +    fn is_enum_variant(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool {
 +        matches!(
 +            cx.qpath_res(qpath, id),
 +            def::Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _)
 +        )
 +    }
 +
 +    fn are_refutable<'a, I: IntoIterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, i: I) -> bool {
 +        i.into_iter().any(|pat| is_refutable(cx, pat))
 +    }
 +
 +    match pat.kind {
 +        PatKind::Wild => false,
 +        PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
 +        PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
 +        PatKind::Lit(..) | PatKind::Range(..) => true,
 +        PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
 +        PatKind::Or(pats) => {
 +            // TODO: should be the honest check, that pats is exhaustive set
 +            are_refutable(cx, pats)
 +        },
 +        PatKind::Tuple(pats, _) => are_refutable(cx, pats),
 +        PatKind::Struct(ref qpath, fields, _) => {
 +            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat))
 +        },
 +        PatKind::TupleStruct(ref qpath, pats, _) => is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats),
 +        PatKind::Slice(head, middle, tail) => {
 +            match &cx.typeck_results().node_type(pat.hir_id).kind() {
 +                rustc_ty::Slice(..) => {
 +                    // [..] is the only irrefutable slice pattern.
 +                    !head.is_empty() || middle.is_none() || !tail.is_empty()
 +                },
 +                rustc_ty::Array(..) => are_refutable(cx, head.iter().chain(middle).chain(tail.iter())),
 +                _ => {
 +                    // unreachable!()
 +                    true
 +                },
 +            }
 +        },
 +    }
 +}
 +
 +/// If the pattern is an `or` pattern, call the function once for each sub pattern. Otherwise, call
 +/// the function once on the given pattern.
 +pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) {
 +    if let PatKind::Or(pats) = pat.kind {
 +        pats.iter().for_each(f);
 +    } else {
 +        f(pat);
 +    }
 +}
 +
 +/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
 +/// implementations have.
 +pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
 +    attrs.iter().any(|attr| attr.has_name(sym::automatically_derived))
 +}
 +
 +/// Remove blocks around an expression.
 +///
 +/// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return
 +/// themselves.
 +pub fn remove_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
 +    while let ExprKind::Block(block, ..) = expr.kind {
 +        match (block.stmts.is_empty(), block.expr.as_ref()) {
 +            (true, Some(e)) => expr = e,
 +            _ => break,
 +        }
 +    }
 +    expr
 +}
 +
 +pub fn is_self(slf: &Param<'_>) -> bool {
 +    if let PatKind::Binding(.., name, _) = slf.pat.kind {
 +        name.name == kw::SelfLower
 +    } else {
 +        false
 +    }
 +}
 +
 +pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
 +    if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind {
 +        if let Res::SelfTy(..) = path.res {
 +            return true;
 +        }
 +    }
 +    false
 +}
 +
 +pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl Iterator<Item = &'tcx Param<'tcx>> {
 +    (0..decl.inputs.len()).map(move |i| &body.params[i])
 +}
 +
 +/// Checks if a given expression is a match expression expanded from the `?`
 +/// operator or the `try` macro.
 +pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
 +    fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 +        if_chain! {
 +            if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind;
 +            if is_lang_ctor(cx, path, ResultOk);
 +            if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
 +            if path_to_local_id(arm.body, hir_id);
 +            then {
 +                return true;
 +            }
 +        }
 +        false
 +    }
 +
 +    fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 +        if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind {
 +            is_lang_ctor(cx, path, ResultErr)
 +        } else {
 +            false
 +        }
 +    }
 +
 +    if let ExprKind::Match(_, arms, ref source) = expr.kind {
 +        // desugared from a `?` operator
 +        if *source == MatchSource::TryDesugar {
 +            return Some(expr);
 +        }
 +
 +        if_chain! {
 +            if arms.len() == 2;
 +            if arms[0].guard.is_none();
 +            if arms[1].guard.is_none();
 +            if (is_ok(cx, &arms[0]) && is_err(cx, &arms[1])) ||
 +                (is_ok(cx, &arms[1]) && is_err(cx, &arms[0]));
 +            then {
 +                return Some(expr);
 +            }
 +        }
 +    }
 +
 +    None
 +}
 +
 +/// Returns `true` if the lint is allowed in the current context
 +///
 +/// Useful for skipping long running code when it's unnecessary
 +pub fn is_lint_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool {
 +    cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow
 +}
 +
 +pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> {
 +    while let PatKind::Ref(subpat, _) = pat.kind {
 +        pat = subpat;
 +    }
 +    pat
 +}
 +
 +pub fn int_bits(tcx: TyCtxt<'_>, ity: rustc_ty::IntTy) -> u64 {
 +    Integer::from_int_ty(&tcx, ity).size().bits()
 +}
 +
 +#[allow(clippy::cast_possible_wrap)]
 +/// Turn a constant int byte representation into an i128
 +pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::IntTy) -> i128 {
 +    let amt = 128 - int_bits(tcx, ity);
 +    ((u as i128) << amt) >> amt
 +}
 +
 +#[allow(clippy::cast_sign_loss)]
 +/// clip unused bytes
 +pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: rustc_ty::IntTy) -> u128 {
 +    let amt = 128 - int_bits(tcx, ity);
 +    ((u as u128) << amt) >> amt
 +}
 +
 +/// clip unused bytes
 +pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: rustc_ty::UintTy) -> u128 {
 +    let bits = Integer::from_uint_ty(&tcx, ity).size().bits();
 +    let amt = 128 - bits;
 +    (u << amt) >> amt
 +}
 +
 +pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool {
 +    let map = &tcx.hir();
 +    let mut prev_enclosing_node = None;
 +    let mut enclosing_node = node;
 +    while Some(enclosing_node) != prev_enclosing_node {
 +        if is_automatically_derived(map.attrs(enclosing_node)) {
 +            return true;
 +        }
 +        prev_enclosing_node = Some(enclosing_node);
 +        enclosing_node = map.get_parent_item(enclosing_node);
 +    }
 +    false
 +}
 +
 +/// Matches a function call with the given path and returns the arguments.
 +///
 +/// Usage:
 +///
 +/// ```rust,ignore
 +/// if let Some(args) = match_function_call(cx, cmp_max_call, &paths::CMP_MAX);
 +/// ```
 +pub fn match_function_call<'tcx>(
 +    cx: &LateContext<'tcx>,
 +    expr: &'tcx Expr<'_>,
 +    path: &[&str],
 +) -> Option<&'tcx [Expr<'tcx>]> {
 +    if_chain! {
 +        if let ExprKind::Call(fun, args) = expr.kind;
 +        if let ExprKind::Path(ref qpath) = fun.kind;
 +        if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
 +        if match_def_path(cx, fun_def_id, path);
 +        then {
 +            return Some(args)
 +        }
 +    };
 +    None
 +}
 +
 +/// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if
 +/// any.
 +///
 +/// Please use `match_any_diagnostic_items` if the targets are all diagnostic items.
 +pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option<usize> {
 +    let search_path = cx.get_def_path(did);
 +    paths
 +        .iter()
 +        .position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().copied()))
 +}
 +
 +/// Checks if the given `DefId` matches any of provided diagnostic items. Returns the index of
 +/// matching path, if any.
 +pub fn match_any_diagnostic_items(cx: &LateContext<'_>, def_id: DefId, diag_items: &[Symbol]) -> Option<usize> {
 +    diag_items
 +        .iter()
 +        .position(|item| cx.tcx.is_diagnostic_item(*item, def_id))
 +}
 +
 +/// Checks if the given `DefId` matches the path.
 +pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool {
 +    // We should probably move to Symbols in Clippy as well rather than interning every time.
 +    let path = cx.get_def_path(did);
 +    syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().copied())
 +}
 +
 +pub fn match_panic_call(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    if let ExprKind::Call(func, [arg]) = expr.kind {
 +        expr_path_res(cx, func)
 +            .opt_def_id()
 +            .map_or(false, |id| match_panic_def_id(cx, id))
 +            .then(|| arg)
 +    } else {
 +        None
 +    }
 +}
 +
 +pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool {
 +    match_any_def_paths(
 +        cx,
 +        did,
 +        &[
 +            &paths::BEGIN_PANIC,
 +            &paths::PANIC_ANY,
 +            &paths::PANICKING_PANIC,
 +            &paths::PANICKING_PANIC_FMT,
 +            &paths::PANICKING_PANIC_STR,
 +        ],
 +    )
 +    .is_some()
 +}
 +
 +/// Returns the list of condition expressions and the list of blocks in a
 +/// sequence of `if/else`.
 +/// E.g., this returns `([a, b], [c, d, e])` for the expression
 +/// `if a { c } else if b { d } else { e }`.
 +pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, Vec<&'tcx Block<'tcx>>) {
 +    let mut conds = Vec::new();
 +    let mut blocks: Vec<&Block<'_>> = Vec::new();
 +
 +    while let Some(higher::IfOrIfLet { cond, then, r#else }) = higher::IfOrIfLet::hir(expr) {
 +        conds.push(&*cond);
 +        if let ExprKind::Block(block, _) = then.kind {
 +            blocks.push(block);
 +        } else {
 +            panic!("ExprKind::If node is not an ExprKind::Block");
 +        }
 +
 +        if let Some(else_expr) = r#else {
 +            expr = else_expr;
 +        } else {
 +            break;
 +        }
 +    }
 +
 +    // final `else {..}`
 +    if !blocks.is_empty() {
 +        if let ExprKind::Block(block, _) = expr.kind {
 +            blocks.push(block);
 +        }
 +    }
 +
 +    (conds, blocks)
 +}
 +
 +/// Checks if the given function kind is an async function.
 +pub fn is_async_fn(kind: FnKind<'_>) -> bool {
 +    matches!(kind, FnKind::ItemFn(_, _, header, _) if header.asyncness == IsAsync::Async)
 +}
 +
 +/// Peels away all the compiler generated code surrounding the body of an async function,
 +pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
 +    if let ExprKind::Call(
 +        _,
- /// Checks whether item either has `test` attribute appelied, or
++        &[
++            Expr {
++                kind: ExprKind::Closure(_, _, body, _, _),
++                ..
++            },
++        ],
 +    ) = body.value.kind
 +    {
 +        if let ExprKind::Block(
 +            Block {
 +                stmts: [],
 +                expr:
 +                    Some(Expr {
 +                        kind: ExprKind::DropTemps(expr),
 +                        ..
 +                    }),
 +                ..
 +            },
 +            _,
 +        ) = tcx.hir().body(body).value.kind
 +        {
 +            return Some(expr);
 +        }
 +    };
 +    None
 +}
 +
 +// Finds the `#[must_use]` attribute, if any
 +pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
 +    attrs.iter().find(|a| a.has_name(sym::must_use))
 +}
 +
 +// check if expr is calling method or function with #[must_use] attribute
 +pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    let did = match expr.kind {
 +        ExprKind::Call(path, _) => if_chain! {
 +            if let ExprKind::Path(ref qpath) = path.kind;
 +            if let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id);
 +            then {
 +                Some(did)
 +            } else {
 +                None
 +            }
 +        },
 +        ExprKind::MethodCall(_, _, _, _) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
 +        _ => None,
 +    };
 +
 +    did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some())
 +}
 +
 +/// Checks if an expression represents the identity function
 +/// Only examines closures and `std::convert::identity`
 +pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 +    /// Checks if a function's body represents the identity function. Looks for bodies of the form:
 +    /// * `|x| x`
 +    /// * `|x| return x`
 +    /// * `|x| { return x }`
 +    /// * `|x| { return x; }`
 +    fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
 +        let id = if_chain! {
 +            if let [param] = func.params;
 +            if let PatKind::Binding(_, id, _, _) = param.pat.kind;
 +            then {
 +                id
 +            } else {
 +                return false;
 +            }
 +        };
 +
 +        let mut expr = &func.value;
 +        loop {
 +            match expr.kind {
 +                #[rustfmt::skip]
 +                ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _, )
 +                | ExprKind::Ret(Some(e)) => expr = e,
 +                #[rustfmt::skip]
 +                ExprKind::Block(&Block { stmts: [stmt], expr: None, .. }, _) => {
 +                    if_chain! {
 +                        if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind;
 +                        if let ExprKind::Ret(Some(ret_val)) = e.kind;
 +                        then {
 +                            expr = ret_val;
 +                        } else {
 +                            return false;
 +                        }
 +                    }
 +                },
 +                _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(),
 +            }
 +        }
 +    }
 +
 +    match expr.kind {
 +        ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
 +        ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY),
 +        _ => false,
 +    }
 +}
 +
 +/// Gets the node where an expression is either used, or it's type is unified with another branch.
 +pub fn get_expr_use_or_unification_node(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<Node<'tcx>> {
 +    let mut child_id = expr.hir_id;
 +    let mut iter = tcx.hir().parent_iter(child_id);
 +    loop {
 +        match iter.next() {
 +            None => break None,
 +            Some((id, Node::Block(_))) => child_id = id,
 +            Some((id, Node::Arm(arm))) if arm.body.hir_id == child_id => child_id = id,
 +            Some((_, Node::Expr(expr))) => match expr.kind {
 +                ExprKind::Match(_, [arm], _) if arm.hir_id == child_id => child_id = expr.hir_id,
 +                ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = expr.hir_id,
 +                ExprKind::If(_, then_expr, None) if then_expr.hir_id == child_id => break None,
 +                _ => break Some(Node::Expr(expr)),
 +            },
 +            Some((_, node)) => break Some(node),
 +        }
 +    }
 +}
 +
 +/// Checks if the result of an expression is used, or it's type is unified with another branch.
 +pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 +    !matches!(
 +        get_expr_use_or_unification_node(tcx, expr),
 +        None | Some(Node::Stmt(Stmt {
 +            kind: StmtKind::Expr(_)
 +                | StmtKind::Semi(_)
 +                | StmtKind::Local(Local {
 +                    pat: Pat {
 +                        kind: PatKind::Wild,
 +                        ..
 +                    },
 +                    ..
 +                }),
 +            ..
 +        }))
 +    )
 +}
 +
 +/// Checks if the expression is the final expression returned from a block.
 +pub fn is_expr_final_block_expr(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 +    matches!(get_parent_node(tcx, expr.hir_id), Some(Node::Block(..)))
 +}
 +
 +pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
 +    cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
 +        if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
 +            attr.path == sym::no_std
 +        } else {
 +            false
 +        }
 +    })
 +}
 +
 +/// Check if parent of a hir node is a trait implementation block.
 +/// For example, `f` in
 +/// ```rust,ignore
 +/// impl Trait for S {
 +///     fn f() {}
 +/// }
 +/// ```
 +pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
 +    if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
 +        matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
 +    } else {
 +        false
 +    }
 +}
 +
 +/// Check if it's even possible to satisfy the `where` clause for the item.
 +///
 +/// `trivial_bounds` feature allows functions with unsatisfiable bounds, for example:
 +///
 +/// ```ignore
 +/// fn foo() where i32: Iterator {
 +///     for _ in 2i32 {}
 +/// }
 +/// ```
 +pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
 +    use rustc_trait_selection::traits;
 +    let predicates = cx
 +        .tcx
 +        .predicates_of(did)
 +        .predicates
 +        .iter()
 +        .filter_map(|(p, _)| if p.is_global(cx.tcx) { Some(*p) } else { None });
 +    traits::impossible_predicates(
 +        cx.tcx,
 +        traits::elaborate_predicates(cx.tcx, predicates)
 +            .map(|o| o.predicate)
 +            .collect::<Vec<_>>(),
 +    )
 +}
 +
 +/// Returns the `DefId` of the callee if the given expression is a function or method call.
 +pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
 +    match &expr.kind {
 +        ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
 +        ExprKind::Call(
 +            Expr {
 +                kind: ExprKind::Path(qpath),
 +                hir_id: path_hir_id,
 +                ..
 +            },
 +            ..,
 +        ) => cx.typeck_results().qpath_res(qpath, *path_hir_id).opt_def_id(),
 +        _ => None,
 +    }
 +}
 +
 +/// Returns Option<String> where String is a textual representation of the type encapsulated in the
 +/// slice iff the given expression is a slice of primitives (as defined in the
 +/// `is_recursively_primitive_type` function) and None otherwise.
 +pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
 +    let expr_type = cx.typeck_results().expr_ty_adjusted(expr);
 +    let expr_kind = expr_type.kind();
 +    let is_primitive = match expr_kind {
 +        rustc_ty::Slice(element_type) => is_recursively_primitive_type(element_type),
 +        rustc_ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &rustc_ty::Slice(_)) => {
 +            if let rustc_ty::Slice(element_type) = inner_ty.kind() {
 +                is_recursively_primitive_type(element_type)
 +            } else {
 +                unreachable!()
 +            }
 +        },
 +        _ => false,
 +    };
 +
 +    if is_primitive {
 +        // if we have wrappers like Array, Slice or Tuple, print these
 +        // and get the type enclosed in the slice ref
 +        match expr_type.peel_refs().walk(cx.tcx).nth(1).unwrap().expect_ty().kind() {
 +            rustc_ty::Slice(..) => return Some("slice".into()),
 +            rustc_ty::Array(..) => return Some("array".into()),
 +            rustc_ty::Tuple(..) => return Some("tuple".into()),
 +            _ => {
 +                // is_recursively_primitive_type() should have taken care
 +                // of the rest and we can rely on the type that is found
 +                let refs_peeled = expr_type.peel_refs();
 +                return Some(refs_peeled.walk(cx.tcx).last().unwrap().to_string());
 +            },
 +        }
 +    }
 +    None
 +}
 +
 +/// returns list of all pairs (a, b) from `exprs` such that `eq(a, b)`
 +/// `hash` must be comformed with `eq`
 +pub fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
 +where
 +    Hash: Fn(&T) -> u64,
 +    Eq: Fn(&T, &T) -> bool,
 +{
 +    match exprs {
 +        [a, b] if eq(a, b) => return vec![(a, b)],
 +        _ if exprs.len() <= 2 => return vec![],
 +        _ => {},
 +    }
 +
 +    let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
 +
 +    let mut map: UnhashMap<u64, Vec<&_>> =
 +        UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
 +
 +    for expr in exprs {
 +        match map.entry(hash(expr)) {
 +            Entry::Occupied(mut o) => {
 +                for o in o.get() {
 +                    if eq(o, expr) {
 +                        match_expr_list.push((o, expr));
 +                    }
 +                }
 +                o.get_mut().push(expr);
 +            },
 +            Entry::Vacant(v) => {
 +                v.insert(vec![expr]);
 +            },
 +        }
 +    }
 +
 +    match_expr_list
 +}
 +
 +/// Peels off all references on the pattern. Returns the underlying pattern and the number of
 +/// references removed.
 +pub fn peel_hir_pat_refs(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
 +    fn peel(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
 +        if let PatKind::Ref(pat, _) = pat.kind {
 +            peel(pat, count + 1)
 +        } else {
 +            (pat, count)
 +        }
 +    }
 +    peel(pat, 0)
 +}
 +
 +/// Peels of expressions while the given closure returns `Some`.
 +pub fn peel_hir_expr_while<'tcx>(
 +    mut expr: &'tcx Expr<'tcx>,
 +    mut f: impl FnMut(&'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>>,
 +) -> &'tcx Expr<'tcx> {
 +    while let Some(e) = f(expr) {
 +        expr = e;
 +    }
 +    expr
 +}
 +
 +/// Peels off up to the given number of references on the expression. Returns the underlying
 +/// expression and the number of references removed.
 +pub fn peel_n_hir_expr_refs(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) {
 +    let mut remaining = count;
 +    let e = peel_hir_expr_while(expr, |e| match e.kind {
 +        ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) if remaining != 0 => {
 +            remaining -= 1;
 +            Some(e)
 +        },
 +        _ => None,
 +    });
 +    (e, count - remaining)
 +}
 +
 +/// Peels off all references on the expression. Returns the underlying expression and the number of
 +/// references removed.
 +pub fn peel_hir_expr_refs(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
 +    let mut count = 0;
 +    let e = peel_hir_expr_while(expr, |e| match e.kind {
 +        ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) => {
 +            count += 1;
 +            Some(e)
 +        },
 +        _ => None,
 +    });
 +    (e, count)
 +}
 +
 +/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
 +/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
 +pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
 +    loop {
 +        match expr.kind {
 +            ExprKind::AddrOf(_, _, e) => expr = e,
 +            ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e,
 +            _ => break,
 +        }
 +    }
 +    expr
 +}
 +
 +#[macro_export]
 +macro_rules! unwrap_cargo_metadata {
 +    ($cx: ident, $lint: ident, $deps: expr) => {{
 +        let mut command = cargo_metadata::MetadataCommand::new();
 +        if !$deps {
 +            command.no_deps();
 +        }
 +
 +        match command.exec() {
 +            Ok(metadata) => metadata,
 +            Err(err) => {
 +                span_lint($cx, $lint, DUMMY_SP, &format!("could not read cargo metadata: {}", err));
 +                return;
 +            },
 +        }
 +    }};
 +}
 +
 +pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
 +    if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
 +        if let Res::Def(_, def_id) = path.res {
 +            return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr);
 +        }
 +    }
 +    false
 +}
 +
 +struct VisitConstTestStruct<'tcx> {
 +    tcx: TyCtxt<'tcx>,
 +    names: Vec<Symbol>,
 +    found: bool,
 +}
 +impl<'hir> ItemLikeVisitor<'hir> for VisitConstTestStruct<'hir> {
 +    fn visit_item(&mut self, item: &Item<'_>) {
 +        if let ItemKind::Const(ty, _body) = item.kind {
 +            if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
 +                // We could also check for the type name `test::TestDescAndFn`
 +                // and the `#[rustc_test_marker]` attribute?
 +                if let Res::Def(DefKind::Struct, _) = path.res {
 +                    let has_test_marker = self
 +                        .tcx
 +                        .hir()
 +                        .attrs(item.hir_id())
 +                        .iter()
 +                        .any(|a| a.has_name(sym::rustc_test_marker));
 +                    if has_test_marker && self.names.contains(&item.ident.name) {
 +                        self.found = true;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +    fn visit_trait_item(&mut self, _: &TraitItem<'_>) {}
 +    fn visit_impl_item(&mut self, _: &ImplItem<'_>) {}
 +    fn visit_foreign_item(&mut self, _: &ForeignItem<'_>) {}
 +}
 +
 +/// Checks if the function containing the given `HirId` is a `#[test]` function
 +///
 +/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
 +pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
 +    let names: Vec<_> = tcx
 +        .hir()
 +        .parent_iter(id)
 +        // Since you can nest functions we need to collect all until we leave
 +        // function scope
 +        .filter_map(|(_id, node)| {
 +            if let Node::Item(item) = node {
 +                if let ItemKind::Fn(_, _, _) = item.kind {
 +                    return Some(item.ident.name);
 +                }
 +            }
 +            None
 +        })
 +        .collect();
 +    let parent_mod = tcx.parent_module(id);
 +    let mut vis = VisitConstTestStruct {
 +        tcx,
 +        names,
 +        found: false,
 +    };
 +    tcx.hir().visit_item_likes_in_module(parent_mod, &mut vis);
 +    vis.found
 +}
 +
++/// Checks whether item either has `test` attribute applied, or
 +/// is a module with `test` in its name.
 +///
 +/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
 +pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
 +    is_in_test_function(tcx, item.hir_id())
 +        || matches!(item.kind, ItemKind::Mod(..))
 +            && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests")
 +}
 +
 +macro_rules! op_utils {
 +    ($($name:ident $assign:ident)*) => {
 +        /// Binary operation traits like `LangItem::Add`
 +        pub static BINOP_TRAITS: &[LangItem] = &[$(LangItem::$name,)*];
 +
 +        /// Operator-Assign traits like `LangItem::AddAssign`
 +        pub static OP_ASSIGN_TRAITS: &[LangItem] = &[$(LangItem::$assign,)*];
 +
 +        /// Converts `BinOpKind::Add` to `(LangItem::Add, LangItem::AddAssign)`, for example
 +        pub fn binop_traits(kind: hir::BinOpKind) -> Option<(LangItem, LangItem)> {
 +            match kind {
 +                $(hir::BinOpKind::$name => Some((LangItem::$name, LangItem::$assign)),)*
 +                _ => None,
 +            }
 +        }
 +    };
 +}
 +
 +op_utils! {
 +    Add    AddAssign
 +    Sub    SubAssign
 +    Mul    MulAssign
 +    Div    DivAssign
 +    Rem    RemAssign
 +    BitXor BitXorAssign
 +    BitAnd BitAndAssign
 +    BitOr  BitOrAssign
 +    Shl    ShlAssign
 +    Shr    ShrAssign
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..cba96e05a2412244e6c36cd78d52b181c985cc8b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,230 @@@
++/// Dealing with sting indices can be hard, this struct ensures that both the
++/// character and byte index are provided for correct indexing.
++#[derive(Debug, Default, PartialEq, Eq)]
++pub struct StrIndex {
++    pub char_index: usize,
++    pub byte_index: usize,
++}
++
++impl StrIndex {
++    pub fn new(char_index: usize, byte_index: usize) -> Self {
++        Self { char_index, byte_index }
++    }
++}
++
++/// Returns the index of the character after the first camel-case component of `s`.
++///
++/// ```
++/// assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
++/// assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
++/// assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
++/// assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
++/// ```
++#[must_use]
++pub fn camel_case_until(s: &str) -> StrIndex {
++    let mut iter = s.char_indices().enumerate();
++    if let Some((_char_index, (_, first))) = iter.next() {
++        if !first.is_uppercase() {
++            return StrIndex::new(0, 0);
++        }
++    } else {
++        return StrIndex::new(0, 0);
++    }
++    let mut up = true;
++    let mut last_index = StrIndex::new(0, 0);
++    for (char_index, (byte_index, c)) in iter {
++        if up {
++            if c.is_lowercase() {
++                up = false;
++            } else {
++                return last_index;
++            }
++        } else if c.is_uppercase() {
++            up = true;
++            last_index.byte_index = byte_index;
++            last_index.char_index = char_index;
++        } else if !c.is_lowercase() {
++            return StrIndex::new(char_index, byte_index);
++        }
++    }
++
++    if up {
++        last_index
++    } else {
++        StrIndex::new(s.chars().count(), s.len())
++    }
++}
++
++/// Returns index of the last camel-case component of `s`.
++///
++/// ```
++/// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
++/// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
++/// assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
++/// assert_eq!(camel_case_start("abcd"), StrIndex::new(4, 4));
++/// assert_eq!(camel_case_start("\u{f6}\u{f6}cd"), StrIndex::new(4, 6));
++/// ```
++#[must_use]
++pub fn camel_case_start(s: &str) -> StrIndex {
++    let char_count = s.chars().count();
++    let range = 0..char_count;
++    let mut iter = range.rev().zip(s.char_indices().rev());
++    if let Some((char_index, (_, first))) = iter.next() {
++        if !first.is_lowercase() {
++            return StrIndex::new(char_index, s.len());
++        }
++    } else {
++        return StrIndex::new(char_count, s.len());
++    }
++    let mut down = true;
++    let mut last_index = StrIndex::new(char_count, s.len());
++    for (char_index, (byte_index, c)) in iter {
++        if down {
++            if c.is_uppercase() {
++                down = false;
++                last_index.byte_index = byte_index;
++                last_index.char_index = char_index;
++            } else if !c.is_lowercase() {
++                return last_index;
++            }
++        } else if c.is_lowercase() {
++            down = true;
++        } else if c.is_uppercase() {
++            last_index.byte_index = byte_index;
++            last_index.char_index = char_index;
++        } else {
++            return last_index;
++        }
++    }
++    last_index
++}
++
++/// Dealing with sting comparison can be complicated, this struct ensures that both the
++/// character and byte count are provided for correct indexing.
++#[derive(Debug, Default, PartialEq, Eq)]
++pub struct StrCount {
++    pub char_count: usize,
++    pub byte_count: usize,
++}
++
++impl StrCount {
++    pub fn new(char_count: usize, byte_count: usize) -> Self {
++        Self { char_count, byte_count }
++    }
++}
++
++/// Returns the number of chars that match from the start
++///
++/// ```
++/// assert_eq!(count_match_start("hello_mouse", "hello_penguin"), StrCount::new(6, 6));
++/// assert_eq!(count_match_start("hello_clippy", "bye_bugs"), StrCount::new(0, 0));
++/// assert_eq!(count_match_start("hello_world", "hello_world"), StrCount::new(11, 11));
++/// assert_eq!(count_match_start("T\u{f6}ffT\u{f6}ff", "T\u{f6}ff"), StrCount::new(4, 5));
++/// ```
++#[must_use]
++pub fn count_match_start(str1: &str, str2: &str) -> StrCount {
++    // (char_index, char1)
++    let char_count = str1.chars().count();
++    let iter1 = (0..=char_count).zip(str1.chars());
++    // (byte_index, char2)
++    let iter2 = str2.char_indices();
++
++    iter1
++        .zip(iter2)
++        .take_while(|((_, c1), (_, c2))| c1 == c2)
++        .last()
++        .map_or_else(StrCount::default, |((char_index, _), (byte_index, character))| {
++            StrCount::new(char_index + 1, byte_index + character.len_utf8())
++        })
++}
++
++/// Returns the number of chars and bytes that match from the end
++///
++/// ```
++/// assert_eq!(count_match_end("hello_cat", "bye_cat"), StrCount::new(4, 4));
++/// assert_eq!(count_match_end("if_item_thing", "enum_value"), StrCount::new(0, 0));
++/// assert_eq!(count_match_end("Clippy", "Clippy"), StrCount::new(6, 6));
++/// assert_eq!(count_match_end("MyT\u{f6}ff", "YourT\u{f6}ff"), StrCount::new(4, 5));
++/// ```
++#[must_use]
++pub fn count_match_end(str1: &str, str2: &str) -> StrCount {
++    let char_count = str1.chars().count();
++    if char_count == 0 {
++        return StrCount::default();
++    }
++
++    // (char_index, char1)
++    let iter1 = (0..char_count).rev().zip(str1.chars().rev());
++    // (byte_index, char2)
++    let byte_count = str2.len();
++    let iter2 = str2.char_indices().rev();
++
++    iter1
++        .zip(iter2)
++        .take_while(|((_, c1), (_, c2))| c1 == c2)
++        .last()
++        .map_or_else(StrCount::default, |((char_index, _), (byte_index, _))| {
++            StrCount::new(char_count - char_index, byte_count - byte_index)
++        })
++}
++
++#[cfg(test)]
++mod test {
++    use super::*;
++
++    #[test]
++    fn camel_case_start_full() {
++        assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
++        assert_eq!(camel_case_start("Abc"), StrIndex::new(0, 0));
++        assert_eq!(camel_case_start("ABcd"), StrIndex::new(0, 0));
++        assert_eq!(camel_case_start("ABcdEf"), StrIndex::new(0, 0));
++        assert_eq!(camel_case_start("AabABcd"), StrIndex::new(0, 0));
++    }
++
++    #[test]
++    fn camel_case_start_partial() {
++        assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
++        assert_eq!(camel_case_start("aDbc"), StrIndex::new(1, 1));
++        assert_eq!(camel_case_start("aabABcd"), StrIndex::new(3, 3));
++        assert_eq!(camel_case_start("\u{f6}\u{f6}AabABcd"), StrIndex::new(2, 4));
++    }
++
++    #[test]
++    fn camel_case_start_not() {
++        assert_eq!(camel_case_start("AbcDef_"), StrIndex::new(7, 7));
++        assert_eq!(camel_case_start("AbcDD"), StrIndex::new(5, 5));
++        assert_eq!(camel_case_start("all_small"), StrIndex::new(9, 9));
++        assert_eq!(camel_case_start("\u{f6}_all_small"), StrIndex::new(11, 12));
++    }
++
++    #[test]
++    fn camel_case_start_caps() {
++        assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
++    }
++
++    #[test]
++    fn camel_case_until_full() {
++        assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
++        assert_eq!(camel_case_until("Abc"), StrIndex::new(3, 3));
++        assert_eq!(camel_case_until("Abc\u{f6}\u{f6}\u{f6}"), StrIndex::new(6, 9));
++    }
++
++    #[test]
++    fn camel_case_until_not() {
++        assert_eq!(camel_case_until("abcDef"), StrIndex::new(0, 0));
++        assert_eq!(camel_case_until("aDbc"), StrIndex::new(0, 0));
++    }
++
++    #[test]
++    fn camel_case_until_partial() {
++        assert_eq!(camel_case_until("AbcDef_"), StrIndex::new(6, 6));
++        assert_eq!(camel_case_until("CallTypeC"), StrIndex::new(8, 8));
++        assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
++        assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
++    }
++
++    #[test]
++    fn until_caps() {
++        assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
++    }
++}
index 004eb28b44640fb59ab3d43c31203ab97c622870,0000000000000000000000000000000000000000..bd32696d6dbda7d15b4b6975a6195f673d2f76c7
mode 100644,000000..100644
--- /dev/null
@@@ -1,669 -1,0 +1,673 @@@
- `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`.
 +# 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)
 +    - [Cargo lints](#cargo-lints)
 +  - [Rustfix tests](#rustfix-tests)
 +  - [Edition 2018 tests](#edition-2018-tests)
 +  - [Testing manually](#testing-manually)
 +  - [Lint declaration](#lint-declaration)
++  - [Lint registration](#lint-registration)
 +  - [Lint passes](#lint-passes)
 +  - [Emitting a lint](#emitting-a-lint)
 +  - [Adding the lint logic](#adding-the-lint-logic)
 +  - [Specifying the lint's minimum supported Rust version (MSRV)](#specifying-the-lints-minimum-supported-rust-version-msrv)
 +  - [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
- 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`:
++`clippy_lints/src/foo_functions.rs`, as well as
++[registering the lint](#lint-registration). 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.
 +
 +Note that you can run multiple test files by specifying a comma separated list:
 +`TESTNAME=foo_functions,test2,test3`.
 +
 +### 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?
 +    ///
 +    /// ### 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 {}
 +```
 +
- store.register_early_pass(|| box foo_functions::FooFunctions);
++[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
++[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
++[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
++[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
++
++## Lint registration
++
++When using `cargo dev new_lint`, the lint is automatically registered and
++nothing more has to be done.
++
++When declaring a new lint by hand and `cargo dev update_lints` is used, the lint
++pass may have to be registered manually in the `register_plugins` function in
++`clippy_lints/src/lib.rs`:
 +
 +```rust
- 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
++store.register_early_pass(|| Box::new(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.
 +
-     The doc comment will be automatically added to the lint documentation.
++One reason that `cargo dev update_lints` 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.
 +
 +## 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_utils/src/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_utils/src/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)
 +
 +Sometimes a lint makes suggestions that require a certain version of Rust. For example, the `manual_strip` lint suggests
 +using `str::strip_prefix` and `str::strip_suffix` which is only available after Rust 1.45. In such cases, you need to
 +ensure that the MSRV configured for the project is >= the MSRV of the required Rust feature. If multiple features are
 +required, just use the one with a lower MSRV.
 +
 +First, add an MSRV alias for the required feature in [`clippy_utils::msrvs`](/clippy_utils/src/msrvs.rs). This can be
 +accessed later as `msrvs::STR_STRIP_PREFIX`, for example.
 +
 +```rust
 +msrv_aliases! {
 +    ..
 +    1,45,0 { STR_STRIP_PREFIX }
 +}
 +```
 +
 +In order to access the project-configured MSRV, you need to have an `msrv` field in the LintPass struct, and a
 +constructor to initialize the field. The `msrv` value is passed to the constructor in `clippy_lints/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 feature MSRV in the LintPass
 +using the `meets_msrv` utility function.
 +
 +``` rust
 +if !meets_msrv(self.msrv.as_ref(), &msrvs::STR_STRIP_PREFIX) {
 +    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.
 +
 +As a last step, the lint should be added to the lint documentation. This is done
 +in `clippy_lints/src/utils/conf.rs`:
 +
 +```rust
 +define_Conf! {
 +    /// Lint: LIST, OF, LINTS, <THE_NEWLY_ADDED_LINT>. The minimum rust version that the project supports
 +    (msrv: Option<String> = None),
 +    ...
 +}
 +```
 +
 +## 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.
 +    ///
 +    /// ### 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: Type = DefaultValue),
 +    ```
++    The doc comment is automatically added to the documentation of the listed lints. The default
++    value will be formatted using the `Debug` implementation of the type.
 +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).
 +    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_*_pass(|| box module::StructName);
 +
 +    // New registration with configuration value
 +    let configuration_ident = conf.configuration_ident.clone();
 +    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_def_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_utils/src/lib.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 67eaf286004f9515cabbfefe3d889ec4b9c74b3f,0000000000000000000000000000000000000000..09554c08987b1ae66902243826bcfec6b063c91f
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,3 @@@
- channel = "nightly-2021-10-21"
 +[toolchain]
++channel = "nightly-2021-11-04"
 +components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
index c15835ef2995687327d9227c861b1decd8b3f85d,0000000000000000000000000000000000000000..f25cf1d3ef56185243762a4f3296f4f7ca2eca98
mode 100644,000000..100644
--- /dev/null
@@@ -1,356 -1,0 +1,359 @@@
-     let mut config = compiletest::Config::default();
 +#![feature(test)] // compiletest_rs requires this attribute
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +
 +use compiletest_rs as compiletest;
 +use compiletest_rs::common::Mode as TestMode;
 +
 +use std::collections::HashMap;
 +use std::env::{self, remove_var, set_var, var_os};
 +use std::ffi::{OsStr, OsString};
 +use std::fs;
 +use std::io;
 +use std::path::{Path, PathBuf};
 +
 +mod cargo;
 +
 +// whether to run internal tests or not
 +const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal-lints");
 +
 +/// All crates used in UI tests are listed here
 +static TEST_DEPENDENCIES: &[&str] = &[
 +    "clippy_utils",
 +    "derive_new",
 +    "if_chain",
 +    "itertools",
 +    "quote",
 +    "regex",
 +    "serde",
 +    "serde_derive",
 +    "syn",
 +];
 +
 +// Test dependencies may need an `extern crate` here to ensure that they show up
 +// in the depinfo file (otherwise cargo thinks they are unused)
 +#[allow(unused_extern_crates)]
 +extern crate clippy_utils;
 +#[allow(unused_extern_crates)]
 +extern crate derive_new;
 +#[allow(unused_extern_crates)]
 +extern crate if_chain;
 +#[allow(unused_extern_crates)]
 +extern crate itertools;
 +#[allow(unused_extern_crates)]
 +extern crate quote;
 +#[allow(unused_extern_crates)]
 +extern crate syn;
 +
 +/// Produces a string with an `--extern` flag for all UI test crate
 +/// dependencies.
 +///
 +/// The dependency files are located by parsing the depinfo file for this test
 +/// module. This assumes the `-Z binary-dep-depinfo` flag is enabled. All test
 +/// dependencies must be added to Cargo.toml at the project root. Test
 +/// dependencies that are not *directly* used by this test module require an
 +/// `extern crate` declaration.
 +fn extern_flags() -> String {
 +    let current_exe_depinfo = {
 +        let mut path = env::current_exe().unwrap();
 +        path.set_extension("d");
 +        std::fs::read_to_string(path).unwrap()
 +    };
 +    let mut crates: HashMap<&str, &str> = HashMap::with_capacity(TEST_DEPENDENCIES.len());
 +    for line in current_exe_depinfo.lines() {
 +        // each dependency is expected to have a Makefile rule like `/path/to/crate-hash.rlib:`
 +        let parse_name_path = || {
 +            if line.starts_with(char::is_whitespace) {
 +                return None;
 +            }
 +            let path_str = line.strip_suffix(':')?;
 +            let path = Path::new(path_str);
 +            if !matches!(path.extension()?.to_str()?, "rlib" | "so" | "dylib" | "dll") {
 +                return None;
 +            }
 +            let (name, _hash) = path.file_stem()?.to_str()?.rsplit_once('-')?;
 +            // the "lib" prefix is not present for dll files
 +            let name = name.strip_prefix("lib").unwrap_or(name);
 +            Some((name, path_str))
 +        };
 +        if let Some((name, path)) = parse_name_path() {
 +            if TEST_DEPENDENCIES.contains(&name) {
 +                // A dependency may be listed twice if it is available in sysroot,
 +                // and the sysroot dependencies are listed first. As of the writing,
 +                // this only seems to apply to if_chain.
 +                crates.insert(name, path);
 +            }
 +        }
 +    }
 +    let not_found: Vec<&str> = TEST_DEPENDENCIES
 +        .iter()
 +        .copied()
 +        .filter(|n| !crates.contains_key(n))
 +        .collect();
 +    assert!(
 +        not_found.is_empty(),
 +        "dependencies not found in depinfo: {:?}\n\
 +        help: Make sure the `-Z binary-dep-depinfo` rust flag is enabled\n\
 +        help: Try adding to dev-dependencies in Cargo.toml",
 +        not_found
 +    );
 +    crates
 +        .into_iter()
 +        .map(|(name, path)| format!(" --extern {}={}", name, path))
 +        .collect()
 +}
 +
 +fn default_config() -> compiletest::Config {
++    let mut config = compiletest::Config {
++        edition: Some("2021".into()),
++        ..compiletest::Config::default()
++    };
 +
 +    if let Ok(filters) = env::var("TESTNAME") {
 +        config.filters = filters.split(',').map(std::string::ToString::to_string).collect();
 +    }
 +
 +    if let Some(path) = option_env!("RUSTC_LIB_PATH") {
 +        let path = PathBuf::from(path);
 +        config.run_lib_path = path.clone();
 +        config.compile_lib_path = path;
 +    }
 +    let current_exe_path = std::env::current_exe().unwrap();
 +    let deps_path = current_exe_path.parent().unwrap();
 +    let profile_path = deps_path.parent().unwrap();
 +
 +    // Using `-L dependency={}` enforces that external dependencies are added with `--extern`.
 +    // This is valuable because a) it allows us to monitor what external dependencies are used
 +    // and b) it ensures that conflicting rlibs are resolved properly.
 +    let host_libs = option_env!("HOST_LIBS")
 +        .map(|p| format!(" -L dependency={}", Path::new(p).join("deps").display()))
 +        .unwrap_or_default();
 +    config.target_rustcflags = Some(format!(
 +        "--emit=metadata -Dwarnings -Zui-testing -L dependency={}{}{}",
 +        deps_path.display(),
 +        host_libs,
 +        extern_flags(),
 +    ));
 +
 +    config.build_base = profile_path.join("test");
 +    config.rustc_path = profile_path.join(if cfg!(windows) {
 +        "clippy-driver.exe"
 +    } else {
 +        "clippy-driver"
 +    });
 +    config
 +}
 +
 +fn run_ui(cfg: &mut compiletest::Config) {
 +    cfg.mode = TestMode::Ui;
 +    cfg.src_base = Path::new("tests").join("ui");
 +    // use tests/clippy.toml
 +    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
 +    compiletest::run_tests(cfg);
 +}
 +
 +fn run_ui_test(cfg: &mut compiletest::Config) {
 +    cfg.mode = TestMode::Ui;
 +    cfg.src_base = Path::new("tests").join("ui_test");
 +    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
 +    let rustcflags = cfg.target_rustcflags.get_or_insert_with(Default::default);
 +    let len = rustcflags.len();
 +    rustcflags.push_str(" --test");
 +    compiletest::run_tests(cfg);
 +    if let Some(ref mut flags) = &mut cfg.target_rustcflags {
 +        flags.truncate(len);
 +    }
 +}
 +
 +fn run_internal_tests(cfg: &mut compiletest::Config) {
 +    // only run internal tests with the internal-tests feature
 +    if !RUN_INTERNAL_TESTS {
 +        return;
 +    }
 +    cfg.mode = TestMode::Ui;
 +    cfg.src_base = Path::new("tests").join("ui-internal");
 +    compiletest::run_tests(cfg);
 +}
 +
 +fn run_ui_toml(config: &mut compiletest::Config) {
 +    fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>) -> Result<bool, io::Error> {
 +        let mut result = true;
 +        let opts = compiletest::test_opts(config);
 +        for dir in fs::read_dir(&config.src_base)? {
 +            let dir = dir?;
 +            if !dir.file_type()?.is_dir() {
 +                continue;
 +            }
 +            let dir_path = dir.path();
 +            let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path);
 +            for file in fs::read_dir(&dir_path)? {
 +                let file = file?;
 +                let file_path = file.path();
 +                if file.file_type()?.is_dir() {
 +                    continue;
 +                }
 +                if file_path.extension() != Some(OsStr::new("rs")) {
 +                    continue;
 +                }
 +                let paths = compiletest::common::TestPaths {
 +                    file: file_path,
 +                    base: config.src_base.clone(),
 +                    relative_dir: dir_path.file_name().unwrap().into(),
 +                };
 +                let test_name = compiletest::make_test_name(config, &paths);
 +                let index = tests
 +                    .iter()
 +                    .position(|test| test.desc.name == test_name)
 +                    .expect("The test should be in there");
 +                result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
 +            }
 +        }
 +        Ok(result)
 +    }
 +
 +    config.mode = TestMode::Ui;
 +    config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap();
 +
 +    let tests = compiletest::make_tests(config);
 +
 +    let res = run_tests(config, tests);
 +    match res {
 +        Ok(true) => {},
 +        Ok(false) => panic!("Some tests failed"),
 +        Err(e) => {
 +            panic!("I/O failure during tests: {:?}", e);
 +        },
 +    }
 +}
 +
 +fn run_ui_cargo(config: &mut compiletest::Config) {
 +    fn run_tests(
 +        config: &compiletest::Config,
 +        filters: &[String],
 +        mut tests: Vec<tester::TestDescAndFn>,
 +    ) -> Result<bool, io::Error> {
 +        let mut result = true;
 +        let opts = compiletest::test_opts(config);
 +
 +        for dir in fs::read_dir(&config.src_base)? {
 +            let dir = dir?;
 +            if !dir.file_type()?.is_dir() {
 +                continue;
 +            }
 +
 +            // Use the filter if provided
 +            let dir_path = dir.path();
 +            for filter in filters {
 +                if !dir_path.ends_with(filter) {
 +                    continue;
 +                }
 +            }
 +
 +            for case in fs::read_dir(&dir_path)? {
 +                let case = case?;
 +                if !case.file_type()?.is_dir() {
 +                    continue;
 +                }
 +
 +                let src_path = case.path().join("src");
 +
 +                // When switching between branches, if the previous branch had a test
 +                // that the current branch does not have, the directory is not removed
 +                // because an ignored Cargo.lock file exists.
 +                if !src_path.exists() {
 +                    continue;
 +                }
 +
 +                env::set_current_dir(&src_path)?;
 +                for file in fs::read_dir(&src_path)? {
 +                    let file = file?;
 +                    if file.file_type()?.is_dir() {
 +                        continue;
 +                    }
 +
 +                    // Search for the main file to avoid running a test for each file in the project
 +                    let file_path = file.path();
 +                    match file_path.file_name().and_then(OsStr::to_str) {
 +                        Some("main.rs") => {},
 +                        _ => continue,
 +                    }
 +                    let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path());
 +                    let paths = compiletest::common::TestPaths {
 +                        file: file_path,
 +                        base: config.src_base.clone(),
 +                        relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(),
 +                    };
 +                    let test_name = compiletest::make_test_name(config, &paths);
 +                    let index = tests
 +                        .iter()
 +                        .position(|test| test.desc.name == test_name)
 +                        .expect("The test should be in there");
 +                    result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
 +                }
 +            }
 +        }
 +        Ok(result)
 +    }
 +
 +    if cargo::is_rustc_test_suite() {
 +        return;
 +    }
 +
 +    config.mode = TestMode::Ui;
 +    config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap();
 +
 +    let tests = compiletest::make_tests(config);
 +
 +    let current_dir = env::current_dir().unwrap();
 +    let res = run_tests(config, &config.filters, tests);
 +    env::set_current_dir(current_dir).unwrap();
 +
 +    match res {
 +        Ok(true) => {},
 +        Ok(false) => panic!("Some tests failed"),
 +        Err(e) => {
 +            panic!("I/O failure during tests: {:?}", e);
 +        },
 +    }
 +}
 +
 +fn prepare_env() {
 +    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
 +    set_var("__CLIPPY_INTERNAL_TESTS", "true");
 +    //set_var("RUST_BACKTRACE", "0");
 +}
 +
 +#[test]
 +fn compile_test() {
 +    prepare_env();
 +    let mut config = default_config();
 +    run_ui(&mut config);
 +    run_ui_test(&mut config);
 +    run_ui_toml(&mut config);
 +    run_ui_cargo(&mut config);
 +    run_internal_tests(&mut config);
 +}
 +
 +/// Restores an env var on drop
 +#[must_use]
 +struct VarGuard {
 +    key: &'static str,
 +    value: Option<OsString>,
 +}
 +
 +impl VarGuard {
 +    fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
 +        let value = var_os(key);
 +        set_var(key, val);
 +        Self { key, value }
 +    }
 +}
 +
 +impl Drop for VarGuard {
 +    fn drop(&mut self) {
 +        match self.value.as_deref() {
 +            None => remove_var(self.key),
 +            Some(value) => set_var(self.key, value),
 +        }
 +    }
 +}
index bd342e390f52f3d065bdef329f2c082ed3f322c7,0000000000000000000000000000000000000000..7d6edc2b1e095fb1cb59e81cca7b28bba7f44497
mode 100644,000000..100644
--- /dev/null
@@@ -1,56 -1,0 +1,69 @@@
- /*
- Test for missing files.
- Since rs files are alphabetically before stderr/stdout, we can sort by the full name
- and iter in that order. If we've seen the file stem for the first time and it's not
- a rust file, it means the rust file has to be missing.
- */
 +#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 +#![warn(rust_2018_idioms, unused_lifetimes)]
 +#![allow(clippy::assertions_on_constants)]
++#![feature(path_file_prefix)]
 +
++use std::cmp::Ordering;
++use std::ffi::OsStr;
 +use std::fs::{self, DirEntry};
 +use std::path::Path;
 +
 +#[test]
 +fn test_missing_tests() {
 +    let missing_files = explore_directory(Path::new("./tests"));
 +    if !missing_files.is_empty() {
 +        assert!(
 +            false,
 +            "Didn't see a test file for the following files:\n\n{}\n",
 +            missing_files
 +                .iter()
 +                .map(|s| format!("\t{}", s))
 +                .collect::<Vec<_>>()
 +                .join("\n")
 +        );
 +    }
 +}
 +
-     files.sort_by_key(std::fs::DirEntry::path);
++// Test for missing files.
 +fn explore_directory(dir: &Path) -> Vec<String> {
 +    let mut missing_files: Vec<String> = Vec::new();
 +    let mut current_file = String::new();
 +    let mut files: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect();
-             let file_stem = path.file_stem().unwrap().to_str().unwrap().to_string();
++    files.sort_by(|x, y| {
++        match x.path().file_prefix().cmp(&y.path().file_prefix()) {
++            Ordering::Equal => (),
++            ord => return ord,
++        }
++        // Sort rs files before the others if they share the same prefix. So when we see
++        // the file prefix for the first time and it's not a rust file, it means the rust
++        // file has to be missing.
++        match (
++            x.path().extension().and_then(OsStr::to_str),
++            y.path().extension().and_then(OsStr::to_str),
++        ) {
++            (Some("rs"), _) => Ordering::Less,
++            (_, Some("rs")) => Ordering::Greater,
++            _ => Ordering::Equal,
++        }
++    });
 +    for entry in &files {
 +        let path = entry.path();
 +        if path.is_dir() {
 +            missing_files.extend(explore_directory(&path));
 +        } else {
-                     "rs" => current_file = file_stem.clone(),
++            let file_prefix = path.file_prefix().unwrap().to_str().unwrap().to_string();
 +            if let Some(ext) = path.extension() {
 +                match ext.to_str().unwrap() {
-                         if file_stem != current_file {
++                    "rs" => current_file = file_prefix.clone(),
 +                    "stderr" | "stdout" => {
++                        if file_prefix != current_file {
 +                            missing_files.push(path.to_str().unwrap().to_string());
 +                        }
 +                    },
 +                    _ => continue,
 +                };
 +            }
 +        }
 +    }
 +    missing_files
 +}
index 33a3ef7513631aab7d1fb367d49c9993ab1c44ad,0000000000000000000000000000000000000000..e678c896fd3e3b3dc8e7bcba92fb5b641a6f8797
mode 100644,000000..100644
--- /dev/null
@@@ -1,61 -1,0 +1,59 @@@
- // edition:2018
 +#![warn(clippy::too_many_lines)]
 +
 +// This function should be considered one line.
 +fn many_comments_but_one_line_of_code() {
 +    /* println!("This is good."); */
 +    // println!("This is good.");
 +    /* */ // println!("This is good.");
 +    /* */ // println!("This is good.");
 +    /* */ // println!("This is good.");
 +    /* */ // println!("This is good.");
 +    /* println!("This is good.");
 +    println!("This is good.");
 +    println!("This is good."); */
 +    println!("This is good.");
 +}
 +
 +// This should be considered two and a fail.
 +fn too_many_lines() {
 +    println!("This is bad.");
 +    println!("This is bad.");
 +}
 +
 +// This should only fail once (#7517).
 +async fn async_too_many_lines() {
 +    println!("This is bad.");
 +    println!("This is bad.");
 +}
 +
 +// This should fail only once, without failing on the closure.
 +fn closure_too_many_lines() {
 +    let _ = {
 +        println!("This is bad.");
 +        println!("This is bad.");
 +    };
 +}
 +
 +// This should be considered one line.
 +#[rustfmt::skip]
 +fn comment_starts_after_code() {
 +    let _ = 5; /* closing comment. */ /*
 +    this line shouldn't be counted theoretically.
 +    */
 +}
 +
 +// This should be considered one line.
 +fn comment_after_code() {
 +    let _ = 5; /* this line should get counted once. */
 +}
 +
 +// This should fail since it is technically two lines.
 +#[rustfmt::skip]
 +fn comment_before_code() {
 +    let _ = "test";
 +    /* This comment extends to the front of
 +    the code but this line should still count. */ let _ = 5;
 +}
 +
 +// This should be considered one line.
 +fn main() {}
index 7551cac9f504b968918e65f3d82ae0ee1b800cf0,0000000000000000000000000000000000000000..d736bf899735a5cfb5ed02eef151b4c20cbd635f
mode 100644,000000..100644
--- /dev/null
@@@ -1,43 -1,0 +1,43 @@@
-   --> $DIR/test.rs:20:1
 +error: this function has too many lines (2/1)
-   --> $DIR/test.rs:26:1
++  --> $DIR/test.rs:18:1
 +   |
 +LL | / fn too_many_lines() {
 +LL | |     println!("This is bad.");
 +LL | |     println!("This is bad.");
 +LL | | }
 +   | |_^
 +   |
 +   = note: `-D clippy::too-many-lines` implied by `-D warnings`
 +
 +error: this function has too many lines (4/1)
-   --> $DIR/test.rs:32:1
++  --> $DIR/test.rs:24:1
 +   |
 +LL | / async fn async_too_many_lines() {
 +LL | |     println!("This is bad.");
 +LL | |     println!("This is bad.");
 +LL | | }
 +   | |_^
 +
 +error: this function has too many lines (4/1)
-   --> $DIR/test.rs:54:1
++  --> $DIR/test.rs:30:1
 +   |
 +LL | / fn closure_too_many_lines() {
 +LL | |     let _ = {
 +LL | |         println!("This is bad.");
 +LL | |         println!("This is bad.");
 +LL | |     };
 +LL | | }
 +   | |_^
 +
 +error: this function has too many lines (2/1)
++  --> $DIR/test.rs:52:1
 +   |
 +LL | / fn comment_before_code() {
 +LL | |     let _ = "test";
 +LL | |     /* This comment extends to the front of
 +LL | |     the code but this line should still count. */ let _ = 5;
 +LL | | }
 +   | |_^
 +
 +error: aborting due to 4 previous errors
 +
index 2180f848d62cd256f7538d100d6cf5c634398ec2,0000000000000000000000000000000000000000..cb516d0f97783fee0b7b4a71c3cc9336a5072c64
mode 100644,000000..100644
--- /dev/null
@@@ -1,34 -1,0 +1,34 @@@
++//FIXME: suggestions are wrongly expanded, this should be fixed along with #7843
 +#![allow(non_fmt_panics)]
 +
 +macro_rules! assert_const {
 +    ($len:expr) => {
 +        assert!($len > 0);
 +        debug_assert!($len < 0);
 +    };
 +}
-     assert!(false, msg.to_uppercase());
 +fn main() {
 +    assert!(true);
 +    assert!(false);
 +    assert!(true, "true message");
 +    assert!(false, "false message");
 +
 +    let msg = "panic message";
++    assert!(false, "{}", msg.to_uppercase());
 +
 +    const B: bool = true;
 +    assert!(B);
 +
 +    const C: bool = false;
 +    assert!(C);
 +    assert!(C, "C message");
 +
 +    debug_assert!(true);
 +    // Don't lint this, since there is no better way for expressing "Only panic in debug mode".
 +    debug_assert!(false); // #3948
 +    assert_const!(3);
 +    assert_const!(-1);
 +
 +    // Don't lint on this:
 +    assert!(cfg!(feature = "hey") || cfg!(not(feature = "asdf")));
 +}
index 4ca1e6f6e88cc783cf0b2ecd25d9b0c44ddfea5e,0000000000000000000000000000000000000000..ec80ec702fb574ad4cf6380b9e7b2179230a8c84
mode 100644,000000..100644
--- /dev/null
@@@ -1,84 -1,0 +1,75 @@@
- error: `assert!(false, "false message")` should probably be replaced
 +error: `assert!(true)` will be optimized out by the compiler
 +  --> $DIR/assertions_on_constants.rs:11:5
 +   |
 +LL |     assert!(true);
 +   |     ^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::assertions-on-constants` implied by `-D warnings`
 +   = help: remove it
 +   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: `assert!(false)` should probably be replaced
 +  --> $DIR/assertions_on_constants.rs:12:5
 +   |
 +LL |     assert!(false);
 +   |     ^^^^^^^^^^^^^^
 +   |
 +   = help: use `panic!()` or `unreachable!()`
 +   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: `assert!(true)` will be optimized out by the compiler
 +  --> $DIR/assertions_on_constants.rs:13:5
 +   |
 +LL |     assert!(true, "true message");
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = help: remove it
 +   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
-    = help: use `panic!("false message")` or `unreachable!("false message")`
-    = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
- error: `assert!(false, msg.to_uppercase())` should probably be replaced
-   --> $DIR/assertions_on_constants.rs:17:5
-    |
- LL |     assert!(false, msg.to_uppercase());
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-    |
-    = help: use `panic!(msg.to_uppercase())` or `unreachable!(msg.to_uppercase())`
++error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced
 +  --> $DIR/assertions_on_constants.rs:14:5
 +   |
 +LL |     assert!(false, "false message");
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
- error: `assert!(false, "C message")` should probably be replaced
++   = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))`
 +   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: `assert!(true)` will be optimized out by the compiler
 +  --> $DIR/assertions_on_constants.rs:20:5
 +   |
 +LL |     assert!(B);
 +   |     ^^^^^^^^^^
 +   |
 +   = help: remove it
 +   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: `assert!(false)` should probably be replaced
 +  --> $DIR/assertions_on_constants.rs:23:5
 +   |
 +LL |     assert!(C);
 +   |     ^^^^^^^^^^
 +   |
 +   = help: use `panic!()` or `unreachable!()`
 +   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
-    = help: use `panic!("C message")` or `unreachable!("C message")`
++error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced
 +  --> $DIR/assertions_on_constants.rs:24:5
 +   |
 +LL |     assert!(C, "C message");
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^
 +   |
- error: aborting due to 9 previous errors
++   = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))`
 +   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: `debug_assert!(true)` will be optimized out by the compiler
 +  --> $DIR/assertions_on_constants.rs:26:5
 +   |
 +LL |     debug_assert!(true);
 +   |     ^^^^^^^^^^^^^^^^^^^
 +   |
 +   = help: remove it
 +   = note: this error originates in the macro `$crate::assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
++error: aborting due to 8 previous errors
 +
index 9b1a7ac3ba9de85493244232abca89ce4d5d5452,0000000000000000000000000000000000000000..e20b58269b93e60485b68b74618b3bc4a6fe77d3
mode 100644,000000..100644
--- /dev/null
@@@ -1,68 -1,0 +1,67 @@@
- // edition:2018
 +// run-rustfix
 +
 +#![feature(async_closure)]
 +#![warn(clippy::async_yields_async)]
 +
 +use core::future::Future;
 +use core::pin::Pin;
 +use core::task::{Context, Poll};
 +
 +struct CustomFutureType;
 +
 +impl Future for CustomFutureType {
 +    type Output = u8;
 +
 +    fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll<Self::Output> {
 +        Poll::Ready(3)
 +    }
 +}
 +
 +fn custom_future_type_ctor() -> CustomFutureType {
 +    CustomFutureType
 +}
 +
 +async fn f() -> CustomFutureType {
 +    // Don't warn for functions since you have to explicitly declare their
 +    // return types.
 +    CustomFutureType
 +}
 +
 +#[rustfmt::skip]
 +fn main() {
 +    let _f = {
 +        3
 +    };
 +    let _g = async {
 +        3
 +    };
 +    let _h = async {
 +        async {
 +            3
 +        }.await
 +    };
 +    let _i = async {
 +        CustomFutureType.await
 +    };
 +    let _i = async || {
 +        3
 +    };
 +    let _j = async || {
 +        async {
 +            3
 +        }.await
 +    };
 +    let _k = async || {
 +        CustomFutureType.await
 +    };
 +    let _l = async || CustomFutureType.await;
 +    let _m = async || {
 +        println!("I'm bored");
 +        // Some more stuff
 +
 +        // Finally something to await
 +        CustomFutureType.await
 +    };
 +    let _n = async || custom_future_type_ctor();
 +    let _o = async || f();
 +}
index 731c094edb42b16b7a8488293fb09affc43d92db,0000000000000000000000000000000000000000..c1dfa398450250f6d67a6d1290e34c139865d8e1
mode 100644,000000..100644
--- /dev/null
@@@ -1,68 -1,0 +1,67 @@@
- // edition:2018
 +// run-rustfix
 +
 +#![feature(async_closure)]
 +#![warn(clippy::async_yields_async)]
 +
 +use core::future::Future;
 +use core::pin::Pin;
 +use core::task::{Context, Poll};
 +
 +struct CustomFutureType;
 +
 +impl Future for CustomFutureType {
 +    type Output = u8;
 +
 +    fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll<Self::Output> {
 +        Poll::Ready(3)
 +    }
 +}
 +
 +fn custom_future_type_ctor() -> CustomFutureType {
 +    CustomFutureType
 +}
 +
 +async fn f() -> CustomFutureType {
 +    // Don't warn for functions since you have to explicitly declare their
 +    // return types.
 +    CustomFutureType
 +}
 +
 +#[rustfmt::skip]
 +fn main() {
 +    let _f = {
 +        3
 +    };
 +    let _g = async {
 +        3
 +    };
 +    let _h = async {
 +        async {
 +            3
 +        }
 +    };
 +    let _i = async {
 +        CustomFutureType
 +    };
 +    let _i = async || {
 +        3
 +    };
 +    let _j = async || {
 +        async {
 +            3
 +        }
 +    };
 +    let _k = async || {
 +        CustomFutureType
 +    };
 +    let _l = async || CustomFutureType;
 +    let _m = async || {
 +        println!("I'm bored");
 +        // Some more stuff
 +
 +        // Finally something to await
 +        CustomFutureType
 +    };
 +    let _n = async || custom_future_type_ctor();
 +    let _o = async || f();
 +}
index 3f2051458f677c219930503943f5ef00ae44224a,0000000000000000000000000000000000000000..b0c4215e7ddf1be1c4bbcaeb031e3896096f9386
mode 100644,000000..100644
--- /dev/null
@@@ -1,96 -1,0 +1,96 @@@
-   --> $DIR/async_yields_async.rs:40:9
 +error: an async construct yields a type which is itself awaitable
-   --> $DIR/async_yields_async.rs:45:9
++  --> $DIR/async_yields_async.rs:39:9
 +   |
 +LL |        let _h = async {
 +   |   ____________________-
 +LL |  |         async {
 +   |  |_________^
 +LL | ||             3
 +LL | ||         }
 +   | ||_________^ awaitable value not awaited
 +LL |  |     };
 +   |  |_____- outer async construct
 +   |
 +   = note: `-D clippy::async-yields-async` implied by `-D warnings`
 +help: consider awaiting this value
 +   |
 +LL ~         async {
 +LL +             3
 +LL +         }.await
 +   |
 +
 +error: an async construct yields a type which is itself awaitable
-   --> $DIR/async_yields_async.rs:51:9
++  --> $DIR/async_yields_async.rs:44:9
 +   |
 +LL |       let _i = async {
 +   |  ____________________-
 +LL | |         CustomFutureType
 +   | |         ^^^^^^^^^^^^^^^^
 +   | |         |
 +   | |         awaitable value not awaited
 +   | |         help: consider awaiting this value: `CustomFutureType.await`
 +LL | |     };
 +   | |_____- outer async construct
 +
 +error: an async construct yields a type which is itself awaitable
-   --> $DIR/async_yields_async.rs:56:9
++  --> $DIR/async_yields_async.rs:50:9
 +   |
 +LL |        let _j = async || {
 +   |   _______________________-
 +LL |  |         async {
 +   |  |_________^
 +LL | ||             3
 +LL | ||         }
 +   | ||_________^ awaitable value not awaited
 +LL |  |     };
 +   |  |_____- outer async construct
 +   |
 +help: consider awaiting this value
 +   |
 +LL ~         async {
 +LL +             3
 +LL +         }.await
 +   |
 +
 +error: an async construct yields a type which is itself awaitable
-   --> $DIR/async_yields_async.rs:58:23
++  --> $DIR/async_yields_async.rs:55:9
 +   |
 +LL |       let _k = async || {
 +   |  _______________________-
 +LL | |         CustomFutureType
 +   | |         ^^^^^^^^^^^^^^^^
 +   | |         |
 +   | |         awaitable value not awaited
 +   | |         help: consider awaiting this value: `CustomFutureType.await`
 +LL | |     };
 +   | |_____- outer async construct
 +
 +error: an async construct yields a type which is itself awaitable
-   --> $DIR/async_yields_async.rs:64:9
++  --> $DIR/async_yields_async.rs:57:23
 +   |
 +LL |     let _l = async || CustomFutureType;
 +   |                       ^^^^^^^^^^^^^^^^
 +   |                       |
 +   |                       outer async construct
 +   |                       awaitable value not awaited
 +   |                       help: consider awaiting this value: `CustomFutureType.await`
 +
 +error: an async construct yields a type which is itself awaitable
++  --> $DIR/async_yields_async.rs:63:9
 +   |
 +LL |       let _m = async || {
 +   |  _______________________-
 +LL | |         println!("I'm bored");
 +LL | |         // Some more stuff
 +LL | |
 +LL | |         // Finally something to await
 +LL | |         CustomFutureType
 +   | |         ^^^^^^^^^^^^^^^^
 +   | |         |
 +   | |         awaitable value not awaited
 +   | |         help: consider awaiting this value: `CustomFutureType.await`
 +LL | |     };
 +   | |_____- outer async construct
 +
 +error: aborting due to 6 previous errors
 +
index 0458950edee1c9660d41a4e15a974038f3949eac,0000000000000000000000000000000000000000..dd6640a387a23877548f96c8b6a40185b27c7cfd
mode 100644,000000..100644
--- /dev/null
@@@ -1,65 -1,0 +1,64 @@@
- // edition:2018
 +#![warn(clippy::await_holding_lock)]
 +
 +use std::sync::Mutex;
 +
 +async fn bad(x: &Mutex<u32>) -> u32 {
 +    let guard = x.lock().unwrap();
 +    baz().await
 +}
 +
 +async fn good(x: &Mutex<u32>) -> u32 {
 +    {
 +        let guard = x.lock().unwrap();
 +        let y = *guard + 1;
 +    }
 +    baz().await;
 +    let guard = x.lock().unwrap();
 +    47
 +}
 +
 +async fn baz() -> u32 {
 +    42
 +}
 +
 +async fn also_bad(x: &Mutex<u32>) -> u32 {
 +    let first = baz().await;
 +
 +    let guard = x.lock().unwrap();
 +
 +    let second = baz().await;
 +
 +    let third = baz().await;
 +
 +    first + second + third
 +}
 +
 +async fn not_good(x: &Mutex<u32>) -> u32 {
 +    let first = baz().await;
 +
 +    let second = {
 +        let guard = x.lock().unwrap();
 +        baz().await
 +    };
 +
 +    let third = baz().await;
 +
 +    first + second + third
 +}
 +
 +#[allow(clippy::manual_async_fn)]
 +fn block_bad(x: &Mutex<u32>) -> impl std::future::Future<Output = u32> + '_ {
 +    async move {
 +        let guard = x.lock().unwrap();
 +        baz().await
 +    }
 +}
 +
 +fn main() {
 +    let m = Mutex::new(100);
 +    good(&m);
 +    bad(&m);
 +    also_bad(&m);
 +    not_good(&m);
 +    block_bad(&m);
 +}
index a5fcff7e0e44363f02087f6c87fdfacc46638734,0000000000000000000000000000000000000000..ddfb104cdfbd07ab1207f133e075182b3d409d0e
mode 100644,000000..100644
--- /dev/null
@@@ -1,63 -1,0 +1,63 @@@
-   --> $DIR/await_holding_lock.rs:7:9
 +error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
-   --> $DIR/await_holding_lock.rs:7:5
++  --> $DIR/await_holding_lock.rs:6:9
 +   |
 +LL |     let guard = x.lock().unwrap();
 +   |         ^^^^^
 +   |
 +   = note: `-D clippy::await-holding-lock` implied by `-D warnings`
 +note: these are all the await points this lock is held through
-   --> $DIR/await_holding_lock.rs:28:9
++  --> $DIR/await_holding_lock.rs:6:5
 +   |
 +LL | /     let guard = x.lock().unwrap();
 +LL | |     baz().await
 +LL | | }
 +   | |_^
 +
 +error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
-   --> $DIR/await_holding_lock.rs:28:5
++  --> $DIR/await_holding_lock.rs:27:9
 +   |
 +LL |     let guard = x.lock().unwrap();
 +   |         ^^^^^
 +   |
 +note: these are all the await points this lock is held through
-   --> $DIR/await_holding_lock.rs:41:13
++  --> $DIR/await_holding_lock.rs:27:5
 +   |
 +LL | /     let guard = x.lock().unwrap();
 +LL | |
 +LL | |     let second = baz().await;
 +LL | |
 +...  |
 +LL | |     first + second + third
 +LL | | }
 +   | |_^
 +
 +error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
-   --> $DIR/await_holding_lock.rs:41:9
++  --> $DIR/await_holding_lock.rs:40:13
 +   |
 +LL |         let guard = x.lock().unwrap();
 +   |             ^^^^^
 +   |
 +note: these are all the await points this lock is held through
-   --> $DIR/await_holding_lock.rs:53:13
++  --> $DIR/await_holding_lock.rs:40:9
 +   |
 +LL | /         let guard = x.lock().unwrap();
 +LL | |         baz().await
 +LL | |     };
 +   | |_____^
 +
 +error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
-   --> $DIR/await_holding_lock.rs:53:9
++  --> $DIR/await_holding_lock.rs:52:13
 +   |
 +LL |         let guard = x.lock().unwrap();
 +   |             ^^^^^
 +   |
 +note: these are all the await points this lock is held through
++  --> $DIR/await_holding_lock.rs:52:9
 +   |
 +LL | /         let guard = x.lock().unwrap();
 +LL | |         baz().await
 +LL | |     }
 +   | |_____^
 +
 +error: aborting due to 4 previous errors
 +
index 88841597bb60bf5bc8a8bff346fdfc9391a40cfe,0000000000000000000000000000000000000000..23b7095de3a39ae31a36bbc37a7b625c38bec5b3
mode 100644,000000..100644
--- /dev/null
@@@ -1,86 -1,0 +1,85 @@@
- // edition:2018
 +#![warn(clippy::await_holding_refcell_ref)]
 +
 +use std::cell::RefCell;
 +
 +async fn bad(x: &RefCell<u32>) -> u32 {
 +    let b = x.borrow();
 +    baz().await
 +}
 +
 +async fn bad_mut(x: &RefCell<u32>) -> u32 {
 +    let b = x.borrow_mut();
 +    baz().await
 +}
 +
 +async fn good(x: &RefCell<u32>) -> u32 {
 +    {
 +        let b = x.borrow_mut();
 +        let y = *b + 1;
 +    }
 +    baz().await;
 +    let b = x.borrow_mut();
 +    47
 +}
 +
 +async fn baz() -> u32 {
 +    42
 +}
 +
 +async fn also_bad(x: &RefCell<u32>) -> u32 {
 +    let first = baz().await;
 +
 +    let b = x.borrow_mut();
 +
 +    let second = baz().await;
 +
 +    let third = baz().await;
 +
 +    first + second + third
 +}
 +
 +async fn less_bad(x: &RefCell<u32>) -> u32 {
 +    let first = baz().await;
 +
 +    let b = x.borrow_mut();
 +
 +    let second = baz().await;
 +
 +    drop(b);
 +
 +    let third = baz().await;
 +
 +    first + second + third
 +}
 +
 +async fn not_good(x: &RefCell<u32>) -> u32 {
 +    let first = baz().await;
 +
 +    let second = {
 +        let b = x.borrow_mut();
 +        baz().await
 +    };
 +
 +    let third = baz().await;
 +
 +    first + second + third
 +}
 +
 +#[allow(clippy::manual_async_fn)]
 +fn block_bad(x: &RefCell<u32>) -> impl std::future::Future<Output = u32> + '_ {
 +    async move {
 +        let b = x.borrow_mut();
 +        baz().await
 +    }
 +}
 +
 +fn main() {
 +    let rc = RefCell::new(100);
 +    good(&rc);
 +    bad(&rc);
 +    bad_mut(&rc);
 +    also_bad(&rc);
 +    less_bad(&rc);
 +    not_good(&rc);
 +    block_bad(&rc);
 +}
index 55e41dbca96f834046b43c624e377ddcb6bbb6d3,0000000000000000000000000000000000000000..67cc0032be2f46742725351dd9beca969d458b4e
mode 100644,000000..100644
--- /dev/null
@@@ -1,95 -1,0 +1,95 @@@
-   --> $DIR/await_holding_refcell_ref.rs:7:9
 +error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
-   --> $DIR/await_holding_refcell_ref.rs:7:5
++  --> $DIR/await_holding_refcell_ref.rs:6:9
 +   |
 +LL |     let b = x.borrow();
 +   |         ^
 +   |
 +   = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings`
 +note: these are all the await points this ref is held through
-   --> $DIR/await_holding_refcell_ref.rs:12:9
++  --> $DIR/await_holding_refcell_ref.rs:6:5
 +   |
 +LL | /     let b = x.borrow();
 +LL | |     baz().await
 +LL | | }
 +   | |_^
 +
 +error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
-   --> $DIR/await_holding_refcell_ref.rs:12:5
++  --> $DIR/await_holding_refcell_ref.rs:11:9
 +   |
 +LL |     let b = x.borrow_mut();
 +   |         ^
 +   |
 +note: these are all the await points this ref is held through
-   --> $DIR/await_holding_refcell_ref.rs:33:9
++  --> $DIR/await_holding_refcell_ref.rs:11:5
 +   |
 +LL | /     let b = x.borrow_mut();
 +LL | |     baz().await
 +LL | | }
 +   | |_^
 +
 +error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
-   --> $DIR/await_holding_refcell_ref.rs:33:5
++  --> $DIR/await_holding_refcell_ref.rs:32:9
 +   |
 +LL |     let b = x.borrow_mut();
 +   |         ^
 +   |
 +note: these are all the await points this ref is held through
-   --> $DIR/await_holding_refcell_ref.rs:45:9
++  --> $DIR/await_holding_refcell_ref.rs:32:5
 +   |
 +LL | /     let b = x.borrow_mut();
 +LL | |
 +LL | |     let second = baz().await;
 +LL | |
 +...  |
 +LL | |     first + second + third
 +LL | | }
 +   | |_^
 +
 +error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
-   --> $DIR/await_holding_refcell_ref.rs:45:5
++  --> $DIR/await_holding_refcell_ref.rs:44:9
 +   |
 +LL |     let b = x.borrow_mut();
 +   |         ^
 +   |
 +note: these are all the await points this ref is held through
-   --> $DIR/await_holding_refcell_ref.rs:60:13
++  --> $DIR/await_holding_refcell_ref.rs:44:5
 +   |
 +LL | /     let b = x.borrow_mut();
 +LL | |
 +LL | |     let second = baz().await;
 +LL | |
 +...  |
 +LL | |     first + second + third
 +LL | | }
 +   | |_^
 +
 +error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
-   --> $DIR/await_holding_refcell_ref.rs:60:9
++  --> $DIR/await_holding_refcell_ref.rs:59:13
 +   |
 +LL |         let b = x.borrow_mut();
 +   |             ^
 +   |
 +note: these are all the await points this ref is held through
-   --> $DIR/await_holding_refcell_ref.rs:72:13
++  --> $DIR/await_holding_refcell_ref.rs:59:9
 +   |
 +LL | /         let b = x.borrow_mut();
 +LL | |         baz().await
 +LL | |     };
 +   | |_____^
 +
 +error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
-   --> $DIR/await_holding_refcell_ref.rs:72:9
++  --> $DIR/await_holding_refcell_ref.rs:71:13
 +   |
 +LL |         let b = x.borrow_mut();
 +   |             ^
 +   |
 +note: these are all the await points this ref is held through
++  --> $DIR/await_holding_refcell_ref.rs:71:9
 +   |
 +LL | /         let b = x.borrow_mut();
 +LL | |         baz().await
 +LL | |     }
 +   | |_____^
 +
 +error: aborting due to 6 previous errors
 +
index 8ee0969b0f0761b16371eb485570ac83ad3abe5d,0000000000000000000000000000000000000000..ebc1ed5587fe30a9b8f6675e6ac51b79f1a9725f
mode 100644,000000..100644
--- /dev/null
@@@ -1,95 -1,0 +1,118 @@@
 +#[warn(
 +    clippy::cast_precision_loss,
 +    clippy::cast_possible_truncation,
 +    clippy::cast_sign_loss,
 +    clippy::cast_possible_wrap
 +)]
 +#[allow(clippy::no_effect, clippy::unnecessary_operation)]
 +fn main() {
 +    // Test clippy::cast_precision_loss
 +    let x0 = 1i32;
 +    x0 as f32;
 +    let x1 = 1i64;
 +    x1 as f32;
 +    x1 as f64;
 +    let x2 = 1u32;
 +    x2 as f32;
 +    let x3 = 1u64;
 +    x3 as f32;
 +    x3 as f64;
 +    // Test clippy::cast_possible_truncation
 +    1f32 as i32;
 +    1f32 as u32;
 +    1f64 as f32;
 +    1i32 as i8;
 +    1i32 as u8;
 +    1f64 as isize;
 +    1f64 as usize;
 +    // Test clippy::cast_possible_wrap
 +    1u8 as i8;
 +    1u16 as i16;
 +    1u32 as i32;
 +    1u64 as i64;
 +    1usize as isize;
 +    // Test clippy::cast_sign_loss
 +    1i32 as u32;
 +    -1i32 as u32;
 +    1isize as usize;
 +    -1isize as usize;
 +    0i8 as u8;
 +    i8::MAX as u8;
 +    i16::MAX as u16;
 +    i32::MAX as u32;
 +    i64::MAX as u64;
 +    i128::MAX as u128;
 +
 +    (-1i8).abs() as u8;
 +    (-1i16).abs() as u16;
 +    (-1i32).abs() as u32;
 +    (-1i64).abs() as u64;
 +    (-1isize).abs() as usize;
 +
 +    (-1i8).checked_abs().unwrap() as u8;
 +    (-1i16).checked_abs().unwrap() as u16;
 +    (-1i32).checked_abs().unwrap() as u32;
 +    (-1i64).checked_abs().unwrap() as u64;
 +    (-1isize).checked_abs().unwrap() as usize;
 +
 +    (-1i8).rem_euclid(1i8) as u8;
 +    (-1i8).rem_euclid(1i8) as u16;
 +    (-1i16).rem_euclid(1i16) as u16;
 +    (-1i16).rem_euclid(1i16) as u32;
 +    (-1i32).rem_euclid(1i32) as u32;
 +    (-1i32).rem_euclid(1i32) as u64;
 +    (-1i64).rem_euclid(1i64) as u64;
 +    (-1i64).rem_euclid(1i64) as u128;
 +    (-1isize).rem_euclid(1isize) as usize;
 +    (1i8).rem_euclid(-1i8) as u8;
 +    (1i8).rem_euclid(-1i8) as u16;
 +    (1i16).rem_euclid(-1i16) as u16;
 +    (1i16).rem_euclid(-1i16) as u32;
 +    (1i32).rem_euclid(-1i32) as u32;
 +    (1i32).rem_euclid(-1i32) as u64;
 +    (1i64).rem_euclid(-1i64) as u64;
 +    (1i64).rem_euclid(-1i64) as u128;
 +    (1isize).rem_euclid(-1isize) as usize;
 +
 +    (-1i8).checked_rem_euclid(1i8).unwrap() as u8;
 +    (-1i8).checked_rem_euclid(1i8).unwrap() as u16;
 +    (-1i16).checked_rem_euclid(1i16).unwrap() as u16;
 +    (-1i16).checked_rem_euclid(1i16).unwrap() as u32;
 +    (-1i32).checked_rem_euclid(1i32).unwrap() as u32;
 +    (-1i32).checked_rem_euclid(1i32).unwrap() as u64;
 +    (-1i64).checked_rem_euclid(1i64).unwrap() as u64;
 +    (-1i64).checked_rem_euclid(1i64).unwrap() as u128;
 +    (-1isize).checked_rem_euclid(1isize).unwrap() as usize;
 +    (1i8).checked_rem_euclid(-1i8).unwrap() as u8;
 +    (1i8).checked_rem_euclid(-1i8).unwrap() as u16;
 +    (1i16).checked_rem_euclid(-1i16).unwrap() as u16;
 +    (1i16).checked_rem_euclid(-1i16).unwrap() as u32;
 +    (1i32).checked_rem_euclid(-1i32).unwrap() as u32;
 +    (1i32).checked_rem_euclid(-1i32).unwrap() as u64;
 +    (1i64).checked_rem_euclid(-1i64).unwrap() as u64;
 +    (1i64).checked_rem_euclid(-1i64).unwrap() as u128;
 +    (1isize).checked_rem_euclid(-1isize).unwrap() as usize;
++
++    // no lint for `cast_possible_truncation`
++    // with `signum` method call (see issue #5395)
++    let x: i64 = 5;
++    let _ = x.signum() as i32;
++
++    let s = x.signum();
++    let _ = s as i32;
++
++    // Test for signed min
++    (-99999999999i64).min(1) as i8; // should be linted because signed
++
++    // Test for various operations that remove enough bits for the result to fit
++    (999999u64 & 1) as u8;
++    (999999u64 % 15) as u8;
++    (999999u64 / 0x1_0000_0000_0000) as u16;
++    ({ 999999u64 >> 56 }) as u8;
++    ({
++        let x = 999999u64;
++        x.min(1)
++    }) as u8;
++    999999u64.clamp(0, 255) as u8;
++    999999u64.clamp(0, 256) as u8; // should still be linted
 +}
index 4c66d736494843955903b39f917ac5ee187f61d5,0000000000000000000000000000000000000000..edf8790cf33d861c3978669145d5e500f2232314
mode 100644,000000..100644
--- /dev/null
@@@ -1,142 -1,0 +1,154 @@@
- error: aborting due to 22 previous errors
 +error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
 +  --> $DIR/cast.rs:11:5
 +   |
 +LL |     x0 as f32;
 +   |     ^^^^^^^^^
 +   |
 +   = note: `-D clippy::cast-precision-loss` implied by `-D warnings`
 +
 +error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
 +  --> $DIR/cast.rs:13:5
 +   |
 +LL |     x1 as f32;
 +   |     ^^^^^^^^^
 +
 +error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
 +  --> $DIR/cast.rs:14:5
 +   |
 +LL |     x1 as f64;
 +   |     ^^^^^^^^^
 +
 +error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
 +  --> $DIR/cast.rs:16:5
 +   |
 +LL |     x2 as f32;
 +   |     ^^^^^^^^^
 +
 +error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
 +  --> $DIR/cast.rs:18:5
 +   |
 +LL |     x3 as f32;
 +   |     ^^^^^^^^^
 +
 +error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
 +  --> $DIR/cast.rs:19:5
 +   |
 +LL |     x3 as f64;
 +   |     ^^^^^^^^^
 +
 +error: casting `f32` to `i32` may truncate the value
 +  --> $DIR/cast.rs:21:5
 +   |
 +LL |     1f32 as i32;
 +   |     ^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
 +
 +error: casting `f32` to `u32` may truncate the value
 +  --> $DIR/cast.rs:22:5
 +   |
 +LL |     1f32 as u32;
 +   |     ^^^^^^^^^^^
 +
 +error: casting `f32` to `u32` may lose the sign of the value
 +  --> $DIR/cast.rs:22:5
 +   |
 +LL |     1f32 as u32;
 +   |     ^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::cast-sign-loss` implied by `-D warnings`
 +
 +error: casting `f64` to `f32` may truncate the value
 +  --> $DIR/cast.rs:23:5
 +   |
 +LL |     1f64 as f32;
 +   |     ^^^^^^^^^^^
 +
 +error: casting `i32` to `i8` may truncate the value
 +  --> $DIR/cast.rs:24:5
 +   |
 +LL |     1i32 as i8;
 +   |     ^^^^^^^^^^
 +
 +error: casting `i32` to `u8` may truncate the value
 +  --> $DIR/cast.rs:25:5
 +   |
 +LL |     1i32 as u8;
 +   |     ^^^^^^^^^^
 +
 +error: casting `f64` to `isize` may truncate the value
 +  --> $DIR/cast.rs:26:5
 +   |
 +LL |     1f64 as isize;
 +   |     ^^^^^^^^^^^^^
 +
 +error: casting `f64` to `usize` may truncate the value
 +  --> $DIR/cast.rs:27:5
 +   |
 +LL |     1f64 as usize;
 +   |     ^^^^^^^^^^^^^
 +
 +error: casting `f64` to `usize` may lose the sign of the value
 +  --> $DIR/cast.rs:27:5
 +   |
 +LL |     1f64 as usize;
 +   |     ^^^^^^^^^^^^^
 +
 +error: casting `u8` to `i8` may wrap around the value
 +  --> $DIR/cast.rs:29:5
 +   |
 +LL |     1u8 as i8;
 +   |     ^^^^^^^^^
 +   |
 +   = note: `-D clippy::cast-possible-wrap` implied by `-D warnings`
 +
 +error: casting `u16` to `i16` may wrap around the value
 +  --> $DIR/cast.rs:30:5
 +   |
 +LL |     1u16 as i16;
 +   |     ^^^^^^^^^^^
 +
 +error: casting `u32` to `i32` may wrap around the value
 +  --> $DIR/cast.rs:31:5
 +   |
 +LL |     1u32 as i32;
 +   |     ^^^^^^^^^^^
 +
 +error: casting `u64` to `i64` may wrap around the value
 +  --> $DIR/cast.rs:32:5
 +   |
 +LL |     1u64 as i64;
 +   |     ^^^^^^^^^^^
 +
 +error: casting `usize` to `isize` may wrap around the value
 +  --> $DIR/cast.rs:33:5
 +   |
 +LL |     1usize as isize;
 +   |     ^^^^^^^^^^^^^^^
 +
 +error: casting `i32` to `u32` may lose the sign of the value
 +  --> $DIR/cast.rs:36:5
 +   |
 +LL |     -1i32 as u32;
 +   |     ^^^^^^^^^^^^
 +
 +error: casting `isize` to `usize` may lose the sign of the value
 +  --> $DIR/cast.rs:38:5
 +   |
 +LL |     -1isize as usize;
 +   |     ^^^^^^^^^^^^^^^^
 +
++error: casting `i64` to `i8` may truncate the value
++  --> $DIR/cast.rs:105:5
++   |
++LL |     (-99999999999i64).min(1) as i8; // should be linted because signed
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++
++error: casting `u64` to `u8` may truncate the value
++  --> $DIR/cast.rs:117:5
++   |
++LL |     999999u64.clamp(0, 256) as u8; // should still be linted
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++
++error: aborting due to 24 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..bee29894b63d5161760ecb81dca245f4785c142e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++fn zero() {
++    unsafe { 0 };
++}
index 4feab7910b7445da53bf0c73ac25bea9ce160a66,0000000000000000000000000000000000000000..9b68cac7ff4854abc60352d7c8cbff472604cf44
mode 100644,000000..100644
--- /dev/null
@@@ -1,51 -1,0 +1,50 @@@
 +// https://github.com/rust-lang/rust-clippy/issues/3969
 +// used to crash: error: internal compiler error:
 +// src/librustc_traits/normalize_erasing_regions.rs:43: could not fully normalize `<i32 as
 +// std::iter::Iterator>::Item test from rustc ./ui/trivial-bounds/trivial-bounds-inconsistent.rs
 +
 +// Check that tautalogically false bounds are accepted, and are used
 +// in type inference.
 +#![feature(trivial_bounds)]
 +#![allow(unused)]
-     for<'a> Dst<A + 'a>: Sized,
 +trait A {}
 +
 +impl A for i32 {}
 +
 +struct Dst<X: ?Sized> {
 +    x: X,
 +}
 +
 +struct TwoStrs(str, str)
 +where
 +    str: Sized;
 +
 +fn unsized_local()
 +where
-     let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
++    for<'a> Dst<dyn A + 'a>: Sized,
 +{
++    let x: Dst<dyn A> = *(Box::new(Dst { x: 1 }) as Box<Dst<dyn A>>);
 +}
 +
 +fn return_str() -> str
 +where
 +    str: Sized,
 +{
 +    *"Sized".to_string().into_boxed_str()
 +}
 +
 +fn use_op(s: String) -> String
 +where
 +    String: ::std::ops::Neg<Output = String>,
 +{
 +    -s
 +}
 +
 +fn use_for()
 +where
 +    i32: Iterator,
 +{
 +    for _ in 2i32 {}
 +}
 +
 +fn main() {}
index 9a89047f072777cd7f6bf3f5588083be74b7f6b0,0000000000000000000000000000000000000000..79018080886c0561d33fc88fe31890911f4ccd9f
mode 100644,000000..100644
--- /dev/null
@@@ -1,30 -1,0 +1,34 @@@
- error: trait objects without an explicit `dyn` are deprecated
-   --> $DIR/ice-3969.rs:25:17
++error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
++  --> $DIR/ice-3969.rs:20:10
 +   |
- LL |     for<'a> Dst<A + 'a>: Sized,
-    |                 ^^^^^^ help: use `dyn`: `dyn A + 'a`
++LL |     str: Sized;
++   |          ^^^^^
 +   |
-    = note: `-D bare-trait-objects` implied by `-D warnings`
-    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
++   = note: `-D trivial-bounds` implied by `-D warnings`
 +
- error: trait objects without an explicit `dyn` are deprecated
-   --> $DIR/ice-3969.rs:27:16
++error: trait bound for<'a> Dst<(dyn A + 'a)>: std::marker::Sized does not depend on any type or lifetime parameters
++  --> $DIR/ice-3969.rs:24:30
 +   |
- LL |     let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
-    |                ^ help: use `dyn`: `dyn A`
++LL |     for<'a> Dst<dyn A + 'a>: Sized,
++   |                              ^^^^^
++
++error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
++  --> $DIR/ice-3969.rs:31:10
 +   |
-    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
++LL |     str: Sized,
++   |          ^^^^^
 +
- error: trait objects without an explicit `dyn` are deprecated
-   --> $DIR/ice-3969.rs:27:57
++error: trait bound std::string::String: std::ops::Neg does not depend on any type or lifetime parameters
++  --> $DIR/ice-3969.rs:38:13
 +   |
- LL |     let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
-    |                                                         ^ help: use `dyn`: `dyn A`
++LL |     String: ::std::ops::Neg<Output = String>,
++   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++
++error: trait bound i32: std::iter::Iterator does not depend on any type or lifetime parameters
++  --> $DIR/ice-3969.rs:45:10
 +   |
-    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
++LL |     i32: Iterator,
++   |          ^^^^^^^^
 +
- error: aborting due to 3 previous errors
++error: aborting due to 5 previous errors
 +
index 1b20c9defac823185ec31b6a3229167d0abb5e58,0000000000000000000000000000000000000000..f463f78a99ab738bc0117ad3391817145323c146
mode 100644,000000..100644
--- /dev/null
@@@ -1,7 -1,0 +1,5 @@@
- // edition:2018
 +// Regression test for https://github.com/rust-lang/rust-clippy/issues/5207
 +
 +pub async fn bar<'a, T: 'a>(_: T) {}
 +
 +fn main() {}
index 2e3d9fd1e9240ed097512ca6216325968fa4c078,0000000000000000000000000000000000000000..0ccf0aae9d74298099fd483995d2d73ce76763b3
mode 100644,000000..100644
--- /dev/null
@@@ -1,15 -1,0 +1,14 @@@
 +// originally from glacier fixed/77919.rs
 +// encountered errors resolving bounds after type-checking
 +trait TypeVal<T> {
 +    const VAL: T;
 +}
 +struct Five;
 +struct Multiply<N, M> {
 +    _n: PhantomData,
 +}
 +impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
 +
 +fn main() {
 +    [1; <Multiply<Five, Five>>::VAL];
 +}
index eaa5e6f51cb4abd51ed518386e1fb9a867061237,0000000000000000000000000000000000000000..c8239897f3abb5b7032d8f574aeae103599b1e71
mode 100644,000000..100644
--- /dev/null
@@@ -1,32 -1,0 +1,36 @@@
-   --> $DIR/ice-6252.rs:9:9
 +error[E0412]: cannot find type `PhantomData` in this scope
- help: consider importing this struct
++  --> $DIR/ice-6252.rs:8:9
 +   |
 +LL |     _n: PhantomData,
 +   |         ^^^^^^^^^^^ not found in this scope
 +   |
-   --> $DIR/ice-6252.rs:11:63
++help: consider importing one of these items
++   |
++LL | use core::marker::PhantomData;
++   |
++LL | use serde::__private::PhantomData;
 +   |
 +LL | use std::marker::PhantomData;
 +   |
 +
 +error[E0412]: cannot find type `VAL` in this scope
-   --> $DIR/ice-6252.rs:11:1
++  --> $DIR/ice-6252.rs:10:63
 +   |
 +LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
 +   |          -                                                    ^^^ not found in this scope
 +   |          |
 +   |          help: you might be missing a type parameter: `, VAL`
 +
 +error[E0046]: not all trait items implemented, missing: `VAL`
++  --> $DIR/ice-6252.rs:10:1
 +   |
 +LL |     const VAL: T;
 +   |     ------------- `VAL` from trait
 +...
 +LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
 +
 +error: aborting due to 3 previous errors
 +
 +Some errors have detailed explanations: E0046, E0412.
 +For more information about an error, try `rustc --explain E0046`.
index 5595d8d1d626978d136f7c61e26daa74a07010dd,0000000000000000000000000000000000000000..4ad0d351372f7559de26a2a84d6974f0cdf3643a
mode 100644,000000..100644
--- /dev/null
@@@ -1,10 -1,0 +1,9 @@@
- // edition:2018
 +#![allow(clippy::never_loop)]
 +
 +async fn f() {
 +    loop {
 +        break;
 +    }
 +}
 +
 +fn main() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c6932164e3bff5bd6d5d06a26b910d4d4f01e61b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++#![warn(clippy::undocumented_unsafe_blocks)]
++#![allow(clippy::no_effect)]
++
++#[path = "auxiliary/ice-7868-aux.rs"]
++mod zero;
++
++fn main() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d7b49eb89a28bb437d14931edb435a3f6e5ec9a8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++error: unsafe block missing a safety comment
++  --> $DIR/auxiliary/ice-7868-aux.rs:2:5
++   |
++LL |     unsafe { 0 };
++   |     ^^^^^^^^^^^^
++   |
++   = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
++help: consider adding a safety comment
++   |
++LL ~     // Safety: ...
++LL ~     unsafe { 0 };
++   |
++
++error: aborting due to previous error
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8f97a063a9a9f1618a41ef2fdafc9e51b1030575
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++enum Tila {
++    TyöAlkoi,
++    TyöKeskeytyi,
++    TyöValmis,
++}
++
++fn main() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4fa9fb27e7659ebb0acbef1778b01d8a8696afd8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++error: all variants have the same prefix: `Työ`
++  --> $DIR/ice-7869.rs:1:1
++   |
++LL | / enum Tila {
++LL | |     TyöAlkoi,
++LL | |     TyöKeskeytyi,
++LL | |     TyöValmis,
++LL | | }
++   | |_^
++   |
++   = note: `-D clippy::enum-variant-names` implied by `-D warnings`
++   = help: remove the prefixes and use full paths to the variants instead of glob imports
++
++error: aborting due to previous error
++
index c57a45dc7aab9b1c1f3e48dfc7e41558b6002fc9,0000000000000000000000000000000000000000..901eb4e50398888f50747c1ba2a496703474d82e
mode 100644,000000..100644
--- /dev/null
@@@ -1,18 -1,0 +1,16 @@@
- // edition:2018
 +use serde::Deserialize;
 +
 +/// Tests that we do not lint for unused underscores in a `MacroAttribute`
 +/// expansion
 +#[deny(clippy::used_underscore_binding)]
 +#[derive(Deserialize)]
 +struct MacroAttributesTest {
 +    _foo: u32,
 +}
 +
 +#[test]
 +fn macro_attributes_test() {
 +    let _ = MacroAttributesTest { _foo: 0 };
 +}
 +
 +fn main() {}
index 477a47118d4116587fc6526ca01f3f72edf639e2,0000000000000000000000000000000000000000..c5de412556567ffe6718fc9ada4471dcb5e4cc8b
mode 100644,000000..100644
--- /dev/null
@@@ -1,133 -1,0 +1,133 @@@
- // compile-flags: --edition=2018
 +#![feature(custom_inner_attributes)]
 +#![rustfmt::skip]
 +#![warn(clippy::debug_assert_with_mut_call)]
 +#![allow(clippy::redundant_closure_call)]
 +
++
 +struct S;
 +
 +impl S {
 +    fn bool_self_ref(&self) -> bool { false }
 +    fn bool_self_mut(&mut self) -> bool { false }
 +    fn bool_self_ref_arg_ref(&self, _: &u32) -> bool { false }
 +    fn bool_self_ref_arg_mut(&self, _: &mut u32) -> bool { false }
 +    fn bool_self_mut_arg_ref(&mut self, _: &u32) -> bool { false }
 +    fn bool_self_mut_arg_mut(&mut self, _: &mut u32) -> bool { false }
 +
 +    fn u32_self_ref(&self) -> u32 { 0 }
 +    fn u32_self_mut(&mut self) -> u32 { 0 }
 +    fn u32_self_ref_arg_ref(&self, _: &u32) -> u32 { 0 }
 +    fn u32_self_ref_arg_mut(&self, _: &mut u32) -> u32 { 0 }
 +    fn u32_self_mut_arg_ref(&mut self, _: &u32) -> u32 { 0 }
 +    fn u32_self_mut_arg_mut(&mut self, _: &mut u32) -> u32 { 0 }
 +}
 +
 +fn bool_ref(_: &u32) -> bool { false }
 +fn bool_mut(_: &mut u32) -> bool { false }
 +fn u32_ref(_: &u32) -> u32 { 0 }
 +fn u32_mut(_: &mut u32) -> u32 { 0 }
 +
 +fn func_non_mutable() {
 +    debug_assert!(bool_ref(&3));
 +    debug_assert!(!bool_ref(&3));
 +
 +    debug_assert_eq!(0, u32_ref(&3));
 +    debug_assert_eq!(u32_ref(&3), 0);
 +
 +    debug_assert_ne!(1, u32_ref(&3));
 +    debug_assert_ne!(u32_ref(&3), 1);
 +}
 +
 +fn func_mutable() {
 +    debug_assert!(bool_mut(&mut 3));
 +    debug_assert!(!bool_mut(&mut 3));
 +
 +    debug_assert_eq!(0, u32_mut(&mut 3));
 +    debug_assert_eq!(u32_mut(&mut 3), 0);
 +
 +    debug_assert_ne!(1, u32_mut(&mut 3));
 +    debug_assert_ne!(u32_mut(&mut 3), 1);
 +}
 +
 +fn method_non_mutable() {
 +    debug_assert!(S.bool_self_ref());
 +    debug_assert!(S.bool_self_ref_arg_ref(&3));
 +
 +    debug_assert_eq!(S.u32_self_ref(), 0);
 +    debug_assert_eq!(S.u32_self_ref_arg_ref(&3), 0);
 +
 +    debug_assert_ne!(S.u32_self_ref(), 1);
 +    debug_assert_ne!(S.u32_self_ref_arg_ref(&3), 1);
 +}
 +
 +fn method_mutable() {
 +    debug_assert!(S.bool_self_mut());
 +    debug_assert!(!S.bool_self_mut());
 +    debug_assert!(S.bool_self_ref_arg_mut(&mut 3));
 +    debug_assert!(S.bool_self_mut_arg_ref(&3));
 +    debug_assert!(S.bool_self_mut_arg_mut(&mut 3));
 +
 +    debug_assert_eq!(S.u32_self_mut(), 0);
 +    debug_assert_eq!(S.u32_self_mut_arg_ref(&3), 0);
 +    debug_assert_eq!(S.u32_self_ref_arg_mut(&mut 3), 0);
 +    debug_assert_eq!(S.u32_self_mut_arg_mut(&mut 3), 0);
 +
 +    debug_assert_ne!(S.u32_self_mut(), 1);
 +    debug_assert_ne!(S.u32_self_mut_arg_ref(&3), 1);
 +    debug_assert_ne!(S.u32_self_ref_arg_mut(&mut 3), 1);
 +    debug_assert_ne!(S.u32_self_mut_arg_mut(&mut 3), 1);
 +}
 +
 +fn misc() {
 +    // with variable
 +    let mut v: Vec<u32> = vec![1, 2, 3, 4];
 +    debug_assert_eq!(v.get(0), Some(&1));
 +    debug_assert_ne!(v[0], 2);
 +    debug_assert_eq!(v.pop(), Some(1));
 +    debug_assert_ne!(Some(3), v.pop());
 +
 +    let a = &mut 3;
 +    debug_assert!(bool_mut(a));
 +
 +    // nested
 +    debug_assert!(!(bool_ref(&u32_mut(&mut 3))));
 +
 +    // chained
 +    debug_assert_eq!(v.pop().unwrap(), 3);
 +
 +    // format args
 +    debug_assert!(bool_ref(&3), "w/o format");
 +    debug_assert!(bool_mut(&mut 3), "w/o format");
 +    debug_assert!(bool_ref(&3), "{} format", "w/");
 +    debug_assert!(bool_mut(&mut 3), "{} format", "w/");
 +
 +    // sub block
 +    let mut x = 42_u32;
 +    debug_assert!({
 +        bool_mut(&mut x);
 +        x > 10
 +    });
 +
 +    // closures
 +    debug_assert!((|| {
 +        let mut x = 42;
 +        bool_mut(&mut x);
 +        x > 10
 +    })());
 +}
 +
 +async fn debug_await() {
 +    debug_assert!(async {
 +        true
 +    }.await);
 +}
 +
 +fn main() {
 +    func_non_mutable();
 +    func_mutable();
 +    method_non_mutable();
 +    method_mutable();
 +
 +    misc();
 +    debug_await();
 +}
index 1943d0092e6244851b9c5480a879116b788e56b9,0000000000000000000000000000000000000000..39a2601fee9aca39e6d3882f27c8d1008ffce339
mode 100644,000000..100644
--- /dev/null
@@@ -1,19 -1,0 +1,18 @@@
- #[warn(clippy::unstable_as_slice)]
- #[warn(clippy::unstable_as_mut_slice)]
- #[warn(clippy::misaligned_transmute)]
- #[warn(clippy::unused_collect)]
- #[warn(clippy::invalid_ref)]
- #[warn(clippy::into_iter_on_array)]
- #[warn(clippy::unused_label)]
- #[warn(clippy::regex_macro)]
- #[warn(clippy::drop_bounds)]
- #[warn(clippy::temporary_cstring_as_ptr)]
- #[warn(clippy::panic_params)]
- #[warn(clippy::unknown_clippy_lints)]
- #[warn(clippy::find_map)]
- #[warn(clippy::filter_map)]
- #[warn(clippy::pub_enum_variant_names)]
- #[warn(clippy::wrong_pub_self_convention)]
- #[warn(clippy::invalid_atomic_ordering)]
++#![warn(clippy::should_assert_eq)]
++#![warn(clippy::extend_from_slice)]
++#![warn(clippy::range_step_by_zero)]
++#![warn(clippy::unstable_as_slice)]
++#![warn(clippy::unstable_as_mut_slice)]
++#![warn(clippy::misaligned_transmute)]
++#![warn(clippy::assign_ops)]
++#![warn(clippy::if_let_redundant_pattern_matching)]
++#![warn(clippy::unsafe_vector_initialization)]
++#![warn(clippy::unused_collect)]
++#![warn(clippy::replace_consts)]
++#![warn(clippy::regex_macro)]
++#![warn(clippy::find_map)]
++#![warn(clippy::filter_map)]
++#![warn(clippy::pub_enum_variant_names)]
++#![warn(clippy::wrong_pub_self_convention)]
 +
 +fn main() {}
index 51048e45c0677c208bb8e050edc7fa0169eb8a82,0000000000000000000000000000000000000000..6095f134d55e0d2ea7452696adfb9a047521f077
mode 100644,000000..100644
--- /dev/null
@@@ -1,106 -1,0 +1,100 @@@
- error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
-   --> $DIR/deprecated.rs:1:8
++error: lint `clippy::should_assert_eq` has been removed: `assert!()` will be more flexible with RFC 2011
++  --> $DIR/deprecated.rs:1:9
 +   |
- LL | #[warn(clippy::unstable_as_slice)]
-    |        ^^^^^^^^^^^^^^^^^^^^^^^^^
++LL | #![warn(clippy::should_assert_eq)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 +
- error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
-   --> $DIR/deprecated.rs:2:8
++error: lint `clippy::extend_from_slice` has been removed: `.extend_from_slice(_)` is a faster way to extend a Vec by a slice
++  --> $DIR/deprecated.rs:2:9
 +   |
- LL | #[warn(clippy::unstable_as_mut_slice)]
-    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++LL | #![warn(clippy::extend_from_slice)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 +
- error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
-   --> $DIR/deprecated.rs:3:8
++error: lint `clippy::range_step_by_zero` has been removed: `iterator.step_by(0)` panics nowadays
++  --> $DIR/deprecated.rs:3:9
 +   |
- LL | #[warn(clippy::misaligned_transmute)]
-    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++LL | #![warn(clippy::range_step_by_zero)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
- error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint
-   --> $DIR/deprecated.rs:4:8
++error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
++  --> $DIR/deprecated.rs:4:9
 +   |
- LL | #[warn(clippy::unused_collect)]
-    |        ^^^^^^^^^^^^^^^^^^^^^^
++LL | #![warn(clippy::unstable_as_slice)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 +
- error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-   --> $DIR/deprecated.rs:5:8
++error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
++  --> $DIR/deprecated.rs:5:9
 +   |
- LL | #[warn(clippy::invalid_ref)]
-    |        ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
++LL | #![warn(clippy::unstable_as_mut_slice)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
- error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-   --> $DIR/deprecated.rs:6:8
++error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
++  --> $DIR/deprecated.rs:6:9
 +   |
- LL | #[warn(clippy::into_iter_on_array)]
-    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
++LL | #![warn(clippy::misaligned_transmute)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
- error: lint `clippy::unused_label` has been renamed to `unused_labels`
-   --> $DIR/deprecated.rs:7:8
++error: lint `clippy::assign_ops` has been removed: using compound assignment operators (e.g., `+=`) is harmless
++  --> $DIR/deprecated.rs:7:9
 +   |
- LL | #[warn(clippy::unused_label)]
-    |        ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
++LL | #![warn(clippy::assign_ops)]
++   |         ^^^^^^^^^^^^^^^^^^
 +
- error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018
-   --> $DIR/deprecated.rs:8:8
++error: lint `clippy::if_let_redundant_pattern_matching` has been removed: this lint has been changed to redundant_pattern_matching
++  --> $DIR/deprecated.rs:8:9
 +   |
- LL | #[warn(clippy::regex_macro)]
-    |        ^^^^^^^^^^^^^^^^^^^
++LL | #![warn(clippy::if_let_redundant_pattern_matching)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
- error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-   --> $DIR/deprecated.rs:9:8
++error: lint `clippy::unsafe_vector_initialization` has been removed: the replacement suggested by this lint had substantially different behavior
++  --> $DIR/deprecated.rs:9:9
 +   |
- LL | #[warn(clippy::drop_bounds)]
-    |        ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
++LL | #![warn(clippy::unsafe_vector_initialization)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
- error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-   --> $DIR/deprecated.rs:10:8
++error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint
++  --> $DIR/deprecated.rs:10:9
 +   |
- LL | #[warn(clippy::temporary_cstring_as_ptr)]
-    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
++LL | #![warn(clippy::unused_collect)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^
 +
- error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-   --> $DIR/deprecated.rs:11:8
++error: lint `clippy::replace_consts` has been removed: associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants
++  --> $DIR/deprecated.rs:11:9
 +   |
- LL | #[warn(clippy::panic_params)]
-    |        ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
++LL | #![warn(clippy::replace_consts)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^
 +
- error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-   --> $DIR/deprecated.rs:12:8
++error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018
++  --> $DIR/deprecated.rs:12:9
 +   |
- LL | #[warn(clippy::unknown_clippy_lints)]
-    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
++LL | #![warn(clippy::regex_macro)]
++   |         ^^^^^^^^^^^^^^^^^^^
 +
 +error: lint `clippy::find_map` has been removed: this lint has been replaced by `manual_find_map`, a more specific lint
-   --> $DIR/deprecated.rs:13:8
++  --> $DIR/deprecated.rs:13:9
 +   |
- LL | #[warn(clippy::find_map)]
-    |        ^^^^^^^^^^^^^^^^
++LL | #![warn(clippy::find_map)]
++   |         ^^^^^^^^^^^^^^^^
 +
 +error: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint
-   --> $DIR/deprecated.rs:14:8
++  --> $DIR/deprecated.rs:14:9
 +   |
- LL | #[warn(clippy::filter_map)]
-    |        ^^^^^^^^^^^^^^^^^^
++LL | #![warn(clippy::filter_map)]
++   |         ^^^^^^^^^^^^^^^^^^
 +
 +error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items
-   --> $DIR/deprecated.rs:15:8
++  --> $DIR/deprecated.rs:15:9
 +   |
- LL | #[warn(clippy::pub_enum_variant_names)]
-    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++LL | #![warn(clippy::pub_enum_variant_names)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items
-   --> $DIR/deprecated.rs:16:8
-    |
- LL | #[warn(clippy::wrong_pub_self_convention)]
-    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-   --> $DIR/deprecated.rs:17:8
++  --> $DIR/deprecated.rs:16:9
 +   |
- LL | #[warn(clippy::invalid_atomic_ordering)]
-    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
++LL | #![warn(clippy::wrong_pub_self_convention)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
- error: aborting due to 17 previous errors
++error: aborting due to 16 previous errors
 +
index 4df241c9fc39be35b1fe3a00ac017e637ad69e82,0000000000000000000000000000000000000000..e27f9fea708ee16c0bcfd889cf27ad6ed7b39b8d
mode 100644,000000..100644
--- /dev/null
@@@ -1,42 -1,0 +1,41 @@@
 +#![warn(clippy::diverging_sub_expression)]
 +#![allow(clippy::match_same_arms, clippy::logic_bug)]
 +#[allow(clippy::empty_loop)]
 +fn diverge() -> ! {
 +    loop {}
 +}
 +
 +struct A;
 +
 +impl A {
 +    fn foo(&self) -> ! {
 +        diverge()
 +    }
 +}
 +
 +#[allow(unused_variables, clippy::unnecessary_operation, clippy::short_circuit_statement)]
 +fn main() {
 +    let b = true;
 +    b || diverge();
 +    b || A.foo();
 +}
 +
 +#[allow(dead_code, unused_variables)]
 +fn foobar() {
 +    loop {
 +        let x = match 5 {
 +            4 => return,
 +            5 => continue,
 +            6 => true || return,
 +            7 => true || continue,
 +            8 => break,
 +            9 => diverge(),
 +            3 => true || diverge(),
 +            10 => match 42 {
 +                99 => return,
 +                _ => true || panic!("boo"),
 +            },
 +            _ => true || break,
 +        };
 +    }
 +}
index 170e7d92de4acff6b643a1ead8d762e2d61e2d8b,0000000000000000000000000000000000000000..c712a6a7e38eaf1433c0aee8f46e4897612370a7
mode 100644,000000..100644
--- /dev/null
@@@ -1,40 -1,0 +1,48 @@@
-   --> $DIR/diverging_sub_expression.rs:20:10
 +error: sub-expression diverges
-   --> $DIR/diverging_sub_expression.rs:21:10
++  --> $DIR/diverging_sub_expression.rs:19:10
 +   |
 +LL |     b || diverge();
 +   |          ^^^^^^^^^
 +   |
 +   = note: `-D clippy::diverging-sub-expression` implied by `-D warnings`
 +
 +error: sub-expression diverges
-   --> $DIR/diverging_sub_expression.rs:30:26
++  --> $DIR/diverging_sub_expression.rs:20:10
 +   |
 +LL |     b || A.foo();
 +   |          ^^^^^^^
 +
 +error: sub-expression diverges
-   --> $DIR/diverging_sub_expression.rs:31:26
++  --> $DIR/diverging_sub_expression.rs:29:26
 +   |
 +LL |             6 => true || return,
 +   |                          ^^^^^^
 +
 +error: sub-expression diverges
-   --> $DIR/diverging_sub_expression.rs:34:26
++  --> $DIR/diverging_sub_expression.rs:30:26
 +   |
 +LL |             7 => true || continue,
 +   |                          ^^^^^^^^
 +
 +error: sub-expression diverges
-   --> $DIR/diverging_sub_expression.rs:39:26
++  --> $DIR/diverging_sub_expression.rs:33:26
 +   |
 +LL |             3 => true || diverge(),
 +   |                          ^^^^^^^^^
 +
 +error: sub-expression diverges
- error: aborting due to 6 previous errors
++  --> $DIR/diverging_sub_expression.rs:36:30
++   |
++LL |                 _ => true || panic!("boo"),
++   |                              ^^^^^^^^^^^^^
++   |
++   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
++
++error: sub-expression diverges
++  --> $DIR/diverging_sub_expression.rs:38:26
 +   |
 +LL |             _ => true || break,
 +   |                          ^^^^^
 +
++error: aborting due to 7 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..747801b40ee10abec3f2769b8c4965d9e91726d1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,215 @@@
++// run-rustfix
++//! This file tests for the `DOC_MARKDOWN` lint.
++
++#![allow(dead_code, incomplete_features)]
++#![warn(clippy::doc_markdown)]
++#![feature(custom_inner_attributes, generic_const_exprs, const_option)]
++#![rustfmt::skip]
++
++/// The `foo_bar` function does _nothing_. See also `foo::bar`. (note the dot there)
++/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not `Foo::some_fun`
++/// which should be reported only once despite being __doubly bad__.
++/// Here be `::a::global:path`, and _`::another::global::path`_.  :: is not a path though.
++/// Import an item from `::awesome::global::blob::` (Intended postfix)
++/// These are the options for `::Cat`: (Intended trailing single colon, shouldn't be linted)
++/// That's not code ~`NotInCodeBlock`~.
++/// `be_sure_we_got_to_the_end_of_it`
++fn foo_bar() {
++}
++
++/// That one tests multiline ticks.
++/// ```rust
++/// foo_bar FOO_BAR
++/// _foo bar_
++/// ```
++///
++/// ~~~rust
++/// foo_bar FOO_BAR
++/// _foo bar_
++/// ~~~
++/// `be_sure_we_got_to_the_end_of_it`
++fn multiline_codeblock() {
++}
++
++/// This _is a test for
++/// multiline
++/// emphasis_.
++/// `be_sure_we_got_to_the_end_of_it`
++fn test_emphasis() {
++}
++
++/// This tests units. See also #835.
++/// kiB MiB GiB TiB PiB EiB
++/// kib Mib Gib Tib Pib Eib
++/// kB MB GB TB PB EB
++/// kb Mb Gb Tb Pb Eb
++/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
++/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
++/// 32kB 32MB 32GB 32TB 32PB 32EB
++/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
++/// NaN
++/// `be_sure_we_got_to_the_end_of_it`
++fn test_units() {
++}
++
++/// This tests allowed identifiers.
++/// KiB MiB GiB TiB PiB EiB
++/// DirectX
++/// ECMAScript
++/// GPLv2 GPLv3
++/// GitHub GitLab
++/// IPv4 IPv6
++/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
++/// NaN NaNs
++/// OAuth GraphQL
++/// OCaml
++/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
++/// WebGL
++/// TensorFlow
++/// TrueType
++/// iOS macOS FreeBSD
++/// TeX LaTeX BibTeX BibLaTeX
++/// MinGW
++/// CamelCase (see also #2395)
++/// `be_sure_we_got_to_the_end_of_it`
++fn test_allowed() {
++}
++
++/// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
++/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
++/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
++/// It can also be [`inline_link2`].
++///
++/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
++/// [inline_link]: https://foobar
++/// [inline_link2]: https://foobar
++/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
++/// `multiline_ticks` functions.
++///
++/// expression of the type  `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
++/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
++/// `be_sure_we_got_to_the_end_of_it`
++fn main() {
++    foo_bar();
++    multiline_codeblock();
++    test_emphasis();
++    test_units();
++}
++
++/// ## `CamelCaseThing`
++/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
++///
++/// # `CamelCaseThing`
++///
++/// Not a title #897 `CamelCaseThing`
++/// `be_sure_we_got_to_the_end_of_it`
++fn issue897() {
++}
++
++/// I am confused by brackets? (`x_y`)
++/// I am confused by brackets? (foo `x_y`)
++/// I am confused by brackets? (`x_y` foo)
++/// `be_sure_we_got_to_the_end_of_it`
++fn issue900() {
++}
++
++/// Diesel queries also have a similar problem to [Iterator][iterator], where
++/// /// More talking
++/// returning them from a function requires exposing the implementation of that
++/// function. The [`helper_types`][helper_types] module exists to help with this,
++/// but you might want to hide the return type or have it conditionally change.
++/// Boxing can achieve both.
++///
++/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
++/// [helper_types]: ../helper_types/index.html
++/// `be_sure_we_got_to_the_end_of_it`
++fn issue883() {
++}
++
++/// `foo_bar
++/// baz_quz`
++/// [foo
++/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
++fn multiline() {
++}
++
++/** E.g., serialization of an empty list: `FooBar`
++```
++That's in a code block: `PackedNode`
++```
++
++And `BarQuz` too.
++`be_sure_we_got_to_the_end_of_it`
++*/
++fn issue1073() {
++}
++
++/** E.g., serialization of an empty list: `FooBar`
++```
++That's in a code block: PackedNode
++```
++
++And `BarQuz` too.
++`be_sure_we_got_to_the_end_of_it`
++*/
++fn issue1073_alt() {
++}
++
++/// Tests more than three quotes:
++/// ````
++/// DoNotWarn
++/// ```
++/// StillDont
++/// ````
++/// `be_sure_we_got_to_the_end_of_it`
++fn four_quotes() {
++}
++
++#[cfg_attr(feature = "a", doc = " ```")]
++#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
++/// fn main() {
++///     let s = "localhost:10000".to_string();
++///     println!("{}", s);
++/// }
++/// ```
++fn issue_1469() {}
++
++/**
++ * This is a doc comment that should not be a list
++ *This would also be an error under a strict common mark interpretation
++ */
++fn issue_1920() {}
++
++/// An iterator over `mycrate::Collection`'s values.
++/// It should not lint a `'static` lifetime in ticks.
++fn issue_2210() {}
++
++/// This should not cause the lint to trigger:
++/// #REQ-data-family.lint_partof_exists
++fn issue_2343() {}
++
++/// This should not cause an ICE:
++/// __|_ _|__||_|
++fn pulldown_cmark_crash() {}
++
++/// This should not lint
++/// (regression test for #7758)
++/// [plain text][path::to::item]
++fn intra_doc_link() {}
++
++// issue #7033 - generic_const_exprs ICE
++struct S<T, const N: usize>
++where [(); N.checked_next_power_of_two().unwrap()]: {
++    arr: [T; N.checked_next_power_of_two().unwrap()],
++    n: usize,
++}
++
++impl<T: Copy + Default, const N: usize> S<T, N>
++where [(); N.checked_next_power_of_two().unwrap()]: {
++    fn new() -> Self {
++        Self {
++            arr: [T::default(); N.checked_next_power_of_two().unwrap()],
++            n: 0,
++        }
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f3cf966157a63f6e9e1a39b1e2183cdcb2e8b63f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,215 @@@
++// run-rustfix
++//! This file tests for the `DOC_MARKDOWN` lint.
++
++#![allow(dead_code, incomplete_features)]
++#![warn(clippy::doc_markdown)]
++#![feature(custom_inner_attributes, generic_const_exprs, const_option)]
++#![rustfmt::skip]
++
++/// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
++/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun
++/// which should be reported only once despite being __doubly bad__.
++/// Here be ::a::global:path, and _::another::global::path_.  :: is not a path though.
++/// Import an item from ::awesome::global::blob:: (Intended postfix)
++/// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted)
++/// That's not code ~NotInCodeBlock~.
++/// be_sure_we_got_to_the_end_of_it
++fn foo_bar() {
++}
++
++/// That one tests multiline ticks.
++/// ```rust
++/// foo_bar FOO_BAR
++/// _foo bar_
++/// ```
++///
++/// ~~~rust
++/// foo_bar FOO_BAR
++/// _foo bar_
++/// ~~~
++/// be_sure_we_got_to_the_end_of_it
++fn multiline_codeblock() {
++}
++
++/// This _is a test for
++/// multiline
++/// emphasis_.
++/// be_sure_we_got_to_the_end_of_it
++fn test_emphasis() {
++}
++
++/// This tests units. See also #835.
++/// kiB MiB GiB TiB PiB EiB
++/// kib Mib Gib Tib Pib Eib
++/// kB MB GB TB PB EB
++/// kb Mb Gb Tb Pb Eb
++/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
++/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
++/// 32kB 32MB 32GB 32TB 32PB 32EB
++/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
++/// NaN
++/// be_sure_we_got_to_the_end_of_it
++fn test_units() {
++}
++
++/// This tests allowed identifiers.
++/// KiB MiB GiB TiB PiB EiB
++/// DirectX
++/// ECMAScript
++/// GPLv2 GPLv3
++/// GitHub GitLab
++/// IPv4 IPv6
++/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
++/// NaN NaNs
++/// OAuth GraphQL
++/// OCaml
++/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
++/// WebGL
++/// TensorFlow
++/// TrueType
++/// iOS macOS FreeBSD
++/// TeX LaTeX BibTeX BibLaTeX
++/// MinGW
++/// CamelCase (see also #2395)
++/// be_sure_we_got_to_the_end_of_it
++fn test_allowed() {
++}
++
++/// This test has [a link_with_underscores][chunked-example] inside it. See #823.
++/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
++/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
++/// It can also be [inline_link2].
++///
++/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
++/// [inline_link]: https://foobar
++/// [inline_link2]: https://foobar
++/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
++/// `multiline_ticks` functions.
++///
++/// expression of the type  `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
++/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
++/// be_sure_we_got_to_the_end_of_it
++fn main() {
++    foo_bar();
++    multiline_codeblock();
++    test_emphasis();
++    test_units();
++}
++
++/// ## CamelCaseThing
++/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
++///
++/// # CamelCaseThing
++///
++/// Not a title #897 CamelCaseThing
++/// be_sure_we_got_to_the_end_of_it
++fn issue897() {
++}
++
++/// I am confused by brackets? (`x_y`)
++/// I am confused by brackets? (foo `x_y`)
++/// I am confused by brackets? (`x_y` foo)
++/// be_sure_we_got_to_the_end_of_it
++fn issue900() {
++}
++
++/// Diesel queries also have a similar problem to [Iterator][iterator], where
++/// /// More talking
++/// returning them from a function requires exposing the implementation of that
++/// function. The [`helper_types`][helper_types] module exists to help with this,
++/// but you might want to hide the return type or have it conditionally change.
++/// Boxing can achieve both.
++///
++/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
++/// [helper_types]: ../helper_types/index.html
++/// be_sure_we_got_to_the_end_of_it
++fn issue883() {
++}
++
++/// `foo_bar
++/// baz_quz`
++/// [foo
++/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
++fn multiline() {
++}
++
++/** E.g., serialization of an empty list: FooBar
++```
++That's in a code block: `PackedNode`
++```
++
++And BarQuz too.
++be_sure_we_got_to_the_end_of_it
++*/
++fn issue1073() {
++}
++
++/** E.g., serialization of an empty list: FooBar
++```
++That's in a code block: PackedNode
++```
++
++And BarQuz too.
++be_sure_we_got_to_the_end_of_it
++*/
++fn issue1073_alt() {
++}
++
++/// Tests more than three quotes:
++/// ````
++/// DoNotWarn
++/// ```
++/// StillDont
++/// ````
++/// be_sure_we_got_to_the_end_of_it
++fn four_quotes() {
++}
++
++#[cfg_attr(feature = "a", doc = " ```")]
++#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
++/// fn main() {
++///     let s = "localhost:10000".to_string();
++///     println!("{}", s);
++/// }
++/// ```
++fn issue_1469() {}
++
++/**
++ * This is a doc comment that should not be a list
++ *This would also be an error under a strict common mark interpretation
++ */
++fn issue_1920() {}
++
++/// An iterator over mycrate::Collection's values.
++/// It should not lint a `'static` lifetime in ticks.
++fn issue_2210() {}
++
++/// This should not cause the lint to trigger:
++/// #REQ-data-family.lint_partof_exists
++fn issue_2343() {}
++
++/// This should not cause an ICE:
++/// __|_ _|__||_|
++fn pulldown_cmark_crash() {}
++
++/// This should not lint
++/// (regression test for #7758)
++/// [plain text][path::to::item]
++fn intra_doc_link() {}
++
++// issue #7033 - generic_const_exprs ICE
++struct S<T, const N: usize>
++where [(); N.checked_next_power_of_two().unwrap()]: {
++    arr: [T; N.checked_next_power_of_two().unwrap()],
++    n: usize,
++}
++
++impl<T: Copy + Default, const N: usize> S<T, N>
++where [(); N.checked_next_power_of_two().unwrap()]: {
++    fn new() -> Self {
++        Self {
++            arr: [T::default(); N.checked_next_power_of_two().unwrap()],
++            n: 0,
++        }
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..31132f86edbc452ecad7166f1cb20e47e33fd22f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,184 @@@
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:9:9
++   |
++LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
++   |         ^^^^^^^ help: try: ``foo_bar``
++   |
++   = note: `-D clippy::doc-markdown` implied by `-D warnings`
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:9:51
++   |
++LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
++   |                                                   ^^^^^^^^ help: try: ``foo::bar``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:10:83
++   |
++LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun
++   |                                                                                   ^^^^^^^^^^^^^ help: try: ``Foo::some_fun``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:12:13
++   |
++LL | /// Here be ::a::global:path, and _::another::global::path_.  :: is not a path though.
++   |             ^^^^^^^^^^^^^^^^ help: try: ``::a::global:path``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:12:36
++   |
++LL | /// Here be ::a::global:path, and _::another::global::path_.  :: is not a path though.
++   |                                    ^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::another::global::path``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:13:25
++   |
++LL | /// Import an item from ::awesome::global::blob:: (Intended postfix)
++   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::awesome::global::blob::``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:14:31
++   |
++LL | /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted)
++   |                               ^^^^^ help: try: ``::Cat``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:15:22
++   |
++LL | /// That's not code ~NotInCodeBlock~.
++   |                      ^^^^^^^^^^^^^^ help: try: ``NotInCodeBlock``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:16:5
++   |
++LL | /// be_sure_we_got_to_the_end_of_it
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:30:5
++   |
++LL | /// be_sure_we_got_to_the_end_of_it
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:37:5
++   |
++LL | /// be_sure_we_got_to_the_end_of_it
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:51:5
++   |
++LL | /// be_sure_we_got_to_the_end_of_it
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:74:5
++   |
++LL | /// be_sure_we_got_to_the_end_of_it
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:78:22
++   |
++LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
++   |                      ^^^^^^^^^^^^^^^^^^^^^ help: try: ``link_with_underscores``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:81:21
++   |
++LL | /// It can also be [inline_link2].
++   |                     ^^^^^^^^^^^^ help: try: ``inline_link2``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:91:5
++   |
++LL | /// be_sure_we_got_to_the_end_of_it
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:99:8
++   |
++LL | /// ## CamelCaseThing
++   |        ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:102:7
++   |
++LL | /// # CamelCaseThing
++   |       ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:104:22
++   |
++LL | /// Not a title #897 CamelCaseThing
++   |                      ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:105:5
++   |
++LL | /// be_sure_we_got_to_the_end_of_it
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:112:5
++   |
++LL | /// be_sure_we_got_to_the_end_of_it
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:125:5
++   |
++LL | /// be_sure_we_got_to_the_end_of_it
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:136:43
++   |
++LL | /** E.g., serialization of an empty list: FooBar
++   |                                           ^^^^^^ help: try: ``FooBar``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:141:5
++   |
++LL | And BarQuz too.
++   |     ^^^^^^ help: try: ``BarQuz``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:142:1
++   |
++LL | be_sure_we_got_to_the_end_of_it
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:147:43
++   |
++LL | /** E.g., serialization of an empty list: FooBar
++   |                                           ^^^^^^ help: try: ``FooBar``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:152:5
++   |
++LL | And BarQuz too.
++   |     ^^^^^^ help: try: ``BarQuz``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:153:1
++   |
++LL | be_sure_we_got_to_the_end_of_it
++   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:164:5
++   |
++LL | /// be_sure_we_got_to_the_end_of_it
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
++
++error: item in documentation is missing backticks
++  --> $DIR/doc-fixable.rs:183:22
++   |
++LL | /// An iterator over mycrate::Collection's values.
++   |                      ^^^^^^^^^^^^^^^^^^^ help: try: ``mycrate::Collection``
++
++error: aborting due to 30 previous errors
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..10586f16d466a35b07674534fc75d2c6c48e3b83
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,9 @@@
++/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels>
++///
++/// Not ok: http://www.unicode.org
++/// Not ok: https://www.unicode.org
++/// Not ok: http://www.unicode.org/
++/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
++fn issue_1832() {}
++
++fn main() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4b0c835dd3f07665a5d99963dda34000c63f811b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++/// See [NIST SP 800-56A, revision 2].
++///
++/// [NIST SP 800-56A, revision 2]:
++///     https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419
++fn issue_902_comment() {}
++
++fn main() {}
index 45ca34e2a8c8b34a2e6ede2509ad9367abac2709,0000000000000000000000000000000000000000..9670e5c24fb3ecbcf5a9febdca1e2a93ddf61c07
mode 100644,000000..100644
--- /dev/null
@@@ -1,64 -1,0 +1,64 @@@
- error: you should put `should_be` between ticks in the documentation
 +error: backticks are unbalanced
 +  --> $DIR/unbalanced_ticks.rs:7:1
 +   |
 +LL | / /// This is a doc comment with `unbalanced_tick marks and several words that
 +LL | | /// should be `encompassed_by` tick marks because they `contain_underscores`.
 +LL | | /// Because of the initial `unbalanced_tick` pair, the error message is
 +LL | | /// very `confusing_and_misleading`.
 +   | |____________________________________^
 +   |
 +   = note: `-D clippy::doc-markdown` implied by `-D warnings`
 +   = help: a backtick may be missing a pair
 +
 +error: backticks are unbalanced
 +  --> $DIR/unbalanced_ticks.rs:13:1
 +   |
 +LL | /// This paragraph has `unbalanced_tick marks and should stop_linting.
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = help: a backtick may be missing a pair
 +
-    |                                ^^^^^^^^^
++error: item in documentation is missing backticks
 +  --> $DIR/unbalanced_ticks.rs:15:32
 +   |
 +LL | /// This paragraph is fine and should_be linted normally.
- error: you should put `not_fine` between ticks in the documentation
++   |                                ^^^^^^^^^ help: try: ``should_be``
 +
 +error: backticks are unbalanced
 +  --> $DIR/unbalanced_ticks.rs:17:1
 +   |
 +LL | /// Double unbalanced backtick from ``here to here` should lint.
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = help: a backtick may be missing a pair
 +
-    |        ^^^^^^^^
++error: item in documentation is missing backticks
 +  --> $DIR/unbalanced_ticks.rs:30:8
 +   |
 +LL | /// ## not_fine
- error: you should put `backticks_here` between ticks in the documentation
++   |        ^^^^^^^^ help: try: ``not_fine``
 +
 +error: backticks are unbalanced
 +  --> $DIR/unbalanced_ticks.rs:32:1
 +   |
 +LL | /// ### `unbalanced
 +   | ^^^^^^^^^^^^^^^^^^^
 +   |
 +   = help: a backtick may be missing a pair
 +
 +error: backticks are unbalanced
 +  --> $DIR/unbalanced_ticks.rs:34:1
 +   |
 +LL | /// - This `item has unbalanced tick marks
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = help: a backtick may be missing a pair
 +
-    |                       ^^^^^^^^^^^^^^
++error: item in documentation is missing backticks
 +  --> $DIR/unbalanced_ticks.rs:35:23
 +   |
 +LL | /// - This item needs backticks_here
++   |                       ^^^^^^^^^^^^^^ help: try: ``backticks_here``
 +
 +error: aborting due to 8 previous errors
 +
index c77a74a58f22c6072dcfb295ea22794afbe1309c,0000000000000000000000000000000000000000..30fdd3b087371226352c9b07dd81f60119f744b3
mode 100644,000000..100644
--- /dev/null
@@@ -1,105 -1,0 +1,104 @@@
- // edition:2018
 +#![warn(clippy::missing_errors_doc)]
 +#![allow(clippy::result_unit_err)]
 +#![allow(clippy::unnecessary_wraps)]
 +
 +use std::io;
 +
 +pub fn pub_fn_missing_errors_header() -> Result<(), ()> {
 +    unimplemented!();
 +}
 +
 +pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> {
 +    unimplemented!();
 +}
 +
 +/// This is not sufficiently documented.
 +pub fn pub_fn_returning_io_result() -> io::Result<()> {
 +    unimplemented!();
 +}
 +
 +/// This is not sufficiently documented.
 +pub async fn async_pub_fn_returning_io_result() -> io::Result<()> {
 +    unimplemented!();
 +}
 +
 +/// # Errors
 +/// A description of the errors goes here.
 +pub fn pub_fn_with_errors_header() -> Result<(), ()> {
 +    unimplemented!();
 +}
 +
 +/// # Errors
 +/// A description of the errors goes here.
 +pub async fn async_pub_fn_with_errors_header() -> Result<(), ()> {
 +    unimplemented!();
 +}
 +
 +/// This function doesn't require the documentation because it is private
 +fn priv_fn_missing_errors_header() -> Result<(), ()> {
 +    unimplemented!();
 +}
 +
 +/// This function doesn't require the documentation because it is private
 +async fn async_priv_fn_missing_errors_header() -> Result<(), ()> {
 +    unimplemented!();
 +}
 +
 +pub struct Struct1;
 +
 +impl Struct1 {
 +    /// This is not sufficiently documented.
 +    pub fn pub_method_missing_errors_header() -> Result<(), ()> {
 +        unimplemented!();
 +    }
 +
 +    /// This is not sufficiently documented.
 +    pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> {
 +        unimplemented!();
 +    }
 +
 +    /// # Errors
 +    /// A description of the errors goes here.
 +    pub fn pub_method_with_errors_header() -> Result<(), ()> {
 +        unimplemented!();
 +    }
 +
 +    /// # Errors
 +    /// A description of the errors goes here.
 +    pub async fn async_pub_method_with_errors_header() -> Result<(), ()> {
 +        unimplemented!();
 +    }
 +
 +    /// This function doesn't require the documentation because it is private.
 +    fn priv_method_missing_errors_header() -> Result<(), ()> {
 +        unimplemented!();
 +    }
 +
 +    /// This function doesn't require the documentation because it is private.
 +    async fn async_priv_method_missing_errors_header() -> Result<(), ()> {
 +        unimplemented!();
 +    }
 +}
 +
 +pub trait Trait1 {
 +    /// This is not sufficiently documented.
 +    fn trait_method_missing_errors_header() -> Result<(), ()>;
 +
 +    /// # Errors
 +    /// A description of the errors goes here.
 +    fn trait_method_with_errors_header() -> Result<(), ()>;
 +}
 +
 +impl Trait1 for Struct1 {
 +    fn trait_method_missing_errors_header() -> Result<(), ()> {
 +        unimplemented!();
 +    }
 +
 +    fn trait_method_with_errors_header() -> Result<(), ()> {
 +        unimplemented!();
 +    }
 +}
 +
 +fn main() -> Result<(), ()> {
 +    Ok(())
 +}
index b5a81419daee35d295197158c9e20d5a17f21871,0000000000000000000000000000000000000000..c7b616e2897087c01ee59976e37fe287afb6dbbc
mode 100644,000000..100644
--- /dev/null
@@@ -1,58 -1,0 +1,58 @@@
-   --> $DIR/doc_errors.rs:8:1
 +error: docs for function returning `Result` missing `# Errors` section
-   --> $DIR/doc_errors.rs:12:1
++  --> $DIR/doc_errors.rs:7:1
 +   |
 +LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> {
 +LL | |     unimplemented!();
 +LL | | }
 +   | |_^
 +   |
 +   = note: `-D clippy::missing-errors-doc` implied by `-D warnings`
 +
 +error: docs for function returning `Result` missing `# Errors` section
-   --> $DIR/doc_errors.rs:17:1
++  --> $DIR/doc_errors.rs:11:1
 +   |
 +LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> {
 +LL | |     unimplemented!();
 +LL | | }
 +   | |_^
 +
 +error: docs for function returning `Result` missing `# Errors` section
-   --> $DIR/doc_errors.rs:22:1
++  --> $DIR/doc_errors.rs:16:1
 +   |
 +LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> {
 +LL | |     unimplemented!();
 +LL | | }
 +   | |_^
 +
 +error: docs for function returning `Result` missing `# Errors` section
-   --> $DIR/doc_errors.rs:52:5
++  --> $DIR/doc_errors.rs:21:1
 +   |
 +LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> {
 +LL | |     unimplemented!();
 +LL | | }
 +   | |_^
 +
 +error: docs for function returning `Result` missing `# Errors` section
-   --> $DIR/doc_errors.rs:57:5
++  --> $DIR/doc_errors.rs:51:5
 +   |
 +LL | /     pub fn pub_method_missing_errors_header() -> Result<(), ()> {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +
 +error: docs for function returning `Result` missing `# Errors` section
-   --> $DIR/doc_errors.rs:86:5
++  --> $DIR/doc_errors.rs:56:5
 +   |
 +LL | /     pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +
 +error: docs for function returning `Result` missing `# Errors` section
++  --> $DIR/doc_errors.rs:85:5
 +   |
 +LL |     fn trait_method_missing_errors_header() -> Result<(), ()>;
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: aborting due to 7 previous errors
 +
index 03bb30f9083ac4f3c21ab23a635747ef8ba128fd,0000000000000000000000000000000000000000..4464a21b3b654bdf89b238a5c0594b61edbf06ce
mode 100644,000000..100644
--- /dev/null
@@@ -1,127 -1,0 +1,132 @@@
 +// aux-build:doc_unsafe_macros.rs
 +
 +#[macro_use]
 +extern crate doc_unsafe_macros;
 +
 +/// This is not sufficiently documented
 +pub unsafe fn destroy_the_planet() {
 +    unimplemented!();
 +}
 +
 +/// This one is
 +///
 +/// # Safety
 +///
 +/// This function shouldn't be called unless the horsemen are ready
 +pub unsafe fn apocalypse(universe: &mut ()) {
 +    unimplemented!();
 +}
 +
 +/// This is a private function, so docs aren't necessary
 +unsafe fn you_dont_see_me() {
 +    unimplemented!();
 +}
 +
 +mod private_mod {
 +    pub unsafe fn only_crate_wide_accessible() {
 +        unimplemented!();
 +    }
 +
 +    pub unsafe fn republished() {
 +        unimplemented!();
 +    }
 +}
 +
 +pub use private_mod::republished;
 +
 +pub trait SafeTraitUnsafeMethods {
 +    unsafe fn woefully_underdocumented(self);
 +
 +    /// # Safety
 +    unsafe fn at_least_somewhat_documented(self);
 +}
 +
 +pub unsafe trait UnsafeTrait {
 +    fn method();
 +}
 +
 +/// # Safety
 +pub unsafe trait DocumentedUnsafeTrait {
 +    fn method2();
 +}
 +
 +pub struct Struct;
 +
 +impl SafeTraitUnsafeMethods for Struct {
 +    unsafe fn woefully_underdocumented(self) {
 +        // all is well
 +    }
 +
 +    unsafe fn at_least_somewhat_documented(self) {
 +        // all is still well
 +    }
 +}
 +
 +unsafe impl UnsafeTrait for Struct {
 +    fn method() {}
 +}
 +
 +unsafe impl DocumentedUnsafeTrait for Struct {
 +    fn method2() {}
 +}
 +
 +impl Struct {
 +    pub unsafe fn more_undocumented_unsafe() -> Self {
 +        unimplemented!();
 +    }
 +
 +    /// # Safety
 +    pub unsafe fn somewhat_documented(&self) {
 +        unimplemented!();
 +    }
 +
 +    unsafe fn private(&self) {
 +        unimplemented!();
 +    }
 +}
 +
 +macro_rules! very_unsafe {
 +    () => {
 +        pub unsafe fn whee() {
 +            unimplemented!()
 +        }
 +
 +        /// # Safety
 +        ///
 +        /// Please keep the seat belt fastened
 +        pub unsafe fn drive() {
 +            whee()
 +        }
 +    };
 +}
 +
 +very_unsafe!();
 +
 +// we don't lint code from external macros
 +undocd_unsafe!();
 +
 +fn main() {
 +    unsafe {
 +        you_dont_see_me();
 +        destroy_the_planet();
 +        let mut universe = ();
 +        apocalypse(&mut universe);
 +        private_mod::only_crate_wide_accessible();
 +        drive();
 +    }
 +}
 +
 +// do not lint if any parent has `#[doc(hidden)]` attribute
 +// see #7347
 +#[doc(hidden)]
 +pub mod __macro {
 +    pub struct T;
 +    impl T {
 +        pub unsafe fn f() {}
 +    }
 +}
++
++/// # Implementation safety
++pub unsafe trait DocumentedUnsafeTraitWithImplementationHeader {
++    fn method();
++}
index 447fbb9e1bff3440c35200354408ccdeb9fe60b1,0000000000000000000000000000000000000000..add8a91e26b85a2b9745a73053ff73d418a54cdd
mode 100644,000000..100644
--- /dev/null
@@@ -1,112 -1,0 +1,112 @@@
- error: all variants have the same prefix: `With`
 +error: variant name ends with the enum's name
 +  --> $DIR/enum_variants.rs:15:5
 +   |
 +LL |     cFoo,
 +   |     ^^^^
 +   |
 +   = note: `-D clippy::enum-variant-names` implied by `-D warnings`
 +
 +error: variant name starts with the enum's name
 +  --> $DIR/enum_variants.rs:26:5
 +   |
 +LL |     FoodGood,
 +   |     ^^^^^^^^
 +
 +error: variant name starts with the enum's name
 +  --> $DIR/enum_variants.rs:27:5
 +   |
 +LL |     FoodMiddle,
 +   |     ^^^^^^^^^^
 +
 +error: variant name starts with the enum's name
 +  --> $DIR/enum_variants.rs:28:5
 +   |
 +LL |     FoodBad,
 +   |     ^^^^^^^
 +
 +error: all variants have the same prefix: `Food`
 +  --> $DIR/enum_variants.rs:25:1
 +   |
 +LL | / enum Food {
 +LL | |     FoodGood,
 +LL | |     FoodMiddle,
 +LL | |     FoodBad,
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the prefixes and use full paths to the variants instead of glob imports
 +
 +error: all variants have the same prefix: `CallType`
 +  --> $DIR/enum_variants.rs:35:1
 +   |
 +LL | / enum BadCallType {
 +LL | |     CallTypeCall,
 +LL | |     CallTypeCreate,
 +LL | |     CallTypeDestroy,
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the prefixes and use full paths to the variants instead of glob imports
 +
 +error: all variants have the same prefix: `Constant`
 +  --> $DIR/enum_variants.rs:47:1
 +   |
 +LL | / enum Consts {
 +LL | |     ConstantInt,
 +LL | |     ConstantCake,
 +LL | |     ConstantLie,
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the prefixes and use full paths to the variants instead of glob imports
 +
++error: all variants have the same prefix: `WithOut`
 +  --> $DIR/enum_variants.rs:81:1
 +   |
 +LL | / enum Seallll {
 +LL | |     WithOutCake,
 +LL | |     WithOutTea,
 +LL | |     WithOut,
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the prefixes and use full paths to the variants instead of glob imports
 +
 +error: all variants have the same prefix: `Prefix`
 +  --> $DIR/enum_variants.rs:87:1
 +   |
 +LL | / enum NonCaps {
 +LL | |     Prefix的,
 +LL | |     PrefixTea,
 +LL | |     PrefixCake,
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the prefixes and use full paths to the variants instead of glob imports
 +
 +error: all variants have the same postfix: `IData`
 +  --> $DIR/enum_variants.rs:136:1
 +   |
 +LL | / enum IDataRequest {
 +LL | |     PutIData(String),
 +LL | |     GetIData(String),
 +LL | |     DeleteUnpubIData(String),
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the postfixes and use full paths to the variants instead of glob imports
 +
 +error: all variants have the same postfix: `HIData`
 +  --> $DIR/enum_variants.rs:142:1
 +   |
 +LL | / enum HIDataRequest {
 +LL | |     PutHIData(String),
 +LL | |     GetHIData(String),
 +LL | |     DeleteUnpubHIData(String),
 +LL | | }
 +   | |_^
 +   |
 +   = help: remove the postfixes and use full paths to the variants instead of glob imports
 +
 +error: aborting due to 11 previous errors
 +
index 8e6a32b7be33d2eccde04199653c2d467942f3c0,0000000000000000000000000000000000000000..aad78319d48209549db51ff8e3de027a5b4a8b59
mode 100644,000000..100644
--- /dev/null
@@@ -1,114 -1,0 +1,112 @@@
- // edition:2018
 +#[warn(clippy::eval_order_dependence)]
 +#[allow(
 +    unused_assignments,
 +    unused_variables,
 +    clippy::no_effect,
 +    dead_code,
 +    clippy::blacklisted_name
 +)]
 +fn main() {
 +    let mut x = 0;
 +    let a = {
 +        x = 1;
 +        1
 +    } + x;
 +
 +    // Example from iss#277
 +    x += {
 +        x = 20;
 +        2
 +    };
 +
 +    // Does it work in weird places?
 +    // ...in the base for a struct expression?
 +    struct Foo {
 +        a: i32,
 +        b: i32,
 +    };
 +    let base = Foo { a: 4, b: 5 };
 +    let foo = Foo {
 +        a: x,
 +        ..{
 +            x = 6;
 +            base
 +        }
 +    };
 +    // ...inside a closure?
 +    let closure = || {
 +        let mut x = 0;
 +        x += {
 +            x = 20;
 +            2
 +        };
 +    };
 +    // ...not across a closure?
 +    let mut y = 0;
 +    let b = (y, || y = 1);
 +
 +    // && and || evaluate left-to-right.
 +    let a = {
 +        x = 1;
 +        true
 +    } && (x == 3);
 +    let a = {
 +        x = 1;
 +        true
 +    } || (x == 3);
 +
 +    // Make sure we don't get confused by alpha conversion.
 +    let a = {
 +        let mut x = 1;
 +        x = 2;
 +        1
 +    } + x;
 +
 +    // No warning if we don't read the variable...
 +    x = {
 +        x = 20;
 +        2
 +    };
 +    // ...if the assignment is in a closure...
 +    let b = {
 +        || {
 +            x = 1;
 +        };
 +        1
 +    } + x;
 +    // ... or the access is under an address.
 +    let b = (
 +        {
 +            let p = &x;
 +            1
 +        },
 +        {
 +            x = 1;
 +            x
 +        },
 +    );
 +
 +    // Limitation: l-values other than simple variables don't trigger
 +    // the warning.
 +    let mut tup = (0, 0);
 +    let c = {
 +        tup.0 = 1;
 +        1
 +    } + tup.0;
 +    // Limitation: you can get away with a read under address-of.
 +    let mut z = 0;
 +    let b = (
 +        &{
 +            z = x;
 +            x
 +        },
 +        {
 +            x = 3;
 +            x
 +        },
 +    );
 +}
 +
 +async fn issue_6925() {
 +    let _ = vec![async { true }.await, async { false }.await];
 +}
index 4f611e308e18619e50f0b408ed7c07f60c28b47d,0000000000000000000000000000000000000000..7c6265a08790deee6d8df446b49846dab095e770
mode 100644,000000..100644
--- /dev/null
@@@ -1,51 -1,0 +1,51 @@@
-   --> $DIR/eval_order_dependence.rs:16:9
 +error: unsequenced read of `x`
-   --> $DIR/eval_order_dependence.rs:14:9
++  --> $DIR/eval_order_dependence.rs:14:9
 +   |
 +LL |     } + x;
 +   |         ^
 +   |
 +   = note: `-D clippy::eval-order-dependence` implied by `-D warnings`
 +note: whether read occurs before this write depends on evaluation order
-   --> $DIR/eval_order_dependence.rs:19:5
++  --> $DIR/eval_order_dependence.rs:12:9
 +   |
 +LL |         x = 1;
 +   |         ^^^^^
 +
 +error: unsequenced read of `x`
-   --> $DIR/eval_order_dependence.rs:20:9
++  --> $DIR/eval_order_dependence.rs:17:5
 +   |
 +LL |     x += {
 +   |     ^
 +   |
 +note: whether read occurs before this write depends on evaluation order
-   --> $DIR/eval_order_dependence.rs:32:12
++  --> $DIR/eval_order_dependence.rs:18:9
 +   |
 +LL |         x = 20;
 +   |         ^^^^^^
 +
 +error: unsequenced read of `x`
-   --> $DIR/eval_order_dependence.rs:34:13
++  --> $DIR/eval_order_dependence.rs:30:12
 +   |
 +LL |         a: x,
 +   |            ^
 +   |
 +note: whether read occurs before this write depends on evaluation order
-   --> $DIR/eval_order_dependence.rs:41:9
++  --> $DIR/eval_order_dependence.rs:32:13
 +   |
 +LL |             x = 6;
 +   |             ^^^^^
 +
 +error: unsequenced read of `x`
-   --> $DIR/eval_order_dependence.rs:42:13
++  --> $DIR/eval_order_dependence.rs:39:9
 +   |
 +LL |         x += {
 +   |         ^
 +   |
 +note: whether read occurs before this write depends on evaluation order
++  --> $DIR/eval_order_dependence.rs:40:13
 +   |
 +LL |             x = 20;
 +   |             ^^^^^^
 +
 +error: aborting due to 4 previous errors
 +
index 495cd97e05e15d472bef961da5a2e9eab1573814,0000000000000000000000000000000000000000..5d5af4e4632970afe821f9b42b82eae5bd445e08
mode 100644,000000..100644
--- /dev/null
@@@ -1,77 -1,0 +1,76 @@@
- #![allow(clippy::if_then_panic)]
 +#![deny(clippy::fallible_impl_from)]
 +
 +// docs example
 +struct Foo(i32);
 +impl From<String> for Foo {
 +    fn from(s: String) -> Self {
 +        Foo(s.parse().unwrap())
 +    }
 +}
 +
 +struct Valid(Vec<u8>);
 +
 +impl<'a> From<&'a str> for Valid {
 +    fn from(s: &'a str) -> Valid {
 +        Valid(s.to_owned().into_bytes())
 +    }
 +}
 +impl From<usize> for Valid {
 +    fn from(i: usize) -> Valid {
 +        Valid(Vec::with_capacity(i))
 +    }
 +}
 +
 +struct Invalid;
 +
 +impl From<usize> for Invalid {
 +    fn from(i: usize) -> Invalid {
 +        if i != 42 {
 +            panic!();
 +        }
 +        Invalid
 +    }
 +}
 +
 +impl From<Option<String>> for Invalid {
 +    fn from(s: Option<String>) -> Invalid {
 +        let s = s.unwrap();
 +        if !s.is_empty() {
 +            panic!("42");
 +        } else if s.parse::<u32>().unwrap() != 42 {
 +            panic!("{:?}", s);
 +        }
 +        Invalid
 +    }
 +}
 +
 +trait ProjStrTrait {
 +    type ProjString;
 +}
 +impl<T> ProjStrTrait for Box<T> {
 +    type ProjString = String;
 +}
 +impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid {
 +    fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid {
 +        if s.parse::<u32>().ok().unwrap() != 42 {
 +            panic!("{:?}", s);
 +        }
 +        Invalid
 +    }
 +}
 +
 +struct Unreachable;
 +
 +impl From<String> for Unreachable {
 +    fn from(s: String) -> Unreachable {
 +        if s.is_empty() {
 +            return Unreachable;
 +        }
 +        match s.chars().next() {
 +            Some(_) => Unreachable,
 +            None => unreachable!(), // do not lint the unreachable macro
 +        }
 +    }
 +}
 +
 +fn main() {}
index f5d0b98c10862cd11a4db14d65c484f90c988dd4,0000000000000000000000000000000000000000..4e0f08a1215c0401fa8f18493fb8ad0a833dcd63
mode 100644,000000..100644
--- /dev/null
@@@ -1,93 -1,0 +1,93 @@@
-   --> $DIR/fallible_impl_from.rs:6:1
 +error: consider implementing `TryFrom` instead
-   --> $DIR/fallible_impl_from.rs:8:13
++  --> $DIR/fallible_impl_from.rs:5:1
 +   |
 +LL | / impl From<String> for Foo {
 +LL | |     fn from(s: String) -> Self {
 +LL | |         Foo(s.parse().unwrap())
 +LL | |     }
 +LL | | }
 +   | |_^
 +   |
 +note: the lint level is defined here
 +  --> $DIR/fallible_impl_from.rs:1:9
 +   |
 +LL | #![deny(clippy::fallible_impl_from)]
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
 +note: potential failure(s)
-   --> $DIR/fallible_impl_from.rs:27:1
++  --> $DIR/fallible_impl_from.rs:7:13
 +   |
 +LL |         Foo(s.parse().unwrap())
 +   |             ^^^^^^^^^^^^^^^^^^
 +
 +error: consider implementing `TryFrom` instead
-   --> $DIR/fallible_impl_from.rs:30:13
++  --> $DIR/fallible_impl_from.rs:26:1
 +   |
 +LL | / impl From<usize> for Invalid {
 +LL | |     fn from(i: usize) -> Invalid {
 +LL | |         if i != 42 {
 +LL | |             panic!();
 +...  |
 +LL | |     }
 +LL | | }
 +   | |_^
 +   |
 +   = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
 +note: potential failure(s)
-    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
++  --> $DIR/fallible_impl_from.rs:29:13
 +   |
 +LL |             panic!();
 +   |             ^^^^^^^^
-   --> $DIR/fallible_impl_from.rs:36:1
++   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: consider implementing `TryFrom` instead
-   --> $DIR/fallible_impl_from.rs:38:17
++  --> $DIR/fallible_impl_from.rs:35:1
 +   |
 +LL | / impl From<Option<String>> for Invalid {
 +LL | |     fn from(s: Option<String>) -> Invalid {
 +LL | |         let s = s.unwrap();
 +LL | |         if !s.is_empty() {
 +...  |
 +LL | |     }
 +LL | | }
 +   | |_^
 +   |
 +   = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
 +note: potential failure(s)
-    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
++  --> $DIR/fallible_impl_from.rs:37:17
 +   |
 +LL |         let s = s.unwrap();
 +   |                 ^^^^^^^^^^
 +LL |         if !s.is_empty() {
 +LL |             panic!("42");
 +   |             ^^^^^^^^^^^^
 +LL |         } else if s.parse::<u32>().unwrap() != 42 {
 +   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
 +LL |             panic!("{:?}", s);
 +   |             ^^^^^^^^^^^^^^^^^
-   --> $DIR/fallible_impl_from.rs:54:1
++   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: consider implementing `TryFrom` instead
-   --> $DIR/fallible_impl_from.rs:56:12
++  --> $DIR/fallible_impl_from.rs:53:1
 +   |
 +LL | / impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid {
 +LL | |     fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid {
 +LL | |         if s.parse::<u32>().ok().unwrap() != 42 {
 +LL | |             panic!("{:?}", s);
 +...  |
 +LL | |     }
 +LL | | }
 +   | |_^
 +   |
 +   = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
 +note: potential failure(s)
-    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
++  --> $DIR/fallible_impl_from.rs:55:12
 +   |
 +LL |         if s.parse::<u32>().ok().unwrap() != 42 {
 +   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +LL |             panic!("{:?}", s);
 +   |             ^^^^^^^^^^^^^^^^^
++   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: aborting due to 4 previous errors
 +
index 73fc750511c78684cdd8650d03e6ce1dc40582b1,0000000000000000000000000000000000000000..64cb7b1cfb80f6c33ff5e81f7af29cceb1e8b73d
mode 100644,000000..100644
--- /dev/null
@@@ -1,74 -1,0 +1,76 @@@
 +// run-rustfix
 +
 +#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)]
 +#![warn(clippy::useless_format)]
 +
 +struct Foo(pub String);
 +
 +macro_rules! foo {
 +    ($($t:tt)*) => (Foo(format!($($t)*)))
 +}
 +
 +fn main() {
 +    "foo".to_string();
 +    "{}".to_string();
 +    "{} abc {}".to_string();
 +    r##"foo {}
 +" bar"##.to_string();
 +
++    let _ = String::new();
++
 +    "foo".to_string();
 +    format!("{:?}", "foo"); // Don't warn about `Debug`.
 +    format!("{:8}", "foo");
 +    format!("{:width$}", "foo", width = 8);
 +    "foo".to_string(); // Warn when the format makes no difference.
 +    "foo".to_string(); // Warn when the format makes no difference.
 +    format!("foo {}", "bar");
 +    format!("{} bar", "foo");
 +
 +    let arg: String = "".to_owned();
 +    arg.to_string();
 +    format!("{:?}", arg); // Don't warn about debug.
 +    format!("{:8}", arg);
 +    format!("{:width$}", arg, width = 8);
 +    arg.to_string(); // Warn when the format makes no difference.
 +    arg.to_string(); // Warn when the format makes no difference.
 +    format!("foo {}", arg);
 +    format!("{} bar", arg);
 +
 +    // We don’t want to warn for non-string args; see issue #697.
 +    format!("{}", 42);
 +    format!("{:?}", 42);
 +    format!("{:+}", 42);
 +    format!("foo {}", 42);
 +    format!("{} bar", 42);
 +
 +    // We only want to warn about `format!` itself.
 +    println!("foo");
 +    println!("{}", "foo");
 +    println!("foo {}", "foo");
 +    println!("{}", 42);
 +    println!("foo {}", 42);
 +
 +    // A `format!` inside a macro should not trigger a warning.
 +    foo!("should not warn");
 +
 +    // Precision on string means slicing without panicking on size.
 +    format!("{:.1}", "foo"); // Could be `"foo"[..1]`
 +    format!("{:.10}", "foo"); // Could not be `"foo"[..10]`
 +    format!("{:.prec$}", "foo", prec = 1);
 +    format!("{:.prec$}", "foo", prec = 10);
 +
 +    42.to_string();
 +    let x = std::path::PathBuf::from("/bar/foo/qux");
 +    x.display().to_string();
 +
 +    // False positive
 +    let a = "foo".to_string();
 +    let _ = Some(a + "bar");
 +
 +    // Wrap it with braces
 +    let v: Vec<String> = vec!["foo".to_string(), "bar".to_string()];
 +    let _s: String = (&*v.join("\n")).to_string();
 +
 +    format!("prepend {:+}", "s");
 +}
index 2f4595650cbf3c8d3cdd716e3ea32a0e24113b58,0000000000000000000000000000000000000000..a065b1b5683c1b9ccbfeb81df5cf1b96d7d12c4d
mode 100644,000000..100644
--- /dev/null
@@@ -1,76 -1,0 +1,78 @@@
 +// run-rustfix
 +
 +#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)]
 +#![warn(clippy::useless_format)]
 +
 +struct Foo(pub String);
 +
 +macro_rules! foo {
 +    ($($t:tt)*) => (Foo(format!($($t)*)))
 +}
 +
 +fn main() {
 +    format!("foo");
 +    format!("{{}}");
 +    format!("{{}} abc {{}}");
 +    format!(
 +        r##"foo {{}}
 +" bar"##
 +    );
 +
++    let _ = format!("");
++
 +    format!("{}", "foo");
 +    format!("{:?}", "foo"); // Don't warn about `Debug`.
 +    format!("{:8}", "foo");
 +    format!("{:width$}", "foo", width = 8);
 +    format!("{:+}", "foo"); // Warn when the format makes no difference.
 +    format!("{:<}", "foo"); // Warn when the format makes no difference.
 +    format!("foo {}", "bar");
 +    format!("{} bar", "foo");
 +
 +    let arg: String = "".to_owned();
 +    format!("{}", arg);
 +    format!("{:?}", arg); // Don't warn about debug.
 +    format!("{:8}", arg);
 +    format!("{:width$}", arg, width = 8);
 +    format!("{:+}", arg); // Warn when the format makes no difference.
 +    format!("{:<}", arg); // Warn when the format makes no difference.
 +    format!("foo {}", arg);
 +    format!("{} bar", arg);
 +
 +    // We don’t want to warn for non-string args; see issue #697.
 +    format!("{}", 42);
 +    format!("{:?}", 42);
 +    format!("{:+}", 42);
 +    format!("foo {}", 42);
 +    format!("{} bar", 42);
 +
 +    // We only want to warn about `format!` itself.
 +    println!("foo");
 +    println!("{}", "foo");
 +    println!("foo {}", "foo");
 +    println!("{}", 42);
 +    println!("foo {}", 42);
 +
 +    // A `format!` inside a macro should not trigger a warning.
 +    foo!("should not warn");
 +
 +    // Precision on string means slicing without panicking on size.
 +    format!("{:.1}", "foo"); // Could be `"foo"[..1]`
 +    format!("{:.10}", "foo"); // Could not be `"foo"[..10]`
 +    format!("{:.prec$}", "foo", prec = 1);
 +    format!("{:.prec$}", "foo", prec = 10);
 +
 +    format!("{}", 42.to_string());
 +    let x = std::path::PathBuf::from("/bar/foo/qux");
 +    format!("{}", x.display().to_string());
 +
 +    // False positive
 +    let a = "foo".to_string();
 +    let _ = Some(format!("{}", a + "bar"));
 +
 +    // Wrap it with braces
 +    let v: Vec<String> = vec!["foo".to_string(), "bar".to_string()];
 +    let _s: String = format!("{}", &*v.join("\n"));
 +
 +    format!("prepend {:+}", "s");
 +}
index 701399b32d62834a9d993339b83df1f5ba8d03ab,0000000000000000000000000000000000000000..58ad7499bb26f530c5202239ac79858ab1aaa79c
mode 100644,000000..100644
--- /dev/null
@@@ -1,97 -1,0 +1,103 @@@
-   --> $DIR/format.rs:21:5
 +error: useless use of `format!`
 +  --> $DIR/format.rs:13:5
 +   |
 +LL |     format!("foo");
 +   |     ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 +   |
 +   = note: `-D clippy::useless-format` implied by `-D warnings`
 +
 +error: useless use of `format!`
 +  --> $DIR/format.rs:14:5
 +   |
 +LL |     format!("{{}}");
 +   |     ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()`
 +
 +error: useless use of `format!`
 +  --> $DIR/format.rs:15:5
 +   |
 +LL |     format!("{{}} abc {{}}");
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()`
 +
 +error: useless use of `format!`
 +  --> $DIR/format.rs:16:5
 +   |
 +LL | /     format!(
 +LL | |         r##"foo {{}}
 +LL | | " bar"##
 +LL | |     );
 +   | |_____^
 +   |
 +help: consider using `.to_string()`
 +   |
 +LL ~     r##"foo {}
 +LL ~ " bar"##.to_string();
 +   |
 +
 +error: useless use of `format!`
-   --> $DIR/format.rs:25:5
++  --> $DIR/format.rs:21:13
++   |
++LL |     let _ = format!("");
++   |             ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
++
++error: useless use of `format!`
++  --> $DIR/format.rs:23:5
 +   |
 +LL |     format!("{}", "foo");
 +   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 +
 +error: useless use of `format!`
-   --> $DIR/format.rs:26:5
++  --> $DIR/format.rs:27:5
 +   |
 +LL |     format!("{:+}", "foo"); // Warn when the format makes no difference.
 +   |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 +
 +error: useless use of `format!`
-   --> $DIR/format.rs:31:5
++  --> $DIR/format.rs:28:5
 +   |
 +LL |     format!("{:<}", "foo"); // Warn when the format makes no difference.
 +   |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 +
 +error: useless use of `format!`
-   --> $DIR/format.rs:35:5
++  --> $DIR/format.rs:33:5
 +   |
 +LL |     format!("{}", arg);
 +   |     ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 +
 +error: useless use of `format!`
-   --> $DIR/format.rs:36:5
++  --> $DIR/format.rs:37:5
 +   |
 +LL |     format!("{:+}", arg); // Warn when the format makes no difference.
 +   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 +
 +error: useless use of `format!`
-   --> $DIR/format.rs:63:5
++  --> $DIR/format.rs:38:5
 +   |
 +LL |     format!("{:<}", arg); // Warn when the format makes no difference.
 +   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 +
 +error: useless use of `format!`
-   --> $DIR/format.rs:65:5
++  --> $DIR/format.rs:65:5
 +   |
 +LL |     format!("{}", 42.to_string());
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
 +
 +error: useless use of `format!`
-   --> $DIR/format.rs:69:18
++  --> $DIR/format.rs:67:5
 +   |
 +LL |     format!("{}", x.display().to_string());
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
 +
 +error: useless use of `format!`
-   --> $DIR/format.rs:73:22
++  --> $DIR/format.rs:71:18
 +   |
 +LL |     let _ = Some(format!("{}", a + "bar"));
 +   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
 +
 +error: useless use of `format!`
- error: aborting due to 14 previous errors
++  --> $DIR/format.rs:75:22
 +   |
 +LL |     let _s: String = format!("{}", &*v.join("/n"));
 +   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
 +
++error: aborting due to 15 previous errors
 +
index 8376566c4d62d57fcfa1c51198500c4ac517e904,0000000000000000000000000000000000000000..69b5e1c722e0320df446f0fb6a01d74d20fead7f
mode 100644,000000..100644
--- /dev/null
@@@ -1,105 -1,0 +1,117 @@@
 +// run-rustfix
 +
 +#![allow(unreachable_code)]
 +#![allow(unused_macros)]
 +#![allow(unused_variables)]
 +#![allow(clippy::assertions_on_constants)]
 +#![allow(clippy::eq_op)]
++#![allow(clippy::print_literal)]
 +#![warn(clippy::to_string_in_format_args)]
 +
 +use std::io::{stdout, Write};
 +use std::ops::Deref;
 +use std::panic::Location;
 +
 +struct Somewhere;
 +
 +impl ToString for Somewhere {
 +    fn to_string(&self) -> String {
 +        String::from("somewhere")
 +    }
 +}
 +
 +struct X(u32);
 +
 +impl Deref for X {
 +    type Target = u32;
 +
 +    fn deref(&self) -> &u32 {
 +        &self.0
 +    }
 +}
 +
 +struct Y<'a>(&'a X);
 +
 +impl<'a> Deref for Y<'a> {
 +    type Target = &'a X;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}
 +
 +struct Z(u32);
 +
 +impl Deref for Z {
 +    type Target = u32;
 +
 +    fn deref(&self) -> &u32 {
 +        &self.0
 +    }
 +}
 +
 +impl std::fmt::Display for Z {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        write!(f, "Z")
 +    }
 +}
 +
 +macro_rules! my_macro {
 +    () => {
 +        // here be dragons, do not enter (or lint)
 +        println!("error: something failed at {}", Location::caller().to_string());
 +    };
 +}
 +
 +macro_rules! my_other_macro {
 +    () => {
 +        Location::caller().to_string()
 +    };
 +}
 +
 +fn main() {
 +    let x = &X(1);
 +    let x_ref = &x;
 +
 +    let _ = format!("error: something failed at {}", Location::caller());
 +    let _ = write!(
 +        stdout(),
 +        "error: something failed at {}",
 +        Location::caller()
 +    );
 +    let _ = writeln!(
 +        stdout(),
 +        "error: something failed at {}",
 +        Location::caller()
 +    );
 +    print!("error: something failed at {}", Location::caller());
 +    println!("error: something failed at {}", Location::caller());
 +    eprint!("error: something failed at {}", Location::caller());
 +    eprintln!("error: something failed at {}", Location::caller());
 +    let _ = format_args!("error: something failed at {}", Location::caller());
 +    assert!(true, "error: something failed at {}", Location::caller());
 +    assert_eq!(0, 0, "error: something failed at {}", Location::caller());
 +    assert_ne!(0, 0, "error: something failed at {}", Location::caller());
 +    panic!("error: something failed at {}", Location::caller());
 +    println!("{}", *X(1));
 +    println!("{}", ***Y(&X(1)));
 +    println!("{}", Z(1));
 +    println!("{}", **x);
 +    println!("{}", ***x_ref);
++    // https://github.com/rust-lang/rust-clippy/issues/7903
++    println!("{foo}{bar}", foo = "foo", bar = "bar");
++    println!("{foo}{bar}", foo = "foo", bar = "bar");
++    println!("{foo}{bar}", bar = "bar", foo = "foo");
++    println!("{foo}{bar}", bar = "bar", foo = "foo");
 +
++    // negative tests
 +    println!("error: something failed at {}", Somewhere.to_string());
++    // The next two tests are negative because caching the string might be faster than calling `<X as
++    // Display>::fmt` twice.
 +    println!("{} and again {0}", x.to_string());
++    println!("{foo}{foo}", foo = "foo".to_string());
 +    my_macro!();
 +    println!("error: something failed at {}", my_other_macro!());
++    // https://github.com/rust-lang/rust-clippy/issues/7903
++    println!("{foo}{foo:?}", foo = "foo".to_string());
 +}
index 164cc07066dc3b892022b616b34f4130083c12ce,0000000000000000000000000000000000000000..3a434c5bf002a3350a08a0da2988747de925bcc9
mode 100644,000000..100644
--- /dev/null
@@@ -1,105 -1,0 +1,117 @@@
 +// run-rustfix
 +
 +#![allow(unreachable_code)]
 +#![allow(unused_macros)]
 +#![allow(unused_variables)]
 +#![allow(clippy::assertions_on_constants)]
 +#![allow(clippy::eq_op)]
++#![allow(clippy::print_literal)]
 +#![warn(clippy::to_string_in_format_args)]
 +
 +use std::io::{stdout, Write};
 +use std::ops::Deref;
 +use std::panic::Location;
 +
 +struct Somewhere;
 +
 +impl ToString for Somewhere {
 +    fn to_string(&self) -> String {
 +        String::from("somewhere")
 +    }
 +}
 +
 +struct X(u32);
 +
 +impl Deref for X {
 +    type Target = u32;
 +
 +    fn deref(&self) -> &u32 {
 +        &self.0
 +    }
 +}
 +
 +struct Y<'a>(&'a X);
 +
 +impl<'a> Deref for Y<'a> {
 +    type Target = &'a X;
 +
 +    fn deref(&self) -> &Self::Target {
 +        &self.0
 +    }
 +}
 +
 +struct Z(u32);
 +
 +impl Deref for Z {
 +    type Target = u32;
 +
 +    fn deref(&self) -> &u32 {
 +        &self.0
 +    }
 +}
 +
 +impl std::fmt::Display for Z {
 +    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 +        write!(f, "Z")
 +    }
 +}
 +
 +macro_rules! my_macro {
 +    () => {
 +        // here be dragons, do not enter (or lint)
 +        println!("error: something failed at {}", Location::caller().to_string());
 +    };
 +}
 +
 +macro_rules! my_other_macro {
 +    () => {
 +        Location::caller().to_string()
 +    };
 +}
 +
 +fn main() {
 +    let x = &X(1);
 +    let x_ref = &x;
 +
 +    let _ = format!("error: something failed at {}", Location::caller().to_string());
 +    let _ = write!(
 +        stdout(),
 +        "error: something failed at {}",
 +        Location::caller().to_string()
 +    );
 +    let _ = writeln!(
 +        stdout(),
 +        "error: something failed at {}",
 +        Location::caller().to_string()
 +    );
 +    print!("error: something failed at {}", Location::caller().to_string());
 +    println!("error: something failed at {}", Location::caller().to_string());
 +    eprint!("error: something failed at {}", Location::caller().to_string());
 +    eprintln!("error: something failed at {}", Location::caller().to_string());
 +    let _ = format_args!("error: something failed at {}", Location::caller().to_string());
 +    assert!(true, "error: something failed at {}", Location::caller().to_string());
 +    assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string());
 +    assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string());
 +    panic!("error: something failed at {}", Location::caller().to_string());
 +    println!("{}", X(1).to_string());
 +    println!("{}", Y(&X(1)).to_string());
 +    println!("{}", Z(1).to_string());
 +    println!("{}", x.to_string());
 +    println!("{}", x_ref.to_string());
++    // https://github.com/rust-lang/rust-clippy/issues/7903
++    println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar");
++    println!("{foo}{bar}", foo = "foo", bar = "bar".to_string());
++    println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo");
++    println!("{foo}{bar}", bar = "bar", foo = "foo".to_string());
 +
++    // negative tests
 +    println!("error: something failed at {}", Somewhere.to_string());
++    // The next two tests are negative because caching the string might be faster than calling `<X as
++    // Display>::fmt` twice.
 +    println!("{} and again {0}", x.to_string());
++    println!("{foo}{foo}", foo = "foo".to_string());
 +    my_macro!();
 +    println!("error: something failed at {}", my_other_macro!());
++    // https://github.com/rust-lang/rust-clippy/issues/7903
++    println!("{foo}{foo:?}", foo = "foo".to_string());
 +}
index 9cfc97edeafb8215fabae9014bc1b543840a650c,0000000000000000000000000000000000000000..c0cbca507958d1306cfbf008fb3b1d16e2f3959d
mode 100644,000000..100644
--- /dev/null
@@@ -1,106 -1,0 +1,130 @@@
-   --> $DIR/format_args.rs:75:72
 +error: `to_string` applied to a type that implements `Display` in `format!` args
-   --> $DIR/format_args.rs:79:27
++  --> $DIR/format_args.rs:76:72
 +   |
 +LL |     let _ = format!("error: something failed at {}", Location::caller().to_string());
 +   |                                                                        ^^^^^^^^^^^^ help: remove this
 +   |
 +   = note: `-D clippy::to-string-in-format-args` implied by `-D warnings`
 +
 +error: `to_string` applied to a type that implements `Display` in `write!` args
-   --> $DIR/format_args.rs:84:27
++  --> $DIR/format_args.rs:80:27
 +   |
 +LL |         Location::caller().to_string()
 +   |                           ^^^^^^^^^^^^ help: remove this
 +
 +error: `to_string` applied to a type that implements `Display` in `writeln!` args
-   --> $DIR/format_args.rs:86:63
++  --> $DIR/format_args.rs:85:27
 +   |
 +LL |         Location::caller().to_string()
 +   |                           ^^^^^^^^^^^^ help: remove this
 +
 +error: `to_string` applied to a type that implements `Display` in `print!` args
-   --> $DIR/format_args.rs:87:65
++  --> $DIR/format_args.rs:87:63
 +   |
 +LL |     print!("error: something failed at {}", Location::caller().to_string());
 +   |                                                               ^^^^^^^^^^^^ help: remove this
 +
 +error: `to_string` applied to a type that implements `Display` in `println!` args
-   --> $DIR/format_args.rs:88:64
++  --> $DIR/format_args.rs:88:65
 +   |
 +LL |     println!("error: something failed at {}", Location::caller().to_string());
 +   |                                                                 ^^^^^^^^^^^^ help: remove this
 +
 +error: `to_string` applied to a type that implements `Display` in `eprint!` args
-   --> $DIR/format_args.rs:89:66
++  --> $DIR/format_args.rs:89:64
 +   |
 +LL |     eprint!("error: something failed at {}", Location::caller().to_string());
 +   |                                                                ^^^^^^^^^^^^ help: remove this
 +
 +error: `to_string` applied to a type that implements `Display` in `eprintln!` args
-   --> $DIR/format_args.rs:90:77
++  --> $DIR/format_args.rs:90:66
 +   |
 +LL |     eprintln!("error: something failed at {}", Location::caller().to_string());
 +   |                                                                  ^^^^^^^^^^^^ help: remove this
 +
 +error: `to_string` applied to a type that implements `Display` in `format_args!` args
-   --> $DIR/format_args.rs:91:70
++  --> $DIR/format_args.rs:91:77
 +   |
 +LL |     let _ = format_args!("error: something failed at {}", Location::caller().to_string());
 +   |                                                                             ^^^^^^^^^^^^ help: remove this
 +
 +error: `to_string` applied to a type that implements `Display` in `assert!` args
-   --> $DIR/format_args.rs:92:73
++  --> $DIR/format_args.rs:92:70
 +   |
 +LL |     assert!(true, "error: something failed at {}", Location::caller().to_string());
 +   |                                                                      ^^^^^^^^^^^^ help: remove this
 +
 +error: `to_string` applied to a type that implements `Display` in `assert_eq!` args
-   --> $DIR/format_args.rs:93:73
++  --> $DIR/format_args.rs:93:73
 +   |
 +LL |     assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string());
 +   |                                                                         ^^^^^^^^^^^^ help: remove this
 +
 +error: `to_string` applied to a type that implements `Display` in `assert_ne!` args
-   --> $DIR/format_args.rs:94:63
++  --> $DIR/format_args.rs:94:73
 +   |
 +LL |     assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string());
 +   |                                                                         ^^^^^^^^^^^^ help: remove this
 +
 +error: `to_string` applied to a type that implements `Display` in `panic!` args
-   --> $DIR/format_args.rs:95:20
++  --> $DIR/format_args.rs:95:63
 +   |
 +LL |     panic!("error: something failed at {}", Location::caller().to_string());
 +   |                                                               ^^^^^^^^^^^^ help: remove this
 +
 +error: `to_string` applied to a type that implements `Display` in `println!` args
-   --> $DIR/format_args.rs:96:20
++  --> $DIR/format_args.rs:96:20
 +   |
 +LL |     println!("{}", X(1).to_string());
 +   |                    ^^^^^^^^^^^^^^^^ help: use this: `*X(1)`
 +
 +error: `to_string` applied to a type that implements `Display` in `println!` args
-   --> $DIR/format_args.rs:97:24
++  --> $DIR/format_args.rs:97:20
 +   |
 +LL |     println!("{}", Y(&X(1)).to_string());
 +   |                    ^^^^^^^^^^^^^^^^^^^^ help: use this: `***Y(&X(1))`
 +
 +error: `to_string` applied to a type that implements `Display` in `println!` args
-   --> $DIR/format_args.rs:98:20
++  --> $DIR/format_args.rs:98:24
 +   |
 +LL |     println!("{}", Z(1).to_string());
 +   |                        ^^^^^^^^^^^^ help: remove this
 +
 +error: `to_string` applied to a type that implements `Display` in `println!` args
-   --> $DIR/format_args.rs:99:20
++  --> $DIR/format_args.rs:99:20
 +   |
 +LL |     println!("{}", x.to_string());
 +   |                    ^^^^^^^^^^^^^ help: use this: `**x`
 +
 +error: `to_string` applied to a type that implements `Display` in `println!` args
- error: aborting due to 17 previous errors
++  --> $DIR/format_args.rs:100:20
 +   |
 +LL |     println!("{}", x_ref.to_string());
 +   |                    ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref`
 +
++error: `to_string` applied to a type that implements `Display` in `println!` args
++  --> $DIR/format_args.rs:102:39
++   |
++LL |     println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar");
++   |                                       ^^^^^^^^^^^^ help: remove this
++
++error: `to_string` applied to a type that implements `Display` in `println!` args
++  --> $DIR/format_args.rs:103:52
++   |
++LL |     println!("{foo}{bar}", foo = "foo", bar = "bar".to_string());
++   |                                                    ^^^^^^^^^^^^ help: remove this
++
++error: `to_string` applied to a type that implements `Display` in `println!` args
++  --> $DIR/format_args.rs:104:39
++   |
++LL |     println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo");
++   |                                       ^^^^^^^^^^^^ help: remove this
++
++error: `to_string` applied to a type that implements `Display` in `println!` args
++  --> $DIR/format_args.rs:105:52
++   |
++LL |     println!("{foo}{bar}", bar = "bar", foo = "foo".to_string());
++   |                                                    ^^^^^^^^^^^^ help: remove this
++
++error: aborting due to 21 previous errors
 +
index a8c06c2bde6645e418bd8d3f76599e24be4d9c2e,0000000000000000000000000000000000000000..b24ddf7321e4000cf7fe20cee6ca5485ab6fab0f
mode 100644,000000..100644
--- /dev/null
@@@ -1,60 -1,0 +1,61 @@@
 +#![allow(clippy::assertions_on_constants)]
 +#![allow(clippy::eq_op)]
 +#![warn(clippy::format_in_format_args)]
 +#![warn(clippy::to_string_in_format_args)]
 +
 +use std::io::{stdout, Error, ErrorKind, Write};
 +use std::ops::Deref;
 +use std::panic::Location;
 +
 +macro_rules! my_macro {
 +    () => {
 +        // here be dragons, do not enter (or lint)
 +        println!("error: {}", format!("something failed at {}", Location::caller()));
 +    };
 +}
 +
 +macro_rules! my_other_macro {
 +    () => {
 +        format!("something failed at {}", Location::caller())
 +    };
 +}
 +
 +fn main() {
 +    let error = Error::new(ErrorKind::Other, "bad thing");
 +    let x = 'x';
 +
 +    println!("error: {}", format!("something failed at {}", Location::caller()));
 +    println!("{}: {}", error, format!("something failed at {}", Location::caller()));
 +    println!("{:?}: {}", error, format!("something failed at {}", Location::caller()));
 +    println!("{{}}: {}", format!("something failed at {}", Location::caller()));
 +    println!(r#"error: "{}""#, format!("something failed at {}", Location::caller()));
 +    println!("error: {}", format!(r#"something failed at "{}""#, Location::caller()));
 +    println!("error: {}", format!("something failed at {} {0}", Location::caller()));
 +    let _ = format!("error: {}", format!("something failed at {}", Location::caller()));
 +    let _ = write!(
 +        stdout(),
 +        "error: {}",
 +        format!("something failed at {}", Location::caller())
 +    );
 +    let _ = writeln!(
 +        stdout(),
 +        "error: {}",
 +        format!("something failed at {}", Location::caller())
 +    );
 +    print!("error: {}", format!("something failed at {}", Location::caller()));
 +    eprint!("error: {}", format!("something failed at {}", Location::caller()));
 +    eprintln!("error: {}", format!("something failed at {}", Location::caller()));
 +    let _ = format_args!("error: {}", format!("something failed at {}", Location::caller()));
 +    assert!(true, "error: {}", format!("something failed at {}", Location::caller()));
 +    assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
 +    assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
 +    panic!("error: {}", format!("something failed at {}", Location::caller()));
 +
++    // negative tests
 +    println!("error: {}", format_args!("something failed at {}", Location::caller()));
 +    println!("error: {:>70}", format!("something failed at {}", Location::caller()));
 +    println!("error: {} {0}", format!("something failed at {}", Location::caller()));
 +    println!("{} and again {0}", format!("hi {}", x));
 +    my_macro!();
 +    println!("error: {}", my_other_macro!());
 +}
index d3a920de4b6ad8a685f3c04096a3afd414826998,0000000000000000000000000000000000000000..858036692d68f401d36c464754b82662f150c540
mode 100644,000000..100644
--- /dev/null
@@@ -1,80 -1,0 +1,79 @@@
- // edition:2018
 +#![warn(clippy::future_not_send)]
 +
 +use std::cell::Cell;
 +use std::rc::Rc;
 +use std::sync::Arc;
 +
 +async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
 +    async { true }.await
 +}
 +
 +pub async fn public_future(rc: Rc<[u8]>) {
 +    async { true }.await;
 +}
 +
 +pub async fn public_send(arc: Arc<[u8]>) -> bool {
 +    async { false }.await
 +}
 +
 +async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
 +    true
 +}
 +
 +pub async fn public_future2(rc: Rc<[u8]>) {}
 +
 +pub async fn public_send2(arc: Arc<[u8]>) -> bool {
 +    false
 +}
 +
 +struct Dummy {
 +    rc: Rc<[u8]>,
 +}
 +
 +impl Dummy {
 +    async fn private_future(&self) -> usize {
 +        async { true }.await;
 +        self.rc.len()
 +    }
 +
 +    pub async fn public_future(&self) {
 +        self.private_future().await;
 +    }
 +
 +    #[allow(clippy::manual_async_fn)]
 +    pub fn public_send(&self) -> impl std::future::Future<Output = bool> {
 +        async { false }
 +    }
 +}
 +
 +async fn generic_future<T>(t: T) -> T
 +where
 +    T: Send,
 +{
 +    let rt = &t;
 +    async { true }.await;
 +    t
 +}
 +
 +async fn generic_future_send<T>(t: T)
 +where
 +    T: Send,
 +{
 +    async { true }.await;
 +}
 +
 +async fn unclear_future<T>(t: T) {}
 +
 +fn main() {
 +    let rc = Rc::new([1, 2, 3]);
 +    private_future(rc.clone(), &Cell::new(42));
 +    public_future(rc.clone());
 +    let arc = Arc::new([4, 5, 6]);
 +    public_send(arc);
 +    generic_future(42);
 +    generic_future_send(42);
 +
 +    let dummy = Dummy { rc };
 +    dummy.public_future();
 +    dummy.public_send();
 +}
index c734051ccf320b086567185414793a707c50a379,0000000000000000000000000000000000000000..3cc05e2fdbec65c0b9574b0c45b924f63bcd6ca5
mode 100644,000000..100644
--- /dev/null
@@@ -1,145 -1,0 +1,145 @@@
-   --> $DIR/future_not_send.rs:8:62
 +error: future cannot be sent between threads safely
-   --> $DIR/future_not_send.rs:9:5
++  --> $DIR/future_not_send.rs:7:62
 +   |
 +LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
 +   |                                                              ^^^^ future returned by `private_future` is not `Send`
 +   |
 +   = note: `-D clippy::future-not-send` implied by `-D warnings`
 +note: future is not `Send` as this value is used across an await
-   --> $DIR/future_not_send.rs:9:5
++  --> $DIR/future_not_send.rs:8:5
 +   |
 +LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
 +   |                         -- has type `std::rc::Rc<[u8]>` which is not `Send`
 +LL |     async { true }.await
 +   |     ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rc` maybe used later
 +LL | }
 +   | - `rc` is later dropped here
 +   = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
 +note: future is not `Send` as this value is used across an await
-   --> $DIR/future_not_send.rs:12:42
++  --> $DIR/future_not_send.rs:8:5
 +   |
 +LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
 +   |                                       ---- has type `&std::cell::Cell<usize>` which is not `Send`
 +LL |     async { true }.await
 +   |     ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `cell` maybe used later
 +LL | }
 +   | - `cell` is later dropped here
 +   = note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
 +
 +error: future cannot be sent between threads safely
-   --> $DIR/future_not_send.rs:13:5
++  --> $DIR/future_not_send.rs:11:42
 +   |
 +LL | pub async fn public_future(rc: Rc<[u8]>) {
 +   |                                          ^ future returned by `public_future` is not `Send`
 +   |
 +note: future is not `Send` as this value is used across an await
-   --> $DIR/future_not_send.rs:20:63
++  --> $DIR/future_not_send.rs:12:5
 +   |
 +LL | pub async fn public_future(rc: Rc<[u8]>) {
 +   |                            -- has type `std::rc::Rc<[u8]>` which is not `Send`
 +LL |     async { true }.await;
 +   |     ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rc` maybe used later
 +LL | }
 +   | - `rc` is later dropped here
 +   = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
 +
 +error: future cannot be sent between threads safely
-   --> $DIR/future_not_send.rs:20:26
++  --> $DIR/future_not_send.rs:19:63
 +   |
 +LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
 +   |                                                               ^^^^ future returned by `private_future2` is not `Send`
 +   |
 +note: captured value is not `Send`
-   --> $DIR/future_not_send.rs:20:40
++  --> $DIR/future_not_send.rs:19:26
 +   |
 +LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
 +   |                          ^^ has type `std::rc::Rc<[u8]>` which is not `Send`
 +   = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
 +note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
-   --> $DIR/future_not_send.rs:24:43
++  --> $DIR/future_not_send.rs:19:40
 +   |
 +LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
 +   |                                        ^^^^ has type `&std::cell::Cell<usize>` which is not `Send`, because `std::cell::Cell<usize>` is not `Sync`
 +   = note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
 +
 +error: future cannot be sent between threads safely
-   --> $DIR/future_not_send.rs:24:29
++  --> $DIR/future_not_send.rs:23:43
 +   |
 +LL | pub async fn public_future2(rc: Rc<[u8]>) {}
 +   |                                           ^ future returned by `public_future2` is not `Send`
 +   |
 +note: captured value is not `Send`
-   --> $DIR/future_not_send.rs:35:39
++  --> $DIR/future_not_send.rs:23:29
 +   |
 +LL | pub async fn public_future2(rc: Rc<[u8]>) {}
 +   |                             ^^ has type `std::rc::Rc<[u8]>` which is not `Send`
 +   = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
 +
 +error: future cannot be sent between threads safely
-   --> $DIR/future_not_send.rs:36:9
++  --> $DIR/future_not_send.rs:34:39
 +   |
 +LL |     async fn private_future(&self) -> usize {
 +   |                                       ^^^^^ future returned by `private_future` is not `Send`
 +   |
 +note: future is not `Send` as this value is used across an await
-   --> $DIR/future_not_send.rs:40:39
++  --> $DIR/future_not_send.rs:35:9
 +   |
 +LL |     async fn private_future(&self) -> usize {
 +   |                             ----- has type `&Dummy` which is not `Send`
 +LL |         async { true }.await;
 +   |         ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `&self` maybe used later
 +LL |         self.rc.len()
 +LL |     }
 +   |     - `&self` is later dropped here
 +   = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
 +
 +error: future cannot be sent between threads safely
-   --> $DIR/future_not_send.rs:41:9
++  --> $DIR/future_not_send.rs:39:39
 +   |
 +LL |     pub async fn public_future(&self) {
 +   |                                       ^ future returned by `public_future` is not `Send`
 +   |
 +note: future is not `Send` as this value is used across an await
-   --> $DIR/future_not_send.rs:50:37
++  --> $DIR/future_not_send.rs:40:9
 +   |
 +LL |     pub async fn public_future(&self) {
 +   |                                ----- has type `&Dummy` which is not `Send`
 +LL |         self.private_future().await;
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `&self` maybe used later
 +LL |     }
 +   |     - `&self` is later dropped here
 +   = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
 +
 +error: future cannot be sent between threads safely
-   --> $DIR/future_not_send.rs:55:5
++  --> $DIR/future_not_send.rs:49:37
 +   |
 +LL | async fn generic_future<T>(t: T) -> T
 +   |                                     ^ future returned by `generic_future` is not `Send`
 +   |
 +note: future is not `Send` as this value is used across an await
-   --> $DIR/future_not_send.rs:66:34
++  --> $DIR/future_not_send.rs:54:5
 +   |
 +LL |     let rt = &t;
 +   |         -- has type `&T` which is not `Send`
 +LL |     async { true }.await;
 +   |     ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rt` maybe used later
 +LL |     t
 +LL | }
 +   | - `rt` is later dropped here
 +   = note: `T` doesn't implement `std::marker::Sync`
 +
 +error: future cannot be sent between threads safely
-   --> $DIR/future_not_send.rs:66:28
++  --> $DIR/future_not_send.rs:65:34
 +   |
 +LL | async fn unclear_future<T>(t: T) {}
 +   |                                  ^ future returned by `unclear_future` is not `Send`
 +   |
 +note: captured value is not `Send`
++  --> $DIR/future_not_send.rs:65:28
 +   |
 +LL | async fn unclear_future<T>(t: T) {}
 +   |                            ^ has type `T` which is not `Send`
 +   = note: `T` doesn't implement `std::marker::Send`
 +
 +error: aborting due to 8 previous errors
 +
index dc3fb1ceac9a44ba1dd69d063040b49f9feff534,0000000000000000000000000000000000000000..b7012b43d29766d154786e866357b15b838d5756
mode 100644,000000..100644
--- /dev/null
@@@ -1,19 -1,0 +1,29 @@@
 +#![warn(clippy::all)]
 +#![warn(clippy::if_not_else)]
 +
++fn foo() -> bool {
++    unimplemented!()
++}
 +fn bla() -> bool {
 +    unimplemented!()
 +}
 +
 +fn main() {
 +    if !bla() {
 +        println!("Bugs");
 +    } else {
 +        println!("Bunny");
 +    }
 +    if 4 != 5 {
 +        println!("Bugs");
 +    } else {
 +        println!("Bunny");
 +    }
++    if !foo() {
++        println!("Foo");
++    } else if !bla() {
++        println!("Bugs");
++    } else {
++        println!("Bunny");
++    }
 +}
index 53d1b86d02a962a639631ea29c6415573cb8ee51,0000000000000000000000000000000000000000..8c8cc44bb035882e2484a96a8874351632c6be89
mode 100644,000000..100644
--- /dev/null
@@@ -1,27 -1,0 +1,27 @@@
-   --> $DIR/if_not_else.rs:9:5
 +error: unnecessary boolean `not` operation
-   --> $DIR/if_not_else.rs:14:5
++  --> $DIR/if_not_else.rs:12:5
 +   |
 +LL | /     if !bla() {
 +LL | |         println!("Bugs");
 +LL | |     } else {
 +LL | |         println!("Bunny");
 +LL | |     }
 +   | |_____^
 +   |
 +   = note: `-D clippy::if-not-else` implied by `-D warnings`
 +   = help: remove the `!` and swap the blocks of the `if`/`else`
 +
 +error: unnecessary `!=` operation
++  --> $DIR/if_not_else.rs:17:5
 +   |
 +LL | /     if 4 != 5 {
 +LL | |         println!("Bugs");
 +LL | |     } else {
 +LL | |         println!("Bunny");
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: change to `==` and swap the blocks of the `if`/`else`
 +
 +error: aborting due to 2 previous errors
 +
index aa69b0974101c822a06a790c742bed645e46813b,0000000000000000000000000000000000000000..fd96ca3f466eabe7cc9ed034040925a658f274c9
mode 100644,000000..100644
--- /dev/null
@@@ -1,103 -1,0 +1,102 @@@
- // edition:2018
 +// aux-build:implicit_hasher_macros.rs
 +#![deny(clippy::implicit_hasher)]
 +#![allow(unused)]
 +
 +#[macro_use]
 +extern crate implicit_hasher_macros;
 +
 +use std::cmp::Eq;
 +use std::collections::{HashMap, HashSet};
 +use std::hash::{BuildHasher, Hash};
 +
 +pub trait Foo<T>: Sized {
 +    fn make() -> (Self, Self);
 +}
 +
 +impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> {
 +    fn make() -> (Self, Self) {
 +        // OK, don't suggest to modify these
 +        let _: HashMap<i32, i32> = HashMap::new();
 +        let _: HashSet<i32> = HashSet::new();
 +
 +        (HashMap::new(), HashMap::with_capacity(10))
 +    }
 +}
 +impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) {
 +    fn make() -> (Self, Self) {
 +        ((HashMap::new(),), (HashMap::with_capacity(10),))
 +    }
 +}
 +impl Foo<i16> for HashMap<String, String> {
 +    fn make() -> (Self, Self) {
 +        (HashMap::new(), HashMap::with_capacity(10))
 +    }
 +}
 +
 +impl<K: Hash + Eq, V, S: BuildHasher + Default> Foo<i32> for HashMap<K, V, S> {
 +    fn make() -> (Self, Self) {
 +        (HashMap::default(), HashMap::with_capacity_and_hasher(10, S::default()))
 +    }
 +}
 +impl<S: BuildHasher + Default> Foo<i64> for HashMap<String, String, S> {
 +    fn make() -> (Self, Self) {
 +        (HashMap::default(), HashMap::with_capacity_and_hasher(10, S::default()))
 +    }
 +}
 +
 +impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
 +    fn make() -> (Self, Self) {
 +        (HashSet::new(), HashSet::with_capacity(10))
 +    }
 +}
 +impl Foo<i16> for HashSet<String> {
 +    fn make() -> (Self, Self) {
 +        (HashSet::new(), HashSet::with_capacity(10))
 +    }
 +}
 +
 +impl<T: Hash + Eq, S: BuildHasher + Default> Foo<i32> for HashSet<T, S> {
 +    fn make() -> (Self, Self) {
 +        (HashSet::default(), HashSet::with_capacity_and_hasher(10, S::default()))
 +    }
 +}
 +impl<S: BuildHasher + Default> Foo<i64> for HashSet<String, S> {
 +    fn make() -> (Self, Self) {
 +        (HashSet::default(), HashSet::with_capacity_and_hasher(10, S::default()))
 +    }
 +}
 +
 +pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
 +
 +macro_rules! gen {
 +    (impl) => {
 +        impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
 +            fn make() -> (Self, Self) {
 +                (HashMap::new(), HashMap::with_capacity(10))
 +            }
 +        }
 +    };
 +
 +    (fn $name:ident) => {
 +        pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
 +    };
 +}
 +#[rustfmt::skip]
 +gen!(impl);
 +gen!(fn bar);
 +
 +// When the macro is in a different file, the suggestion spans can't be combined properly
 +// and should not cause an ICE
 +// See #2707
 +#[macro_use]
 +#[path = "auxiliary/test_macro.rs"]
 +pub mod test_macro;
 +__implicit_hasher_test_macro!(impl<K, V> for HashMap<K, V> where V: test_macro::A);
 +
 +// #4260
 +implicit_hasher_fn!();
 +
 +// #7712
 +pub async fn election_vote(_data: HashMap<i32, i32>) {}
 +
 +fn main() {}
index 3f5f56b923fe2453b25e792bc9b5a912f880cd90,0000000000000000000000000000000000000000..59b0fba2a4cfee460b8e2d120a91b01fb1c3d952
mode 100644,000000..100644
--- /dev/null
@@@ -1,164 -1,0 +1,164 @@@
-   --> $DIR/implicit_hasher.rs:17:35
 +error: impl for `HashMap` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:3:9
++  --> $DIR/implicit_hasher.rs:16:35
 +   |
 +LL | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> {
 +   |                                   ^^^^^^^^^^^^^
 +   |
 +note: the lint level is defined here
-   --> $DIR/implicit_hasher.rs:26:36
++  --> $DIR/implicit_hasher.rs:2:9
 +   |
 +LL | #![deny(clippy::implicit_hasher)]
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^
 +help: consider adding a type parameter
 +   |
 +LL | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashMap<K, V, S> {
 +   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~             ~~~~~~~~~~~~~~~~
 +help: ...and use generic constructor
 +   |
 +LL |         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
 +   |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +error: impl for `HashMap` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:31:19
++  --> $DIR/implicit_hasher.rs:25:36
 +   |
 +LL | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) {
 +   |                                    ^^^^^^^^^^^^^
 +   |
 +help: consider adding a type parameter
 +   |
 +LL | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for (HashMap<K, V, S>,) {
 +   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~              ~~~~~~~~~~~~~~~~
 +help: ...and use generic constructor
 +   |
 +LL |         ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Default::default()),))
 +   |           ~~~~~~~~~~~~~~~~~~     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +error: impl for `HashMap` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:48:32
++  --> $DIR/implicit_hasher.rs:30:19
 +   |
 +LL | impl Foo<i16> for HashMap<String, String> {
 +   |                   ^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a type parameter
 +   |
 +LL | impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashMap<String, String, S> {
 +   |     +++++++++++++++++++++++++++++++++++++++              ~~~~~~~~~~~~~~~~~~~~~~~~~~
 +help: ...and use generic constructor
 +   |
 +LL |         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
 +   |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +error: impl for `HashSet` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:53:19
++  --> $DIR/implicit_hasher.rs:47:32
 +   |
 +LL | impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
 +   |                                ^^^^^^^^^^
 +   |
 +help: consider adding a type parameter
 +   |
 +LL | impl<T: Hash + Eq, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashSet<T, S> {
 +   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~             ~~~~~~~~~~~~~
 +help: ...and use generic constructor
 +   |
 +LL |         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
 +   |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +error: impl for `HashSet` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:70:23
++  --> $DIR/implicit_hasher.rs:52:19
 +   |
 +LL | impl Foo<i16> for HashSet<String> {
 +   |                   ^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a type parameter
 +   |
 +LL | impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashSet<String, S> {
 +   |     +++++++++++++++++++++++++++++++++++++++              ~~~~~~~~~~~~~~~~~~
 +help: ...and use generic constructor
 +   |
 +LL |         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
 +   |          ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +error: parameter of type `HashMap` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:70:53
++  --> $DIR/implicit_hasher.rs:69:23
 +   |
 +LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
 +   |                       ^^^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a type parameter
 +   |
 +LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) {}
 +   |           +++++++++++++++++++++++++++++            ~~~~~~~~~~~~~~~~~~~~
 +
 +error: parameter of type `HashSet` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:74:43
++  --> $DIR/implicit_hasher.rs:69:53
 +   |
 +LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
 +   |                                                     ^^^^^^^^^^^^
 +   |
 +help: consider adding a type parameter
 +   |
 +LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {}
 +   |           +++++++++++++++++++++++++++++                                          ~~~~~~~~~~~~~~~
 +
 +error: impl for `HashMap` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:82:33
++  --> $DIR/implicit_hasher.rs:73:43
 +   |
 +LL |         impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
 +   |                                           ^^^^^^^^^^^^^
 +...
 +LL | gen!(impl);
 +   | ---------- in this macro invocation
 +   |
 +   = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info)
 +help: consider adding a type parameter
 +   |
 +LL |         impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<u8> for HashMap<K, V, S> {
 +   |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~             ~~~~~~~~~~~~~~~~
 +help: ...and use generic constructor
 +   |
 +LL |                 (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
 +   |                  ~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +error: parameter of type `HashMap` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:82:63
++  --> $DIR/implicit_hasher.rs:81:33
 +   |
 +LL |         pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
 +   |                                 ^^^^^^^^^^^^^^^^^
 +...
 +LL | gen!(fn bar);
 +   | ------------ in this macro invocation
 +   |
 +   = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info)
 +help: consider adding a type parameter
 +   |
 +LL |         pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) {}
 +   |                     +++++++++++++++++++++++++++++            ~~~~~~~~~~~~~~~~~~~~
 +
 +error: parameter of type `HashSet` should be generalized over different hashers
-   --> $DIR/implicit_hasher.rs:101:35
++  --> $DIR/implicit_hasher.rs:81:63
 +   |
 +LL |         pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
 +   |                                                               ^^^^^^^^^^^^
 +...
 +LL | gen!(fn bar);
 +   | ------------ in this macro invocation
 +   |
 +   = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info)
 +help: consider adding a type parameter
 +   |
 +LL |         pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {}
 +   |                     +++++++++++++++++++++++++++++                                          ~~~~~~~~~~~~~~~
 +
 +error: parameter of type `HashMap` should be generalized over different hashers
++  --> $DIR/implicit_hasher.rs:100:35
 +   |
 +LL | pub async fn election_vote(_data: HashMap<i32, i32>) {}
 +   |                                   ^^^^^^^^^^^^^^^^^
 +   |
 +help: consider adding a type parameter
 +   |
 +LL | pub async fn election_vote<S: ::std::hash::BuildHasher>(_data: HashMap<i32, i32, S>) {}
 +   |                           +++++++++++++++++++++++++++++        ~~~~~~~~~~~~~~~~~~~~
 +
 +error: aborting due to 11 previous errors
 +
index 7698b88a88c8aa80a143ac27ab11e145a880ef51,0000000000000000000000000000000000000000..a51f7bc6a29ffff52a301b84053f3c8f58bddc53
mode 100644,000000..100644
--- /dev/null
@@@ -1,131 -1,0 +1,130 @@@
- // edition:2018
 +// run-rustfix
 +
 +#![warn(clippy::implicit_return)]
 +#![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)]
 +
 +fn test_end_of_fn() -> bool {
 +    if true {
 +        // no error!
 +        return true;
 +    }
 +
 +    return true
 +}
 +
 +fn test_if_block() -> bool {
 +    if true { return true } else { return false }
 +}
 +
 +#[rustfmt::skip]
 +fn test_match(x: bool) -> bool {
 +    match x {
 +        true => return false,
 +        false => { return true },
 +    }
 +}
 +
 +fn test_match_with_unreachable(x: bool) -> bool {
 +    match x {
 +        true => return false,
 +        false => unreachable!(),
 +    }
 +}
 +
 +fn test_loop() -> bool {
 +    loop {
 +        return true;
 +    }
 +}
 +
 +fn test_loop_with_block() -> bool {
 +    loop {
 +        {
 +            return true;
 +        }
 +    }
 +}
 +
 +fn test_loop_with_nests() -> bool {
 +    loop {
 +        if true {
 +            return true;
 +        } else {
 +            let _ = true;
 +        }
 +    }
 +}
 +
 +#[allow(clippy::redundant_pattern_matching)]
 +fn test_loop_with_if_let() -> bool {
 +    loop {
 +        if let Some(x) = Some(true) {
 +            return x;
 +        }
 +    }
 +}
 +
 +fn test_closure() {
 +    #[rustfmt::skip]
 +    let _ = || { return true };
 +    let _ = || return true;
 +}
 +
 +fn test_panic() -> bool {
 +    panic!()
 +}
 +
 +fn test_return_macro() -> String {
 +    return format!("test {}", "test")
 +}
 +
 +fn macro_branch_test() -> bool {
 +    macro_rules! m {
 +        ($t:expr, $f:expr) => {
 +            if true { $t } else { $f }
 +        };
 +    }
 +    return m!(true, false)
 +}
 +
 +fn loop_test() -> bool {
 +    'outer: loop {
 +        if true {
 +            return true;
 +        }
 +
 +        let _ = loop {
 +            if false {
 +                return false;
 +            }
 +            if true {
 +                break true;
 +            }
 +        };
 +    }
 +}
 +
 +fn loop_macro_test() -> bool {
 +    macro_rules! m {
 +        ($e:expr) => {
 +            break $e
 +        };
 +    }
 +    return loop {
 +        m!(true);
 +    }
 +}
 +
 +fn divergent_test() -> bool {
 +    fn diverge() -> ! {
 +        panic!()
 +    }
 +    diverge()
 +}
 +
 +// issue #6940
 +async fn foo() -> bool {
 +    return true
 +}
 +
 +fn main() {}
index 45bbc2ec670e05463d1a0f8d6f8d5fc557561cfe,0000000000000000000000000000000000000000..03f8ec49d51e5457a57e2c9a71e30669fb984b1d
mode 100644,000000..100644
--- /dev/null
@@@ -1,131 -1,0 +1,130 @@@
- // edition:2018
 +// run-rustfix
 +
 +#![warn(clippy::implicit_return)]
 +#![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)]
 +
 +fn test_end_of_fn() -> bool {
 +    if true {
 +        // no error!
 +        return true;
 +    }
 +
 +    true
 +}
 +
 +fn test_if_block() -> bool {
 +    if true { true } else { false }
 +}
 +
 +#[rustfmt::skip]
 +fn test_match(x: bool) -> bool {
 +    match x {
 +        true => false,
 +        false => { true },
 +    }
 +}
 +
 +fn test_match_with_unreachable(x: bool) -> bool {
 +    match x {
 +        true => return false,
 +        false => unreachable!(),
 +    }
 +}
 +
 +fn test_loop() -> bool {
 +    loop {
 +        break true;
 +    }
 +}
 +
 +fn test_loop_with_block() -> bool {
 +    loop {
 +        {
 +            break true;
 +        }
 +    }
 +}
 +
 +fn test_loop_with_nests() -> bool {
 +    loop {
 +        if true {
 +            break true;
 +        } else {
 +            let _ = true;
 +        }
 +    }
 +}
 +
 +#[allow(clippy::redundant_pattern_matching)]
 +fn test_loop_with_if_let() -> bool {
 +    loop {
 +        if let Some(x) = Some(true) {
 +            return x;
 +        }
 +    }
 +}
 +
 +fn test_closure() {
 +    #[rustfmt::skip]
 +    let _ = || { true };
 +    let _ = || true;
 +}
 +
 +fn test_panic() -> bool {
 +    panic!()
 +}
 +
 +fn test_return_macro() -> String {
 +    format!("test {}", "test")
 +}
 +
 +fn macro_branch_test() -> bool {
 +    macro_rules! m {
 +        ($t:expr, $f:expr) => {
 +            if true { $t } else { $f }
 +        };
 +    }
 +    m!(true, false)
 +}
 +
 +fn loop_test() -> bool {
 +    'outer: loop {
 +        if true {
 +            break true;
 +        }
 +
 +        let _ = loop {
 +            if false {
 +                break 'outer false;
 +            }
 +            if true {
 +                break true;
 +            }
 +        };
 +    }
 +}
 +
 +fn loop_macro_test() -> bool {
 +    macro_rules! m {
 +        ($e:expr) => {
 +            break $e
 +        };
 +    }
 +    loop {
 +        m!(true);
 +    }
 +}
 +
 +fn divergent_test() -> bool {
 +    fn diverge() -> ! {
 +        panic!()
 +    }
 +    diverge()
 +}
 +
 +// issue #6940
 +async fn foo() -> bool {
 +    true
 +}
 +
 +fn main() {}
index 5e078b15ce393f6070b3f932ec0553d0c880f91f,0000000000000000000000000000000000000000..522bc3bf895a7a3159dccdb74e56fe032c10c483
mode 100644,000000..100644
--- /dev/null
@@@ -1,109 -1,0 +1,109 @@@
-   --> $DIR/implicit_return.rs:13:5
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:17:15
++  --> $DIR/implicit_return.rs:12:5
 +   |
 +LL |     true
 +   |     ^^^^ help: add `return` as shown: `return true`
 +   |
 +   = note: `-D clippy::implicit-return` implied by `-D warnings`
 +
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:17:29
++  --> $DIR/implicit_return.rs:16:15
 +   |
 +LL |     if true { true } else { false }
 +   |               ^^^^ help: add `return` as shown: `return true`
 +
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:23:17
++  --> $DIR/implicit_return.rs:16:29
 +   |
 +LL |     if true { true } else { false }
 +   |                             ^^^^^ help: add `return` as shown: `return false`
 +
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:24:20
++  --> $DIR/implicit_return.rs:22:17
 +   |
 +LL |         true => false,
 +   |                 ^^^^^ help: add `return` as shown: `return false`
 +
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:37:9
++  --> $DIR/implicit_return.rs:23:20
 +   |
 +LL |         false => { true },
 +   |                    ^^^^ help: add `return` as shown: `return true`
 +
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:44:13
++  --> $DIR/implicit_return.rs:36:9
 +   |
 +LL |         break true;
 +   |         ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 +
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:52:13
++  --> $DIR/implicit_return.rs:43:13
 +   |
 +LL |             break true;
 +   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 +
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:70:18
++  --> $DIR/implicit_return.rs:51:13
 +   |
 +LL |             break true;
 +   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 +
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:71:16
++  --> $DIR/implicit_return.rs:69:18
 +   |
 +LL |     let _ = || { true };
 +   |                  ^^^^ help: add `return` as shown: `return true`
 +
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:79:5
++  --> $DIR/implicit_return.rs:70:16
 +   |
 +LL |     let _ = || true;
 +   |                ^^^^ help: add `return` as shown: `return true`
 +
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:88:5
++  --> $DIR/implicit_return.rs:78:5
 +   |
 +LL |     format!("test {}", "test")
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")`
 +
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:94:13
++  --> $DIR/implicit_return.rs:87:5
 +   |
 +LL |     m!(true, false)
 +   |     ^^^^^^^^^^^^^^^ help: add `return` as shown: `return m!(true, false)`
 +
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:99:17
++  --> $DIR/implicit_return.rs:93:13
 +   |
 +LL |             break true;
 +   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
 +
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:114:5
++  --> $DIR/implicit_return.rs:98:17
 +   |
 +LL |                 break 'outer false;
 +   |                 ^^^^^^^^^^^^^^^^^^ help: change `break` to `return` as shown: `return false`
 +
 +error: missing `return` statement
-   --> $DIR/implicit_return.rs:128:5
++  --> $DIR/implicit_return.rs:113:5
 +   |
 +LL | /     loop {
 +LL | |         m!(true);
 +LL | |     }
 +   | |_____^
 +   |
 +help: add `return` as shown
 +   |
 +LL ~     return loop {
 +LL +         m!(true);
 +LL +     }
 +   |
 +
 +error: missing `return` statement
++  --> $DIR/implicit_return.rs:127:5
 +   |
 +LL |     true
 +   |     ^^^^ help: add `return` as shown: `return true`
 +
 +error: aborting due to 16 previous errors
 +
index d1025743790a9747bfb95c6bb746d0b1e15b917c,0000000000000000000000000000000000000000..eb66d1afddce39dfce67d421a7229232b52b2b6f
mode 100644,000000..100644
--- /dev/null
@@@ -1,74 -1,0 +1,73 @@@
- // edition:2018
 +// run-rustfix
 +#![warn(clippy::inconsistent_struct_constructor)]
 +#![allow(clippy::redundant_field_names)]
 +#![allow(clippy::unnecessary_operation)]
 +#![allow(clippy::no_effect)]
 +#![allow(dead_code)]
 +
 +#[derive(Default)]
 +struct Foo {
 +    x: i32,
 +    y: i32,
 +    z: i32,
 +}
 +
 +macro_rules! new_foo {
 +    () => {
 +        let x = 1;
 +        let y = 1;
 +        let z = 1;
 +        Foo { y, x, z }
 +    };
 +}
 +
 +mod without_base {
 +    use super::Foo;
 +
 +    fn test() {
 +        let x = 1;
 +        let y = 1;
 +        let z = 1;
 +
 +        // Should lint.
 +        Foo { x, y, z };
 +
 +        // Should NOT lint.
 +        // issue #7069.
 +        new_foo!();
 +
 +        // Shoule NOT lint because the order is the same as in the definition.
 +        Foo { x, y, z };
 +
 +        // Should NOT lint because z is not a shorthand init.
 +        Foo { y, x, z: z };
 +    }
 +}
 +
 +mod with_base {
 +    use super::Foo;
 +
 +    fn test() {
 +        let x = 1;
 +        let z = 1;
 +
 +        // Should lint.
 +        Foo { x, z, ..Default::default() };
 +
 +        // Should NOT lint because the order is consistent with the definition.
 +        Foo {
 +            x,
 +            z,
 +            ..Default::default()
 +        };
 +
 +        // Should NOT lint because z is not a shorthand init.
 +        Foo {
 +            z: z,
 +            x,
 +            ..Default::default()
 +        };
 +    }
 +}
 +
 +fn main() {}
index b095aa64a2174371e94d9f2c240ed910c9c893ca,0000000000000000000000000000000000000000..5caadc7c62083fb2b214df04ded3b16e2bb665f7
mode 100644,000000..100644
--- /dev/null
@@@ -1,78 -1,0 +1,77 @@@
- // edition:2018
 +// run-rustfix
 +#![warn(clippy::inconsistent_struct_constructor)]
 +#![allow(clippy::redundant_field_names)]
 +#![allow(clippy::unnecessary_operation)]
 +#![allow(clippy::no_effect)]
 +#![allow(dead_code)]
 +
 +#[derive(Default)]
 +struct Foo {
 +    x: i32,
 +    y: i32,
 +    z: i32,
 +}
 +
 +macro_rules! new_foo {
 +    () => {
 +        let x = 1;
 +        let y = 1;
 +        let z = 1;
 +        Foo { y, x, z }
 +    };
 +}
 +
 +mod without_base {
 +    use super::Foo;
 +
 +    fn test() {
 +        let x = 1;
 +        let y = 1;
 +        let z = 1;
 +
 +        // Should lint.
 +        Foo { y, x, z };
 +
 +        // Should NOT lint.
 +        // issue #7069.
 +        new_foo!();
 +
 +        // Shoule NOT lint because the order is the same as in the definition.
 +        Foo { x, y, z };
 +
 +        // Should NOT lint because z is not a shorthand init.
 +        Foo { y, x, z: z };
 +    }
 +}
 +
 +mod with_base {
 +    use super::Foo;
 +
 +    fn test() {
 +        let x = 1;
 +        let z = 1;
 +
 +        // Should lint.
 +        Foo {
 +            z,
 +            x,
 +            ..Default::default()
 +        };
 +
 +        // Should NOT lint because the order is consistent with the definition.
 +        Foo {
 +            x,
 +            z,
 +            ..Default::default()
 +        };
 +
 +        // Should NOT lint because z is not a shorthand init.
 +        Foo {
 +            z: z,
 +            x,
 +            ..Default::default()
 +        };
 +    }
 +}
 +
 +fn main() {}
index ef308dedb1661c331703d68d9ab973477f473d51,0000000000000000000000000000000000000000..c90189e964f09e68cea01babbb5d25ba03689909
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,20 @@@
-   --> $DIR/inconsistent_struct_constructor.rs:34:9
 +error: struct constructor field order is inconsistent with struct definition field order
-   --> $DIR/inconsistent_struct_constructor.rs:56:9
++  --> $DIR/inconsistent_struct_constructor.rs:33:9
 +   |
 +LL |         Foo { y, x, z };
 +   |         ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }`
 +   |
 +   = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings`
 +
 +error: struct constructor field order is inconsistent with struct definition field order
++  --> $DIR/inconsistent_struct_constructor.rs:55:9
 +   |
 +LL | /         Foo {
 +LL | |             z,
 +LL | |             x,
 +LL | |             ..Default::default()
 +LL | |         };
 +   | |_________^ help: try: `Foo { x, z, ..Default::default() }`
 +
 +error: aborting due to 2 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..463a48b24a321e5ed8a91c20fee0029c35876f42
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,19 @@@
++error: sub-expression diverges
++  --> $DIR/issue-7447.rs:23:15
++   |
++LL |     byte_view(panic!());
++   |               ^^^^^^^^
++   |
++   = note: `-D clippy::diverging-sub-expression` implied by `-D warnings`
++   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
++
++error: sub-expression diverges
++  --> $DIR/issue-7447.rs:24:19
++   |
++LL |     group_entries(panic!());
++   |                   ^^^^^^^^
++   |
++   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
++
++error: aborting due to 2 previous errors
++
index cc699b79e433ca39756717f16714487a05421da7,0000000000000000000000000000000000000000..d9d48189bd74e741f381f9449783ecefd5cce514
mode 100644,000000..100644
--- /dev/null
@@@ -1,39 -1,0 +1,38 @@@
- // edition:2018
 +#![allow(dead_code)]
 +
 +async fn sink1<'a>(_: &'a str) {} // lint
 +async fn sink1_elided(_: &str) {} // ok
 +
 +// lint
 +async fn one_to_one<'a>(s: &'a str) -> &'a str {
 +    s
 +}
 +
 +// ok
 +async fn one_to_one_elided(s: &str) -> &str {
 +    s
 +}
 +
 +// ok
 +async fn all_to_one<'a>(a: &'a str, _b: &'a str) -> &'a str {
 +    a
 +}
 +
 +// async fn unrelated(_: &str, _: &str) {} // Not allowed in async fn
 +
 +// #3988
 +struct Foo;
 +impl Foo {
 +    // ok
 +    pub async fn new(&mut self) -> Self {
 +        Foo {}
 +    }
 +}
 +
 +// rust-lang/rust#61115
 +// ok
 +async fn print(s: &str) {
 +    println!("{}", s);
 +}
 +
 +fn main() {}
index 0426508e622f8fd471a61e0464e1ba53ccf537a3,0000000000000000000000000000000000000000..20419457b47f0ee3018f9ec888939e1d96cfbae4
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,16 @@@
-   --> $DIR/issue_4266.rs:4:1
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/issue_4266.rs:8:1
++  --> $DIR/issue_4266.rs:3:1
 +   |
 +LL | async fn sink1<'a>(_: &'a str) {} // lint
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::needless-lifetimes` implied by `-D warnings`
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
++  --> $DIR/issue_4266.rs:7:1
 +   |
 +LL | async fn one_to_one<'a>(s: &'a str) -> &'a str {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: aborting due to 2 previous errors
 +
index b9d66347c27487b9857e99e2be575796273ac6b7,0000000000000000000000000000000000000000..1e938e72b57775356d326a9f0bac9dcae6b57525
mode 100644,000000..100644
--- /dev/null
@@@ -1,287 -1,0 +1,285 @@@
- // edition:2018
 +#![warn(clippy::len_without_is_empty)]
 +#![allow(dead_code, unused)]
 +
 +pub struct PubOne;
 +
 +impl PubOne {
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +}
 +
 +impl PubOne {
 +    // A second impl for this struct -- the error span shouldn't mention this.
 +    pub fn irrelevant(&self) -> bool {
 +        false
 +    }
 +}
 +
 +// Identical to `PubOne`, but with an `allow` attribute on the impl complaining `len`.
 +pub struct PubAllowed;
 +
 +#[allow(clippy::len_without_is_empty)]
 +impl PubAllowed {
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +}
 +
 +// No `allow` attribute on this impl block, but that doesn't matter -- we only require one on the
 +// impl containing `len`.
 +impl PubAllowed {
 +    pub fn irrelevant(&self) -> bool {
 +        false
 +    }
 +}
 +
 +pub struct PubAllowedFn;
 +
 +impl PubAllowedFn {
 +    #[allow(clippy::len_without_is_empty)]
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +}
 +
 +#[allow(clippy::len_without_is_empty)]
 +pub struct PubAllowedStruct;
 +
 +impl PubAllowedStruct {
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +}
 +
 +pub trait PubTraitsToo {
 +    fn len(&self) -> isize;
 +}
 +
 +impl PubTraitsToo for One {
 +    fn len(&self) -> isize {
 +        0
 +    }
 +}
 +
 +pub struct HasIsEmpty;
 +
 +impl HasIsEmpty {
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +
 +    fn is_empty(&self) -> bool {
 +        false
 +    }
 +}
 +
 +pub struct HasWrongIsEmpty;
 +
 +impl HasWrongIsEmpty {
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +
 +    pub fn is_empty(&self, x: u32) -> bool {
 +        false
 +    }
 +}
 +
 +pub struct MismatchedSelf;
 +
 +impl MismatchedSelf {
 +    pub fn len(self) -> isize {
 +        1
 +    }
 +
 +    pub fn is_empty(&self) -> bool {
 +        false
 +    }
 +}
 +
 +struct NotPubOne;
 +
 +impl NotPubOne {
 +    pub fn len(&self) -> isize {
 +        // No error; `len` is pub but `NotPubOne` is not exported anyway.
 +        1
 +    }
 +}
 +
 +struct One;
 +
 +impl One {
 +    fn len(&self) -> isize {
 +        // No error; `len` is private; see issue #1085.
 +        1
 +    }
 +}
 +
 +trait TraitsToo {
 +    fn len(&self) -> isize;
 +    // No error; `len` is private; see issue #1085.
 +}
 +
 +impl TraitsToo for One {
 +    fn len(&self) -> isize {
 +        0
 +    }
 +}
 +
 +struct HasPrivateIsEmpty;
 +
 +impl HasPrivateIsEmpty {
 +    pub fn len(&self) -> isize {
 +        1
 +    }
 +
 +    fn is_empty(&self) -> bool {
 +        false
 +    }
 +}
 +
 +struct Wither;
 +
 +pub trait WithIsEmpty {
 +    fn len(&self) -> isize;
 +    fn is_empty(&self) -> bool;
 +}
 +
 +impl WithIsEmpty for Wither {
 +    fn len(&self) -> isize {
 +        1
 +    }
 +
 +    fn is_empty(&self) -> bool {
 +        false
 +    }
 +}
 +
 +pub trait Empty {
 +    fn is_empty(&self) -> bool;
 +}
 +
 +pub trait InheritingEmpty: Empty {
 +    // Must not trigger `LEN_WITHOUT_IS_EMPTY`.
 +    fn len(&self) -> isize;
 +}
 +
 +// This used to ICE.
 +pub trait Foo: Sized {}
 +
 +pub trait DependsOnFoo: Foo {
 +    fn len(&mut self) -> usize;
 +}
 +
 +// issue #1562
 +pub struct MultipleImpls;
 +
 +impl MultipleImpls {
 +    pub fn len(&self) -> usize {
 +        1
 +    }
 +}
 +
 +impl MultipleImpls {
 +    pub fn is_empty(&self) -> bool {
 +        false
 +    }
 +}
 +
 +// issue #6958
 +pub struct OptionalLen;
 +
 +impl OptionalLen {
 +    pub fn len(&self) -> Option<usize> {
 +        Some(0)
 +    }
 +
 +    pub fn is_empty(&self) -> Option<bool> {
 +        Some(true)
 +    }
 +}
 +
 +pub struct OptionalLen2;
 +impl OptionalLen2 {
 +    pub fn len(&self) -> Option<usize> {
 +        Some(0)
 +    }
 +
 +    pub fn is_empty(&self) -> bool {
 +        true
 +    }
 +}
 +
 +pub struct OptionalLen3;
 +impl OptionalLen3 {
 +    pub fn len(&self) -> usize {
 +        0
 +    }
 +
 +    // should lint, len is not an option
 +    pub fn is_empty(&self) -> Option<bool> {
 +        None
 +    }
 +}
 +
 +pub struct ResultLen;
 +impl ResultLen {
 +    pub fn len(&self) -> Result<usize, ()> {
 +        Ok(0)
 +    }
 +
 +    // Differing result types
 +    pub fn is_empty(&self) -> Option<bool> {
 +        Some(true)
 +    }
 +}
 +
 +pub struct ResultLen2;
 +impl ResultLen2 {
 +    pub fn len(&self) -> Result<usize, ()> {
 +        Ok(0)
 +    }
 +
 +    pub fn is_empty(&self) -> Result<bool, ()> {
 +        Ok(true)
 +    }
 +}
 +
 +pub struct ResultLen3;
 +impl ResultLen3 {
 +    pub fn len(&self) -> Result<usize, ()> {
 +        Ok(0)
 +    }
 +
 +    // Non-fallible result is ok.
 +    pub fn is_empty(&self) -> bool {
 +        true
 +    }
 +}
 +
 +pub struct OddLenSig;
 +impl OddLenSig {
 +    // don't lint
 +    pub fn len(&self) -> bool {
 +        true
 +    }
 +}
 +
 +// issue #6958
 +pub struct AsyncLen;
 +impl AsyncLen {
 +    async fn async_task(&self) -> bool {
 +        true
 +    }
 +
 +    pub async fn len(&self) -> usize {
 +        if self.async_task().await { 0 } else { 1 }
 +    }
 +
 +    pub async fn is_empty(&self) -> bool {
 +        self.len().await == 0
 +    }
 +}
 +
 +fn main() {}
index 3282709bcd6717f664ef135c6132b38e9ab3a389,0000000000000000000000000000000000000000..a1f48f7610b44857edf7f6f8f9e6dbbc520c1a0d
mode 100644,000000..100644
--- /dev/null
@@@ -1,123 -1,0 +1,123 @@@
-   --> $DIR/len_without_is_empty.rs:9:5
 +error: struct `PubOne` has a public `len` method, but no `is_empty` method
-   --> $DIR/len_without_is_empty.rs:57:1
++  --> $DIR/len_without_is_empty.rs:7:5
 +   |
 +LL |     pub fn len(&self) -> isize {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::len-without-is-empty` implied by `-D warnings`
 +
 +error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` method
-   --> $DIR/len_without_is_empty.rs:70:5
++  --> $DIR/len_without_is_empty.rs:55:1
 +   |
 +LL | / pub trait PubTraitsToo {
 +LL | |     fn len(&self) -> isize;
 +LL | | }
 +   | |_^
 +
 +error: struct `HasIsEmpty` has a public `len` method, but a private `is_empty` method
-   --> $DIR/len_without_is_empty.rs:74:5
++  --> $DIR/len_without_is_empty.rs:68:5
 +   |
 +LL |     pub fn len(&self) -> isize {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +note: `is_empty` defined here
-   --> $DIR/len_without_is_empty.rs:82:5
++  --> $DIR/len_without_is_empty.rs:72:5
 +   |
 +LL |     fn is_empty(&self) -> bool {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: struct `HasWrongIsEmpty` has a public `len` method, but the `is_empty` method has an unexpected signature
-   --> $DIR/len_without_is_empty.rs:86:5
++  --> $DIR/len_without_is_empty.rs:80:5
 +   |
 +LL |     pub fn len(&self) -> isize {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +note: `is_empty` defined here
-   --> $DIR/len_without_is_empty.rs:94:5
++  --> $DIR/len_without_is_empty.rs:84:5
 +   |
 +LL |     pub fn is_empty(&self, x: u32) -> bool {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   = note: expected signature: `(&self) -> bool`
 +
 +error: struct `MismatchedSelf` has a public `len` method, but the `is_empty` method has an unexpected signature
-   --> $DIR/len_without_is_empty.rs:98:5
++  --> $DIR/len_without_is_empty.rs:92:5
 +   |
 +LL |     pub fn len(self) -> isize {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +note: `is_empty` defined here
-   --> $DIR/len_without_is_empty.rs:173:1
++  --> $DIR/len_without_is_empty.rs:96:5
 +   |
 +LL |     pub fn is_empty(&self) -> bool {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   = note: expected signature: `(self) -> bool`
 +
 +error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_empty` method
-   --> $DIR/len_without_is_empty.rs:218:5
++  --> $DIR/len_without_is_empty.rs:171:1
 +   |
 +LL | / pub trait DependsOnFoo: Foo {
 +LL | |     fn len(&mut self) -> usize;
 +LL | | }
 +   | |_^
 +
 +error: struct `OptionalLen3` has a public `len` method, but the `is_empty` method has an unexpected signature
-   --> $DIR/len_without_is_empty.rs:223:5
++  --> $DIR/len_without_is_empty.rs:216:5
 +   |
 +LL |     pub fn len(&self) -> usize {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +note: `is_empty` defined here
-   --> $DIR/len_without_is_empty.rs:230:5
++  --> $DIR/len_without_is_empty.rs:221:5
 +   |
 +LL |     pub fn is_empty(&self) -> Option<bool> {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   = note: expected signature: `(&self) -> bool`
 +
 +error: struct `ResultLen` has a public `len` method, but the `is_empty` method has an unexpected signature
-   --> $DIR/len_without_is_empty.rs:235:5
++  --> $DIR/len_without_is_empty.rs:228:5
 +   |
 +LL |     pub fn len(&self) -> Result<usize, ()> {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +note: `is_empty` defined here
-   --> $DIR/len_without_is_empty.rs:230:5
++  --> $DIR/len_without_is_empty.rs:233:5
 +   |
 +LL |     pub fn is_empty(&self) -> Option<bool> {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   = note: expected signature: `(&self) -> bool` or `(&self) -> Result<bool>
 +
 +error: this returns a `Result<_, ()>`
-   --> $DIR/len_without_is_empty.rs:242:5
++  --> $DIR/len_without_is_empty.rs:228:5
 +   |
 +LL |     pub fn len(&self) -> Result<usize, ()> {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::result-unit-err` implied by `-D warnings`
 +   = help: use a custom `Error` type instead
 +
 +error: this returns a `Result<_, ()>`
-   --> $DIR/len_without_is_empty.rs:246:5
++  --> $DIR/len_without_is_empty.rs:240:5
 +   |
 +LL |     pub fn len(&self) -> Result<usize, ()> {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = help: use a custom `Error` type instead
 +
 +error: this returns a `Result<_, ()>`
-   --> $DIR/len_without_is_empty.rs:253:5
++  --> $DIR/len_without_is_empty.rs:244:5
 +   |
 +LL |     pub fn is_empty(&self) -> Result<bool, ()> {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = help: use a custom `Error` type instead
 +
 +error: this returns a `Result<_, ()>`
++  --> $DIR/len_without_is_empty.rs:251:5
 +   |
 +LL |     pub fn len(&self) -> Result<usize, ()> {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = help: use a custom `Error` type instead
 +
 +error: aborting due to 12 previous errors
 +
index a72a74b9131d8bb21fb3b2431fd344c2d069706c,0000000000000000000000000000000000000000..e60ce8492fc7716f70f3f490086d03d76904f07f
mode 100644,000000..100644
--- /dev/null
@@@ -1,41 -1,0 +1,42 @@@
- #![allow(clippy::unseparated_literal_suffix)]
 +// does not test any rustfixable lints
 +
 +#![warn(clippy::mixed_case_hex_literals)]
 +#![warn(clippy::zero_prefixed_literal)]
++#![warn(clippy::unseparated_literal_suffix)]
++#![warn(clippy::separated_literal_suffix)]
 +#![allow(dead_code)]
 +
 +fn main() {
 +    let ok1 = 0xABCD;
 +    let ok3 = 0xab_cd;
 +    let ok4 = 0xab_cd_i32;
 +    let ok5 = 0xAB_CD_u32;
 +    let ok5 = 0xAB_CD_isize;
 +    let fail1 = 0xabCD;
 +    let fail2 = 0xabCD_u32;
 +    let fail2 = 0xabCD_isize;
 +    let fail_multi_zero = 000_123usize;
 +
 +    let ok9 = 0;
 +    let ok10 = 0_i64;
 +    let fail8 = 0123;
 +
 +    let ok11 = 0o123;
 +    let ok12 = 0b10_1010;
 +
 +    let ok13 = 0xab_abcd;
 +    let ok14 = 0xBAFE_BAFE;
 +    let ok15 = 0xab_cabc_abca_bcab_cabc;
 +    let ok16 = 0xFE_BAFE_ABAB_ABCD;
 +    let ok17 = 0x123_4567_8901_usize;
 +    let ok18 = 0xF;
 +
 +    let fail19 = 12_3456_21;
 +    let fail22 = 3__4___23;
 +    let fail23 = 3__16___23;
 +
 +    let fail24 = 0xAB_ABC_AB;
 +    let fail25 = 0b01_100_101;
 +    let ok26 = 0x6_A0_BF;
 +    let ok27 = 0b1_0010_0101;
 +}
index 99542e20f785fea9f916c59976b20850fcd8edc7,0000000000000000000000000000000000000000..365b240747352d76bc06b3e802e04f0049dabec6
mode 100644,000000..100644
--- /dev/null
@@@ -1,87 -1,0 +1,139 @@@
-   --> $DIR/literals.rs:14:17
++error: integer type suffix should not be separated by an underscore
++  --> $DIR/literals.rs:12:15
++   |
++LL |     let ok4 = 0xab_cd_i32;
++   |               ^^^^^^^^^^^ help: remove the underscore: `0xab_cdi32`
++   |
++   = note: `-D clippy::separated-literal-suffix` implied by `-D warnings`
++
++error: integer type suffix should not be separated by an underscore
++  --> $DIR/literals.rs:13:15
++   |
++LL |     let ok5 = 0xAB_CD_u32;
++   |               ^^^^^^^^^^^ help: remove the underscore: `0xAB_CDu32`
++
++error: integer type suffix should not be separated by an underscore
++  --> $DIR/literals.rs:14:15
++   |
++LL |     let ok5 = 0xAB_CD_isize;
++   |               ^^^^^^^^^^^^^ help: remove the underscore: `0xAB_CDisize`
++
 +error: inconsistent casing in hexadecimal literal
-   --> $DIR/literals.rs:15:17
++  --> $DIR/literals.rs:15:17
 +   |
 +LL |     let fail1 = 0xabCD;
 +   |                 ^^^^^^
 +   |
 +   = note: `-D clippy::mixed-case-hex-literals` implied by `-D warnings`
 +
++error: integer type suffix should not be separated by an underscore
++  --> $DIR/literals.rs:16:17
++   |
++LL |     let fail2 = 0xabCD_u32;
++   |                 ^^^^^^^^^^ help: remove the underscore: `0xabCDu32`
++
 +error: inconsistent casing in hexadecimal literal
-   --> $DIR/literals.rs:16:17
++  --> $DIR/literals.rs:16:17
 +   |
 +LL |     let fail2 = 0xabCD_u32;
 +   |                 ^^^^^^^^^^
 +
++error: integer type suffix should not be separated by an underscore
++  --> $DIR/literals.rs:17:17
++   |
++LL |     let fail2 = 0xabCD_isize;
++   |                 ^^^^^^^^^^^^ help: remove the underscore: `0xabCDisize`
++
 +error: inconsistent casing in hexadecimal literal
-   --> $DIR/literals.rs:17:27
++  --> $DIR/literals.rs:17:17
 +   |
 +LL |     let fail2 = 0xabCD_isize;
 +   |                 ^^^^^^^^^^^^
 +
++error: integer type suffix should be separated by an underscore
++  --> $DIR/literals.rs:18:27
++   |
++LL |     let fail_multi_zero = 000_123usize;
++   |                           ^^^^^^^^^^^^ help: add an underscore: `000_123_usize`
++   |
++   = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
++
 +error: this is a decimal constant
-   --> $DIR/literals.rs:21:17
++  --> $DIR/literals.rs:18:27
 +   |
 +LL |     let fail_multi_zero = 000_123usize;
 +   |                           ^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::zero-prefixed-literal` implied by `-D warnings`
 +help: if you mean to use a decimal constant, remove the `0` to avoid confusion
 +   |
 +LL |     let fail_multi_zero = 123usize;
 +   |                           ~~~~~~~~
 +help: if you mean to use an octal constant, use `0o`
 +   |
 +LL |     let fail_multi_zero = 0o123usize;
 +   |                           ~~~~~~~~~~
 +
++error: integer type suffix should not be separated by an underscore
++  --> $DIR/literals.rs:21:16
++   |
++LL |     let ok10 = 0_i64;
++   |                ^^^^^ help: remove the underscore: `0i64`
++
 +error: this is a decimal constant
-   --> $DIR/literals.rs:33:18
++  --> $DIR/literals.rs:22:17
 +   |
 +LL |     let fail8 = 0123;
 +   |                 ^^^^
 +   |
 +help: if you mean to use a decimal constant, remove the `0` to avoid confusion
 +   |
 +LL |     let fail8 = 123;
 +   |                 ~~~
 +help: if you mean to use an octal constant, use `0o`
 +   |
 +LL |     let fail8 = 0o123;
 +   |                 ~~~~~
 +
++error: integer type suffix should not be separated by an underscore
++  --> $DIR/literals.rs:31:16
++   |
++LL |     let ok17 = 0x123_4567_8901_usize;
++   |                ^^^^^^^^^^^^^^^^^^^^^ help: remove the underscore: `0x123_4567_8901usize`
++
 +error: digits grouped inconsistently by underscores
-   --> $DIR/literals.rs:34:18
++  --> $DIR/literals.rs:34:18
 +   |
 +LL |     let fail19 = 12_3456_21;
 +   |                  ^^^^^^^^^^ help: consider: `12_345_621`
 +   |
 +   = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings`
 +
 +error: digits grouped inconsistently by underscores
-   --> $DIR/literals.rs:35:18
++  --> $DIR/literals.rs:35:18
 +   |
 +LL |     let fail22 = 3__4___23;
 +   |                  ^^^^^^^^^ help: consider: `3_423`
 +
 +error: digits grouped inconsistently by underscores
-   --> $DIR/literals.rs:37:18
++  --> $DIR/literals.rs:36:18
 +   |
 +LL |     let fail23 = 3__16___23;
 +   |                  ^^^^^^^^^^ help: consider: `31_623`
 +
 +error: digits of hex or binary literal not grouped by four
-   --> $DIR/literals.rs:38:18
++  --> $DIR/literals.rs:38:18
 +   |
 +LL |     let fail24 = 0xAB_ABC_AB;
 +   |                  ^^^^^^^^^^^ help: consider: `0x0ABA_BCAB`
 +   |
 +   = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
 +
 +error: digits of hex or binary literal not grouped by four
- error: aborting due to 10 previous errors
++  --> $DIR/literals.rs:39:18
 +   |
 +LL |     let fail25 = 0b01_100_101;
 +   |                  ^^^^^^^^^^^^ help: consider: `0b0110_0101`
 +
++error: aborting due to 18 previous errors
 +
index 70d49d9f2c4ae1edd8497e9133f3598369431148,0000000000000000000000000000000000000000..9171558f3a2d74d1f79d2c9b62d6a3282db33b82
mode 100644,000000..100644
--- /dev/null
@@@ -1,48 -1,0 +1,47 @@@
- // compile-flags: --edition 2018
 +// aux-build:macro_rules.rs
 +// aux-build:macro_use_helper.rs
 +// aux-build:proc_macro_derive.rs
 +// run-rustfix
 +// ignore-32bit
 +
 +#![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)]
 +#![allow(clippy::single_component_path_imports)]
 +#![warn(clippy::macro_use_imports)]
 +
 +#[macro_use]
 +extern crate macro_use_helper as mac;
 +
 +#[macro_use]
 +extern crate proc_macro_derive as mini_mac;
 +
 +mod a {
 +    use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};
 +    use mac;
 +    use mini_mac::ClippyMiniMacroTest;
 +    use mini_mac;
 +    use mac::{inner::foofoo, inner::try_err};
 +    use mac::inner;
 +    use mac::inner::nested::string_add;
 +    use mac::inner::nested;
 +
 +    #[derive(ClippyMiniMacroTest)]
 +    struct Test;
 +
 +    fn test() {
 +        pub_macro!();
 +        inner_mod_macro!();
 +        pub_in_private_macro!(_var);
 +        function_macro!();
 +        let v: ty_macro!() = Vec::default();
 +
 +        inner::try_err!();
 +        inner::foofoo!();
 +        nested::string_add!();
 +    }
 +}
 +
 +// issue #7015, ICE due to calling `item_children` with local `DefId`
 +#[macro_use]
 +use a as b;
 +
 +fn main() {}
index 68370023861145dc15a29d4a6696138e06910d05,0000000000000000000000000000000000000000..cd01fd43f6d325eefb79e07d1bc71753ef1a164c
mode 100644,000000..100644
--- /dev/null
@@@ -1,48 -1,0 +1,47 @@@
- // compile-flags: --edition 2018
 +// aux-build:macro_rules.rs
 +// aux-build:macro_use_helper.rs
 +// aux-build:proc_macro_derive.rs
 +// run-rustfix
 +// ignore-32bit
 +
 +#![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)]
 +#![allow(clippy::single_component_path_imports)]
 +#![warn(clippy::macro_use_imports)]
 +
 +#[macro_use]
 +extern crate macro_use_helper as mac;
 +
 +#[macro_use]
 +extern crate proc_macro_derive as mini_mac;
 +
 +mod a {
 +    #[macro_use]
 +    use mac;
 +    #[macro_use]
 +    use mini_mac;
 +    #[macro_use]
 +    use mac::inner;
 +    #[macro_use]
 +    use mac::inner::nested;
 +
 +    #[derive(ClippyMiniMacroTest)]
 +    struct Test;
 +
 +    fn test() {
 +        pub_macro!();
 +        inner_mod_macro!();
 +        pub_in_private_macro!(_var);
 +        function_macro!();
 +        let v: ty_macro!() = Vec::default();
 +
 +        inner::try_err!();
 +        inner::foofoo!();
 +        nested::string_add!();
 +    }
 +}
 +
 +// issue #7015, ICE due to calling `item_children` with local `DefId`
 +#[macro_use]
 +use a as b;
 +
 +fn main() {}
index 49314b7506d336187642b16deee4aad13d34f342,0000000000000000000000000000000000000000..f8c86c8d9179f8af918b684eb9294c18ea4a7008
mode 100644,000000..100644
--- /dev/null
@@@ -1,28 -1,0 +1,28 @@@
-   --> $DIR/macro_use_imports.rs:19:5
 +error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-   --> $DIR/macro_use_imports.rs:25:5
++  --> $DIR/macro_use_imports.rs:18:5
 +   |
 +LL |     #[macro_use]
 +   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};`
 +   |
 +   = note: `-D clippy::macro-use-imports` implied by `-D warnings`
 +
 +error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-    |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
++  --> $DIR/macro_use_imports.rs:20:5
 +   |
 +LL |     #[macro_use]
-   --> $DIR/macro_use_imports.rs:21:5
++   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
 +
 +error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-    |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
++  --> $DIR/macro_use_imports.rs:22:5
 +   |
 +LL |     #[macro_use]
-   --> $DIR/macro_use_imports.rs:23:5
++   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
 +
 +error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-    |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
++  --> $DIR/macro_use_imports.rs:24:5
 +   |
 +LL |     #[macro_use]
++   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
 +
 +error: aborting due to 4 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..11fe06c572471cb9f95e5dad3915ceb10d638601
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,43 @@@
++// revisions: edition2018 edition2021
++// [edition2018] edition:2018
++// [edition2021] edition:2021
++// run-rustfix
++#![warn(clippy::manual_assert)]
++
++fn main() {
++    let a = vec![1, 2, 3];
++    let c = Some(2);
++    if !a.is_empty()
++        && a.len() == 3
++        && c != None
++        && !a.is_empty()
++        && a.len() == 3
++        && !a.is_empty()
++        && a.len() == 3
++        && !a.is_empty()
++        && a.len() == 3
++    {
++        panic!("qaqaq{:?}", a);
++    }
++    assert!(a.is_empty(), "qaqaq{:?}", a);
++    assert!(a.is_empty(), "qwqwq");
++    if a.len() == 3 {
++        println!("qwq");
++        println!("qwq");
++        println!("qwq");
++    }
++    if let Some(b) = c {
++        panic!("orz {}", b);
++    }
++    if a.len() == 3 {
++        panic!("qaqaq");
++    } else {
++        println!("qwq");
++    }
++    let b = vec![1, 2, 3];
++    assert!(!b.is_empty(), "panic1");
++    assert!(!(b.is_empty() && a.is_empty()), "panic2");
++    assert!(!(a.is_empty() && !b.is_empty()), "panic3");
++    assert!(!(b.is_empty() || a.is_empty()), "panic4");
++    assert!(!(a.is_empty() || !b.is_empty()), "panic5");
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..03c03472f908f0c58d64a765798dc8cc89a09fbb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,60 @@@
++error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:22:5
++   |
++LL | /     if !a.is_empty() {
++LL | |         panic!("qaqaq{:?}", a);
++LL | |     }
++   | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
++   |
++   = note: `-D clippy::manual-assert` implied by `-D warnings`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:25:5
++   |
++LL | /     if !a.is_empty() {
++LL | |         panic!("qwqwq");
++LL | |     }
++   | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:42:5
++   |
++LL | /     if b.is_empty() {
++LL | |         panic!("panic1");
++LL | |     }
++   | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:45:5
++   |
++LL | /     if b.is_empty() && a.is_empty() {
++LL | |         panic!("panic2");
++LL | |     }
++   | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:48:5
++   |
++LL | /     if a.is_empty() && !b.is_empty() {
++LL | |         panic!("panic3");
++LL | |     }
++   | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:51:5
++   |
++LL | /     if b.is_empty() || a.is_empty() {
++LL | |         panic!("panic4");
++LL | |     }
++   | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:54:5
++   |
++LL | /     if a.is_empty() || !b.is_empty() {
++LL | |         panic!("panic5");
++LL | |     }
++   | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
++
++error: aborting due to 7 previous errors
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..11fe06c572471cb9f95e5dad3915ceb10d638601
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,43 @@@
++// revisions: edition2018 edition2021
++// [edition2018] edition:2018
++// [edition2021] edition:2021
++// run-rustfix
++#![warn(clippy::manual_assert)]
++
++fn main() {
++    let a = vec![1, 2, 3];
++    let c = Some(2);
++    if !a.is_empty()
++        && a.len() == 3
++        && c != None
++        && !a.is_empty()
++        && a.len() == 3
++        && !a.is_empty()
++        && a.len() == 3
++        && !a.is_empty()
++        && a.len() == 3
++    {
++        panic!("qaqaq{:?}", a);
++    }
++    assert!(a.is_empty(), "qaqaq{:?}", a);
++    assert!(a.is_empty(), "qwqwq");
++    if a.len() == 3 {
++        println!("qwq");
++        println!("qwq");
++        println!("qwq");
++    }
++    if let Some(b) = c {
++        panic!("orz {}", b);
++    }
++    if a.len() == 3 {
++        panic!("qaqaq");
++    } else {
++        println!("qwq");
++    }
++    let b = vec![1, 2, 3];
++    assert!(!b.is_empty(), "panic1");
++    assert!(!(b.is_empty() && a.is_empty()), "panic2");
++    assert!(!(a.is_empty() && !b.is_empty()), "panic3");
++    assert!(!(b.is_empty() || a.is_empty()), "panic4");
++    assert!(!(a.is_empty() || !b.is_empty()), "panic5");
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..03c03472f908f0c58d64a765798dc8cc89a09fbb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,60 @@@
++error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:22:5
++   |
++LL | /     if !a.is_empty() {
++LL | |         panic!("qaqaq{:?}", a);
++LL | |     }
++   | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
++   |
++   = note: `-D clippy::manual-assert` implied by `-D warnings`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:25:5
++   |
++LL | /     if !a.is_empty() {
++LL | |         panic!("qwqwq");
++LL | |     }
++   | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:42:5
++   |
++LL | /     if b.is_empty() {
++LL | |         panic!("panic1");
++LL | |     }
++   | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:45:5
++   |
++LL | /     if b.is_empty() && a.is_empty() {
++LL | |         panic!("panic2");
++LL | |     }
++   | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:48:5
++   |
++LL | /     if a.is_empty() && !b.is_empty() {
++LL | |         panic!("panic3");
++LL | |     }
++   | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:51:5
++   |
++LL | /     if b.is_empty() || a.is_empty() {
++LL | |         panic!("panic4");
++LL | |     }
++   | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
++
++error: only a `panic!` in `if`-then statement
++  --> $DIR/manual_assert.rs:54:5
++   |
++LL | /     if a.is_empty() || !b.is_empty() {
++LL | |         panic!("panic5");
++LL | |     }
++   | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
++
++error: aborting due to 7 previous errors
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..11fe06c572471cb9f95e5dad3915ceb10d638601
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,43 @@@
++// revisions: edition2018 edition2021
++// [edition2018] edition:2018
++// [edition2021] edition:2021
++// run-rustfix
++#![warn(clippy::manual_assert)]
++
++fn main() {
++    let a = vec![1, 2, 3];
++    let c = Some(2);
++    if !a.is_empty()
++        && a.len() == 3
++        && c != None
++        && !a.is_empty()
++        && a.len() == 3
++        && !a.is_empty()
++        && a.len() == 3
++        && !a.is_empty()
++        && a.len() == 3
++    {
++        panic!("qaqaq{:?}", a);
++    }
++    assert!(a.is_empty(), "qaqaq{:?}", a);
++    assert!(a.is_empty(), "qwqwq");
++    if a.len() == 3 {
++        println!("qwq");
++        println!("qwq");
++        println!("qwq");
++    }
++    if let Some(b) = c {
++        panic!("orz {}", b);
++    }
++    if a.len() == 3 {
++        panic!("qaqaq");
++    } else {
++        println!("qwq");
++    }
++    let b = vec![1, 2, 3];
++    assert!(!b.is_empty(), "panic1");
++    assert!(!(b.is_empty() && a.is_empty()), "panic2");
++    assert!(!(a.is_empty() && !b.is_empty()), "panic3");
++    assert!(!(b.is_empty() || a.is_empty()), "panic4");
++    assert!(!(a.is_empty() || !b.is_empty()), "panic5");
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8713426fc8886b9223e7631a6241162c7fc8ce88
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,57 @@@
++// revisions: edition2018 edition2021
++// [edition2018] edition:2018
++// [edition2021] edition:2021
++// run-rustfix
++#![warn(clippy::manual_assert)]
++
++fn main() {
++    let a = vec![1, 2, 3];
++    let c = Some(2);
++    if !a.is_empty()
++        && a.len() == 3
++        && c != None
++        && !a.is_empty()
++        && a.len() == 3
++        && !a.is_empty()
++        && a.len() == 3
++        && !a.is_empty()
++        && a.len() == 3
++    {
++        panic!("qaqaq{:?}", a);
++    }
++    if !a.is_empty() {
++        panic!("qaqaq{:?}", a);
++    }
++    if !a.is_empty() {
++        panic!("qwqwq");
++    }
++    if a.len() == 3 {
++        println!("qwq");
++        println!("qwq");
++        println!("qwq");
++    }
++    if let Some(b) = c {
++        panic!("orz {}", b);
++    }
++    if a.len() == 3 {
++        panic!("qaqaq");
++    } else {
++        println!("qwq");
++    }
++    let b = vec![1, 2, 3];
++    if b.is_empty() {
++        panic!("panic1");
++    }
++    if b.is_empty() && a.is_empty() {
++        panic!("panic2");
++    }
++    if a.is_empty() && !b.is_empty() {
++        panic!("panic3");
++    }
++    if b.is_empty() || a.is_empty() {
++        panic!("panic4");
++    }
++    if a.is_empty() || !b.is_empty() {
++        panic!("panic5");
++    }
++}
index 5184f6fdb88b3991850aead57bf02ea0a75b46cf,0000000000000000000000000000000000000000..136cc96be70cafa57951fc7edd89c784892803b1
mode 100644,000000..100644
--- /dev/null
@@@ -1,111 -1,0 +1,110 @@@
- // edition:2018
 +// run-rustfix
 +#![warn(clippy::manual_async_fn)]
 +#![allow(unused)]
 +
 +use std::future::Future;
 +
 +async fn fut() -> i32 { 42 }
 +
 +#[rustfmt::skip]
 +async fn fut2() -> i32 { 42 }
 +
 +#[rustfmt::skip]
 +async fn fut3() -> i32 { 42 }
 +
 +async fn empty_fut() {}
 +
 +#[rustfmt::skip]
 +async fn empty_fut2() {}
 +
 +#[rustfmt::skip]
 +async fn empty_fut3() {}
 +
 +async fn core_fut() -> i32 { 42 }
 +
 +// should be ignored
 +fn has_other_stmts() -> impl core::future::Future<Output = i32> {
 +    let _ = 42;
 +    async move { 42 }
 +}
 +
 +// should be ignored
 +fn not_fut() -> i32 {
 +    42
 +}
 +
 +// should be ignored
 +async fn already_async() -> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +struct S {}
 +impl S {
 +    async fn inh_fut() -> i32 {
 +        // NOTE: this code is here just to check that the indentation is correct in the suggested fix
 +        let a = 42;
 +        let b = 21;
 +        if a < b {
 +            let c = 21;
 +            let d = 42;
 +            if c < d {
 +                let _ = 42;
 +            }
 +        }
 +        42
 +    }
 +
 +    // should be ignored
 +    fn not_fut(&self) -> i32 {
 +        42
 +    }
 +
 +    // should be ignored
 +    fn has_other_stmts() -> impl core::future::Future<Output = i32> {
 +        let _ = 42;
 +        async move { 42 }
 +    }
 +
 +    // should be ignored
 +    async fn already_async(&self) -> impl Future<Output = i32> {
 +        async { 42 }
 +    }
 +}
 +
 +// Tests related to lifetime capture
 +
 +async fn elided(_: &i32) -> i32 { 42 }
 +
 +// should be ignored
 +fn elided_not_bound(_: &i32) -> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { 42 }
 +
 +// should be ignored
 +#[allow(clippy::needless_lifetimes)]
 +fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +// should be ignored
 +mod issue_5765 {
 +    use std::future::Future;
 +
 +    struct A;
 +    impl A {
 +        fn f(&self) -> impl Future<Output = ()> {
 +            async {}
 +        }
 +    }
 +
 +    fn test() {
 +        let _future = {
 +            let a = A;
 +            a.f()
 +        };
 +    }
 +}
 +
 +fn main() {}
index 68c0e591f0b6eed6b4ffd5eeb1b8bd0fde47bae1,0000000000000000000000000000000000000000..ddc453ffdb7500958c5e26cbf62a65a4859640f7
mode 100644,000000..100644
--- /dev/null
@@@ -1,131 -1,0 +1,130 @@@
- // edition:2018
 +// run-rustfix
 +#![warn(clippy::manual_async_fn)]
 +#![allow(unused)]
 +
 +use std::future::Future;
 +
 +fn fut() -> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +#[rustfmt::skip]
 +fn fut2() ->impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +#[rustfmt::skip]
 +fn fut3()-> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +fn empty_fut() -> impl Future<Output = ()> {
 +    async {}
 +}
 +
 +#[rustfmt::skip]
 +fn empty_fut2() ->impl Future<Output = ()> {
 +    async {}
 +}
 +
 +#[rustfmt::skip]
 +fn empty_fut3()-> impl Future<Output = ()> {
 +    async {}
 +}
 +
 +fn core_fut() -> impl core::future::Future<Output = i32> {
 +    async move { 42 }
 +}
 +
 +// should be ignored
 +fn has_other_stmts() -> impl core::future::Future<Output = i32> {
 +    let _ = 42;
 +    async move { 42 }
 +}
 +
 +// should be ignored
 +fn not_fut() -> i32 {
 +    42
 +}
 +
 +// should be ignored
 +async fn already_async() -> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +struct S {}
 +impl S {
 +    fn inh_fut() -> impl Future<Output = i32> {
 +        async {
 +            // NOTE: this code is here just to check that the indentation is correct in the suggested fix
 +            let a = 42;
 +            let b = 21;
 +            if a < b {
 +                let c = 21;
 +                let d = 42;
 +                if c < d {
 +                    let _ = 42;
 +                }
 +            }
 +            42
 +        }
 +    }
 +
 +    // should be ignored
 +    fn not_fut(&self) -> i32 {
 +        42
 +    }
 +
 +    // should be ignored
 +    fn has_other_stmts() -> impl core::future::Future<Output = i32> {
 +        let _ = 42;
 +        async move { 42 }
 +    }
 +
 +    // should be ignored
 +    async fn already_async(&self) -> impl Future<Output = i32> {
 +        async { 42 }
 +    }
 +}
 +
 +// Tests related to lifetime capture
 +
 +fn elided(_: &i32) -> impl Future<Output = i32> + '_ {
 +    async { 42 }
 +}
 +
 +// should be ignored
 +fn elided_not_bound(_: &i32) -> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b {
 +    async { 42 }
 +}
 +
 +// should be ignored
 +#[allow(clippy::needless_lifetimes)]
 +fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> {
 +    async { 42 }
 +}
 +
 +// should be ignored
 +mod issue_5765 {
 +    use std::future::Future;
 +
 +    struct A;
 +    impl A {
 +        fn f(&self) -> impl Future<Output = ()> {
 +            async {}
 +        }
 +    }
 +
 +    fn test() {
 +        let _future = {
 +            let a = A;
 +            a.f()
 +        };
 +    }
 +}
 +
 +fn main() {}
index 51f1a52b6dd65154d3b50d0a56bedfb8d24c37c9,0000000000000000000000000000000000000000..7435f46074c8167287b383f5cee7f67c3e5afb0f
mode 100644,000000..100644
--- /dev/null
@@@ -1,158 -1,0 +1,158 @@@
-   --> $DIR/manual_async_fn.rs:8:1
 +error: this function can be simplified using the `async fn` syntax
-   --> $DIR/manual_async_fn.rs:13:1
++  --> $DIR/manual_async_fn.rs:7:1
 +   |
 +LL | fn fut() -> impl Future<Output = i32> {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::manual-async-fn` implied by `-D warnings`
 +help: make the function `async` and return the output of the future directly
 +   |
 +LL | async fn fut() -> i32 {
 +   | ~~~~~~~~~~~~~~~~~~~~~
 +help: move the body of the async block to the enclosing function
 +   |
 +LL | fn fut() -> impl Future<Output = i32> { 42 }
 +   |                                       ~~~~~~
 +
 +error: this function can be simplified using the `async fn` syntax
-   --> $DIR/manual_async_fn.rs:18:1
++  --> $DIR/manual_async_fn.rs:12:1
 +   |
 +LL | fn fut2() ->impl Future<Output = i32> {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: make the function `async` and return the output of the future directly
 +   |
 +LL | async fn fut2() -> i32 {
 +   | ~~~~~~~~~~~~~~~~~~~~~~
 +help: move the body of the async block to the enclosing function
 +   |
 +LL | fn fut2() ->impl Future<Output = i32> { 42 }
 +   |                                       ~~~~~~
 +
 +error: this function can be simplified using the `async fn` syntax
-   --> $DIR/manual_async_fn.rs:22:1
++  --> $DIR/manual_async_fn.rs:17:1
 +   |
 +LL | fn fut3()-> impl Future<Output = i32> {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: make the function `async` and return the output of the future directly
 +   |
 +LL | async fn fut3() -> i32 {
 +   | ~~~~~~~~~~~~~~~~~~~~~~
 +help: move the body of the async block to the enclosing function
 +   |
 +LL | fn fut3()-> impl Future<Output = i32> { 42 }
 +   |                                       ~~~~~~
 +
 +error: this function can be simplified using the `async fn` syntax
-   --> $DIR/manual_async_fn.rs:27:1
++  --> $DIR/manual_async_fn.rs:21:1
 +   |
 +LL | fn empty_fut() -> impl Future<Output = ()> {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: make the function `async` and remove the return type
 +   |
 +LL | async fn empty_fut() {
 +   | ~~~~~~~~~~~~~~~~~~~~
 +help: move the body of the async block to the enclosing function
 +   |
 +LL | fn empty_fut() -> impl Future<Output = ()> {}
 +   |                                            ~~
 +
 +error: this function can be simplified using the `async fn` syntax
-   --> $DIR/manual_async_fn.rs:32:1
++  --> $DIR/manual_async_fn.rs:26:1
 +   |
 +LL | fn empty_fut2() ->impl Future<Output = ()> {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: make the function `async` and remove the return type
 +   |
 +LL | async fn empty_fut2() {
 +   | ~~~~~~~~~~~~~~~~~~~~~
 +help: move the body of the async block to the enclosing function
 +   |
 +LL | fn empty_fut2() ->impl Future<Output = ()> {}
 +   |                                            ~~
 +
 +error: this function can be simplified using the `async fn` syntax
-   --> $DIR/manual_async_fn.rs:36:1
++  --> $DIR/manual_async_fn.rs:31:1
 +   |
 +LL | fn empty_fut3()-> impl Future<Output = ()> {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: make the function `async` and remove the return type
 +   |
 +LL | async fn empty_fut3() {
 +   | ~~~~~~~~~~~~~~~~~~~~~
 +help: move the body of the async block to the enclosing function
 +   |
 +LL | fn empty_fut3()-> impl Future<Output = ()> {}
 +   |                                            ~~
 +
 +error: this function can be simplified using the `async fn` syntax
-   --> $DIR/manual_async_fn.rs:58:5
++  --> $DIR/manual_async_fn.rs:35:1
 +   |
 +LL | fn core_fut() -> impl core::future::Future<Output = i32> {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: make the function `async` and return the output of the future directly
 +   |
 +LL | async fn core_fut() -> i32 {
 +   | ~~~~~~~~~~~~~~~~~~~~~~~~~~
 +help: move the body of the async block to the enclosing function
 +   |
 +LL | fn core_fut() -> impl core::future::Future<Output = i32> { 42 }
 +   |                                                          ~~~~~~
 +
 +error: this function can be simplified using the `async fn` syntax
-   --> $DIR/manual_async_fn.rs:93:1
++  --> $DIR/manual_async_fn.rs:57:5
 +   |
 +LL |     fn inh_fut() -> impl Future<Output = i32> {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: make the function `async` and return the output of the future directly
 +   |
 +LL |     async fn inh_fut() -> i32 {
 +   |     ~~~~~~~~~~~~~~~~~~~~~~~~~
 +help: move the body of the async block to the enclosing function
 +   |
 +LL ~     fn inh_fut() -> impl Future<Output = i32> {
 +LL +         // NOTE: this code is here just to check that the indentation is correct in the suggested fix
 +LL +         let a = 42;
 +LL +         let b = 21;
 +LL +         if a < b {
 +LL +             let c = 21;
 + ...
 +
 +error: this function can be simplified using the `async fn` syntax
-   --> $DIR/manual_async_fn.rs:102:1
++  --> $DIR/manual_async_fn.rs:92:1
 +   |
 +LL | fn elided(_: &i32) -> impl Future<Output = i32> + '_ {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: make the function `async` and return the output of the future directly
 +   |
 +LL | async fn elided(_: &i32) -> i32 {
 +   | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +help: move the body of the async block to the enclosing function
 +   |
 +LL | fn elided(_: &i32) -> impl Future<Output = i32> + '_ { 42 }
 +   |                                                      ~~~~~~
 +
 +error: this function can be simplified using the `async fn` syntax
++  --> $DIR/manual_async_fn.rs:101:1
 +   |
 +LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +help: make the function `async` and return the output of the future directly
 +   |
 +LL | async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 {
 +   | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +help: move the body of the async block to the enclosing function
 +   |
 +LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b { 42 }
 +   |                                                                                    ~~~~~~
 +
 +error: aborting due to 10 previous errors
 +
index 40d01df6379a696496028454027d8acaba84f1c8,0000000000000000000000000000000000000000..294d79abc0459fe481a9125f07b1fd8faf67ac69
mode 100644,000000..100644
--- /dev/null
@@@ -1,156 -1,0 +1,155 @@@
- // edition:2018
 +// run-rustfix
 +
 +#![warn(clippy::manual_map)]
 +#![allow(
 +    clippy::no_effect,
 +    clippy::map_identity,
 +    clippy::unit_arg,
 +    clippy::match_ref_pats,
 +    clippy::redundant_pattern_matching,
 +    dead_code
 +)]
 +
 +fn main() {
 +    Some(0).map(|_| 2);
 +
 +    Some(0).map(|x| x + 1);
 +
 +    Some("").map(|x| x.is_empty());
 +
 +    Some(0).map(|x| !x);
 +
 +    #[rustfmt::skip]
 +    Some(0).map(std::convert::identity);
 +
 +    Some(&String::new()).map(|x| str::len(x));
 +
 +    match Some(0) {
 +        Some(x) if false => Some(x + 1),
 +        _ => None,
 +    };
 +
 +    Some([0, 1]).as_ref().map(|x| x[0]);
 +
 +    Some(0).map(|x| x * 2);
 +
 +    Some(String::new()).as_ref().map(|x| x.is_empty());
 +
 +    Some(String::new()).as_ref().map(|x| x.len());
 +
 +    Some(0).map(|x| x + x);
 +
 +    #[warn(clippy::option_map_unit_fn)]
 +    match &mut Some(String::new()) {
 +        Some(x) => Some(x.push_str("")),
 +        None => None,
 +    };
 +
 +    #[allow(clippy::option_map_unit_fn)]
 +    {
 +        Some(String::new()).as_mut().map(|x| x.push_str(""));
 +    }
 +
 +    Some(String::new()).as_ref().map(|x| x.len());
 +
 +    Some(String::new()).as_ref().map(|x| x.is_empty());
 +
 +    Some((0, 1, 2)).map(|(x, y, z)| x + y + z);
 +
 +    Some([1, 2, 3]).map(|[first, ..]| first);
 +
 +    Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x));
 +
 +    match Some((String::new(), 0)) {
 +        Some((ref x, y)) => Some((y, x)),
 +        None => None,
 +    };
 +
 +    match Some(Some(0)) {
 +        Some(Some(_)) | Some(None) => Some(0),
 +        None => None,
 +    };
 +
 +    match Some(Some((0, 1))) {
 +        Some(Some((x, 1))) => Some(x),
 +        _ => None,
 +    };
 +
 +    // #6795
 +    fn f1() -> Result<(), ()> {
 +        let _ = match Some(Ok(())) {
 +            Some(x) => Some(x?),
 +            None => None,
 +        };
 +        Ok(())
 +    }
 +
 +    for &x in Some(Some(true)).iter() {
 +        let _ = match x {
 +            Some(x) => Some(if x { continue } else { x }),
 +            None => None,
 +        };
 +    }
 +
 +    // #6797
 +    let x1 = (Some(String::new()), 0);
 +    let x2 = x1.0;
 +    match x2 {
 +        Some(x) => Some((x, x1.1)),
 +        None => None,
 +    };
 +
 +    struct S1 {
 +        x: Option<String>,
 +        y: u32,
 +    }
 +    impl S1 {
 +        fn f(self) -> Option<(String, u32)> {
 +            match self.x {
 +                Some(x) => Some((x, self.y)),
 +                None => None,
 +            }
 +        }
 +    }
 +
 +    // #6811
 +    Some(0).map(|x| vec![x]);
 +
 +    option_env!("").map(String::from);
 +
 +    // #6819
 +    async fn f2(x: u32) -> u32 {
 +        x
 +    }
 +
 +    async fn f3() {
 +        match Some(0) {
 +            Some(x) => Some(f2(x).await),
 +            None => None,
 +        };
 +    }
 +
 +    // #6847
 +    if let Some(_) = Some(0) {
 +        Some(0)
 +    } else { Some(0).map(|x| x + 1) };
 +
 +    if true {
 +        Some(0)
 +    } else { Some(0).map(|x| x + 1) };
 +
 +    // #6967
 +    const fn f4() {
 +        match Some(0) {
 +            Some(x) => Some(x + 1),
 +            None => None,
 +        };
 +    }
 +
 +    // #7077
 +    let s = &String::new();
 +    let _: Option<&str> = match Some(s) {
 +        Some(s) => Some(s),
 +        None => None,
 +    };
 +}
index cfef0c5cc4ec66207834005b7b151d666737c0fa,0000000000000000000000000000000000000000..d11bf5ecb825ae28a1ae76ba6f1594199e37dfc8
mode 100644,000000..100644
--- /dev/null
@@@ -1,222 -1,0 +1,221 @@@
- // edition:2018
 +// run-rustfix
 +
 +#![warn(clippy::manual_map)]
 +#![allow(
 +    clippy::no_effect,
 +    clippy::map_identity,
 +    clippy::unit_arg,
 +    clippy::match_ref_pats,
 +    clippy::redundant_pattern_matching,
 +    dead_code
 +)]
 +
 +fn main() {
 +    match Some(0) {
 +        Some(_) => Some(2),
 +        None::<u32> => None,
 +    };
 +
 +    match Some(0) {
 +        Some(x) => Some(x + 1),
 +        _ => None,
 +    };
 +
 +    match Some("") {
 +        Some(x) => Some(x.is_empty()),
 +        None => None,
 +    };
 +
 +    if let Some(x) = Some(0) {
 +        Some(!x)
 +    } else {
 +        None
 +    };
 +
 +    #[rustfmt::skip]
 +    match Some(0) {
 +        Some(x) => { Some(std::convert::identity(x)) }
 +        None => { None }
 +    };
 +
 +    match Some(&String::new()) {
 +        Some(x) => Some(str::len(x)),
 +        None => None,
 +    };
 +
 +    match Some(0) {
 +        Some(x) if false => Some(x + 1),
 +        _ => None,
 +    };
 +
 +    match &Some([0, 1]) {
 +        Some(x) => Some(x[0]),
 +        &None => None,
 +    };
 +
 +    match &Some(0) {
 +        &Some(x) => Some(x * 2),
 +        None => None,
 +    };
 +
 +    match Some(String::new()) {
 +        Some(ref x) => Some(x.is_empty()),
 +        _ => None,
 +    };
 +
 +    match &&Some(String::new()) {
 +        Some(x) => Some(x.len()),
 +        _ => None,
 +    };
 +
 +    match &&Some(0) {
 +        &&Some(x) => Some(x + x),
 +        &&_ => None,
 +    };
 +
 +    #[warn(clippy::option_map_unit_fn)]
 +    match &mut Some(String::new()) {
 +        Some(x) => Some(x.push_str("")),
 +        None => None,
 +    };
 +
 +    #[allow(clippy::option_map_unit_fn)]
 +    {
 +        match &mut Some(String::new()) {
 +            Some(x) => Some(x.push_str("")),
 +            None => None,
 +        };
 +    }
 +
 +    match &mut Some(String::new()) {
 +        Some(ref x) => Some(x.len()),
 +        None => None,
 +    };
 +
 +    match &mut &Some(String::new()) {
 +        Some(x) => Some(x.is_empty()),
 +        &mut _ => None,
 +    };
 +
 +    match Some((0, 1, 2)) {
 +        Some((x, y, z)) => Some(x + y + z),
 +        None => None,
 +    };
 +
 +    match Some([1, 2, 3]) {
 +        Some([first, ..]) => Some(first),
 +        None => None,
 +    };
 +
 +    match &Some((String::new(), "test")) {
 +        Some((x, y)) => Some((y, x)),
 +        None => None,
 +    };
 +
 +    match Some((String::new(), 0)) {
 +        Some((ref x, y)) => Some((y, x)),
 +        None => None,
 +    };
 +
 +    match Some(Some(0)) {
 +        Some(Some(_)) | Some(None) => Some(0),
 +        None => None,
 +    };
 +
 +    match Some(Some((0, 1))) {
 +        Some(Some((x, 1))) => Some(x),
 +        _ => None,
 +    };
 +
 +    // #6795
 +    fn f1() -> Result<(), ()> {
 +        let _ = match Some(Ok(())) {
 +            Some(x) => Some(x?),
 +            None => None,
 +        };
 +        Ok(())
 +    }
 +
 +    for &x in Some(Some(true)).iter() {
 +        let _ = match x {
 +            Some(x) => Some(if x { continue } else { x }),
 +            None => None,
 +        };
 +    }
 +
 +    // #6797
 +    let x1 = (Some(String::new()), 0);
 +    let x2 = x1.0;
 +    match x2 {
 +        Some(x) => Some((x, x1.1)),
 +        None => None,
 +    };
 +
 +    struct S1 {
 +        x: Option<String>,
 +        y: u32,
 +    }
 +    impl S1 {
 +        fn f(self) -> Option<(String, u32)> {
 +            match self.x {
 +                Some(x) => Some((x, self.y)),
 +                None => None,
 +            }
 +        }
 +    }
 +
 +    // #6811
 +    match Some(0) {
 +        Some(x) => Some(vec![x]),
 +        None => None,
 +    };
 +
 +    match option_env!("") {
 +        Some(x) => Some(String::from(x)),
 +        None => None,
 +    };
 +
 +    // #6819
 +    async fn f2(x: u32) -> u32 {
 +        x
 +    }
 +
 +    async fn f3() {
 +        match Some(0) {
 +            Some(x) => Some(f2(x).await),
 +            None => None,
 +        };
 +    }
 +
 +    // #6847
 +    if let Some(_) = Some(0) {
 +        Some(0)
 +    } else if let Some(x) = Some(0) {
 +        Some(x + 1)
 +    } else {
 +        None
 +    };
 +
 +    if true {
 +        Some(0)
 +    } else if let Some(x) = Some(0) {
 +        Some(x + 1)
 +    } else {
 +        None
 +    };
 +
 +    // #6967
 +    const fn f4() {
 +        match Some(0) {
 +            Some(x) => Some(x + 1),
 +            None => None,
 +        };
 +    }
 +
 +    // #7077
 +    let s = &String::new();
 +    let _: Option<&str> = match Some(s) {
 +        Some(s) => Some(s),
 +        None => None,
 +    };
 +}
index cdc2c0e62a9b9434838946240bbbc1f44e3a7f5c,0000000000000000000000000000000000000000..0036b8151ded0514259d03687784e3597716b977
mode 100644,000000..100644
--- /dev/null
@@@ -1,198 -1,0 +1,198 @@@
-   --> $DIR/manual_map_option.rs:15:5
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:20:5
++  --> $DIR/manual_map_option.rs:14:5
 +   |
 +LL | /     match Some(0) {
 +LL | |         Some(_) => Some(2),
 +LL | |         None::<u32> => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some(0).map(|_| 2)`
 +   |
 +   = note: `-D clippy::manual-map` implied by `-D warnings`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:25:5
++  --> $DIR/manual_map_option.rs:19:5
 +   |
 +LL | /     match Some(0) {
 +LL | |         Some(x) => Some(x + 1),
 +LL | |         _ => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some(0).map(|x| x + 1)`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:30:5
++  --> $DIR/manual_map_option.rs:24:5
 +   |
 +LL | /     match Some("") {
 +LL | |         Some(x) => Some(x.is_empty()),
 +LL | |         None => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some("").map(|x| x.is_empty())`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:37:5
++  --> $DIR/manual_map_option.rs:29:5
 +   |
 +LL | /     if let Some(x) = Some(0) {
 +LL | |         Some(!x)
 +LL | |     } else {
 +LL | |         None
 +LL | |     };
 +   | |_____^ help: try this: `Some(0).map(|x| !x)`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:42:5
++  --> $DIR/manual_map_option.rs:36:5
 +   |
 +LL | /     match Some(0) {
 +LL | |         Some(x) => { Some(std::convert::identity(x)) }
 +LL | |         None => { None }
 +LL | |     };
 +   | |_____^ help: try this: `Some(0).map(std::convert::identity)`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:52:5
++  --> $DIR/manual_map_option.rs:41:5
 +   |
 +LL | /     match Some(&String::new()) {
 +LL | |         Some(x) => Some(str::len(x)),
 +LL | |         None => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some(&String::new()).map(|x| str::len(x))`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:57:5
++  --> $DIR/manual_map_option.rs:51:5
 +   |
 +LL | /     match &Some([0, 1]) {
 +LL | |         Some(x) => Some(x[0]),
 +LL | |         &None => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some([0, 1]).as_ref().map(|x| x[0])`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:62:5
++  --> $DIR/manual_map_option.rs:56:5
 +   |
 +LL | /     match &Some(0) {
 +LL | |         &Some(x) => Some(x * 2),
 +LL | |         None => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some(0).map(|x| x * 2)`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:67:5
++  --> $DIR/manual_map_option.rs:61:5
 +   |
 +LL | /     match Some(String::new()) {
 +LL | |         Some(ref x) => Some(x.is_empty()),
 +LL | |         _ => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:72:5
++  --> $DIR/manual_map_option.rs:66:5
 +   |
 +LL | /     match &&Some(String::new()) {
 +LL | |         Some(x) => Some(x.len()),
 +LL | |         _ => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:85:9
++  --> $DIR/manual_map_option.rs:71:5
 +   |
 +LL | /     match &&Some(0) {
 +LL | |         &&Some(x) => Some(x + x),
 +LL | |         &&_ => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some(0).map(|x| x + x)`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:91:5
++  --> $DIR/manual_map_option.rs:84:9
 +   |
 +LL | /         match &mut Some(String::new()) {
 +LL | |             Some(x) => Some(x.push_str("")),
 +LL | |             None => None,
 +LL | |         };
 +   | |_________^ help: try this: `Some(String::new()).as_mut().map(|x| x.push_str(""))`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:96:5
++  --> $DIR/manual_map_option.rs:90:5
 +   |
 +LL | /     match &mut Some(String::new()) {
 +LL | |         Some(ref x) => Some(x.len()),
 +LL | |         None => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:101:5
++  --> $DIR/manual_map_option.rs:95:5
 +   |
 +LL | /     match &mut &Some(String::new()) {
 +LL | |         Some(x) => Some(x.is_empty()),
 +LL | |         &mut _ => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:106:5
++  --> $DIR/manual_map_option.rs:100:5
 +   |
 +LL | /     match Some((0, 1, 2)) {
 +LL | |         Some((x, y, z)) => Some(x + y + z),
 +LL | |         None => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some((0, 1, 2)).map(|(x, y, z)| x + y + z)`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:111:5
++  --> $DIR/manual_map_option.rs:105:5
 +   |
 +LL | /     match Some([1, 2, 3]) {
 +LL | |         Some([first, ..]) => Some(first),
 +LL | |         None => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some([1, 2, 3]).map(|[first, ..]| first)`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:169:5
++  --> $DIR/manual_map_option.rs:110:5
 +   |
 +LL | /     match &Some((String::new(), "test")) {
 +LL | |         Some((x, y)) => Some((y, x)),
 +LL | |         None => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:174:5
++  --> $DIR/manual_map_option.rs:168:5
 +   |
 +LL | /     match Some(0) {
 +LL | |         Some(x) => Some(vec![x]),
 +LL | |         None => None,
 +LL | |     };
 +   | |_____^ help: try this: `Some(0).map(|x| vec![x])`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:194:12
++  --> $DIR/manual_map_option.rs:173:5
 +   |
 +LL | /     match option_env!("") {
 +LL | |         Some(x) => Some(String::from(x)),
 +LL | |         None => None,
 +LL | |     };
 +   | |_____^ help: try this: `option_env!("").map(String::from)`
 +
 +error: manual implementation of `Option::map`
-   --> $DIR/manual_map_option.rs:202:12
++  --> $DIR/manual_map_option.rs:193:12
 +   |
 +LL |       } else if let Some(x) = Some(0) {
 +   |  ____________^
 +LL | |         Some(x + 1)
 +LL | |     } else {
 +LL | |         None
 +LL | |     };
 +   | |_____^ help: try this: `{ Some(0).map(|x| x + 1) }`
 +
 +error: manual implementation of `Option::map`
++  --> $DIR/manual_map_option.rs:201:12
 +   |
 +LL |       } else if let Some(x) = Some(0) {
 +   |  ____________^
 +LL | |         Some(x + 1)
 +LL | |     } else {
 +LL | |         None
 +LL | |     };
 +   | |_____^ help: try this: `{ Some(0).map(|x| x + 1) }`
 +
 +error: aborting due to 21 previous errors
 +
index ff91c4498ec62afd43c12497579a6a66925fd42a,0000000000000000000000000000000000000000..845986a4eadabeee40414a90d26162cbb4ba5007
mode 100644,000000..100644
--- /dev/null
@@@ -1,110 -1,0 +1,117 @@@
 +#![feature(exclusive_range_pattern)]
 +#![feature(half_open_range_patterns)]
 +#![warn(clippy::match_overlapping_arm)]
 +#![allow(clippy::redundant_pattern_matching)]
 +#![allow(clippy::if_same_then_else, clippy::equatable_if_let)]
 +
 +/// Tests for match_overlapping_arm
 +
 +fn overlapping() {
 +    const FOO: u64 = 2;
 +
 +    match 42 {
 +        0..=10 => println!("0..=10"),
 +        0..=11 => println!("0..=11"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        0..=5 => println!("0..=5"),
 +        6..=7 => println!("6..=7"),
 +        FOO..=11 => println!("FOO..=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"),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        3.. => println!("3.."),
 +        0.. => println!("0.."),
 +        _ => (),
 +    }
 +
 +    match 42 {
 +        ..=23 => println!("..=23"),
 +        ..26 => println!("..26"),
 +        _ => (),
 +    }
 +
++    // Issue #7829
++    match 0 {
++        -1..=1 => (),
++        -2..=2 => (),
++        _ => (),
++    }
++
 +    if let None = Some(42) {
 +        // nothing
 +    } else if let None = Some(42) {
 +        // another nothing :-)
 +    }
 +}
 +
 +fn main() {}
index 50246486bb6fc9371206f17adfe284b5e722a566,0000000000000000000000000000000000000000..7e3674ab8c9f2c633094cce82c11d3351ebb8cb8
mode 100644,000000..100644
--- /dev/null
@@@ -1,117 -1,0 +1,117 @@@
- #![allow(clippy::equatable_if_let)]
 +#![warn(clippy::match_ref_pats)]
++#![allow(clippy::equatable_if_let, clippy::enum_variant_names)]
 +
 +fn ref_pats() {
 +    {
 +        let v = &Some(0);
 +        match v {
 +            &Some(v) => println!("{:?}", v),
 +            &None => println!("none"),
 +        }
 +        match v {
 +            // This doesn't trigger; we have a different pattern.
 +            &Some(v) => println!("some"),
 +            other => println!("other"),
 +        }
 +    }
 +    let tup = &(1, 2);
 +    match tup {
 +        &(v, 1) => println!("{}", v),
 +        _ => println!("none"),
 +    }
 +    // Special case: using `&` both in expr and pats.
 +    let w = Some(0);
 +    match &w {
 +        &Some(v) => println!("{:?}", v),
 +        &None => println!("none"),
 +    }
 +    // False positive: only wildcard pattern.
 +    let w = Some(0);
 +    #[allow(clippy::match_single_binding)]
 +    match w {
 +        _ => println!("none"),
 +    }
 +
 +    let a = &Some(0);
 +    if let &None = a {
 +        println!("none");
 +    }
 +
 +    let b = Some(0);
 +    if let &None = &b {
 +        println!("none");
 +    }
 +}
 +
 +mod ice_3719 {
 +    macro_rules! foo_variant(
 +        ($idx:expr) => (Foo::get($idx).unwrap())
 +    );
 +
 +    enum Foo {
 +        A,
 +        B,
 +    }
 +
 +    impl Foo {
 +        fn get(idx: u8) -> Option<&'static Self> {
 +            match idx {
 +                0 => Some(&Foo::A),
 +                1 => Some(&Foo::B),
 +                _ => None,
 +            }
 +        }
 +    }
 +
 +    fn ice_3719() {
 +        // ICE #3719
 +        match foo_variant!(0) {
 +            &Foo::A => println!("A"),
 +            _ => println!("Wild"),
 +        }
 +    }
 +}
 +
 +mod issue_7740 {
 +    macro_rules! foobar_variant(
 +        ($idx:expr) => (FooBar::get($idx).unwrap())
 +    );
 +
 +    enum FooBar {
 +        Foo,
 +        Bar,
 +        FooBar,
 +        BarFoo,
 +    }
 +
 +    impl FooBar {
 +        fn get(idx: u8) -> Option<&'static Self> {
 +            match idx {
 +                0 => Some(&FooBar::Foo),
 +                1 => Some(&FooBar::Bar),
 +                2 => Some(&FooBar::FooBar),
 +                3 => Some(&FooBar::BarFoo),
 +                _ => None,
 +            }
 +        }
 +    }
 +
 +    fn issue_7740() {
 +        // Issue #7740
 +        match foobar_variant!(0) {
 +            &FooBar::Foo => println!("Foo"),
 +            &FooBar::Bar => println!("Bar"),
 +            &FooBar::FooBar => println!("FooBar"),
 +            _ => println!("Wild"),
 +        }
 +
 +        // This shouldn't trigger
 +        if let &FooBar::BarFoo = foobar_variant!(3) {
 +            println!("BarFoo");
 +        } else {
 +            println!("Wild");
 +        }
 +    }
 +}
 +
 +fn main() {}
index 208a4bba3d23c40d5cf2cbe4a2f650c18ba584b5,0000000000000000000000000000000000000000..ac555c87d83b21a14beecece000d2cd7a55cbbdf
mode 100644,000000..100644
--- /dev/null
@@@ -1,98 -1,0 +1,184 @@@
 +#![warn(clippy::match_str_case_mismatch)]
 +
 +// Valid
 +
 +fn as_str_match() {
 +    let var = "BAR";
 +
 +    match var.to_ascii_lowercase().as_str() {
 +        "foo" => {},
 +        "bar" => {},
 +        _ => {},
 +    }
 +}
 +
++fn non_alphabetic() {
++    let var = "~!@#$%^&*()-_=+FOO";
++
++    match var.to_ascii_lowercase().as_str() {
++        "1234567890" => {},
++        "~!@#$%^&*()-_=+foo" => {},
++        "\n\r\t\x7F" => {},
++        _ => {},
++    }
++}
++
++fn unicode_cased() {
++    let var = "ВОДЫ";
++
++    match var.to_lowercase().as_str() {
++        "水" => {},
++        "νερό" => {},
++        "воды" => {},
++        "물" => {},
++        _ => {},
++    }
++}
++
++fn titlecase() {
++    let var = "BarDz";
++
++    match var.to_lowercase().as_str() {
++        "foolj" => {},
++        "bardz" => {},
++        _ => {},
++    }
++}
++
++fn no_case_equivalent() {
++    let var = "barʁ";
++
++    match var.to_uppercase().as_str() {
++        "FOOɕ" => {},
++        "BARʁ" => {},
++        _ => {},
++    }
++}
++
 +fn addrof_unary_match() {
 +    let var = "BAR";
 +
 +    match &*var.to_ascii_lowercase() {
 +        "foo" => {},
 +        "bar" => {},
 +        _ => {},
 +    }
 +}
 +
 +fn alternating_chain() {
 +    let var = "BAR";
 +
 +    match &*var
 +        .to_ascii_lowercase()
 +        .to_uppercase()
 +        .to_lowercase()
 +        .to_ascii_uppercase()
 +    {
 +        "FOO" => {},
 +        "BAR" => {},
 +        _ => {},
 +    }
 +}
 +
 +fn unrelated_method() {
 +    struct Item {
 +        a: String,
 +    }
 +
 +    impl Item {
 +        #[allow(clippy::wrong_self_convention)]
 +        fn to_lowercase(self) -> String {
 +            self.a
 +        }
 +    }
 +
 +    let item = Item { a: String::from("BAR") };
 +
 +    match &*item.to_lowercase() {
 +        "FOO" => {},
 +        "BAR" => {},
 +        _ => {},
 +    }
 +}
 +
 +// Invalid
 +
 +fn as_str_match_mismatch() {
 +    let var = "BAR";
 +
 +    match var.to_ascii_lowercase().as_str() {
 +        "foo" => {},
 +        "Bar" => {},
 +        _ => {},
 +    }
 +}
 +
++fn non_alphabetic_mismatch() {
++    let var = "~!@#$%^&*()-_=+FOO";
++
++    match var.to_ascii_lowercase().as_str() {
++        "1234567890" => {},
++        "~!@#$%^&*()-_=+Foo" => {},
++        "\n\r\t\x7F" => {},
++        _ => {},
++    }
++}
++
++fn unicode_cased_mismatch() {
++    let var = "ВОДЫ";
++
++    match var.to_lowercase().as_str() {
++        "水" => {},
++        "νερό" => {},
++        "Воды" => {},
++        "물" => {},
++        _ => {},
++    }
++}
++
++fn titlecase_mismatch() {
++    let var = "BarDz";
++
++    match var.to_lowercase().as_str() {
++        "foolj" => {},
++        "barDz" => {},
++        _ => {},
++    }
++}
++
++fn no_case_equivalent_mismatch() {
++    let var = "barʁ";
++
++    match var.to_uppercase().as_str() {
++        "FOOɕ" => {},
++        "bARʁ" => {},
++        _ => {},
++    }
++}
++
 +fn addrof_unary_match_mismatch() {
 +    let var = "BAR";
 +
 +    match &*var.to_ascii_lowercase() {
 +        "foo" => {},
 +        "Bar" => {},
 +        _ => {},
 +    }
 +}
 +
 +fn alternating_chain_mismatch() {
 +    let var = "BAR";
 +
 +    match &*var
 +        .to_ascii_lowercase()
 +        .to_uppercase()
 +        .to_lowercase()
 +        .to_ascii_uppercase()
 +    {
 +        "FOO" => {},
 +        "bAR" => {},
 +        _ => {},
 +    }
 +}
 +
 +fn main() {}
index fa023477a9c334d20c7a934e93091b270bd41bf0,0000000000000000000000000000000000000000..92baa40ef28f06f99746326de19b31e53055d703
mode 100644,000000..100644
--- /dev/null
@@@ -1,36 -1,0 +1,80 @@@
-   --> $DIR/match_str_case_mismatch.rs:68:9
 +error: this `match` arm has a differing case than its expression
-   --> $DIR/match_str_case_mismatch.rs:78:9
++  --> $DIR/match_str_case_mismatch.rs:111:9
 +   |
 +LL |         "Bar" => {},
 +   |         ^^^^^
 +   |
 +   = note: `-D clippy::match-str-case-mismatch` implied by `-D warnings`
 +help: consider changing the case of this arm to respect `to_ascii_lowercase`
 +   |
 +LL |         "bar" => {},
 +   |         ~~~~~
 +
 +error: this `match` arm has a differing case than its expression
-   --> $DIR/match_str_case_mismatch.rs:93:9
++  --> $DIR/match_str_case_mismatch.rs:121:9
++   |
++LL |         "~!@#$%^&*()-_=+Foo" => {},
++   |         ^^^^^^^^^^^^^^^^^^^^
++   |
++help: consider changing the case of this arm to respect `to_ascii_lowercase`
++   |
++LL |         "~!@#$%^&*()-_=+foo" => {},
++   |         ~~~~~~~~~~~~~~~~~~~~
++
++error: this `match` arm has a differing case than its expression
++  --> $DIR/match_str_case_mismatch.rs:133:9
++   |
++LL |         "Воды" => {},
++   |         ^^^^^^
++   |
++help: consider changing the case of this arm to respect `to_lowercase`
++   |
++LL |         "воды" => {},
++   |         ~~~~~~
++
++error: this `match` arm has a differing case than its expression
++  --> $DIR/match_str_case_mismatch.rs:144:9
++   |
++LL |         "barDz" => {},
++   |         ^^^^^^
++   |
++help: consider changing the case of this arm to respect `to_lowercase`
++   |
++LL |         "bardz" => {},
++   |         ~~~~~~
++
++error: this `match` arm has a differing case than its expression
++  --> $DIR/match_str_case_mismatch.rs:154:9
++   |
++LL |         "bARʁ" => {},
++   |         ^^^^^^
++   |
++help: consider changing the case of this arm to respect `to_uppercase`
++   |
++LL |         "BARʁ" => {},
++   |         ~~~~~~
++
++error: this `match` arm has a differing case than its expression
++  --> $DIR/match_str_case_mismatch.rs:164:9
 +   |
 +LL |         "Bar" => {},
 +   |         ^^^^^
 +   |
 +help: consider changing the case of this arm to respect `to_ascii_lowercase`
 +   |
 +LL |         "bar" => {},
 +   |         ~~~~~
 +
 +error: this `match` arm has a differing case than its expression
- error: aborting due to 3 previous errors
++  --> $DIR/match_str_case_mismatch.rs:179:9
 +   |
 +LL |         "bAR" => {},
 +   |         ^^^^^
 +   |
 +help: consider changing the case of this arm to respect `to_ascii_uppercase`
 +   |
 +LL |         "BAR" => {},
 +   |         ~~~~~
 +
++error: aborting due to 7 previous errors
 +
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2a4012039ba97a62b993f0234906695186293e7f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,35 @@@
++error: `Err(_)` matches all errors
++  --> $DIR/match_wild_err_arm.rs:14:9
++   |
++LL |         Err(_) => panic!("err"),
++   |         ^^^^^^
++   |
++   = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
++   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
++
++error: `Err(_)` matches all errors
++  --> $DIR/match_wild_err_arm.rs:20:9
++   |
++LL |         Err(_) => panic!(),
++   |         ^^^^^^
++   |
++   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
++
++error: `Err(_)` matches all errors
++  --> $DIR/match_wild_err_arm.rs:26:9
++   |
++LL |         Err(_) => {
++   |         ^^^^^^
++   |
++   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
++
++error: `Err(_e)` matches all errors
++  --> $DIR/match_wild_err_arm.rs:34:9
++   |
++LL |         Err(_e) => panic!(),
++   |         ^^^^^^^
++   |
++   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
++
++error: aborting due to 4 previous errors
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2a4012039ba97a62b993f0234906695186293e7f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,35 @@@
++error: `Err(_)` matches all errors
++  --> $DIR/match_wild_err_arm.rs:14:9
++   |
++LL |         Err(_) => panic!("err"),
++   |         ^^^^^^
++   |
++   = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
++   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
++
++error: `Err(_)` matches all errors
++  --> $DIR/match_wild_err_arm.rs:20:9
++   |
++LL |         Err(_) => panic!(),
++   |         ^^^^^^
++   |
++   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
++
++error: `Err(_)` matches all errors
++  --> $DIR/match_wild_err_arm.rs:26:9
++   |
++LL |         Err(_) => {
++   |         ^^^^^^
++   |
++   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
++
++error: `Err(_e)` matches all errors
++  --> $DIR/match_wild_err_arm.rs:34:9
++   |
++LL |         Err(_e) => panic!(),
++   |         ^^^^^^^
++   |
++   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
++
++error: aborting due to 4 previous errors
++
index 823be65efe065703b8481ced833636d15b245373,0000000000000000000000000000000000000000..0a86144b95d5bcc59b148e298783caa02d017217
mode 100644,000000..100644
--- /dev/null
@@@ -1,65 -1,0 +1,68 @@@
++// revisions: edition2018 edition2021
++// [edition2018] edition:2018
++// [edition2021] edition:2021
 +#![feature(exclusive_range_pattern)]
 +#![allow(clippy::match_same_arms)]
 +#![warn(clippy::match_wild_err_arm)]
 +
 +fn match_wild_err_arm() {
 +    let x: Result<i32, &str> = Ok(3);
 +
 +    match x {
 +        Ok(3) => println!("ok"),
 +        Ok(_) => println!("ok"),
 +        Err(_) => panic!("err"),
 +    }
 +
 +    match x {
 +        Ok(3) => println!("ok"),
 +        Ok(_) => println!("ok"),
 +        Err(_) => panic!(),
 +    }
 +
 +    match x {
 +        Ok(3) => println!("ok"),
 +        Ok(_) => println!("ok"),
 +        Err(_) => {
 +            panic!();
 +        },
 +    }
 +
 +    match x {
 +        Ok(3) => println!("ok"),
 +        Ok(_) => println!("ok"),
 +        Err(_e) => panic!(),
 +    }
 +
 +    // Allowed when used in `panic!`.
 +    match x {
 +        Ok(3) => println!("ok"),
 +        Ok(_) => println!("ok"),
 +        Err(_e) => panic!("{}", _e),
 +    }
 +
 +    // Allowed when not with `panic!` block.
 +    match x {
 +        Ok(3) => println!("ok"),
 +        Ok(_) => println!("ok"),
 +        Err(_) => println!("err"),
 +    }
 +
 +    // Allowed when used with `unreachable!`.
 +    match x {
 +        Ok(3) => println!("ok"),
 +        Ok(_) => println!("ok"),
 +        Err(_) => unreachable!(),
 +    }
 +
 +    // Allowed when used with `unreachable!`.
 +    match x {
 +        Ok(3) => println!("ok"),
 +        Ok(_) => println!("ok"),
 +        Err(_) => {
 +            unreachable!();
 +        },
 +    }
 +}
 +
 +fn main() {}
index c441b35b9920390c89edfc6ac504716cf25eae2f,0000000000000000000000000000000000000000..977ce54327b3d984a4f61fca7c2967b734a3ce57
mode 100644,000000..100644
--- /dev/null
@@@ -1,141 -1,0 +1,140 @@@
- // edition:2018
 +// aux-build:option_helpers.rs
 +
 +#![warn(clippy::all, clippy::pedantic)]
 +#![allow(
 +    clippy::blacklisted_name,
 +    clippy::default_trait_access,
 +    clippy::missing_docs_in_private_items,
 +    clippy::missing_safety_doc,
 +    clippy::non_ascii_literal,
 +    clippy::new_without_default,
 +    clippy::needless_pass_by_value,
 +    clippy::needless_lifetimes,
 +    clippy::print_stdout,
 +    clippy::must_use_candidate,
 +    clippy::use_self,
 +    clippy::useless_format,
 +    clippy::wrong_self_convention,
 +    clippy::unused_self,
 +    unused
 +)]
 +
 +#[macro_use]
 +extern crate option_helpers;
 +
 +use std::collections::BTreeMap;
 +use std::collections::HashMap;
 +use std::collections::HashSet;
 +use std::collections::VecDeque;
 +use std::iter::FromIterator;
 +use std::ops::Mul;
 +use std::rc::{self, Rc};
 +use std::sync::{self, Arc};
 +
 +use option_helpers::{IteratorFalsePositives, IteratorMethodFalsePositives};
 +
 +struct Lt<'a> {
 +    foo: &'a u32,
 +}
 +
 +impl<'a> Lt<'a> {
 +    // The lifetime is different, but that’s irrelevant; see issue #734.
 +    #[allow(clippy::needless_lifetimes)]
 +    pub fn new<'b>(s: &'b str) -> Lt<'b> {
 +        unimplemented!()
 +    }
 +}
 +
 +struct Lt2<'a> {
 +    foo: &'a u32,
 +}
 +
 +impl<'a> Lt2<'a> {
 +    // The lifetime is different, but that’s irrelevant; see issue #734.
 +    pub fn new(s: &str) -> Lt2 {
 +        unimplemented!()
 +    }
 +}
 +
 +struct Lt3<'a> {
 +    foo: &'a u32,
 +}
 +
 +impl<'a> Lt3<'a> {
 +    // The lifetime is different, but that’s irrelevant; see issue #734.
 +    pub fn new() -> Lt3<'static> {
 +        unimplemented!()
 +    }
 +}
 +
 +#[derive(Clone, Copy)]
 +struct U;
 +
 +impl U {
 +    fn new() -> Self {
 +        U
 +    }
 +    // Ok because `U` is `Copy`.
 +    fn to_something(self) -> u32 {
 +        0
 +    }
 +}
 +
 +struct V<T> {
 +    _dummy: T,
 +}
 +
 +impl<T> V<T> {
 +    fn new() -> Option<V<T>> {
 +        None
 +    }
 +}
 +
 +struct AsyncNew;
 +
 +impl AsyncNew {
 +    async fn new() -> Option<Self> {
 +        None
 +    }
 +}
 +
 +struct BadNew;
 +
 +impl BadNew {
 +    fn new() -> i32 {
 +        0
 +    }
 +}
 +
 +struct T;
 +
 +impl Mul<T> for T {
 +    type Output = T;
 +    // No error, obviously.
 +    fn mul(self, other: T) -> T {
 +        self
 +    }
 +}
 +
 +/// Checks implementation of `FILTER_NEXT` lint.
 +#[rustfmt::skip]
 +fn filter_next() {
 +    let v = vec![3, 2, 1, 0, -1, -2, -3];
 +
 +    // Multi-line case.
 +    let _ = v.iter().filter(|&x| {
 +                                *x < 0
 +                            }
 +                   ).next();
 +
 +    // Check that we don't lint if the caller is not an `Iterator`.
 +    let foo = IteratorFalsePositives { foo: 0 };
 +    let _ = foo.filter().next();
 +
 +    let foo = IteratorMethodFalsePositives {};
 +    let _ = foo.filter(42).next();
 +}
 +
 +fn main() {
 +    filter_next();
 +}
index 4643e09e2702835ac9803b6050b49f1ba7267171,0000000000000000000000000000000000000000..b63672dd6fdbb546dac805e74727f9bf8982851f
mode 100644,000000..100644
--- /dev/null
@@@ -1,24 -1,0 +1,24 @@@
-   --> $DIR/methods.rs:105:5
 +error: methods called `new` usually return `Self`
-   --> $DIR/methods.rs:126:13
++  --> $DIR/methods.rs:104:5
 +   |
 +LL | /     fn new() -> i32 {
 +LL | |         0
 +LL | |     }
 +   | |_____^
 +   |
 +   = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
 +
 +error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
++  --> $DIR/methods.rs:125:13
 +   |
 +LL |       let _ = v.iter().filter(|&x| {
 +   |  _____________^
 +LL | |                                 *x < 0
 +LL | |                             }
 +LL | |                    ).next();
 +   | |___________________________^
 +   |
 +   = note: `-D clippy::filter-next` implied by `-D warnings`
 +
 +error: aborting due to 2 previous errors
 +
index a9bf7140a1e594ae61cf64f9a000ee6716b669b3,0000000000000000000000000000000000000000..148531c285d3d310ed9011992604cf8a5d4c4b43
mode 100644,000000..100644
--- /dev/null
@@@ -1,102 -1,0 +1,101 @@@
 +#![warn(clippy::missing_docs_in_private_items)]
 +// When denying at the crate level, be sure to not get random warnings from the
 +// injected intrinsics by the compiler.
 +#![allow(dead_code)]
 +#![feature(global_asm)]
-     pub use internal_impl::documented as foo;
-     pub use internal_impl::globbed::*;
-     pub use internal_impl::undocumented1 as bar;
-     pub use internal_impl::{documented, undocumented2};
 +//! Some garbage docs for the crate here
 +#![doc = "More garbage"]
 +
 +type Typedef = String;
 +pub type PubTypedef = String;
 +
 +mod module_no_dox {}
 +pub mod pub_module_no_dox {}
 +
 +/// dox
 +pub fn foo() {}
 +pub fn foo2() {}
 +fn foo3() {}
 +#[allow(clippy::missing_docs_in_private_items)]
 +pub fn foo4() {}
 +
 +// It sure is nice if doc(hidden) implies allow(missing_docs), and that it
 +// applies recursively
 +#[doc(hidden)]
 +mod a {
 +    pub fn baz() {}
 +    pub mod b {
 +        pub fn baz() {}
 +    }
 +}
 +
 +enum Baz {
 +    BazA { a: isize, b: isize },
 +    BarB,
 +}
 +
 +pub enum PubBaz {
 +    PubBazA { a: isize },
 +}
 +
 +/// dox
 +pub enum PubBaz2 {
 +    /// dox
 +    PubBaz2A {
 +        /// dox
 +        a: isize,
 +    },
 +}
 +
 +#[allow(clippy::missing_docs_in_private_items)]
 +pub enum PubBaz3 {
 +    PubBaz3A { b: isize },
 +}
 +
 +#[doc(hidden)]
 +pub fn baz() {}
 +
 +const FOO: u32 = 0;
 +/// dox
 +pub const FOO1: u32 = 0;
 +#[allow(clippy::missing_docs_in_private_items)]
 +pub const FOO2: u32 = 0;
 +#[doc(hidden)]
 +pub const FOO3: u32 = 0;
 +pub const FOO4: u32 = 0;
 +
 +static BAR: u32 = 0;
 +/// dox
 +pub static BAR1: u32 = 0;
 +#[allow(clippy::missing_docs_in_private_items)]
 +pub static BAR2: u32 = 0;
 +#[doc(hidden)]
 +pub static BAR3: u32 = 0;
 +pub static BAR4: u32 = 0;
 +
 +mod internal_impl {
 +    /// dox
 +    pub fn documented() {}
 +    pub fn undocumented1() {}
 +    pub fn undocumented2() {}
 +    fn undocumented3() {}
 +    /// dox
 +    pub mod globbed {
 +        /// dox
 +        pub fn also_documented() {}
 +        pub fn also_undocumented1() {}
 +        fn also_undocumented2() {}
 +    }
 +}
 +/// dox
 +pub mod public_interface {
++    pub use crate::internal_impl::documented as foo;
++    pub use crate::internal_impl::globbed::*;
++    pub use crate::internal_impl::undocumented1 as bar;
++    pub use crate::internal_impl::{documented, undocumented2};
 +}
 +
 +fn main() {}
 +
 +// Ensure global asm doesn't require documentation.
 +global_asm! { "" }
index a876dc078ebff96f25c8e34efad90156b896a70a,0000000000000000000000000000000000000000..7a3a448c9d6c2730e407e220b73297e57e576119
mode 100644,000000..100644
--- /dev/null
@@@ -1,159 -1,0 +1,159 @@@
-   --> $DIR/missing-doc.rs:10:1
 +error: missing documentation for a type alias
-   --> $DIR/missing-doc.rs:11:1
++  --> $DIR/missing-doc.rs:9:1
 +   |
 +LL | type Typedef = String;
 +   | ^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
 +
 +error: missing documentation for a type alias
-   --> $DIR/missing-doc.rs:13:1
++  --> $DIR/missing-doc.rs:10:1
 +   |
 +LL | pub type PubTypedef = String;
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: missing documentation for a module
-   --> $DIR/missing-doc.rs:14:1
++  --> $DIR/missing-doc.rs:12:1
 +   |
 +LL | mod module_no_dox {}
 +   | ^^^^^^^^^^^^^^^^^^^^
 +
 +error: missing documentation for a module
-   --> $DIR/missing-doc.rs:18:1
++  --> $DIR/missing-doc.rs:13:1
 +   |
 +LL | pub mod pub_module_no_dox {}
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: missing documentation for a function
-   --> $DIR/missing-doc.rs:19:1
++  --> $DIR/missing-doc.rs:17:1
 +   |
 +LL | pub fn foo2() {}
 +   | ^^^^^^^^^^^^^^^^
 +
 +error: missing documentation for a function
-   --> $DIR/missing-doc.rs:33:1
++  --> $DIR/missing-doc.rs:18:1
 +   |
 +LL | fn foo3() {}
 +   | ^^^^^^^^^^^^
 +
 +error: missing documentation for an enum
-   --> $DIR/missing-doc.rs:34:5
++  --> $DIR/missing-doc.rs:32:1
 +   |
 +LL | / enum Baz {
 +LL | |     BazA { a: isize, b: isize },
 +LL | |     BarB,
 +LL | | }
 +   | |_^
 +
 +error: missing documentation for a variant
-   --> $DIR/missing-doc.rs:34:12
++  --> $DIR/missing-doc.rs:33:5
 +   |
 +LL |     BazA { a: isize, b: isize },
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: missing documentation for a struct field
-   --> $DIR/missing-doc.rs:34:22
++  --> $DIR/missing-doc.rs:33:12
 +   |
 +LL |     BazA { a: isize, b: isize },
 +   |            ^^^^^^^^
 +
 +error: missing documentation for a struct field
-   --> $DIR/missing-doc.rs:35:5
++  --> $DIR/missing-doc.rs:33:22
 +   |
 +LL |     BazA { a: isize, b: isize },
 +   |                      ^^^^^^^^
 +
 +error: missing documentation for a variant
-   --> $DIR/missing-doc.rs:38:1
++  --> $DIR/missing-doc.rs:34:5
 +   |
 +LL |     BarB,
 +   |     ^^^^
 +
 +error: missing documentation for an enum
-   --> $DIR/missing-doc.rs:39:5
++  --> $DIR/missing-doc.rs:37:1
 +   |
 +LL | / pub enum PubBaz {
 +LL | |     PubBazA { a: isize },
 +LL | | }
 +   | |_^
 +
 +error: missing documentation for a variant
-   --> $DIR/missing-doc.rs:39:15
++  --> $DIR/missing-doc.rs:38:5
 +   |
 +LL |     PubBazA { a: isize },
 +   |     ^^^^^^^^^^^^^^^^^^^^
 +
 +error: missing documentation for a struct field
-   --> $DIR/missing-doc.rs:59:1
++  --> $DIR/missing-doc.rs:38:15
 +   |
 +LL |     PubBazA { a: isize },
 +   |               ^^^^^^^^
 +
 +error: missing documentation for a constant
-   --> $DIR/missing-doc.rs:66:1
++  --> $DIR/missing-doc.rs:58:1
 +   |
 +LL | const FOO: u32 = 0;
 +   | ^^^^^^^^^^^^^^^^^^^
 +
 +error: missing documentation for a constant
-   --> $DIR/missing-doc.rs:68:1
++  --> $DIR/missing-doc.rs:65:1
 +   |
 +LL | pub const FOO4: u32 = 0;
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: missing documentation for a static
-   --> $DIR/missing-doc.rs:75:1
++  --> $DIR/missing-doc.rs:67:1
 +   |
 +LL | static BAR: u32 = 0;
 +   | ^^^^^^^^^^^^^^^^^^^^
 +
 +error: missing documentation for a static
-   --> $DIR/missing-doc.rs:77:1
++  --> $DIR/missing-doc.rs:74:1
 +   |
 +LL | pub static BAR4: u32 = 0;
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: missing documentation for a module
-   --> $DIR/missing-doc.rs:80:5
++  --> $DIR/missing-doc.rs:76:1
 +   |
 +LL | / mod internal_impl {
 +LL | |     /// dox
 +LL | |     pub fn documented() {}
 +LL | |     pub fn undocumented1() {}
 +...  |
 +LL | |     }
 +LL | | }
 +   | |_^
 +
 +error: missing documentation for a function
-   --> $DIR/missing-doc.rs:81:5
++  --> $DIR/missing-doc.rs:79:5
 +   |
 +LL |     pub fn undocumented1() {}
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: missing documentation for a function
-   --> $DIR/missing-doc.rs:82:5
++  --> $DIR/missing-doc.rs:80:5
 +   |
 +LL |     pub fn undocumented2() {}
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: missing documentation for a function
-   --> $DIR/missing-doc.rs:87:9
++  --> $DIR/missing-doc.rs:81:5
 +   |
 +LL |     fn undocumented3() {}
 +   |     ^^^^^^^^^^^^^^^^^^^^^
 +
 +error: missing documentation for a function
-   --> $DIR/missing-doc.rs:88:9
++  --> $DIR/missing-doc.rs:86:9
 +   |
 +LL |         pub fn also_undocumented1() {}
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: missing documentation for a function
++  --> $DIR/missing-doc.rs:87:9
 +   |
 +LL |         fn also_undocumented2() {}
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: aborting due to 24 previous errors
 +
index 2e1379a58a67bbd2a32f1676fa684445e194cda9,0000000000000000000000000000000000000000..7dc44529206d551a423dbfea3762038b3b610074
mode 100644,000000..100644
--- /dev/null
@@@ -1,154 -1,0 +1,153 @@@
 +#![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 needs to be documented
 +pub fn unreachable_and_panic() {
 +    if true { unreachable!() } else { panic!() }
 +}
 +
 +/// This needs to be documented
 +pub fn assert_eq() {
 +    let x = 0;
 +    assert_eq!(x, 0);
 +}
 +
 +/// This needs to be documented
 +pub fn assert_ne() {
 +    let x = 0;
 +    assert_ne!(x, 0);
 +}
 +
 +/// 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 documented
 +///
 +/// # Panics
 +///
 +/// We still need to do this part
 +pub fn unreachable_amd_panic_documented() {
 +    if true { unreachable!() } else { panic!() }
 +}
 +
 +/// This is documented
 +///
 +/// # Panics
 +///
 +/// Panics if `x` is not 0.
 +pub fn assert_eq_documented() {
 +    let x = 0;
 +    assert_eq!(x, 0);
 +}
 +
 +/// This is documented
 +///
 +/// # Panics
 +///
 +/// Panics if `x` is 0.
 +pub fn assert_ne_documented() {
 +    let x = 0;
 +    assert_ne!(x, 0);
 +}
 +
 +/// 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!()
 +        }
 +    });
 +}
 +
 +/// This is okay because unreachable
 +pub fn unreachable() {
 +    unreachable!("This function panics")
 +}
 +
 +/// #6970.
 +/// This is okay because it is expansion of `debug_assert` family.
 +pub fn debug_assertions() {
 +    debug_assert!(false);
 +    debug_assert_eq!(1, 2);
 +    debug_assert_ne!(1, 2);
 +}
index b863063b626dbe68183eda66c717ef6156b78881,0000000000000000000000000000000000000000..60282939ef0334008f00c7d78ea12693c2b22595
mode 100644,000000..100644
--- /dev/null
@@@ -1,114 -1,0 +1,114 @@@
-   --> $DIR/missing_panics_doc.rs:7:1
 +error: docs for function which may panic missing `# Panics` section
-   --> $DIR/missing_panics_doc.rs:9:5
++  --> $DIR/missing_panics_doc.rs:6: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/missing_panics_doc.rs:13:1
++  --> $DIR/missing_panics_doc.rs:8:5
 +   |
 +LL |     result.unwrap()
 +   |     ^^^^^^^^^^^^^^^
 +
 +error: docs for function which may panic missing `# Panics` section
-   --> $DIR/missing_panics_doc.rs:14:5
++  --> $DIR/missing_panics_doc.rs:12:1
 +   |
 +LL | / pub fn panic() {
 +LL | |     panic!("This function panics")
 +LL | | }
 +   | |_^
 +   |
 +note: first possible panic found here
-    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
++  --> $DIR/missing_panics_doc.rs:13:5
 +   |
 +LL |     panic!("This function panics")
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   --> $DIR/missing_panics_doc.rs:18:1
++   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: docs for function which may panic missing `# Panics` section
-   --> $DIR/missing_panics_doc.rs:19:5
++  --> $DIR/missing_panics_doc.rs:17:1
 +   |
 +LL | / pub fn todo() {
 +LL | |     todo!()
 +LL | | }
 +   | |_^
 +   |
 +note: first possible panic found here
-   --> $DIR/missing_panics_doc.rs:23:1
++  --> $DIR/missing_panics_doc.rs:18:5
 +   |
 +LL |     todo!()
 +   |     ^^^^^^^
 +   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: docs for function which may panic missing `# Panics` section
-   --> $DIR/missing_panics_doc.rs:26:13
++  --> $DIR/missing_panics_doc.rs:22: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
-    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
++  --> $DIR/missing_panics_doc.rs:25:13
 +   |
 +LL |             panic!()
 +   |             ^^^^^^^^
-   --> $DIR/missing_panics_doc.rs:32:1
++   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: docs for function which may panic missing `# Panics` section
-   --> $DIR/missing_panics_doc.rs:33:39
++  --> $DIR/missing_panics_doc.rs:31:1
 +   |
 +LL | / pub fn unreachable_and_panic() {
 +LL | |     if true { unreachable!() } else { panic!() }
 +LL | | }
 +   | |_^
 +   |
 +note: first possible panic found here
-    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
++  --> $DIR/missing_panics_doc.rs:32:39
 +   |
 +LL |     if true { unreachable!() } else { panic!() }
 +   |                                       ^^^^^^^^
-   --> $DIR/missing_panics_doc.rs:37:1
++   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: docs for function which may panic missing `# Panics` section
-   --> $DIR/missing_panics_doc.rs:39:5
++  --> $DIR/missing_panics_doc.rs:36:1
 +   |
 +LL | / pub fn assert_eq() {
 +LL | |     let x = 0;
 +LL | |     assert_eq!(x, 0);
 +LL | | }
 +   | |_^
 +   |
 +note: first possible panic found here
-   --> $DIR/missing_panics_doc.rs:43:1
++  --> $DIR/missing_panics_doc.rs:38:5
 +   |
 +LL |     assert_eq!(x, 0);
 +   |     ^^^^^^^^^^^^^^^^
 +   = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: docs for function which may panic missing `# Panics` section
-   --> $DIR/missing_panics_doc.rs:45:5
++  --> $DIR/missing_panics_doc.rs:42:1
 +   |
 +LL | / pub fn assert_ne() {
 +LL | |     let x = 0;
 +LL | |     assert_ne!(x, 0);
 +LL | | }
 +   | |_^
 +   |
 +note: first possible panic found here
++  --> $DIR/missing_panics_doc.rs:44:5
 +   |
 +LL |     assert_ne!(x, 0);
 +   |     ^^^^^^^^^^^^^^^^
 +   = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: aborting due to 7 previous errors
 +
index 7a8137778b44607cd397c03b04205f43e27aeb84,0000000000000000000000000000000000000000..04b6283da3c3b88d8a5b16c44edfd5d53133dbe6
mode 100644,000000..100644
--- /dev/null
@@@ -1,151 -1,0 +1,150 @@@
- // edition:2018
 +// FIXME: run-rustfix waiting on multi-span suggestions
 +
 +#![warn(clippy::needless_borrow)]
 +#![allow(clippy::needless_borrowed_reference)]
 +
 +fn f1(_: &str) {}
 +macro_rules! m1 {
 +    ($e:expr) => {
 +        f1($e)
 +    };
 +}
 +macro_rules! m3 {
 +    ($i:ident) => {
 +        Some(ref $i)
 +    };
 +}
 +macro_rules! if_chain {
 +    (if $e:expr; $($rest:tt)*) => {
 +        if $e {
 +            if_chain!($($rest)*)
 +        }
 +    };
 +
 +    (if let $p:pat = $e:expr; $($rest:tt)*) => {
 +        if let $p = $e {
 +            if_chain!($($rest)*)
 +        }
 +    };
 +
 +    (then $b:block) => {
 +        $b
 +    };
 +}
 +
 +#[allow(dead_code)]
 +fn main() {
 +    let x = String::new();
 +
 +    // Ok, reference to a String.
 +    let _: &String = match Some(x.clone()) {
 +        Some(ref x) => x,
 +        None => return,
 +    };
 +
 +    // Ok, reference to a &mut String
 +    let _: &&mut String = match Some(&mut x.clone()) {
 +        Some(ref x) => x,
 +        None => return,
 +    };
 +
 +    // Ok, the pattern is from a macro
 +    let _: &String = match Some(&x) {
 +        m3!(x) => x,
 +        None => return,
 +    };
 +
 +    // Err, reference to a &String
 +    let _: &String = match Some(&x) {
 +        Some(ref x) => x,
 +        None => return,
 +    };
 +
 +    // Err, reference to a &String.
 +    let _: &String = match Some(&x) {
 +        Some(ref x) => *x,
 +        None => return,
 +    };
 +
 +    // Err, reference to a &String
 +    let _: &String = match Some(&x) {
 +        Some(ref x) => {
 +            f1(x);
 +            f1(*x);
 +            x
 +        },
 +        None => return,
 +    };
 +
 +    // Err, reference to a &String
 +    match Some(&x) {
 +        Some(ref x) => m1!(x),
 +        None => return,
 +    };
 +
 +    // Err, reference to a &String
 +    let _ = |&ref x: &&String| {
 +        let _: &String = x;
 +    };
 +
 +    // Err, reference to a &String
 +    let (ref y,) = (&x,);
 +    let _: &String = *y;
 +
 +    let y = &&x;
 +    // Ok, different y
 +    let _: &String = *y;
 +
 +    let x = (0, 0);
 +    // Err, reference to a &u32. Don't suggest adding a reference to the field access.
 +    let _: u32 = match Some(&x) {
 +        Some(ref x) => x.0,
 +        None => return,
 +    };
 +
 +    enum E {
 +        A(&'static u32),
 +        B(&'static u32),
 +    }
 +    // Err, reference to &u32.
 +    let _: &u32 = match E::A(&0) {
 +        E::A(ref x) | E::B(ref x) => *x,
 +    };
 +
 +    // Err, reference to &String.
 +    if_chain! {
 +        if true;
 +        if let Some(ref x) = Some(&String::new());
 +        then {
 +            f1(x);
 +        }
 +    }
 +}
 +
 +// Err, reference to a &String
 +fn f2<'a>(&ref x: &&'a String) -> &'a String {
 +    let _: &String = x;
 +    *x
 +}
 +
 +trait T1 {
 +    // Err, reference to a &String
 +    fn f(&ref x: &&String) {
 +        let _: &String = x;
 +    }
 +}
 +
 +struct S;
 +impl T1 for S {
 +    // Err, reference to a &String
 +    fn f(&ref x: &&String) {
 +        let _: &String = *x;
 +    }
 +}
 +
 +// Ok - used to error due to rustc bug
 +#[allow(dead_code)]
 +#[derive(Debug)]
 +enum Foo<'a> {
 +    Str(&'a str),
 +}
index 365ecd68d8ff2e9cabc8e0635670712e744d17b1,0000000000000000000000000000000000000000..db3b52b8850e1cfd252e3eda54933f1abe4f8b60
mode 100644,000000..100644
--- /dev/null
@@@ -1,112 -1,0 +1,112 @@@
-   --> $DIR/needless_borrow_pat.rs:60:14
 +error: this pattern creates a reference to a reference
-   --> $DIR/needless_borrow_pat.rs:66:14
++  --> $DIR/needless_borrow_pat.rs:59:14
 +   |
 +LL |         Some(ref x) => x,
 +   |              ^^^^^ help: try this: `x`
 +   |
 +   = note: `-D clippy::needless-borrow` implied by `-D warnings`
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/needless_borrow_pat.rs:72:14
++  --> $DIR/needless_borrow_pat.rs:65:14
 +   |
 +LL |         Some(ref x) => *x,
 +   |              ^^^^^
 +   |
 +help: try this
 +   |
 +LL |         Some(x) => x,
 +   |              ~     ~
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/needless_borrow_pat.rs:82:14
++  --> $DIR/needless_borrow_pat.rs:71:14
 +   |
 +LL |         Some(ref x) => {
 +   |              ^^^^^
 +   |
 +help: try this
 +   |
 +LL ~         Some(x) => {
 +LL |             f1(x);
 +LL ~             f1(x);
 +   |
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/needless_borrow_pat.rs:87:15
++  --> $DIR/needless_borrow_pat.rs:81:14
 +   |
 +LL |         Some(ref x) => m1!(x),
 +   |              ^^^^^ help: try this: `x`
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/needless_borrow_pat.rs:92:10
++  --> $DIR/needless_borrow_pat.rs:86:15
 +   |
 +LL |     let _ = |&ref x: &&String| {
 +   |               ^^^^^ help: try this: `x`
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/needless_borrow_pat.rs:102:14
++  --> $DIR/needless_borrow_pat.rs:91:10
 +   |
 +LL |     let (ref y,) = (&x,);
 +   |          ^^^^^
 +   |
 +help: try this
 +   |
 +LL ~     let (y,) = (&x,);
 +LL ~     let _: &String = y;
 +   |
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/needless_borrow_pat.rs:112:14
++  --> $DIR/needless_borrow_pat.rs:101:14
 +   |
 +LL |         Some(ref x) => x.0,
 +   |              ^^^^^ help: try this: `x`
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/needless_borrow_pat.rs:118:21
++  --> $DIR/needless_borrow_pat.rs:111:14
 +   |
 +LL |         E::A(ref x) | E::B(ref x) => *x,
 +   |              ^^^^^         ^^^^^
 +   |
 +help: try this
 +   |
 +LL |         E::A(x) | E::B(x) => x,
 +   |              ~         ~     ~
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/needless_borrow_pat.rs:126:12
++  --> $DIR/needless_borrow_pat.rs:117:21
 +   |
 +LL |         if let Some(ref x) = Some(&String::new());
 +   |                     ^^^^^ help: try this: `x`
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/needless_borrow_pat.rs:133:11
++  --> $DIR/needless_borrow_pat.rs:125:12
 +   |
 +LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
 +   |            ^^^^^
 +   |
 +help: try this
 +   |
 +LL ~ fn f2<'a>(&x: &&'a String) -> &'a String {
 +LL |     let _: &String = x;
 +LL ~     x
 +   |
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/needless_borrow_pat.rs:141:11
++  --> $DIR/needless_borrow_pat.rs:132:11
 +   |
 +LL |     fn f(&ref x: &&String) {
 +   |           ^^^^^ help: try this: `x`
 +
 +error: this pattern creates a reference to a reference
++  --> $DIR/needless_borrow_pat.rs:140:11
 +   |
 +LL |     fn f(&ref x: &&String) {
 +   |           ^^^^^
 +   |
 +help: try this
 +   |
 +LL ~     fn f(&x: &&String) {
 +LL ~         let _: &String = x;
 +   |
 +
 +error: aborting due to 12 previous errors
 +
index 1d77382bf2cd1132549232dd03fe41af93de9389,0000000000000000000000000000000000000000..b07c4a2381031f2f4c617c4e355e904c8243f9a6
mode 100644,000000..100644
--- /dev/null
@@@ -1,367 -1,0 +1,372 @@@
 +#![warn(clippy::needless_lifetimes)]
 +#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps, dyn_drop)]
 +
 +fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
 +
 +fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
 +
 +// No error; same lifetime on two params.
 +fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) {}
 +
 +// No error; static involved.
 +fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) {}
 +
 +fn mut_and_static_input(_x: &mut u8, _y: &'static str) {}
 +
 +fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
 +    x
 +}
 +
 +// No error; multiple input refs.
 +fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 {
 +    x
 +}
 +
 +// No error; multiple input refs.
 +fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 {
 +    x
 +}
 +
++// No error; multiple input refs
++async fn func<'a>(args: &[&'a str]) -> Option<&'a str> {
++    args.get(0).cloned()
++}
++
 +// No error; static involved.
 +fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 {
 +    x
 +}
 +
 +// No error.
 +fn deep_reference_1<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> {
 +    Ok(x)
 +}
 +
 +// No error; two input refs.
 +fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 {
 +    x.unwrap()
 +}
 +
 +fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
 +    Ok(x)
 +}
 +
 +// Where-clause, but without lifetimes.
 +fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
 +where
 +    T: Copy,
 +{
 +    Ok(x)
 +}
 +
 +type Ref<'r> = &'r u8;
 +
 +// No error; same lifetime on two params.
 +fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {}
 +
 +fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
 +
 +// No error; bounded lifetime.
 +fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {}
 +
 +// No error; bounded lifetime.
 +fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8)
 +where
 +    'b: 'a,
 +{
 +}
 +
 +struct Lt<'a, I: 'static> {
 +    x: &'a I,
 +}
 +
 +// No error; fn bound references `'a`.
 +fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
 +where
 +    F: Fn(Lt<'a, I>) -> Lt<'a, I>,
 +{
 +    unreachable!()
 +}
 +
 +fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
 +where
 +    for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>,
 +{
 +    unreachable!()
 +}
 +
 +// No error; see below.
 +fn fn_bound_3<'a, F: FnOnce(&'a i32)>(x: &'a i32, f: F) {
 +    f(x);
 +}
 +
 +fn fn_bound_3_cannot_elide() {
 +    let x = 42;
 +    let p = &x;
 +    let mut q = &x;
 +    // This will fail if we elide lifetimes of `fn_bound_3`.
 +    fn_bound_3(p, |y| q = y);
 +}
 +
 +// No error; multiple input refs.
 +fn fn_bound_4<'a, F: FnOnce() -> &'a ()>(cond: bool, x: &'a (), f: F) -> &'a () {
 +    if cond { x } else { f() }
 +}
 +
 +struct X {
 +    x: u8,
 +}
 +
 +impl X {
 +    fn self_and_out<'s>(&'s self) -> &'s u8 {
 +        &self.x
 +    }
 +
 +    // No error; multiple input refs.
 +    fn self_and_in_out<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 {
 +        &self.x
 +    }
 +
 +    fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
 +
 +    // No error; same lifetimes on two params.
 +    fn self_and_same_in<'s>(&'s self, _x: &'s u8) {}
 +}
 +
 +struct Foo<'a>(&'a u8);
 +
 +impl<'a> Foo<'a> {
 +    // No error; lifetime `'a` not defined in method.
 +    fn self_shared_lifetime(&self, _: &'a u8) {}
 +    // No error; bounds exist.
 +    fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {}
 +}
 +
 +fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 {
 +    unimplemented!()
 +}
 +
 +fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
 +    unimplemented!()
 +}
 +
 +// No warning; two input lifetimes (named on the reference, anonymous on `Foo`).
 +fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str {
 +    unimplemented!()
 +}
 +
 +// No warning; two input lifetimes (anonymous on the reference, named on `Foo`).
 +fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str {
 +    unimplemented!()
 +}
 +
 +// No warning; two input lifetimes.
 +fn struct_with_lt4<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str {
 +    unimplemented!()
 +}
 +
 +trait WithLifetime<'a> {}
 +
 +type WithLifetimeAlias<'a> = dyn WithLifetime<'a>;
 +
 +// Should not warn because it won't build without the lifetime.
 +fn trait_obj_elided<'a>(_arg: &'a dyn WithLifetime) -> &'a str {
 +    unimplemented!()
 +}
 +
 +// Should warn because there is no lifetime on `Drop`, so this would be
 +// unambiguous if we elided the lifetime.
 +fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
 +    unimplemented!()
 +}
 +
 +type FooAlias<'a> = Foo<'a>;
 +
 +fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
 +    unimplemented!()
 +}
 +
 +// No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`).
 +fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str {
 +    unimplemented!()
 +}
 +
 +// No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`).
 +fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str {
 +    unimplemented!()
 +}
 +
 +// No warning; two input lifetimes.
 +fn alias_with_lt4<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str {
 +    unimplemented!()
 +}
 +
 +fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
 +    unimplemented!()
 +}
 +
 +fn elided_input_named_output<'a>(_arg: &str) -> &'a str {
 +    unimplemented!()
 +}
 +
 +fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
 +    unimplemented!()
 +}
 +fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) {
 +    unimplemented!()
 +}
 +
 +// Don't warn on these; see issue #292.
 +fn trait_bound_bug<'a, T: WithLifetime<'a>>() {
 +    unimplemented!()
 +}
 +
 +// See issue #740.
 +struct Test {
 +    vec: Vec<usize>,
 +}
 +
 +impl Test {
 +    fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = usize> + 'a> {
 +        unimplemented!()
 +    }
 +}
 +
 +trait LintContext<'a> {}
 +
 +fn f<'a, T: LintContext<'a>>(_: &T) {}
 +
 +fn test<'a>(x: &'a [u8]) -> u8 {
 +    let y: &'a u8 = &x[5];
 +    *y
 +}
 +
 +// Issue #3284: give hint regarding lifetime in return type.
 +struct Cow<'a> {
 +    x: &'a str,
 +}
 +fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
 +    unimplemented!()
 +}
 +
 +// Make sure we still warn on implementations
 +mod issue4291 {
 +    trait BadTrait {
 +        fn needless_lt<'a>(x: &'a u8) {}
 +    }
 +
 +    impl BadTrait for () {
 +        fn needless_lt<'a>(_x: &'a u8) {}
 +    }
 +}
 +
 +mod issue2944 {
 +    trait Foo {}
 +    struct Bar {}
 +    struct Baz<'a> {
 +        bar: &'a Bar,
 +    }
 +
 +    impl<'a> Foo for Baz<'a> {}
 +    impl Bar {
 +        fn baz<'a>(&'a self) -> impl Foo + 'a {
 +            Baz { bar: self }
 +        }
 +    }
 +}
 +
 +mod nested_elision_sites {
 +    // issue #issue2944
 +
 +    // closure trait bounds subject to nested elision
 +    // don't lint because they refer to outer lifetimes
 +    fn trait_fn<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
 +        move || i
 +    }
 +    fn trait_fn_mut<'a>(i: &'a i32) -> impl FnMut() -> &'a i32 {
 +        move || i
 +    }
 +    fn trait_fn_once<'a>(i: &'a i32) -> impl FnOnce() -> &'a i32 {
 +        move || i
 +    }
 +
 +    // don't lint
 +    fn impl_trait_in_input_position<'a>(f: impl Fn() -> &'a i32) -> &'a i32 {
 +        f()
 +    }
 +    fn impl_trait_in_output_position<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
 +        move || i
 +    }
 +    // lint
 +    fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
 +        f(i)
 +    }
 +    fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
 +        f(i)
 +    }
 +
 +    // don't lint
 +    fn generics_not_elidable<'a, T: Fn() -> &'a i32>(f: T) -> &'a i32 {
 +        f()
 +    }
 +    // lint
 +    fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
 +        f(i)
 +    }
 +
 +    // don't lint
 +    fn where_clause_not_elidable<'a, T>(f: T) -> &'a i32
 +    where
 +        T: Fn() -> &'a i32,
 +    {
 +        f()
 +    }
 +    // lint
 +    fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
 +    where
 +        T: Fn(&i32) -> &i32,
 +    {
 +        f(i)
 +    }
 +
 +    // don't lint
 +    fn pointer_fn_in_input_position<'a>(f: fn(&'a i32) -> &'a i32, i: &'a i32) -> &'a i32 {
 +        f(i)
 +    }
 +    fn pointer_fn_in_output_position<'a>(_: &'a i32) -> fn(&'a i32) -> &'a i32 {
 +        |i| i
 +    }
 +    // lint
 +    fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
 +        f(i)
 +    }
 +
 +    // don't lint
 +    fn nested_fn_pointer_1<'a>(_: &'a i32) -> fn(fn(&'a i32) -> &'a i32) -> i32 {
 +        |f| 42
 +    }
 +    fn nested_fn_pointer_2<'a>(_: &'a i32) -> impl Fn(fn(&'a i32)) {
 +        |f| ()
 +    }
 +
 +    // lint
 +    fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
 +        |f| 42
 +    }
 +    fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
 +        |f| ()
 +    }
 +}
 +
 +mod issue6159 {
 +    use std::ops::Deref;
 +    pub fn apply_deref<'a, T, F, R>(x: &'a T, f: F) -> R
 +    where
 +        T: Deref,
 +        F: FnOnce(&'a T::Target) -> R,
 +    {
 +        f(x.deref())
 +    }
 +}
 +
 +fn main() {}
index 33a6de1618d12c1a509df271c43b8f57e11d9282,0000000000000000000000000000000000000000..4114e6f1832fc694ddbffecd65819900de31df43
mode 100644,000000..100644
--- /dev/null
@@@ -1,154 -1,0 +1,154 @@@
-   --> $DIR/needless_lifetimes.rs:45:1
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
 +  --> $DIR/needless_lifetimes.rs:4:1
 +   |
 +LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   |
 +   = note: `-D clippy::needless-lifetimes` implied by `-D warnings`
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
 +  --> $DIR/needless_lifetimes.rs:6:1
 +   |
 +LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
 +  --> $DIR/needless_lifetimes.rs:16:1
 +   |
 +LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:50:1
++  --> $DIR/needless_lifetimes.rs:50:1
 +   |
 +LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:62:1
++  --> $DIR/needless_lifetimes.rs:55:1
 +   |
 +LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:86:1
++  --> $DIR/needless_lifetimes.rs:67:1
 +   |
 +LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:116:5
++  --> $DIR/needless_lifetimes.rs:91:1
 +   |
 +LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:125:5
++  --> $DIR/needless_lifetimes.rs:121:5
 +   |
 +LL |     fn self_and_out<'s>(&'s self) -> &'s u8 {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:144:1
++  --> $DIR/needless_lifetimes.rs:130:5
 +   |
 +LL |     fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:174:1
++  --> $DIR/needless_lifetimes.rs:149:1
 +   |
 +LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:180:1
++  --> $DIR/needless_lifetimes.rs:179:1
 +   |
 +LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:199:1
++  --> $DIR/needless_lifetimes.rs:185:1
 +   |
 +LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:207:1
++  --> $DIR/needless_lifetimes.rs:204:1
 +   |
 +LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:243:1
++  --> $DIR/needless_lifetimes.rs:212:1
 +   |
 +LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:250:9
++  --> $DIR/needless_lifetimes.rs:248:1
 +   |
 +LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
 +   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:254:9
++  --> $DIR/needless_lifetimes.rs:255:9
 +   |
 +LL |         fn needless_lt<'a>(x: &'a u8) {}
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:267:9
++  --> $DIR/needless_lifetimes.rs:259:9
 +   |
 +LL |         fn needless_lt<'a>(_x: &'a u8) {}
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:296:5
++  --> $DIR/needless_lifetimes.rs:272:9
 +   |
 +LL |         fn baz<'a>(&'a self) -> impl Foo + 'a {
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:299:5
++  --> $DIR/needless_lifetimes.rs:301:5
 +   |
 +LL |     fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:308:5
++  --> $DIR/needless_lifetimes.rs:304:5
 +   |
 +LL |     fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:320:5
++  --> $DIR/needless_lifetimes.rs:313:5
 +   |
 +LL |     fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:335:5
++  --> $DIR/needless_lifetimes.rs:325:5
 +   |
 +LL |     fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:348:5
++  --> $DIR/needless_lifetimes.rs:340:5
 +   |
 +LL |     fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-   --> $DIR/needless_lifetimes.rs:351:5
++  --> $DIR/needless_lifetimes.rs:353:5
 +   |
 +LL |     fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
++  --> $DIR/needless_lifetimes.rs:356:5
 +   |
 +LL |     fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: aborting due to 25 previous errors
 +
index 9c999e12b4cbc4c6d5a3afed29e97cffa3638623,0000000000000000000000000000000000000000..812ce7163cd50ab215cd7130493b1e816d71ccf4
mode 100644,000000..100644
--- /dev/null
@@@ -1,215 -1,0 +1,214 @@@
- // edition:2018
 +// run-rustfix
 +
 +#![feature(let_else)]
 +#![allow(unused)]
 +#![allow(
 +    clippy::if_same_then_else,
 +    clippy::single_match,
 +    clippy::needless_bool,
 +    clippy::equatable_if_let
 +)]
 +#![warn(clippy::needless_return)]
 +
 +macro_rules! the_answer {
 +    () => {
 +        42
 +    };
 +}
 +
 +fn test_end_of_fn() -> bool {
 +    if true {
 +        // no error!
 +        return true;
 +    }
 +    true
 +}
 +
 +fn test_no_semicolon() -> bool {
 +    true
 +}
 +
 +fn test_if_block() -> bool {
 +    if true {
 +        true
 +    } else {
 +        false
 +    }
 +}
 +
 +fn test_match(x: bool) -> bool {
 +    match x {
 +        true => false,
 +        false => {
 +            true
 +        },
 +    }
 +}
 +
 +fn test_closure() {
 +    let _ = || {
 +        true
 +    };
 +    let _ = || true;
 +}
 +
 +fn test_macro_call() -> i32 {
 +    return the_answer!();
 +}
 +
 +fn test_void_fun() {
 +    
 +}
 +
 +fn test_void_if_fun(b: bool) {
 +    if b {
 +        
 +    } else {
 +        
 +    }
 +}
 +
 +fn test_void_match(x: u32) {
 +    match x {
 +        0 => (),
 +        _ => {},
 +    }
 +}
 +
 +fn read_line() -> String {
 +    use std::io::BufRead;
 +    let stdin = ::std::io::stdin();
 +    return stdin.lock().lines().next().unwrap().unwrap();
 +}
 +
 +fn borrows_but_not_last(value: bool) -> String {
 +    if value {
 +        use std::io::BufRead;
 +        let stdin = ::std::io::stdin();
 +        let _a = stdin.lock().lines().next().unwrap().unwrap();
 +        String::from("test")
 +    } else {
 +        String::new()
 +    }
 +}
 +
 +macro_rules! needed_return {
 +    ($e:expr) => {
 +        if $e > 3 {
 +            return;
 +        }
 +    };
 +}
 +
 +fn test_return_in_macro() {
 +    // This will return and the macro below won't be executed. Removing the `return` from the macro
 +    // will change semantics.
 +    needed_return!(10);
 +    needed_return!(0);
 +}
 +
 +mod issue6501 {
 +    fn foo(bar: Result<(), ()>) {
 +        bar.unwrap_or_else(|_| {})
 +    }
 +
 +    fn test_closure() {
 +        let _ = || {
 +            
 +        };
 +        let _ = || {};
 +    }
 +
 +    struct Foo;
 +    #[allow(clippy::unnecessary_lazy_evaluations)]
 +    fn bar(res: Result<Foo, u8>) -> Foo {
 +        res.unwrap_or_else(|_| Foo)
 +    }
 +}
 +
 +async fn async_test_end_of_fn() -> bool {
 +    if true {
 +        // no error!
 +        return true;
 +    }
 +    true
 +}
 +
 +async fn async_test_no_semicolon() -> bool {
 +    true
 +}
 +
 +async fn async_test_if_block() -> bool {
 +    if true {
 +        true
 +    } else {
 +        false
 +    }
 +}
 +
 +async fn async_test_match(x: bool) -> bool {
 +    match x {
 +        true => false,
 +        false => {
 +            true
 +        },
 +    }
 +}
 +
 +async fn async_test_closure() {
 +    let _ = || {
 +        true
 +    };
 +    let _ = || true;
 +}
 +
 +async fn async_test_macro_call() -> i32 {
 +    return the_answer!();
 +}
 +
 +async fn async_test_void_fun() {
 +    
 +}
 +
 +async fn async_test_void_if_fun(b: bool) {
 +    if b {
 +        
 +    } else {
 +        
 +    }
 +}
 +
 +async fn async_test_void_match(x: u32) {
 +    match x {
 +        0 => (),
 +        _ => {},
 +    }
 +}
 +
 +async fn async_read_line() -> String {
 +    use std::io::BufRead;
 +    let stdin = ::std::io::stdin();
 +    return stdin.lock().lines().next().unwrap().unwrap();
 +}
 +
 +async fn async_borrows_but_not_last(value: bool) -> String {
 +    if value {
 +        use std::io::BufRead;
 +        let stdin = ::std::io::stdin();
 +        let _a = stdin.lock().lines().next().unwrap().unwrap();
 +        String::from("test")
 +    } else {
 +        String::new()
 +    }
 +}
 +
 +async fn async_test_return_in_macro() {
 +    needed_return!(10);
 +    needed_return!(0);
 +}
 +
 +fn let_else() {
 +    let Some(1) = Some(1) else { return };
 +}
 +
 +fn main() {}
index da7dcf4f0a9ea377596a830996947f6d5afa60fb,0000000000000000000000000000000000000000..c42567b517c9115819b3446d5c5281c0da273884
mode 100644,000000..100644
--- /dev/null
@@@ -1,215 -1,0 +1,214 @@@
- // edition:2018
 +// run-rustfix
 +
 +#![feature(let_else)]
 +#![allow(unused)]
 +#![allow(
 +    clippy::if_same_then_else,
 +    clippy::single_match,
 +    clippy::needless_bool,
 +    clippy::equatable_if_let
 +)]
 +#![warn(clippy::needless_return)]
 +
 +macro_rules! the_answer {
 +    () => {
 +        42
 +    };
 +}
 +
 +fn test_end_of_fn() -> bool {
 +    if true {
 +        // no error!
 +        return true;
 +    }
 +    return true;
 +}
 +
 +fn test_no_semicolon() -> bool {
 +    return true;
 +}
 +
 +fn test_if_block() -> bool {
 +    if true {
 +        return true;
 +    } else {
 +        return false;
 +    }
 +}
 +
 +fn test_match(x: bool) -> bool {
 +    match x {
 +        true => return false,
 +        false => {
 +            return true;
 +        },
 +    }
 +}
 +
 +fn test_closure() {
 +    let _ = || {
 +        return true;
 +    };
 +    let _ = || return true;
 +}
 +
 +fn test_macro_call() -> i32 {
 +    return the_answer!();
 +}
 +
 +fn test_void_fun() {
 +    return;
 +}
 +
 +fn test_void_if_fun(b: bool) {
 +    if b {
 +        return;
 +    } else {
 +        return;
 +    }
 +}
 +
 +fn test_void_match(x: u32) {
 +    match x {
 +        0 => (),
 +        _ => return,
 +    }
 +}
 +
 +fn read_line() -> String {
 +    use std::io::BufRead;
 +    let stdin = ::std::io::stdin();
 +    return stdin.lock().lines().next().unwrap().unwrap();
 +}
 +
 +fn borrows_but_not_last(value: bool) -> String {
 +    if value {
 +        use std::io::BufRead;
 +        let stdin = ::std::io::stdin();
 +        let _a = stdin.lock().lines().next().unwrap().unwrap();
 +        return String::from("test");
 +    } else {
 +        return String::new();
 +    }
 +}
 +
 +macro_rules! needed_return {
 +    ($e:expr) => {
 +        if $e > 3 {
 +            return;
 +        }
 +    };
 +}
 +
 +fn test_return_in_macro() {
 +    // This will return and the macro below won't be executed. Removing the `return` from the macro
 +    // will change semantics.
 +    needed_return!(10);
 +    needed_return!(0);
 +}
 +
 +mod issue6501 {
 +    fn foo(bar: Result<(), ()>) {
 +        bar.unwrap_or_else(|_| return)
 +    }
 +
 +    fn test_closure() {
 +        let _ = || {
 +            return;
 +        };
 +        let _ = || return;
 +    }
 +
 +    struct Foo;
 +    #[allow(clippy::unnecessary_lazy_evaluations)]
 +    fn bar(res: Result<Foo, u8>) -> Foo {
 +        res.unwrap_or_else(|_| return Foo)
 +    }
 +}
 +
 +async fn async_test_end_of_fn() -> bool {
 +    if true {
 +        // no error!
 +        return true;
 +    }
 +    return true;
 +}
 +
 +async fn async_test_no_semicolon() -> bool {
 +    return true;
 +}
 +
 +async fn async_test_if_block() -> bool {
 +    if true {
 +        return true;
 +    } else {
 +        return false;
 +    }
 +}
 +
 +async fn async_test_match(x: bool) -> bool {
 +    match x {
 +        true => return false,
 +        false => {
 +            return true;
 +        },
 +    }
 +}
 +
 +async fn async_test_closure() {
 +    let _ = || {
 +        return true;
 +    };
 +    let _ = || return true;
 +}
 +
 +async fn async_test_macro_call() -> i32 {
 +    return the_answer!();
 +}
 +
 +async fn async_test_void_fun() {
 +    return;
 +}
 +
 +async fn async_test_void_if_fun(b: bool) {
 +    if b {
 +        return;
 +    } else {
 +        return;
 +    }
 +}
 +
 +async fn async_test_void_match(x: u32) {
 +    match x {
 +        0 => (),
 +        _ => return,
 +    }
 +}
 +
 +async fn async_read_line() -> String {
 +    use std::io::BufRead;
 +    let stdin = ::std::io::stdin();
 +    return stdin.lock().lines().next().unwrap().unwrap();
 +}
 +
 +async fn async_borrows_but_not_last(value: bool) -> String {
 +    if value {
 +        use std::io::BufRead;
 +        let stdin = ::std::io::stdin();
 +        let _a = stdin.lock().lines().next().unwrap().unwrap();
 +        return String::from("test");
 +    } else {
 +        return String::new();
 +    }
 +}
 +
 +async fn async_test_return_in_macro() {
 +    needed_return!(10);
 +    needed_return!(0);
 +}
 +
 +fn let_else() {
 +    let Some(1) = Some(1) else { return };
 +}
 +
 +fn main() {}
index 2e802cff1e686917ddef5a3c5e1ba7421c617ec4,0000000000000000000000000000000000000000..74dda971fdabb632633f4a125ba15d6e2d5ad1a3
mode 100644,000000..100644
--- /dev/null
@@@ -1,196 -1,0 +1,196 @@@
-   --> $DIR/needless_return.rs:25:5
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:29:5
++  --> $DIR/needless_return.rs:24:5
 +   |
 +LL |     return true;
 +   |     ^^^^^^^^^^^^ help: remove `return`: `true`
 +   |
 +   = note: `-D clippy::needless-return` implied by `-D warnings`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:34:9
++  --> $DIR/needless_return.rs:28:5
 +   |
 +LL |     return true;
 +   |     ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:36:9
++  --> $DIR/needless_return.rs:33:9
 +   |
 +LL |         return true;
 +   |         ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:42:17
++  --> $DIR/needless_return.rs:35:9
 +   |
 +LL |         return false;
 +   |         ^^^^^^^^^^^^^ help: remove `return`: `false`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:44:13
++  --> $DIR/needless_return.rs:41:17
 +   |
 +LL |         true => return false,
 +   |                 ^^^^^^^^^^^^ help: remove `return`: `false`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:51:9
++  --> $DIR/needless_return.rs:43:13
 +   |
 +LL |             return true;
 +   |             ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:53:16
++  --> $DIR/needless_return.rs:50:9
 +   |
 +LL |         return true;
 +   |         ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:61:5
++  --> $DIR/needless_return.rs:52:16
 +   |
 +LL |     let _ = || return true;
 +   |                ^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:66:9
++  --> $DIR/needless_return.rs:60:5
 +   |
 +LL |     return;
 +   |     ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:68:9
++  --> $DIR/needless_return.rs:65:9
 +   |
 +LL |         return;
 +   |         ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:75:14
++  --> $DIR/needless_return.rs:67:9
 +   |
 +LL |         return;
 +   |         ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:90:9
++  --> $DIR/needless_return.rs:74:14
 +   |
 +LL |         _ => return,
 +   |              ^^^^^^ help: replace `return` with an empty block: `{}`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:92:9
++  --> $DIR/needless_return.rs:89:9
 +   |
 +LL |         return String::from("test");
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:113:32
++  --> $DIR/needless_return.rs:91:9
 +   |
 +LL |         return String::new();
 +   |         ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:118:13
++  --> $DIR/needless_return.rs:112:32
 +   |
 +LL |         bar.unwrap_or_else(|_| return)
 +   |                                ^^^^^^ help: replace `return` with an empty block: `{}`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:120:20
++  --> $DIR/needless_return.rs:117:13
 +   |
 +LL |             return;
 +   |             ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:126:32
++  --> $DIR/needless_return.rs:119:20
 +   |
 +LL |         let _ = || return;
 +   |                    ^^^^^^ help: replace `return` with an empty block: `{}`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:135:5
++  --> $DIR/needless_return.rs:125:32
 +   |
 +LL |         res.unwrap_or_else(|_| return Foo)
 +   |                                ^^^^^^^^^^ help: remove `return`: `Foo`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:139:5
++  --> $DIR/needless_return.rs:134:5
 +   |
 +LL |     return true;
 +   |     ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:144:9
++  --> $DIR/needless_return.rs:138:5
 +   |
 +LL |     return true;
 +   |     ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:146:9
++  --> $DIR/needless_return.rs:143:9
 +   |
 +LL |         return true;
 +   |         ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:152:17
++  --> $DIR/needless_return.rs:145:9
 +   |
 +LL |         return false;
 +   |         ^^^^^^^^^^^^^ help: remove `return`: `false`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:154:13
++  --> $DIR/needless_return.rs:151:17
 +   |
 +LL |         true => return false,
 +   |                 ^^^^^^^^^^^^ help: remove `return`: `false`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:161:9
++  --> $DIR/needless_return.rs:153:13
 +   |
 +LL |             return true;
 +   |             ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:163:16
++  --> $DIR/needless_return.rs:160:9
 +   |
 +LL |         return true;
 +   |         ^^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:171:5
++  --> $DIR/needless_return.rs:162:16
 +   |
 +LL |     let _ = || return true;
 +   |                ^^^^^^^^^^^ help: remove `return`: `true`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:176:9
++  --> $DIR/needless_return.rs:170:5
 +   |
 +LL |     return;
 +   |     ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:178:9
++  --> $DIR/needless_return.rs:175:9
 +   |
 +LL |         return;
 +   |         ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:185:14
++  --> $DIR/needless_return.rs:177:9
 +   |
 +LL |         return;
 +   |         ^^^^^^^ help: remove `return`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:200:9
++  --> $DIR/needless_return.rs:184:14
 +   |
 +LL |         _ => return,
 +   |              ^^^^^^ help: replace `return` with an empty block: `{}`
 +
 +error: unneeded `return` statement
-   --> $DIR/needless_return.rs:202:9
++  --> $DIR/needless_return.rs:199:9
 +   |
 +LL |         return String::from("test");
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
 +
 +error: unneeded `return` statement
++  --> $DIR/needless_return.rs:201:9
 +   |
 +LL |         return String::new();
 +   |         ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
 +
 +error: aborting due to 32 previous errors
 +
index 58415b4aede260b668dbd3db7a0f9a56bc56ecd8,0000000000000000000000000000000000000000..961f6f409ddd2202916bfe14c17111d208359592
mode 100644,000000..100644
--- /dev/null
@@@ -1,56 -1,0 +1,56 @@@
-             MaybeInst::Split1(goto1) => panic!(1),
-             MaybeInst::Split2(goto2) => panic!(2),
 +#![warn(clippy::all)]
 +#![allow(unused, clippy::println_empty_string)]
 +
 +#[derive(Clone, Debug)]
 +enum MaybeInst {
 +    Split,
 +    Split1(usize),
 +    Split2(usize),
 +}
 +
 +struct InstSplit {
 +    uiae: usize,
 +}
 +
 +impl MaybeInst {
 +    fn fill(&mut self) {
 +        let filled = match *self {
++            MaybeInst::Split1(goto1) => panic!("1"),
++            MaybeInst::Split2(goto2) => panic!("2"),
 +            _ => unimplemented!(),
 +        };
 +        unimplemented!()
 +    }
 +}
 +
 +fn underscores_and_numbers() {
 +    let _1 = 1; //~ERROR Consider a more descriptive name
 +    let ____1 = 1; //~ERROR Consider a more descriptive name
 +    let __1___2 = 12; //~ERROR Consider a more descriptive name
 +    let _1_ok = 1;
 +}
 +
 +fn issue2927() {
 +    let args = 1;
 +    format!("{:?}", 2);
 +}
 +
 +fn issue3078() {
 +    match "a" {
 +        stringify!(a) => {},
 +        _ => {},
 +    }
 +}
 +
 +struct Bar;
 +
 +impl Bar {
 +    fn bar() {
 +        let _1 = 1;
 +        let ____1 = 1;
 +        let __1___2 = 12;
 +        let _1_ok = 1;
 +    }
 +}
 +
 +fn main() {}
index 4077f1920a3837758a6f02f6f5b5ea8c6a2b078e,0000000000000000000000000000000000000000..9cb6a9d1ecc9bc9e91c0cf071c748ab45a962711
mode 100644,000000..100644
--- /dev/null
@@@ -1,150 -1,0 +1,149 @@@
- // edition:2018
 +// run-rustfix
 +#![warn(clippy::option_if_let_else)]
 +#![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)]
 +
 +fn bad1(string: Option<&str>) -> (bool, &str) {
 +    string.map_or((false, "hello"), |x| (true, x))
 +}
 +
 +fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> {
 +    if string.is_none() {
 +        None
 +    } else if let Some(x) = string {
 +        Some((true, x))
 +    } else {
 +        Some((false, ""))
 +    }
 +}
 +
 +fn unop_bad(string: &Option<&str>, mut num: Option<i32>) {
 +    let _ = string.map_or(0, |s| s.len());
 +    let _ = num.as_ref().map_or(&0, |s| s);
 +    let _ = num.as_mut().map_or(&mut 0, |s| {
 +        *s += 1;
 +        s
 +    });
 +    let _ = num.as_ref().map_or(&0, |s| s);
 +    let _ = num.map_or(0, |mut s| {
 +        s += 1;
 +        s
 +    });
 +    let _ = num.as_mut().map_or(&mut 0, |s| {
 +        *s += 1;
 +        s
 +    });
 +}
 +
 +fn longer_body(arg: Option<u32>) -> u32 {
 +    arg.map_or(13, |x| {
 +        let y = x * x;
 +        y * y
 +    })
 +}
 +
 +fn impure_else(arg: Option<i32>) {
 +    let side_effect = || {
 +        println!("return 1");
 +        1
 +    };
 +    let _ = arg.map_or_else(|| side_effect(), |x| x);
 +}
 +
 +fn test_map_or_else(arg: Option<u32>) {
 +    let _ = arg.map_or_else(|| {
 +        let mut y = 1;
 +        y = (y + 2 / y) / 2;
 +        y = (y + 2 / y) / 2;
 +        y
 +    }, |x| x * x * x * x);
 +}
 +
 +fn negative_tests(arg: Option<u32>) -> u32 {
 +    let _ = if let Some(13) = arg { "unlucky" } else { "lucky" };
 +    for _ in 0..10 {
 +        let _ = if let Some(x) = arg {
 +            x
 +        } else {
 +            continue;
 +        };
 +    }
 +    let _ = if let Some(x) = arg {
 +        return x;
 +    } else {
 +        5
 +    };
 +    7
 +}
 +
 +fn main() {
 +    let optional = Some(5);
 +    let _ = optional.map_or(5, |x| x + 2);
 +    let _ = bad1(None);
 +    let _ = else_if_option(None);
 +    unop_bad(&None, None);
 +    let _ = longer_body(None);
 +    test_map_or_else(None);
 +    let _ = negative_tests(None);
 +    let _ = impure_else(None);
 +
 +    let _ = Some(0).map_or(0, |x| loop {
 +            if x == 0 {
 +                break x;
 +            }
 +        });
 +
 +    // #7576
 +    const fn _f(x: Option<u32>) -> u32 {
 +        // Don't lint, `map_or` isn't const
 +        if let Some(x) = x { x } else { 10 }
 +    }
 +
 +    // #5822
 +    let s = String::new();
 +    // Don't lint, `Some` branch consumes `s`, but else branch uses `s`
 +    let _ = if let Some(x) = Some(0) {
 +        let s = s;
 +        s.len() + x
 +    } else {
 +        s.len()
 +    };
 +
 +    let s = String::new();
 +    // Lint, both branches immutably borrow `s`.
 +    let _ = Some(0).map_or_else(|| s.len(), |x| s.len() + x);
 +
 +    let s = String::new();
 +    // Lint, `Some` branch consumes `s`, but else branch doesn't use `s`.
 +    let _ = Some(0).map_or(1, |x| {
 +        let s = s;
 +        s.len() + x
 +    });
 +
 +    let s = Some(String::new());
 +    // Don't lint, `Some` branch borrows `s`, but else branch consumes `s`
 +    let _ = if let Some(x) = &s {
 +        x.len()
 +    } else {
 +        let _s = s;
 +        10
 +    };
 +
 +    let mut s = Some(String::new());
 +    // Don't lint, `Some` branch mutably borrows `s`, but else branch also borrows  `s`
 +    let _ = if let Some(x) = &mut s {
 +        x.push_str("test");
 +        x.len()
 +    } else {
 +        let _s = &s;
 +        10
 +    };
 +
 +    async fn _f1(x: u32) -> u32 {
 +        x
 +    }
 +
 +    async fn _f2() {
 +        // Don't lint. `await` can't be moved into a closure.
 +        let _ = if let Some(x) = Some(0) { _f1(x).await } else { 0 };
 +    }
 +}
index 2f414e129d5a77c9952b88bd8e9efa5d0acc4249,0000000000000000000000000000000000000000..b3ba5eb870a693e65053cf50bbc1c914520fbe4a
mode 100644,000000..100644
--- /dev/null
@@@ -1,175 -1,0 +1,174 @@@
- // edition:2018
 +// run-rustfix
 +#![warn(clippy::option_if_let_else)]
 +#![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)]
 +
 +fn bad1(string: Option<&str>) -> (bool, &str) {
 +    if let Some(x) = string {
 +        (true, x)
 +    } else {
 +        (false, "hello")
 +    }
 +}
 +
 +fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> {
 +    if string.is_none() {
 +        None
 +    } else if let Some(x) = string {
 +        Some((true, x))
 +    } else {
 +        Some((false, ""))
 +    }
 +}
 +
 +fn unop_bad(string: &Option<&str>, mut num: Option<i32>) {
 +    let _ = if let Some(s) = *string { s.len() } else { 0 };
 +    let _ = if let Some(s) = &num { s } else { &0 };
 +    let _ = if let Some(s) = &mut num {
 +        *s += 1;
 +        s
 +    } else {
 +        &mut 0
 +    };
 +    let _ = if let Some(ref s) = num { s } else { &0 };
 +    let _ = if let Some(mut s) = num {
 +        s += 1;
 +        s
 +    } else {
 +        0
 +    };
 +    let _ = if let Some(ref mut s) = num {
 +        *s += 1;
 +        s
 +    } else {
 +        &mut 0
 +    };
 +}
 +
 +fn longer_body(arg: Option<u32>) -> u32 {
 +    if let Some(x) = arg {
 +        let y = x * x;
 +        y * y
 +    } else {
 +        13
 +    }
 +}
 +
 +fn impure_else(arg: Option<i32>) {
 +    let side_effect = || {
 +        println!("return 1");
 +        1
 +    };
 +    let _ = if let Some(x) = arg {
 +        x
 +    } else {
 +        // map_or_else must be suggested
 +        side_effect()
 +    };
 +}
 +
 +fn test_map_or_else(arg: Option<u32>) {
 +    let _ = if let Some(x) = arg {
 +        x * x * x * x
 +    } else {
 +        let mut y = 1;
 +        y = (y + 2 / y) / 2;
 +        y = (y + 2 / y) / 2;
 +        y
 +    };
 +}
 +
 +fn negative_tests(arg: Option<u32>) -> u32 {
 +    let _ = if let Some(13) = arg { "unlucky" } else { "lucky" };
 +    for _ in 0..10 {
 +        let _ = if let Some(x) = arg {
 +            x
 +        } else {
 +            continue;
 +        };
 +    }
 +    let _ = if let Some(x) = arg {
 +        return x;
 +    } else {
 +        5
 +    };
 +    7
 +}
 +
 +fn main() {
 +    let optional = Some(5);
 +    let _ = if let Some(x) = optional { x + 2 } else { 5 };
 +    let _ = bad1(None);
 +    let _ = else_if_option(None);
 +    unop_bad(&None, None);
 +    let _ = longer_body(None);
 +    test_map_or_else(None);
 +    let _ = negative_tests(None);
 +    let _ = impure_else(None);
 +
 +    let _ = if let Some(x) = Some(0) {
 +        loop {
 +            if x == 0 {
 +                break x;
 +            }
 +        }
 +    } else {
 +        0
 +    };
 +
 +    // #7576
 +    const fn _f(x: Option<u32>) -> u32 {
 +        // Don't lint, `map_or` isn't const
 +        if let Some(x) = x { x } else { 10 }
 +    }
 +
 +    // #5822
 +    let s = String::new();
 +    // Don't lint, `Some` branch consumes `s`, but else branch uses `s`
 +    let _ = if let Some(x) = Some(0) {
 +        let s = s;
 +        s.len() + x
 +    } else {
 +        s.len()
 +    };
 +
 +    let s = String::new();
 +    // Lint, both branches immutably borrow `s`.
 +    let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
 +
 +    let s = String::new();
 +    // Lint, `Some` branch consumes `s`, but else branch doesn't use `s`.
 +    let _ = if let Some(x) = Some(0) {
 +        let s = s;
 +        s.len() + x
 +    } else {
 +        1
 +    };
 +
 +    let s = Some(String::new());
 +    // Don't lint, `Some` branch borrows `s`, but else branch consumes `s`
 +    let _ = if let Some(x) = &s {
 +        x.len()
 +    } else {
 +        let _s = s;
 +        10
 +    };
 +
 +    let mut s = Some(String::new());
 +    // Don't lint, `Some` branch mutably borrows `s`, but else branch also borrows  `s`
 +    let _ = if let Some(x) = &mut s {
 +        x.push_str("test");
 +        x.len()
 +    } else {
 +        let _s = &s;
 +        10
 +    };
 +
 +    async fn _f1(x: u32) -> u32 {
 +        x
 +    }
 +
 +    async fn _f2() {
 +        // Don't lint. `await` can't be moved into a closure.
 +        let _ = if let Some(x) = Some(0) { _f1(x).await } else { 0 };
 +    }
 +}
index 803d941c36df8b2d8aa80ca7fa381ee8c35c780a,0000000000000000000000000000000000000000..685bb48ea37bc05baf1945d6a66b7c12f69c0934
mode 100644,000000..100644
--- /dev/null
@@@ -1,200 -1,0 +1,200 @@@
-   --> $DIR/option_if_let_else.rs:7:5
 +error: use Option::map_or instead of an if let/else
-   --> $DIR/option_if_let_else.rs:25:13
++  --> $DIR/option_if_let_else.rs:6:5
 +   |
 +LL | /     if let Some(x) = string {
 +LL | |         (true, x)
 +LL | |     } else {
 +LL | |         (false, "hello")
 +LL | |     }
 +   | |_____^ help: try: `string.map_or((false, "hello"), |x| (true, x))`
 +   |
 +   = note: `-D clippy::option-if-let-else` implied by `-D warnings`
 +
 +error: use Option::map_or instead of an if let/else
-   --> $DIR/option_if_let_else.rs:26:13
++  --> $DIR/option_if_let_else.rs:24:13
 +   |
 +LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
 +
 +error: use Option::map_or instead of an if let/else
-   --> $DIR/option_if_let_else.rs:27:13
++  --> $DIR/option_if_let_else.rs:25:13
 +   |
 +LL |     let _ = if let Some(s) = &num { s } else { &0 };
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 +
 +error: use Option::map_or instead of an if let/else
-   --> $DIR/option_if_let_else.rs:33:13
++  --> $DIR/option_if_let_else.rs:26:13
 +   |
 +LL |       let _ = if let Some(s) = &mut num {
 +   |  _____________^
 +LL | |         *s += 1;
 +LL | |         s
 +LL | |     } else {
 +LL | |         &mut 0
 +LL | |     };
 +   | |_____^
 +   |
 +help: try
 +   |
 +LL ~     let _ = num.as_mut().map_or(&mut 0, |s| {
 +LL +         *s += 1;
 +LL +         s
 +LL ~     });
 +   |
 +
 +error: use Option::map_or instead of an if let/else
-   --> $DIR/option_if_let_else.rs:34:13
++  --> $DIR/option_if_let_else.rs:32:13
 +   |
 +LL |     let _ = if let Some(ref s) = num { s } else { &0 };
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 +
 +error: use Option::map_or instead of an if let/else
-   --> $DIR/option_if_let_else.rs:40:13
++  --> $DIR/option_if_let_else.rs:33:13
 +   |
 +LL |       let _ = if let Some(mut s) = num {
 +   |  _____________^
 +LL | |         s += 1;
 +LL | |         s
 +LL | |     } else {
 +LL | |         0
 +LL | |     };
 +   | |_____^
 +   |
 +help: try
 +   |
 +LL ~     let _ = num.map_or(0, |mut s| {
 +LL +         s += 1;
 +LL +         s
 +LL ~     });
 +   |
 +
 +error: use Option::map_or instead of an if let/else
-   --> $DIR/option_if_let_else.rs:49:5
++  --> $DIR/option_if_let_else.rs:39:13
 +   |
 +LL |       let _ = if let Some(ref mut s) = num {
 +   |  _____________^
 +LL | |         *s += 1;
 +LL | |         s
 +LL | |     } else {
 +LL | |         &mut 0
 +LL | |     };
 +   | |_____^
 +   |
 +help: try
 +   |
 +LL ~     let _ = num.as_mut().map_or(&mut 0, |s| {
 +LL +         *s += 1;
 +LL +         s
 +LL ~     });
 +   |
 +
 +error: use Option::map_or instead of an if let/else
-   --> $DIR/option_if_let_else.rs:62:13
++  --> $DIR/option_if_let_else.rs:48:5
 +   |
 +LL | /     if let Some(x) = arg {
 +LL | |         let y = x * x;
 +LL | |         y * y
 +LL | |     } else {
 +LL | |         13
 +LL | |     }
 +   | |_____^
 +   |
 +help: try
 +   |
 +LL ~     arg.map_or(13, |x| {
 +LL +         let y = x * x;
 +LL +         y * y
 +LL +     })
 +   |
 +
 +error: use Option::map_or_else instead of an if let/else
-   --> $DIR/option_if_let_else.rs:71:13
++  --> $DIR/option_if_let_else.rs:61:13
 +   |
 +LL |       let _ = if let Some(x) = arg {
 +   |  _____________^
 +LL | |         x
 +LL | |     } else {
 +LL | |         // map_or_else must be suggested
 +LL | |         side_effect()
 +LL | |     };
 +   | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
 +
 +error: use Option::map_or_else instead of an if let/else
-   --> $DIR/option_if_let_else.rs:100:13
++  --> $DIR/option_if_let_else.rs:70:13
 +   |
 +LL |       let _ = if let Some(x) = arg {
 +   |  _____________^
 +LL | |         x * x * x * x
 +LL | |     } else {
 +LL | |         let mut y = 1;
 +...  |
 +LL | |         y
 +LL | |     };
 +   | |_____^
 +   |
 +help: try
 +   |
 +LL ~     let _ = arg.map_or_else(|| {
 +LL +         let mut y = 1;
 +LL +         y = (y + 2 / y) / 2;
 +LL +         y = (y + 2 / y) / 2;
 +LL +         y
 +LL ~     }, |x| x * x * x * x);
 +   |
 +
 +error: use Option::map_or instead of an if let/else
-   --> $DIR/option_if_let_else.rs:109:13
++  --> $DIR/option_if_let_else.rs:99:13
 +   |
 +LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 +
 +error: use Option::map_or instead of an if let/else
-   --> $DIR/option_if_let_else.rs:137:13
++  --> $DIR/option_if_let_else.rs:108:13
 +   |
 +LL |       let _ = if let Some(x) = Some(0) {
 +   |  _____________^
 +LL | |         loop {
 +LL | |             if x == 0 {
 +LL | |                 break x;
 +...  |
 +LL | |         0
 +LL | |     };
 +   | |_____^
 +   |
 +help: try
 +   |
 +LL ~     let _ = Some(0).map_or(0, |x| loop {
 +LL +             if x == 0 {
 +LL +                 break x;
 +LL +             }
 +LL ~         });
 +   |
 +
 +error: use Option::map_or_else instead of an if let/else
-   --> $DIR/option_if_let_else.rs:141:13
++  --> $DIR/option_if_let_else.rs:136:13
 +   |
 +LL |     let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or_else(|| s.len(), |x| s.len() + x)`
 +
 +error: use Option::map_or instead of an if let/else
++  --> $DIR/option_if_let_else.rs:140:13
 +   |
 +LL |       let _ = if let Some(x) = Some(0) {
 +   |  _____________^
 +LL | |         let s = s;
 +LL | |         s.len() + x
 +LL | |     } else {
 +LL | |         1
 +LL | |     };
 +   | |_____^
 +   |
 +help: try
 +   |
 +LL ~     let _ = Some(0).map_or(1, |x| {
 +LL +         let s = s;
 +LL +         s.len() + x
 +LL ~     });
 +   |
 +
 +error: aborting due to 14 previous errors
 +
index 3d3c19a1be5199e70c2a08f6c439aaca2e8a9645,0000000000000000000000000000000000000000..e75eb1b6eadd85ca225d830e3cb8ffe96bf584fa
mode 100644,000000..100644
--- /dev/null
@@@ -1,71 -1,0 +1,70 @@@
 +#![warn(clippy::panic_in_result_fn)]
 +#![allow(clippy::unnecessary_wraps)]
 +struct A;
 +
 +impl A {
 +    fn result_with_panic() -> Result<bool, String> // should emit lint
 +    {
 +        panic!("error");
 +    }
 +
 +    fn result_with_unimplemented() -> Result<bool, String> // should emit lint
 +    {
 +        unimplemented!();
 +    }
 +
 +    fn result_with_unreachable() -> Result<bool, String> // should emit lint
 +    {
 +        unreachable!();
 +    }
 +
 +    fn result_with_todo() -> Result<bool, String> // should emit lint
 +    {
 +        todo!("Finish this");
 +    }
 +
 +    fn other_with_panic() // should not emit lint
 +    {
 +        panic!("");
 +    }
 +
 +    fn other_with_unreachable() // should not emit lint
 +    {
 +        unreachable!();
 +    }
 +
 +    fn other_with_unimplemented() // should not emit lint
 +    {
 +        unimplemented!();
 +    }
 +
 +    fn other_with_todo() // should not emit lint
 +    {
 +        todo!("finish this")
 +    }
 +
 +    fn result_without_banned_functions() -> Result<bool, String> // should not emit lint
 +    {
 +        Ok(true)
 +    }
 +}
 +
 +fn function_result_with_panic() -> Result<bool, String> // should emit lint
 +{
 +    panic!("error");
 +}
 +
 +fn todo() {
 +    println!("something");
 +}
 +
 +fn function_result_with_custom_todo() -> Result<bool, String> // should not emit lint
 +{
 +    todo();
 +    Ok(true)
 +}
 +
 +fn main() -> Result<(), String> {
 +    todo!("finish main method");
 +    Ok(())
 +}
index f56c2d03c664fb2d98448f7127c92acabb6b2bdc,0000000000000000000000000000000000000000..78d09b8b2108a134b0c91a4c37e5bbd238de6387
mode 100644,000000..100644
--- /dev/null
@@@ -1,105 -1,0 +1,105 @@@
-   --> $DIR/panic_in_result_fn.rs:7:5
 +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
-   --> $DIR/panic_in_result_fn.rs:9:9
++  --> $DIR/panic_in_result_fn.rs:6:5
 +   |
 +LL | /     fn result_with_panic() -> Result<bool, String> // should emit lint
 +LL | |     {
 +LL | |         panic!("error");
 +LL | |     }
 +   | |_____^
 +   |
 +   = note: `-D clippy::panic-in-result-fn` implied by `-D warnings`
 +   = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
 +note: return Err() instead of panicking
-    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
++  --> $DIR/panic_in_result_fn.rs:8:9
 +   |
 +LL |         panic!("error");
 +   |         ^^^^^^^^^^^^^^^
-   --> $DIR/panic_in_result_fn.rs:12:5
++   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
-   --> $DIR/panic_in_result_fn.rs:14:9
++  --> $DIR/panic_in_result_fn.rs:11:5
 +   |
 +LL | /     fn result_with_unimplemented() -> Result<bool, String> // should emit lint
 +LL | |     {
 +LL | |         unimplemented!();
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
 +note: return Err() instead of panicking
-   --> $DIR/panic_in_result_fn.rs:17:5
++  --> $DIR/panic_in_result_fn.rs:13:9
 +   |
 +LL |         unimplemented!();
 +   |         ^^^^^^^^^^^^^^^^
 +   = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
-   --> $DIR/panic_in_result_fn.rs:19:9
++  --> $DIR/panic_in_result_fn.rs:16:5
 +   |
 +LL | /     fn result_with_unreachable() -> Result<bool, String> // should emit lint
 +LL | |     {
 +LL | |         unreachable!();
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
 +note: return Err() instead of panicking
-   --> $DIR/panic_in_result_fn.rs:22:5
++  --> $DIR/panic_in_result_fn.rs:18:9
 +   |
 +LL |         unreachable!();
 +   |         ^^^^^^^^^^^^^^
 +   = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
-   --> $DIR/panic_in_result_fn.rs:24:9
++  --> $DIR/panic_in_result_fn.rs:21:5
 +   |
 +LL | /     fn result_with_todo() -> Result<bool, String> // should emit lint
 +LL | |     {
 +LL | |         todo!("Finish this");
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
 +note: return Err() instead of panicking
-   --> $DIR/panic_in_result_fn.rs:53:1
++  --> $DIR/panic_in_result_fn.rs:23:9
 +   |
 +LL |         todo!("Finish this");
 +   |         ^^^^^^^^^^^^^^^^^^^^
 +   = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
-   --> $DIR/panic_in_result_fn.rs:55:5
++  --> $DIR/panic_in_result_fn.rs:52:1
 +   |
 +LL | / fn function_result_with_panic() -> Result<bool, String> // should emit lint
 +LL | | {
 +LL | |     panic!("error");
 +LL | | }
 +   | |_^
 +   |
 +   = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
 +note: return Err() instead of panicking
-    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
++  --> $DIR/panic_in_result_fn.rs:54:5
 +   |
 +LL |     panic!("error");
 +   |     ^^^^^^^^^^^^^^^
-   --> $DIR/panic_in_result_fn.rs:68:1
++   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
-   --> $DIR/panic_in_result_fn.rs:69:5
++  --> $DIR/panic_in_result_fn.rs:67:1
 +   |
 +LL | / fn main() -> Result<(), String> {
 +LL | |     todo!("finish main method");
 +LL | |     Ok(())
 +LL | | }
 +   | |_^
 +   |
 +   = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
 +note: return Err() instead of panicking
++  --> $DIR/panic_in_result_fn.rs:68:5
 +   |
 +LL |     todo!("finish main method");
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +   = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
 +
 +error: aborting due to 6 previous errors
 +
index 99e6d2aad8dd6b46ac5229da0866d36218688f0a,0000000000000000000000000000000000000000..67bfef06a05e8cdd3e7b73c19fbc629d5e6fbf3e
mode 100644,000000..100644
--- /dev/null
@@@ -1,162 -1,0 +1,161 @@@
- #![allow(
-     unused,
-     clippy::many_single_char_names,
-     clippy::redundant_clone,
-     clippy::if_then_panic
- )]
++#![allow(unused, clippy::many_single_char_names, clippy::redundant_clone)]
 +#![warn(clippy::ptr_arg)]
 +
 +use std::borrow::Cow;
 +use std::path::PathBuf;
 +
 +fn do_vec(x: &Vec<i64>) {
 +    //Nothing here
 +}
 +
 +fn do_vec_mut(x: &mut Vec<i64>) {
 +    // no error here
 +    //Nothing here
 +}
 +
 +fn do_str(x: &String) {
 +    //Nothing here either
 +}
 +
 +fn do_str_mut(x: &mut String) {
 +    // no error here
 +    //Nothing here either
 +}
 +
 +fn do_path(x: &PathBuf) {
 +    //Nothing here either
 +}
 +
 +fn do_path_mut(x: &mut PathBuf) {
 +    // no error here
 +    //Nothing here either
 +}
 +
 +fn main() {}
 +
 +trait Foo {
 +    type Item;
 +    fn do_vec(x: &Vec<i64>);
 +    fn do_item(x: &Self::Item);
 +}
 +
 +struct Bar;
 +
 +// no error, in trait impl (#425)
 +impl Foo for Bar {
 +    type Item = Vec<u8>;
 +    fn do_vec(x: &Vec<i64>) {}
 +    fn do_item(x: &Vec<u8>) {}
 +}
 +
 +fn cloned(x: &Vec<u8>) -> Vec<u8> {
 +    let e = x.clone();
 +    let f = e.clone(); // OK
 +    let g = x;
 +    let h = g.clone(); // Alas, we cannot reliably detect this without following data.
 +    let i = (e).clone();
 +    x.clone()
 +}
 +
 +fn str_cloned(x: &String) -> String {
 +    let a = x.clone();
 +    let b = x.clone();
 +    let c = b.clone();
 +    let d = a.clone().clone().clone();
 +    x.clone()
 +}
 +
 +fn path_cloned(x: &PathBuf) -> PathBuf {
 +    let a = x.clone();
 +    let b = x.clone();
 +    let c = b.clone();
 +    let d = a.clone().clone().clone();
 +    x.clone()
 +}
 +
 +fn false_positive_capacity(x: &Vec<u8>, y: &String) {
 +    let a = x.capacity();
 +    let b = y.clone();
 +    let c = y.as_str();
 +}
 +
 +fn false_positive_capacity_too(x: &String) -> String {
 +    if x.capacity() > 1024 {
 +        panic!("Too large!");
 +    }
 +    x.clone()
 +}
 +
 +#[allow(dead_code)]
 +fn test_cow_with_ref(c: &Cow<[i32]>) {}
 +
 +fn test_cow(c: Cow<[i32]>) {
 +    let _c = c;
 +}
 +
 +trait Foo2 {
 +    fn do_string(&self);
 +}
 +
 +// no error for &self references where self is of type String (#2293)
 +impl Foo2 for String {
 +    fn do_string(&self) {}
 +}
 +
 +// Check that the allow attribute on parameters is honored
 +mod issue_5644 {
 +    use std::borrow::Cow;
 +    use std::path::PathBuf;
 +
 +    fn allowed(
 +        #[allow(clippy::ptr_arg)] _v: &Vec<u32>,
 +        #[allow(clippy::ptr_arg)] _s: &String,
 +        #[allow(clippy::ptr_arg)] _p: &PathBuf,
 +        #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
 +    ) {
 +    }
 +
 +    struct S {}
 +    impl S {
 +        fn allowed(
 +            #[allow(clippy::ptr_arg)] _v: &Vec<u32>,
 +            #[allow(clippy::ptr_arg)] _s: &String,
 +            #[allow(clippy::ptr_arg)] _p: &PathBuf,
 +            #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
 +        ) {
 +        }
 +    }
 +
 +    trait T {
 +        fn allowed(
 +            #[allow(clippy::ptr_arg)] _v: &Vec<u32>,
 +            #[allow(clippy::ptr_arg)] _s: &String,
 +            #[allow(clippy::ptr_arg)] _p: &PathBuf,
 +            #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
 +        ) {
 +        }
 +    }
 +}
 +
 +mod issue6509 {
 +    use std::path::PathBuf;
 +
 +    fn foo_vec(vec: &Vec<u8>) {
 +        let _ = vec.clone().pop();
 +        let _ = vec.clone().clone();
 +    }
 +
 +    fn foo_path(path: &PathBuf) {
 +        let _ = path.clone().pop();
 +        let _ = path.clone().clone();
 +    }
 +
 +    fn foo_str(str: &PathBuf) {
 +        let _ = str.clone().pop();
 +        let _ = str.clone().clone();
 +    }
 +}
++
++// No error for types behind an alias (#7699)
++type A = Vec<u8>;
++fn aliased(a: &A) {}
index 42183447ead737cf34275a3fe9be5edf01a406c4,0000000000000000000000000000000000000000..64594eb870c2c5067b413095f6eabdeded968ebc
mode 100644,000000..100644
--- /dev/null
@@@ -1,175 -1,0 +1,175 @@@
-   --> $DIR/ptr_arg.rs:12:14
 +error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
-   --> $DIR/ptr_arg.rs:21:14
++  --> $DIR/ptr_arg.rs:7:14
 +   |
 +LL | fn do_vec(x: &Vec<i64>) {
 +   |              ^^^^^^^^^ help: change this to: `&[i64]`
 +   |
 +   = note: `-D clippy::ptr-arg` implied by `-D warnings`
 +
 +error: writing `&String` instead of `&str` involves a new object where a slice will do
-   --> $DIR/ptr_arg.rs:30:15
++  --> $DIR/ptr_arg.rs:16:14
 +   |
 +LL | fn do_str(x: &String) {
 +   |              ^^^^^^^ help: change this to: `&str`
 +
 +error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-   --> $DIR/ptr_arg.rs:43:18
++  --> $DIR/ptr_arg.rs:25:15
 +   |
 +LL | fn do_path(x: &PathBuf) {
 +   |               ^^^^^^^^ help: change this to: `&Path`
 +
 +error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
-   --> $DIR/ptr_arg.rs:56:14
++  --> $DIR/ptr_arg.rs:38:18
 +   |
 +LL |     fn do_vec(x: &Vec<i64>);
 +   |                  ^^^^^^^^^ help: change this to: `&[i64]`
 +
 +error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
-   --> $DIR/ptr_arg.rs:65:18
++  --> $DIR/ptr_arg.rs:51:14
 +   |
 +LL | fn cloned(x: &Vec<u8>) -> Vec<u8> {
 +   |              ^^^^^^^^
 +   |
 +help: change this to
 +   |
 +LL | fn cloned(x: &[u8]) -> Vec<u8> {
 +   |              ~~~~~
 +help: change `x.clone()` to
 +   |
 +LL |     let e = x.to_owned();
 +   |             ~~~~~~~~~~~~
 +help: change `x.clone()` to
 +   |
 +LL |     x.to_owned()
 +   |
 +
 +error: writing `&String` instead of `&str` involves a new object where a slice will do
-   --> $DIR/ptr_arg.rs:73:19
++  --> $DIR/ptr_arg.rs:60:18
 +   |
 +LL | fn str_cloned(x: &String) -> String {
 +   |                  ^^^^^^^
 +   |
 +help: change this to
 +   |
 +LL | fn str_cloned(x: &str) -> String {
 +   |                  ~~~~
 +help: change `x.clone()` to
 +   |
 +LL |     let a = x.to_string();
 +   |             ~~~~~~~~~~~~~
 +help: change `x.clone()` to
 +   |
 +LL |     let b = x.to_string();
 +   |             ~~~~~~~~~~~~~
 +help: change `x.clone()` to
 +   |
 +LL |     x.to_string()
 +   |
 +
 +error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-   --> $DIR/ptr_arg.rs:81:44
++  --> $DIR/ptr_arg.rs:68:19
 +   |
 +LL | fn path_cloned(x: &PathBuf) -> PathBuf {
 +   |                   ^^^^^^^^
 +   |
 +help: change this to
 +   |
 +LL | fn path_cloned(x: &Path) -> PathBuf {
 +   |                   ~~~~~
 +help: change `x.clone()` to
 +   |
 +LL |     let a = x.to_path_buf();
 +   |             ~~~~~~~~~~~~~~~
 +help: change `x.clone()` to
 +   |
 +LL |     let b = x.to_path_buf();
 +   |             ~~~~~~~~~~~~~~~
 +help: change `x.clone()` to
 +   |
 +LL |     x.to_path_buf()
 +   |
 +
 +error: writing `&String` instead of `&str` involves a new object where a slice will do
-   --> $DIR/ptr_arg.rs:95:25
++  --> $DIR/ptr_arg.rs:76:44
 +   |
 +LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) {
 +   |                                            ^^^^^^^
 +   |
 +help: change this to
 +   |
 +LL | fn false_positive_capacity(x: &Vec<u8>, y: &str) {
 +   |                                            ~~~~
 +help: change `y.clone()` to
 +   |
 +LL |     let b = y.to_string();
 +   |             ~~~~~~~~~~~~~
 +help: change `y.as_str()` to
 +   |
 +LL |     let c = y;
 +   |             ~
 +
 +error: using a reference to `Cow` is not recommended
-   --> $DIR/ptr_arg.rs:148:21
++  --> $DIR/ptr_arg.rs:90:25
 +   |
 +LL | fn test_cow_with_ref(c: &Cow<[i32]>) {}
 +   |                         ^^^^^^^^^^^ help: change this to: `&[i32]`
 +
 +error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
-   --> $DIR/ptr_arg.rs:153:23
++  --> $DIR/ptr_arg.rs:143:21
 +   |
 +LL |     fn foo_vec(vec: &Vec<u8>) {
 +   |                     ^^^^^^^^
 +   |
 +help: change this to
 +   |
 +LL |     fn foo_vec(vec: &[u8]) {
 +   |                     ~~~~~
 +help: change `vec.clone()` to
 +   |
 +LL |         let _ = vec.to_owned().pop();
 +   |                 ~~~~~~~~~~~~~~
 +help: change `vec.clone()` to
 +   |
 +LL |         let _ = vec.to_owned().clone();
 +   |                 ~~~~~~~~~~~~~~
 +
 +error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-   --> $DIR/ptr_arg.rs:158:21
++  --> $DIR/ptr_arg.rs:148:23
 +   |
 +LL |     fn foo_path(path: &PathBuf) {
 +   |                       ^^^^^^^^
 +   |
 +help: change this to
 +   |
 +LL |     fn foo_path(path: &Path) {
 +   |                       ~~~~~
 +help: change `path.clone()` to
 +   |
 +LL |         let _ = path.to_path_buf().pop();
 +   |                 ~~~~~~~~~~~~~~~~~~
 +help: change `path.clone()` to
 +   |
 +LL |         let _ = path.to_path_buf().clone();
 +   |                 ~~~~~~~~~~~~~~~~~~
 +
 +error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
++  --> $DIR/ptr_arg.rs:153:21
 +   |
 +LL |     fn foo_str(str: &PathBuf) {
 +   |                     ^^^^^^^^
 +   |
 +help: change this to
 +   |
 +LL |     fn foo_str(str: &Path) {
 +   |                     ~~~~~
 +help: change `str.clone()` to
 +   |
 +LL |         let _ = str.to_path_buf().pop();
 +   |                 ~~~~~~~~~~~~~~~~~
 +help: change `str.clone()` to
 +   |
 +LL |         let _ = str.to_path_buf().clone();
 +   |                 ~~~~~~~~~~~~~~~~~
 +
 +error: aborting due to 12 previous errors
 +
index ccb2e5a302e91590feb0ba2af50ae467e00e8115,0000000000000000000000000000000000000000..e93469e5f556bd55737c0628961e540e7caf5be1
mode 100644,000000..100644
--- /dev/null
@@@ -1,143 -1,0 +1,160 @@@
- fn result_func(x: Result<i32, &str>) -> Result<i32, &str> {
 +// run-rustfix
 +#![allow(unreachable_code)]
 +#![allow(clippy::unnecessary_wraps)]
 +
 +fn some_func(a: Option<u32>) -> Option<u32> {
 +    a?;
 +
 +    a
 +}
 +
 +fn some_other_func(a: Option<u32>) -> Option<u32> {
 +    if a.is_none() {
 +        return None;
 +    } else {
 +        return Some(0);
 +    }
 +    unreachable!()
 +}
 +
 +pub enum SeemsOption<T> {
 +    Some(T),
 +    None,
 +}
 +
 +impl<T> SeemsOption<T> {
 +    pub fn is_none(&self) -> bool {
 +        match *self {
 +            SeemsOption::None => true,
 +            SeemsOption::Some(_) => false,
 +        }
 +    }
 +}
 +
 +fn returns_something_similar_to_option(a: SeemsOption<u32>) -> SeemsOption<u32> {
 +    if a.is_none() {
 +        return SeemsOption::None;
 +    }
 +
 +    a
 +}
 +
 +pub struct CopyStruct {
 +    pub opt: Option<u32>,
 +}
 +
 +impl CopyStruct {
 +    #[rustfmt::skip]
 +    pub fn func(&self) -> Option<u32> {
 +        (self.opt)?;
 +
 +        self.opt?;
 +
 +        let _ = Some(self.opt?);
 +
 +        let _ = self.opt?;
 +
 +        self.opt
 +    }
 +}
 +
 +#[derive(Clone)]
 +pub struct MoveStruct {
 +    pub opt: Option<Vec<u32>>,
 +}
 +
 +impl MoveStruct {
 +    pub fn ref_func(&self) -> Option<Vec<u32>> {
 +        self.opt.as_ref()?;
 +
 +        self.opt.clone()
 +    }
 +
 +    pub fn mov_func_reuse(self) -> Option<Vec<u32>> {
 +        self.opt.as_ref()?;
 +
 +        self.opt
 +    }
 +
 +    pub fn mov_func_no_use(self) -> Option<Vec<u32>> {
 +        self.opt.as_ref()?;
 +        Some(Vec::new())
 +    }
 +
 +    pub fn if_let_ref_func(self) -> Option<Vec<u32>> {
 +        let v: &Vec<_> = self.opt.as_ref()?;
 +
 +        Some(v.clone())
 +    }
 +
 +    pub fn if_let_mov_func(self) -> Option<Vec<u32>> {
 +        let v = self.opt?;
 +
 +        Some(v)
 +    }
 +}
 +
 +fn func() -> Option<i32> {
 +    fn f() -> Option<String> {
 +        Some(String::new())
 +    }
 +
 +    f()?;
 +
 +    Some(0)
 +}
 +
-         return Err("some error");
++fn func_returning_result() -> Result<i32, i32> {
++    Ok(1)
++}
++
++fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
 +    let _ = x?;
 +
 +    x?;
 +
 +    // No warning
 +    let y = if let Ok(x) = x {
 +        x
 +    } else {
++        return Err(0);
++    };
++
++    // issue #7859
++    // no warning
++    let _ = if let Ok(x) = func_returning_result() {
++        x
++    } else {
++        return Err(0);
 +    };
 +
++    // no warning
++    if func_returning_result().is_err() {
++        return func_returning_result();
++    }
++
 +    Ok(y)
 +}
 +
 +fn main() {
 +    some_func(Some(42));
 +    some_func(None);
 +    some_other_func(Some(42));
 +
 +    let copy_struct = CopyStruct { opt: Some(54) };
 +    copy_struct.func();
 +
 +    let move_struct = MoveStruct {
 +        opt: Some(vec![42, 1337]),
 +    };
 +    move_struct.ref_func();
 +    move_struct.clone().mov_func_reuse();
 +    move_struct.mov_func_no_use();
 +
 +    let so = SeemsOption::Some(45);
 +    returns_something_similar_to_option(so);
 +
 +    func();
 +
 +    let _ = result_func(Ok(42));
 +}
index ca3722371f524b53b27ca94f15fd1a46e7d867ca,0000000000000000000000000000000000000000..dd179e9bee8f87d57c6623617d0b646fb154c684
mode 100644,000000..100644
--- /dev/null
@@@ -1,175 -1,0 +1,192 @@@
- fn result_func(x: Result<i32, &str>) -> Result<i32, &str> {
 +// run-rustfix
 +#![allow(unreachable_code)]
 +#![allow(clippy::unnecessary_wraps)]
 +
 +fn some_func(a: Option<u32>) -> Option<u32> {
 +    if a.is_none() {
 +        return None;
 +    }
 +
 +    a
 +}
 +
 +fn some_other_func(a: Option<u32>) -> Option<u32> {
 +    if a.is_none() {
 +        return None;
 +    } else {
 +        return Some(0);
 +    }
 +    unreachable!()
 +}
 +
 +pub enum SeemsOption<T> {
 +    Some(T),
 +    None,
 +}
 +
 +impl<T> SeemsOption<T> {
 +    pub fn is_none(&self) -> bool {
 +        match *self {
 +            SeemsOption::None => true,
 +            SeemsOption::Some(_) => false,
 +        }
 +    }
 +}
 +
 +fn returns_something_similar_to_option(a: SeemsOption<u32>) -> SeemsOption<u32> {
 +    if a.is_none() {
 +        return SeemsOption::None;
 +    }
 +
 +    a
 +}
 +
 +pub struct CopyStruct {
 +    pub opt: Option<u32>,
 +}
 +
 +impl CopyStruct {
 +    #[rustfmt::skip]
 +    pub fn func(&self) -> Option<u32> {
 +        if (self.opt).is_none() {
 +            return None;
 +        }
 +
 +        if self.opt.is_none() {
 +            return None
 +        }
 +
 +        let _ = if self.opt.is_none() {
 +            return None;
 +        } else {
 +            self.opt
 +        };
 +
 +        let _ = if let Some(x) = self.opt {
 +            x
 +        } else {
 +            return None;
 +        };
 +
 +        self.opt
 +    }
 +}
 +
 +#[derive(Clone)]
 +pub struct MoveStruct {
 +    pub opt: Option<Vec<u32>>,
 +}
 +
 +impl MoveStruct {
 +    pub fn ref_func(&self) -> Option<Vec<u32>> {
 +        if self.opt.is_none() {
 +            return None;
 +        }
 +
 +        self.opt.clone()
 +    }
 +
 +    pub fn mov_func_reuse(self) -> Option<Vec<u32>> {
 +        if self.opt.is_none() {
 +            return None;
 +        }
 +
 +        self.opt
 +    }
 +
 +    pub fn mov_func_no_use(self) -> Option<Vec<u32>> {
 +        if self.opt.is_none() {
 +            return None;
 +        }
 +        Some(Vec::new())
 +    }
 +
 +    pub fn if_let_ref_func(self) -> Option<Vec<u32>> {
 +        let v: &Vec<_> = if let Some(ref v) = self.opt {
 +            v
 +        } else {
 +            return None;
 +        };
 +
 +        Some(v.clone())
 +    }
 +
 +    pub fn if_let_mov_func(self) -> Option<Vec<u32>> {
 +        let v = if let Some(v) = self.opt {
 +            v
 +        } else {
 +            return None;
 +        };
 +
 +        Some(v)
 +    }
 +}
 +
 +fn func() -> Option<i32> {
 +    fn f() -> Option<String> {
 +        Some(String::new())
 +    }
 +
 +    if f().is_none() {
 +        return None;
 +    }
 +
 +    Some(0)
 +}
 +
-         return Err("some error");
++fn func_returning_result() -> Result<i32, i32> {
++    Ok(1)
++}
++
++fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
 +    let _ = if let Ok(x) = x { x } else { return x };
 +
 +    if x.is_err() {
 +        return x;
 +    }
 +
 +    // No warning
 +    let y = if let Ok(x) = x {
 +        x
 +    } else {
++        return Err(0);
++    };
++
++    // issue #7859
++    // no warning
++    let _ = if let Ok(x) = func_returning_result() {
++        x
++    } else {
++        return Err(0);
 +    };
 +
++    // no warning
++    if func_returning_result().is_err() {
++        return func_returning_result();
++    }
++
 +    Ok(y)
 +}
 +
 +fn main() {
 +    some_func(Some(42));
 +    some_func(None);
 +    some_other_func(Some(42));
 +
 +    let copy_struct = CopyStruct { opt: Some(54) };
 +    copy_struct.func();
 +
 +    let move_struct = MoveStruct {
 +        opt: Some(vec![42, 1337]),
 +    };
 +    move_struct.ref_func();
 +    move_struct.clone().mov_func_reuse();
 +    move_struct.mov_func_no_use();
 +
 +    let so = SeemsOption::Some(45);
 +    returns_something_similar_to_option(so);
 +
 +    func();
 +
 +    let _ = result_func(Ok(42));
 +}
index 161588cb73cba06797561917e4ee5fe6fa3710d9,0000000000000000000000000000000000000000..8d782b71dd6a47ae8368b0d8f8c7ba89b13b34b6
mode 100644,000000..100644
--- /dev/null
@@@ -1,118 -1,0 +1,118 @@@
-   --> $DIR/question_mark.rs:138:13
 +error: this block may be rewritten with the `?` operator
 +  --> $DIR/question_mark.rs:6:5
 +   |
 +LL | /     if a.is_none() {
 +LL | |         return None;
 +LL | |     }
 +   | |_____^ help: replace it with: `a?;`
 +   |
 +   = note: `-D clippy::question-mark` implied by `-D warnings`
 +
 +error: this block may be rewritten with the `?` operator
 +  --> $DIR/question_mark.rs:51:9
 +   |
 +LL | /         if (self.opt).is_none() {
 +LL | |             return None;
 +LL | |         }
 +   | |_________^ help: replace it with: `(self.opt)?;`
 +
 +error: this block may be rewritten with the `?` operator
 +  --> $DIR/question_mark.rs:55:9
 +   |
 +LL | /         if self.opt.is_none() {
 +LL | |             return None
 +LL | |         }
 +   | |_________^ help: replace it with: `self.opt?;`
 +
 +error: this block may be rewritten with the `?` operator
 +  --> $DIR/question_mark.rs:59:17
 +   |
 +LL |           let _ = if self.opt.is_none() {
 +   |  _________________^
 +LL | |             return None;
 +LL | |         } else {
 +LL | |             self.opt
 +LL | |         };
 +   | |_________^ help: replace it with: `Some(self.opt?)`
 +
 +error: this if-let-else may be rewritten with the `?` operator
 +  --> $DIR/question_mark.rs:65:17
 +   |
 +LL |           let _ = if let Some(x) = self.opt {
 +   |  _________________^
 +LL | |             x
 +LL | |         } else {
 +LL | |             return None;
 +LL | |         };
 +   | |_________^ help: replace it with: `self.opt?`
 +
 +error: this block may be rewritten with the `?` operator
 +  --> $DIR/question_mark.rs:82:9
 +   |
 +LL | /         if self.opt.is_none() {
 +LL | |             return None;
 +LL | |         }
 +   | |_________^ help: replace it with: `self.opt.as_ref()?;`
 +
 +error: this block may be rewritten with the `?` operator
 +  --> $DIR/question_mark.rs:90:9
 +   |
 +LL | /         if self.opt.is_none() {
 +LL | |             return None;
 +LL | |         }
 +   | |_________^ help: replace it with: `self.opt.as_ref()?;`
 +
 +error: this block may be rewritten with the `?` operator
 +  --> $DIR/question_mark.rs:98:9
 +   |
 +LL | /         if self.opt.is_none() {
 +LL | |             return None;
 +LL | |         }
 +   | |_________^ help: replace it with: `self.opt.as_ref()?;`
 +
 +error: this if-let-else may be rewritten with the `?` operator
 +  --> $DIR/question_mark.rs:105:26
 +   |
 +LL |           let v: &Vec<_> = if let Some(ref v) = self.opt {
 +   |  __________________________^
 +LL | |             v
 +LL | |         } else {
 +LL | |             return None;
 +LL | |         };
 +   | |_________^ help: replace it with: `self.opt.as_ref()?`
 +
 +error: this if-let-else may be rewritten with the `?` operator
 +  --> $DIR/question_mark.rs:115:17
 +   |
 +LL |           let v = if let Some(v) = self.opt {
 +   |  _________________^
 +LL | |             v
 +LL | |         } else {
 +LL | |             return None;
 +LL | |         };
 +   | |_________^ help: replace it with: `self.opt?`
 +
 +error: this block may be rewritten with the `?` operator
 +  --> $DIR/question_mark.rs:130:5
 +   |
 +LL | /     if f().is_none() {
 +LL | |         return None;
 +LL | |     }
 +   | |_____^ help: replace it with: `f()?;`
 +
 +error: this if-let-else may be rewritten with the `?` operator
-   --> $DIR/question_mark.rs:140:5
++  --> $DIR/question_mark.rs:142:13
 +   |
 +LL |     let _ = if let Ok(x) = x { x } else { return x };
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?`
 +
 +error: this block may be rewritten with the `?` operator
++  --> $DIR/question_mark.rs:144:5
 +   |
 +LL | /     if x.is_err() {
 +LL | |         return x;
 +LL | |     }
 +   | |_____^ help: replace it with: `x?;`
 +
 +error: aborting due to 13 previous errors
 +
index 2d711082746e73aab40867f0bcc2285137e5aca2,0000000000000000000000000000000000000000..16b40dcd902869d7184cb1d6b384139166d04380
mode 100644,000000..100644
--- /dev/null
@@@ -1,236 -1,0 +1,236 @@@
-     foo(&x.clone(), move || {
 +// run-rustfix
 +// rustfix-only-machine-applicable
 +
 +#![allow(clippy::implicit_clone)]
 +use std::ffi::OsString;
 +use std::path::Path;
 +
 +fn main() {
 +    let _s = ["lorem", "ipsum"].join(" ");
 +
 +    let s = String::from("foo");
 +    let _s = s;
 +
 +    let s = String::from("foo");
 +    let _s = s;
 +
 +    let s = String::from("foo");
 +    let _s = s;
 +
 +    let _s = Path::new("/a/b/").join("c");
 +
 +    let _s = Path::new("/a/b/").join("c");
 +
 +    let _s = OsString::new();
 +
 +    let _s = OsString::new();
 +
 +    // Check that lint level works
 +    #[allow(clippy::redundant_clone)]
 +    let _s = String::new().to_string();
 +
 +    let tup = (String::from("foo"),);
 +    let _t = tup.0;
 +
 +    let tup_ref = &(String::from("foo"),);
 +    let _s = tup_ref.0.clone(); // this `.clone()` cannot be removed
 +
 +    {
 +        let x = String::new();
 +        let y = &x;
 +
 +        let _x = x.clone(); // ok; `x` is borrowed by `y`
 +
 +        let _ = y.len();
 +    }
 +
 +    let x = (String::new(),);
 +    let _ = Some(String::new()).unwrap_or_else(|| x.0.clone()); // ok; closure borrows `x`
 +
 +    with_branch(Alpha, true);
 +    cannot_double_move(Alpha);
 +    cannot_move_from_type_with_drop();
 +    borrower_propagation();
 +    not_consumed();
 +    issue_5405();
 +    manually_drop();
 +    clone_then_move_cloned();
 +    hashmap_neg();
 +    false_negative_5707();
 +}
 +
 +#[derive(Clone)]
 +struct Alpha;
 +fn with_branch(a: Alpha, b: bool) -> (Alpha, Alpha) {
 +    if b { (a.clone(), a) } else { (Alpha, a) }
 +}
 +
 +fn cannot_double_move(a: Alpha) -> (Alpha, Alpha) {
 +    (a.clone(), a)
 +}
 +
 +struct TypeWithDrop {
 +    x: String,
 +}
 +
 +impl Drop for TypeWithDrop {
 +    fn drop(&mut self) {}
 +}
 +
 +fn cannot_move_from_type_with_drop() -> String {
 +    let s = TypeWithDrop { x: String::new() };
 +    s.x.clone() // removing this `clone()` summons E0509
 +}
 +
 +fn borrower_propagation() {
 +    let s = String::new();
 +    let t = String::new();
 +
 +    {
 +        fn b() -> bool {
 +            unimplemented!()
 +        }
 +        let _u = if b() { &s } else { &t };
 +
 +        // ok; `s` and `t` are possibly borrowed
 +        let _s = s.clone();
 +        let _t = t.clone();
 +    }
 +
 +    {
 +        let _u = || s.len();
 +        let _v = [&t; 32];
 +        let _s = s.clone(); // ok
 +        let _t = t.clone(); // ok
 +    }
 +
 +    {
 +        let _u = {
 +            let u = Some(&s);
 +            let _ = s.clone(); // ok
 +            u
 +        };
 +        let _s = s.clone(); // ok
 +    }
 +
 +    {
 +        use std::convert::identity as id;
 +        let _u = id(id(&s));
 +        let _s = s.clone(); // ok, `u` borrows `s`
 +    }
 +
 +    let _s = s;
 +    let _t = t;
 +
 +    #[derive(Clone)]
 +    struct Foo {
 +        x: usize,
 +    }
 +
 +    {
 +        let f = Foo { x: 123 };
 +        let _x = Some(f.x);
 +        let _f = f;
 +    }
 +
 +    {
 +        let f = Foo { x: 123 };
 +        let _x = &f.x;
 +        let _f = f.clone(); // ok
 +    }
 +}
 +
 +fn not_consumed() {
 +    let x = std::path::PathBuf::from("home");
 +    let y = x.join("matthias");
 +    // join() creates a new owned PathBuf, does not take a &mut to x variable, thus the .clone() is
 +    // redundant. (It also does not consume the PathBuf)
 +
 +    println!("x: {:?}, y: {:?}", x, y);
 +
 +    let mut s = String::new();
 +    s.clone().push_str("foo"); // OK, removing this `clone()` will change the behavior.
 +    s.push_str("bar");
 +    assert_eq!(s, "bar");
 +
 +    let t = Some(s);
 +    // OK
 +    if let Some(x) = t.clone() {
 +        println!("{}", x);
 +    }
 +    if let Some(x) = t {
 +        println!("{}", x);
 +    }
 +}
 +
 +#[allow(clippy::clone_on_copy)]
 +fn issue_5405() {
 +    let a: [String; 1] = [String::from("foo")];
 +    let _b: String = a[0].clone();
 +
 +    let c: [usize; 2] = [2, 3];
 +    let _d: usize = c[1].clone();
 +}
 +
 +fn manually_drop() {
 +    use std::mem::ManuallyDrop;
 +    use std::sync::Arc;
 +
 +    let a = ManuallyDrop::new(Arc::new("Hello!".to_owned()));
 +    let _ = a.clone(); // OK
 +
 +    let p: *const String = Arc::into_raw(ManuallyDrop::into_inner(a));
 +    unsafe {
 +        Arc::from_raw(p);
 +        Arc::from_raw(p);
 +    }
 +}
 +
 +fn clone_then_move_cloned() {
 +    // issue #5973
 +    let x = Some(String::new());
 +    // ok, x is moved while the clone is in use.
 +    assert_eq!(x.clone(), None, "not equal {}", x.unwrap());
 +
 +    // issue #5595
 +    fn foo<F: Fn()>(_: &Alpha, _: F) {}
 +    let x = Alpha;
 +    // ok, data is moved while the clone is in use.
++    foo(&x, move || {
 +        let _ = x;
 +    });
 +
 +    // issue #6998
 +    struct S(String);
 +    impl S {
 +        fn m(&mut self) {}
 +    }
 +    let mut x = S(String::new());
 +    x.0.clone().chars().for_each(|_| x.m());
 +}
 +
 +fn hashmap_neg() {
 +    // issue 5707
 +    use std::collections::HashMap;
 +    use std::path::PathBuf;
 +
 +    let p = PathBuf::from("/");
 +
 +    let mut h: HashMap<&str, &str> = HashMap::new();
 +    h.insert("orig-p", p.to_str().unwrap());
 +
 +    let mut q = p.clone();
 +    q.push("foo");
 +
 +    println!("{:?} {}", h, q.display());
 +}
 +
 +fn false_negative_5707() {
 +    fn foo(_x: &Alpha, _y: &mut Alpha) {}
 +
 +    let x = Alpha;
 +    let mut y = Alpha;
 +    foo(&x, &mut y);
 +    let _z = x.clone(); // pr 7346 can't lint on `x`
 +    drop(y);
 +}
index fbc90493ae94b85986e8381ef82e395fbc202e9e,0000000000000000000000000000000000000000..9f59017b26199cad1ae2acb9fe1b96c8048ac363
mode 100644,000000..100644
--- /dev/null
@@@ -1,171 -1,0 +1,183 @@@
- error: aborting due to 14 previous errors
 +error: redundant clone
 +  --> $DIR/redundant_clone.rs:9:42
 +   |
 +LL |     let _s = ["lorem", "ipsum"].join(" ").to_string();
 +   |                                          ^^^^^^^^^^^^ help: remove this
 +   |
 +   = note: `-D clippy::redundant-clone` implied by `-D warnings`
 +note: this value is dropped without further use
 +  --> $DIR/redundant_clone.rs:9:14
 +   |
 +LL |     let _s = ["lorem", "ipsum"].join(" ").to_string();
 +   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: redundant clone
 +  --> $DIR/redundant_clone.rs:12:15
 +   |
 +LL |     let _s = s.clone();
 +   |               ^^^^^^^^ help: remove this
 +   |
 +note: this value is dropped without further use
 +  --> $DIR/redundant_clone.rs:12:14
 +   |
 +LL |     let _s = s.clone();
 +   |              ^
 +
 +error: redundant clone
 +  --> $DIR/redundant_clone.rs:15:15
 +   |
 +LL |     let _s = s.to_string();
 +   |               ^^^^^^^^^^^^ help: remove this
 +   |
 +note: this value is dropped without further use
 +  --> $DIR/redundant_clone.rs:15:14
 +   |
 +LL |     let _s = s.to_string();
 +   |              ^
 +
 +error: redundant clone
 +  --> $DIR/redundant_clone.rs:18:15
 +   |
 +LL |     let _s = s.to_owned();
 +   |               ^^^^^^^^^^^ help: remove this
 +   |
 +note: this value is dropped without further use
 +  --> $DIR/redundant_clone.rs:18:14
 +   |
 +LL |     let _s = s.to_owned();
 +   |              ^
 +
 +error: redundant clone
 +  --> $DIR/redundant_clone.rs:20:42
 +   |
 +LL |     let _s = Path::new("/a/b/").join("c").to_owned();
 +   |                                          ^^^^^^^^^^^ help: remove this
 +   |
 +note: this value is dropped without further use
 +  --> $DIR/redundant_clone.rs:20:14
 +   |
 +LL |     let _s = Path::new("/a/b/").join("c").to_owned();
 +   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: redundant clone
 +  --> $DIR/redundant_clone.rs:22:42
 +   |
 +LL |     let _s = Path::new("/a/b/").join("c").to_path_buf();
 +   |                                          ^^^^^^^^^^^^^^ help: remove this
 +   |
 +note: this value is dropped without further use
 +  --> $DIR/redundant_clone.rs:22:14
 +   |
 +LL |     let _s = Path::new("/a/b/").join("c").to_path_buf();
 +   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +error: redundant clone
 +  --> $DIR/redundant_clone.rs:24:29
 +   |
 +LL |     let _s = OsString::new().to_owned();
 +   |                             ^^^^^^^^^^^ help: remove this
 +   |
 +note: this value is dropped without further use
 +  --> $DIR/redundant_clone.rs:24:14
 +   |
 +LL |     let _s = OsString::new().to_owned();
 +   |              ^^^^^^^^^^^^^^^
 +
 +error: redundant clone
 +  --> $DIR/redundant_clone.rs:26:29
 +   |
 +LL |     let _s = OsString::new().to_os_string();
 +   |                             ^^^^^^^^^^^^^^^ help: remove this
 +   |
 +note: this value is dropped without further use
 +  --> $DIR/redundant_clone.rs:26:14
 +   |
 +LL |     let _s = OsString::new().to_os_string();
 +   |              ^^^^^^^^^^^^^^^
 +
 +error: redundant clone
 +  --> $DIR/redundant_clone.rs:33:19
 +   |
 +LL |     let _t = tup.0.clone();
 +   |                   ^^^^^^^^ help: remove this
 +   |
 +note: this value is dropped without further use
 +  --> $DIR/redundant_clone.rs:33:14
 +   |
 +LL |     let _t = tup.0.clone();
 +   |              ^^^^^
 +
 +error: redundant clone
 +  --> $DIR/redundant_clone.rs:65:25
 +   |
 +LL |     if b { (a.clone(), a.clone()) } else { (Alpha, a) }
 +   |                         ^^^^^^^^ help: remove this
 +   |
 +note: this value is dropped without further use
 +  --> $DIR/redundant_clone.rs:65:24
 +   |
 +LL |     if b { (a.clone(), a.clone()) } else { (Alpha, a) }
 +   |                        ^
 +
 +error: redundant clone
 +  --> $DIR/redundant_clone.rs:122:15
 +   |
 +LL |     let _s = s.clone();
 +   |               ^^^^^^^^ help: remove this
 +   |
 +note: this value is dropped without further use
 +  --> $DIR/redundant_clone.rs:122:14
 +   |
 +LL |     let _s = s.clone();
 +   |              ^
 +
 +error: redundant clone
 +  --> $DIR/redundant_clone.rs:123:15
 +   |
 +LL |     let _t = t.clone();
 +   |               ^^^^^^^^ help: remove this
 +   |
 +note: this value is dropped without further use
 +  --> $DIR/redundant_clone.rs:123:14
 +   |
 +LL |     let _t = t.clone();
 +   |              ^
 +
 +error: redundant clone
 +  --> $DIR/redundant_clone.rs:133:19
 +   |
 +LL |         let _f = f.clone();
 +   |                   ^^^^^^^^ help: remove this
 +   |
 +note: this value is dropped without further use
 +  --> $DIR/redundant_clone.rs:133:18
 +   |
 +LL |         let _f = f.clone();
 +   |                  ^
 +
 +error: redundant clone
 +  --> $DIR/redundant_clone.rs:145:14
 +   |
 +LL |     let y = x.clone().join("matthias");
 +   |              ^^^^^^^^ help: remove this
 +   |
 +note: cloned value is neither consumed nor mutated
 +  --> $DIR/redundant_clone.rs:145:13
 +   |
 +LL |     let y = x.clone().join("matthias");
 +   |             ^^^^^^^^^
 +
++error: redundant clone
++  --> $DIR/redundant_clone.rs:199:11
++   |
++LL |     foo(&x.clone(), move || {
++   |           ^^^^^^^^ help: remove this
++   |
++note: this value is dropped without further use
++  --> $DIR/redundant_clone.rs:199:10
++   |
++LL |     foo(&x.clone(), move || {
++   |          ^
++
++error: aborting due to 15 previous errors
 +
index cd6db8ddc8864fd2a08de85ed9de26c8c31fd553,0000000000000000000000000000000000000000..fe742a4c2f4c5acd69d1300242eb59bb0de67aa2
mode 100644,000000..100644
--- /dev/null
@@@ -1,76 -1,0 +1,75 @@@
- // edition:2018
 +// FIXME: run-rustfix waiting on multi-span suggestions
 +
 +#![warn(clippy::ref_binding_to_reference)]
 +#![allow(clippy::needless_borrowed_reference)]
 +
 +fn f1(_: &str) {}
 +macro_rules! m2 {
 +    ($e:expr) => {
 +        f1(*$e)
 +    };
 +}
 +macro_rules! m3 {
 +    ($i:ident) => {
 +        Some(ref $i)
 +    };
 +}
 +
 +#[allow(dead_code)]
 +fn main() {
 +    let x = String::new();
 +
 +    // Ok, the pattern is from a macro
 +    let _: &&String = match Some(&x) {
 +        m3!(x) => x,
 +        None => return,
 +    };
 +
 +    // Err, reference to a &String
 +    let _: &&String = match Some(&x) {
 +        Some(ref x) => x,
 +        None => return,
 +    };
 +
 +    // Err, reference to a &String
 +    let _: &&String = match Some(&x) {
 +        Some(ref x) => {
 +            f1(x);
 +            f1(*x);
 +            x
 +        },
 +        None => return,
 +    };
 +
 +    // Err, reference to a &String
 +    match Some(&x) {
 +        Some(ref x) => m2!(x),
 +        None => return,
 +    }
 +
 +    // Err, reference to a &String
 +    let _ = |&ref x: &&String| {
 +        let _: &&String = x;
 +    };
 +}
 +
 +// Err, reference to a &String
 +fn f2<'a>(&ref x: &&'a String) -> &'a String {
 +    let _: &&String = x;
 +    *x
 +}
 +
 +trait T1 {
 +    // Err, reference to a &String
 +    fn f(&ref x: &&String) {
 +        let _: &&String = x;
 +    }
 +}
 +
 +struct S;
 +impl T1 for S {
 +    // Err, reference to a &String
 +    fn f(&ref x: &&String) {
 +        let _: &&String = x;
 +    }
 +}
index eb36cd516a246a9e4f581b7079efb0bacc8cc09d,0000000000000000000000000000000000000000..c5856e15fa987b3a4c19737019941430373606ce
mode 100644,000000..100644
--- /dev/null
@@@ -1,88 -1,0 +1,88 @@@
-   --> $DIR/ref_binding_to_reference.rs:31:14
 +error: this pattern creates a reference to a reference
-   --> $DIR/ref_binding_to_reference.rs:37:14
++  --> $DIR/ref_binding_to_reference.rs:30:14
 +   |
 +LL |         Some(ref x) => x,
 +   |              ^^^^^
 +   |
 +   = note: `-D clippy::ref-binding-to-reference` implied by `-D warnings`
 +help: try this
 +   |
 +LL |         Some(x) => &x,
 +   |              ~     ~~
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/ref_binding_to_reference.rs:47:14
++  --> $DIR/ref_binding_to_reference.rs:36:14
 +   |
 +LL |         Some(ref x) => {
 +   |              ^^^^^
 +   |
 +help: try this
 +   |
 +LL ~         Some(x) => {
 +LL |             f1(x);
 +LL ~             f1(x);
 +LL ~             &x
 +   |
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/ref_binding_to_reference.rs:52:15
++  --> $DIR/ref_binding_to_reference.rs:46:14
 +   |
 +LL |         Some(ref x) => m2!(x),
 +   |              ^^^^^
 +   |
 +help: try this
 +   |
 +LL |         Some(x) => m2!(&x),
 +   |              ~         ~~
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/ref_binding_to_reference.rs:58:12
++  --> $DIR/ref_binding_to_reference.rs:51:15
 +   |
 +LL |     let _ = |&ref x: &&String| {
 +   |               ^^^^^
 +   |
 +help: try this
 +   |
 +LL ~     let _ = |&x: &&String| {
 +LL ~         let _: &&String = &x;
 +   |
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/ref_binding_to_reference.rs:65:11
++  --> $DIR/ref_binding_to_reference.rs:57:12
 +   |
 +LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
 +   |            ^^^^^
 +   |
 +help: try this
 +   |
 +LL ~ fn f2<'a>(&x: &&'a String) -> &'a String {
 +LL ~     let _: &&String = &x;
 +LL ~     x
 +   |
 +
 +error: this pattern creates a reference to a reference
-   --> $DIR/ref_binding_to_reference.rs:73:11
++  --> $DIR/ref_binding_to_reference.rs:64:11
 +   |
 +LL |     fn f(&ref x: &&String) {
 +   |           ^^^^^
 +   |
 +help: try this
 +   |
 +LL ~     fn f(&x: &&String) {
 +LL ~         let _: &&String = &x;
 +   |
 +
 +error: this pattern creates a reference to a reference
++  --> $DIR/ref_binding_to_reference.rs:72:11
 +   |
 +LL |     fn f(&ref x: &&String) {
 +   |           ^^^^^
 +   |
 +help: try this
 +   |
 +LL ~     fn f(&x: &&String) {
 +LL ~         let _: &&String = &x;
 +   |
 +
 +error: aborting due to 7 previous errors
 +
index a66c2e587c8736111e067f1b2dd8a41d583840a5,0000000000000000000000000000000000000000..cc295b509bc51973cd1bf3f03d591bee3bc732e3
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,63 @@@
- #[warn(clippy::module_name_repetitions)]
 +//! Test for Clippy lint renames.
 +// run-rustfix
 +
 +#![allow(dead_code)]
 +// allow the new lint name here, to test if the new name works
 +#![allow(clippy::module_name_repetitions)]
 +#![allow(clippy::new_without_default)]
 +#![allow(clippy::redundant_static_lifetimes)]
++#![allow(clippy::bind_instead_of_map)]
++#![allow(clippy::box_collection)]
++#![allow(clippy::blocks_in_if_conditions)]
++#![allow(clippy::map_unwrap_or)]
++#![allow(clippy::unwrap_used)]
++#![allow(clippy::expect_used)]
++#![allow(clippy::for_loops_over_fallibles)]
++#![allow(clippy::useless_conversion)]
++#![allow(clippy::invisible_characters)]
++#![allow(clippy::single_char_add_str)]
++#![allow(clippy::match_result_ok)]
++// uplifted lints
++#![allow(invalid_value)]
++#![allow(array_into_iter)]
++#![allow(unused_labels)]
++#![allow(drop_bounds)]
++#![allow(temporary_cstring_as_ptr)]
++#![allow(non_fmt_panics)]
++#![allow(unknown_lints)]
++#![allow(invalid_atomic_ordering)]
++#![allow(enum_intrinsics_non_enums)]
 +// warn for the old lint name here, to test if the renaming worked
++#![warn(clippy::module_name_repetitions)]
++#![warn(clippy::new_without_default)]
++#![warn(clippy::redundant_static_lifetimes)]
 +#![warn(clippy::cognitive_complexity)]
++#![warn(clippy::bind_instead_of_map)]
++#![warn(clippy::box_collection)]
++#![warn(clippy::blocks_in_if_conditions)]
++#![warn(clippy::blocks_in_if_conditions)]
++#![warn(clippy::map_unwrap_or)]
++#![warn(clippy::map_unwrap_or)]
++#![warn(clippy::map_unwrap_or)]
++#![warn(clippy::unwrap_used)]
++#![warn(clippy::unwrap_used)]
++#![warn(clippy::expect_used)]
++#![warn(clippy::expect_used)]
++#![warn(clippy::for_loops_over_fallibles)]
++#![warn(clippy::for_loops_over_fallibles)]
++#![warn(clippy::useless_conversion)]
++#![warn(clippy::invisible_characters)]
++#![warn(clippy::single_char_add_str)]
++#![warn(clippy::match_result_ok)]
++// uplifted lints
++#![warn(invalid_value)]
++#![warn(array_into_iter)]
++#![warn(unused_labels)]
++#![warn(drop_bounds)]
++#![warn(temporary_cstring_as_ptr)]
++#![warn(non_fmt_panics)]
++#![warn(unknown_lints)]
++#![warn(invalid_atomic_ordering)]
 +#![warn(enum_intrinsics_non_enums)]
 +
- #[warn(clippy::new_without_default)]
- struct Foo;
- #[warn(clippy::redundant_static_lifetimes)]
- fn foo() {}
 +fn main() {}
index fa81201a2daf305fd675ddf65668882cdb842419,0000000000000000000000000000000000000000..377075c02464a85becebae4817f176745f490ea0
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,63 @@@
- #[warn(clippy::stutter)]
 +//! Test for Clippy lint renames.
 +// run-rustfix
 +
 +#![allow(dead_code)]
 +// allow the new lint name here, to test if the new name works
 +#![allow(clippy::module_name_repetitions)]
 +#![allow(clippy::new_without_default)]
 +#![allow(clippy::redundant_static_lifetimes)]
++#![allow(clippy::bind_instead_of_map)]
++#![allow(clippy::box_collection)]
++#![allow(clippy::blocks_in_if_conditions)]
++#![allow(clippy::map_unwrap_or)]
++#![allow(clippy::unwrap_used)]
++#![allow(clippy::expect_used)]
++#![allow(clippy::for_loops_over_fallibles)]
++#![allow(clippy::useless_conversion)]
++#![allow(clippy::invisible_characters)]
++#![allow(clippy::single_char_add_str)]
++#![allow(clippy::match_result_ok)]
++// uplifted lints
++#![allow(invalid_value)]
++#![allow(array_into_iter)]
++#![allow(unused_labels)]
++#![allow(drop_bounds)]
++#![allow(temporary_cstring_as_ptr)]
++#![allow(non_fmt_panics)]
++#![allow(unknown_lints)]
++#![allow(invalid_atomic_ordering)]
++#![allow(enum_intrinsics_non_enums)]
 +// warn for the old lint name here, to test if the renaming worked
++#![warn(clippy::stutter)]
++#![warn(clippy::new_without_default_derive)]
++#![warn(clippy::const_static_lifetime)]
 +#![warn(clippy::cyclomatic_complexity)]
++#![warn(clippy::option_and_then_some)]
++#![warn(clippy::box_vec)]
++#![warn(clippy::block_in_if_condition_expr)]
++#![warn(clippy::block_in_if_condition_stmt)]
++#![warn(clippy::option_map_unwrap_or)]
++#![warn(clippy::option_map_unwrap_or_else)]
++#![warn(clippy::result_map_unwrap_or_else)]
++#![warn(clippy::option_unwrap_used)]
++#![warn(clippy::result_unwrap_used)]
++#![warn(clippy::option_expect_used)]
++#![warn(clippy::result_expect_used)]
++#![warn(clippy::for_loop_over_option)]
++#![warn(clippy::for_loop_over_result)]
++#![warn(clippy::identity_conversion)]
++#![warn(clippy::zero_width_space)]
++#![warn(clippy::single_char_push_str)]
++#![warn(clippy::if_let_some_result)]
++// uplifted lints
++#![warn(clippy::invalid_ref)]
++#![warn(clippy::into_iter_on_array)]
++#![warn(clippy::unused_label)]
++#![warn(clippy::drop_bounds)]
++#![warn(clippy::temporary_cstring_as_ptr)]
++#![warn(clippy::panic_params)]
++#![warn(clippy::unknown_clippy_lints)]
++#![warn(clippy::invalid_atomic_ordering)]
 +#![warn(clippy::mem_discriminant_non_enum)]
 +
- #[warn(clippy::new_without_default_derive)]
- struct Foo;
- #[warn(clippy::const_static_lifetime)]
- fn foo() {}
 +fn main() {}
index 05c7854074c60cd3ba9291173c7c70421cf17ccf,0000000000000000000000000000000000000000..d720f10d117c097ad2df27ae1ac45e9b63e971ee
mode 100644,000000..100644
--- /dev/null
@@@ -1,34 -1,0 +1,184 @@@
-   --> $DIR/rename.rs:10:9
++error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
++  --> $DIR/rename.rs:31:9
++   |
++LL | #![warn(clippy::stutter)]
++   |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
++   |
++   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
++
++error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
++  --> $DIR/rename.rs:32:9
++   |
++LL | #![warn(clippy::new_without_default_derive)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
++
++error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
++  --> $DIR/rename.rs:33:9
++   |
++LL | #![warn(clippy::const_static_lifetime)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
++
 +error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
++  --> $DIR/rename.rs:34:9
 +   |
 +LL | #![warn(clippy::cyclomatic_complexity)]
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
++
++error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
++  --> $DIR/rename.rs:35:9
 +   |
- error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-   --> $DIR/rename.rs:11:9
++LL | #![warn(clippy::option_and_then_some)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 +
- LL | #![warn(clippy::mem_discriminant_non_enum)]
-    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
++error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
++  --> $DIR/rename.rs:36:9
 +   |
- error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-   --> $DIR/rename.rs:13:8
++LL | #![warn(clippy::box_vec)]
++   |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 +
- LL | #[warn(clippy::stutter)]
-    |        ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
++error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
++  --> $DIR/rename.rs:37:9
 +   |
- error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-   --> $DIR/rename.rs:16:8
++LL | #![warn(clippy::block_in_if_condition_expr)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 +
- LL | #[warn(clippy::new_without_default_derive)]
-    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
++error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
++  --> $DIR/rename.rs:38:9
 +   |
- error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-   --> $DIR/rename.rs:19:8
++LL | #![warn(clippy::block_in_if_condition_stmt)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 +
- LL | #[warn(clippy::const_static_lifetime)]
-    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
++error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
++  --> $DIR/rename.rs:39:9
++   |
++LL | #![warn(clippy::option_map_unwrap_or)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
++
++error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
++  --> $DIR/rename.rs:40:9
++   |
++LL | #![warn(clippy::option_map_unwrap_or_else)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
++
++error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
++  --> $DIR/rename.rs:41:9
++   |
++LL | #![warn(clippy::result_map_unwrap_or_else)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
++
++error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
++  --> $DIR/rename.rs:42:9
++   |
++LL | #![warn(clippy::option_unwrap_used)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
++
++error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
++  --> $DIR/rename.rs:43:9
++   |
++LL | #![warn(clippy::result_unwrap_used)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
++
++error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
++  --> $DIR/rename.rs:44:9
++   |
++LL | #![warn(clippy::option_expect_used)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
++
++error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
++  --> $DIR/rename.rs:45:9
++   |
++LL | #![warn(clippy::result_expect_used)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
++
++error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
++  --> $DIR/rename.rs:46:9
++   |
++LL | #![warn(clippy::for_loop_over_option)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
++
++error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
++  --> $DIR/rename.rs:47:9
++   |
++LL | #![warn(clippy::for_loop_over_result)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
++
++error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
++  --> $DIR/rename.rs:48:9
++   |
++LL | #![warn(clippy::identity_conversion)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
++
++error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
++  --> $DIR/rename.rs:49:9
++   |
++LL | #![warn(clippy::zero_width_space)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
++
++error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
++  --> $DIR/rename.rs:50:9
++   |
++LL | #![warn(clippy::single_char_push_str)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
++
++error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
++  --> $DIR/rename.rs:51:9
++   |
++LL | #![warn(clippy::if_let_some_result)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
++
++error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
++  --> $DIR/rename.rs:53:9
++   |
++LL | #![warn(clippy::invalid_ref)]
++   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
++
++error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
++  --> $DIR/rename.rs:54:9
++   |
++LL | #![warn(clippy::into_iter_on_array)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
++
++error: lint `clippy::unused_label` has been renamed to `unused_labels`
++  --> $DIR/rename.rs:55:9
++   |
++LL | #![warn(clippy::unused_label)]
++   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
++
++error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
++  --> $DIR/rename.rs:56:9
++   |
++LL | #![warn(clippy::drop_bounds)]
++   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
++
++error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
++  --> $DIR/rename.rs:57:9
++   |
++LL | #![warn(clippy::temporary_cstring_as_ptr)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
++
++error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
++  --> $DIR/rename.rs:58:9
++   |
++LL | #![warn(clippy::panic_params)]
++   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
++
++error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
++  --> $DIR/rename.rs:59:9
++   |
++LL | #![warn(clippy::unknown_clippy_lints)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
++
++error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
++  --> $DIR/rename.rs:60:9
++   |
++LL | #![warn(clippy::invalid_atomic_ordering)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
++
++error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
++  --> $DIR/rename.rs:61:9
 +   |
- error: aborting due to 5 previous errors
++LL | #![warn(clippy::mem_discriminant_non_enum)]
++   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 +
++error: aborting due to 30 previous errors
 +
index a7f8f54f2be04cb98667127b87d3db75c50e1301,0000000000000000000000000000000000000000..d7e8d02bd1998fbab6b24867d1ec325556a6e72f
mode 100644,000000..100644
--- /dev/null
@@@ -1,84 -1,0 +1,82 @@@
- // 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 69a3390b03b0b2cac0988e1f35dc1796e0bcd41d,0000000000000000000000000000000000000000..ea962f943173aed4359f392e9ee99de13e9b8ec4
mode 100644,000000..100644
--- /dev/null
@@@ -1,88 -1,0 +1,86 @@@
- // 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 86c63946516ce84453725eff5a31b58cb1ac246c,0000000000000000000000000000000000000000..bf8b47d5626d283095c5df5db7ed86cccc2ffb40
mode 100644,000000..100644
--- /dev/null
@@@ -1,143 -1,0 +1,143 @@@
-   --> $DIR/method_list_1.rs:26:5
 +error: method `add` can be confused for the standard trait method `std::ops::Add::add`
-   --> $DIR/method_list_1.rs:30:5
++  --> $DIR/method_list_1.rs:24: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:34:5
++  --> $DIR/method_list_1.rs:28: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:38:5
++  --> $DIR/method_list_1.rs:32: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:42:5
++  --> $DIR/method_list_1.rs:36: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:46:5
++  --> $DIR/method_list_1.rs:40: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:50:5
++  --> $DIR/method_list_1.rs:44: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:54:5
++  --> $DIR/method_list_1.rs:48: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:58:5
++  --> $DIR/method_list_1.rs:52: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:62:5
++  --> $DIR/method_list_1.rs:56: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:70:5
++  --> $DIR/method_list_1.rs:60: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:74:5
++  --> $DIR/method_list_1.rs:68: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:78:5
++  --> $DIR/method_list_1.rs:72: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:82:5
++  --> $DIR/method_list_1.rs:76: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:80: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 2cdc1a06fe689dab34e495eee9466253e7836c8d,0000000000000000000000000000000000000000..b663568806d218dd9e8ac3bb6d2206acad140550
mode 100644,000000..100644
--- /dev/null
@@@ -1,89 -1,0 +1,87 @@@
- // edition:2018
 +#![warn(clippy::all, clippy::pedantic)]
 +#![allow(
 +    clippy::missing_errors_doc,
 +    clippy::needless_pass_by_value,
 +    clippy::must_use_candidate,
 +    clippy::unused_self,
 +    clippy::needless_lifetimes,
 +    clippy::missing_safety_doc,
 +    clippy::wrong_self_convention,
 +    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 0142e2991081c79ae4099788ea6c85ed02535428,0000000000000000000000000000000000000000..426fe3b1adc9de12e9ba88e9f51a034407d6d007
mode 100644,000000..100644
--- /dev/null
@@@ -1,153 -1,0 +1,153 @@@
-   --> $DIR/method_list_2.rs:27:5
 +error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq`
-   --> $DIR/method_list_2.rs:31:5
++  --> $DIR/method_list_2.rs:25: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:35:5
++  --> $DIR/method_list_2.rs:29: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:39:5
++  --> $DIR/method_list_2.rs:33: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:43:5
++  --> $DIR/method_list_2.rs:37: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:47:5
++  --> $DIR/method_list_2.rs:41: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:51:5
++  --> $DIR/method_list_2.rs:45: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:55:5
++  --> $DIR/method_list_2.rs:49: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:59:5
++  --> $DIR/method_list_2.rs:53: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:63:5
++  --> $DIR/method_list_2.rs:57: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:67:5
++  --> $DIR/method_list_2.rs:61: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:71:5
++  --> $DIR/method_list_2.rs:65: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:75:5
++  --> $DIR/method_list_2.rs:69: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:79:5
++  --> $DIR/method_list_2.rs:73: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:83:5
++  --> $DIR/method_list_2.rs:77: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:81:5
 +   |
 +LL | /     pub fn sub(self, rhs: Self) -> Self {
 +LL | |         unimplemented!()
 +LL | |     }
 +   | |_____^
 +   |
 +   = help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name
 +
 +error: aborting due to 15 previous errors
 +
index f66b445b7b6a35249600338185df6d6bb7774bb6,0000000000000000000000000000000000000000..4c40739d6f553874865157ad7c9cb06a1051ea0a
mode 100644,000000..100644
--- /dev/null
@@@ -1,34 -1,0 +1,33 @@@
- // edition:2018
 +// run-rustfix
 +#![warn(clippy::single_component_path_imports)]
 +#![allow(unused_imports)]
 +
 +
 +use serde as edres;
 +pub use serde;
 +
 +macro_rules! m {
 +    () => {
 +        use regex;
 +    };
 +}
 +
 +fn main() {
 +    regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
 +
 +    // False positive #5154, shouldn't trigger lint.
 +    m!();
 +}
 +
 +mod hello_mod {
 +    
 +    #[allow(dead_code)]
 +    fn hello_mod() {}
 +}
 +
 +mod hi_mod {
 +    use self::regex::{Regex, RegexSet};
 +    use regex;
 +    #[allow(dead_code)]
 +    fn hi_mod() {}
 +}
index 09d4865859584ed792063e9e6bb510a1b679c012,0000000000000000000000000000000000000000..9280bab3c71b5cae19b6d4f7e57b47bb7a5a478f
mode 100644,000000..100644
--- /dev/null
@@@ -1,34 -1,0 +1,33 @@@
- // edition:2018
 +// run-rustfix
 +#![warn(clippy::single_component_path_imports)]
 +#![allow(unused_imports)]
 +
 +use regex;
 +use serde as edres;
 +pub use serde;
 +
 +macro_rules! m {
 +    () => {
 +        use regex;
 +    };
 +}
 +
 +fn main() {
 +    regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
 +
 +    // False positive #5154, shouldn't trigger lint.
 +    m!();
 +}
 +
 +mod hello_mod {
 +    use regex;
 +    #[allow(dead_code)]
 +    fn hello_mod() {}
 +}
 +
 +mod hi_mod {
 +    use self::regex::{Regex, RegexSet};
 +    use regex;
 +    #[allow(dead_code)]
 +    fn hi_mod() {}
 +}
index 7005fa8f125d36255c12bf6c8b93cf6644f64eba,0000000000000000000000000000000000000000..509c88ac256a8c0dc99ecdbcac0a8dd6fe97529f
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,16 @@@
-   --> $DIR/single_component_path_imports.rs:24:5
 +error: this import is redundant
-   --> $DIR/single_component_path_imports.rs:6:1
++  --> $DIR/single_component_path_imports.rs:23:5
 +   |
 +LL |     use regex;
 +   |     ^^^^^^^^^^ help: remove it entirely
 +   |
 +   = note: `-D clippy::single-component-path-imports` implied by `-D warnings`
 +
 +error: this import is redundant
++  --> $DIR/single_component_path_imports.rs:5:1
 +   |
 +LL | use regex;
 +   | ^^^^^^^^^^ help: remove it entirely
 +
 +error: aborting due to 2 previous errors
 +
index 05863f9a2bf488c06722209622ceae63cce12de7,0000000000000000000000000000000000000000..e43f5d381aaa1087a928a49d86529693a74fdba9
mode 100644,000000..100644
--- /dev/null
@@@ -1,21 -1,0 +1,20 @@@
- // edition:2018
 +// run-rustfix
 +#![warn(clippy::single_component_path_imports)]
 +#![allow(unused_imports)]
 +
 +// #7106: use statements exporting a macro within a crate should not trigger lint
 +
 +macro_rules! m1 {
 +    () => {};
 +}
 +pub(crate) use m1; // ok
 +
 +macro_rules! m2 {
 +    () => {};
 +}
 + // fail
 +
 +fn main() {
 +    m1!();
 +    m2!();
 +}
index 633deea348b81d415778fc372cae9a720c5c5ffc,0000000000000000000000000000000000000000..3c65ca3054c6919eb859317608a43151ea71eb5c
mode 100644,000000..100644
--- /dev/null
@@@ -1,21 -1,0 +1,20 @@@
- // edition:2018
 +// run-rustfix
 +#![warn(clippy::single_component_path_imports)]
 +#![allow(unused_imports)]
 +
 +// #7106: use statements exporting a macro within a crate should not trigger lint
 +
 +macro_rules! m1 {
 +    () => {};
 +}
 +pub(crate) use m1; // ok
 +
 +macro_rules! m2 {
 +    () => {};
 +}
 +use m2; // fail
 +
 +fn main() {
 +    m1!();
 +    m2!();
 +}
index 239efb393b1ab4ac058a959ebe323044cad662f1,0000000000000000000000000000000000000000..37d5176129ff30a2d06733b35c2b2c9b5404574f
mode 100644,000000..100644
--- /dev/null
@@@ -1,10 -1,0 +1,10 @@@
-   --> $DIR/single_component_path_imports_macro.rs:16:1
 +error: this import is redundant
++  --> $DIR/single_component_path_imports_macro.rs:15:1
 +   |
 +LL | use m2; // fail
 +   | ^^^^^^^ help: remove it entirely
 +   |
 +   = note: `-D clippy::single-component-path-imports` implied by `-D warnings`
 +
 +error: aborting due to previous error
 +
index 94117061b270da718a68172b91b920c1c18c434b,0000000000000000000000000000000000000000..c75beb747861882c0a158a46a92b67ca5af5af6e
mode 100644,000000..100644
--- /dev/null
@@@ -1,17 -1,0 +1,16 @@@
- // edition:2018
 +#![warn(clippy::single_component_path_imports)]
 +#![allow(unused_imports)]
 +
 +use regex;
 +use serde as edres;
 +pub use serde;
 +
 +fn main() {
 +    regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
 +}
 +
 +mod root_nested_use_mod {
 +    use {regex, serde};
 +    #[allow(dead_code)]
 +    fn root_nested_use_mod() {}
 +}
index 0c3256c1ce43a71ea37159b4a65991603e493a59,0000000000000000000000000000000000000000..cf990be1b9ff1cea7a0efe5c9509652b1a1ec271
mode 100644,000000..100644
--- /dev/null
@@@ -1,25 -1,0 +1,25 @@@
-   --> $DIR/single_component_path_imports_nested_first.rs:14:10
 +error: this import is redundant
-   --> $DIR/single_component_path_imports_nested_first.rs:14:17
++  --> $DIR/single_component_path_imports_nested_first.rs:13:10
 +   |
 +LL |     use {regex, serde};
 +   |          ^^^^^
 +   |
 +   = note: `-D clippy::single-component-path-imports` implied by `-D warnings`
 +   = help: remove this import
 +
 +error: this import is redundant
-   --> $DIR/single_component_path_imports_nested_first.rs:5:1
++  --> $DIR/single_component_path_imports_nested_first.rs:13:17
 +   |
 +LL |     use {regex, serde};
 +   |                 ^^^^^
 +   |
 +   = help: remove this import
 +
 +error: this import is redundant
++  --> $DIR/single_component_path_imports_nested_first.rs:4:1
 +   |
 +LL | use regex;
 +   | ^^^^^^^^^^ help: remove it entirely
 +
 +error: aborting due to 3 previous errors
 +
index 94319ade0ac4b9672ad2064bab6844db2e634887,0000000000000000000000000000000000000000..48e8e530261bea39d8b1586d2f60cde8233ee65a
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,15 @@@
- // edition:2018
 +#![warn(clippy::single_component_path_imports)]
 +#![allow(unused_imports)]
 +
 +use self::regex::{Regex as xeger, RegexSet as tesxeger};
 +pub use self::{
 +    regex::{Regex, RegexSet},
 +    some_mod::SomeType,
 +};
 +use regex;
 +
 +mod some_mod {
 +    pub struct SomeType;
 +}
 +
 +fn main() {}
index c7437b234566a95f08dd4794f7cecc2af1430adf,0000000000000000000000000000000000000000..4fb0cf40b6e00d40bb2c0345a28457af33695442
mode 100644,000000..100644
--- /dev/null
@@@ -1,17 -1,0 +1,16 @@@
- // edition:2018
 +#![warn(clippy::single_component_path_imports)]
 +#![allow(unused_imports)]
 +
 +use regex;
 +
 +use self::regex::{Regex as xeger, RegexSet as tesxeger};
 +pub use self::{
 +    regex::{Regex, RegexSet},
 +    some_mod::SomeType,
 +};
 +
 +mod some_mod {
 +    pub struct SomeType;
 +}
 +
 +fn main() {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..be4dfc8816c7f178091a88305c3fa162ee261a78
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,10 @@@
++#[warn(clippy::string_slice)]
++#[allow(clippy::no_effect)]
++
++fn main() {
++    &"Ölkanne"[1..];
++    let m = "Mötörhead";
++    &m[2..5];
++    let s = String::from(m);
++    &s[0..2];
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..55040bf5df2de6d3689f825132ee06e3798dcf3f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++error: indexing into a string may panic if the index is within a UTF-8 character
++  --> $DIR/string_slice.rs:5:6
++   |
++LL |     &"Ölkanne"[1..];
++   |      ^^^^^^^^^^^^^^
++   |
++   = note: `-D clippy::string-slice` implied by `-D warnings`
++
++error: indexing into a string may panic if the index is within a UTF-8 character
++  --> $DIR/string_slice.rs:7:6
++   |
++LL |     &m[2..5];
++   |      ^^^^^^^
++
++error: indexing into a string may panic if the index is within a UTF-8 character
++  --> $DIR/string_slice.rs:9:6
++   |
++LL |     &s[0..2];
++   |      ^^^^^^^
++
++error: aborting due to 3 previous errors
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..989916c239bad090ad71a54dcb6109220da07b3f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,27 @@@
++#![warn(clippy::unit_hash)]
++
++use std::collections::hash_map::DefaultHasher;
++use std::hash::Hash;
++
++enum Foo {
++    Empty,
++    WithValue(u8),
++}
++
++fn do_nothing() {}
++
++fn main() {
++    let mut state = DefaultHasher::new();
++    let my_enum = Foo::Empty;
++
++    match my_enum {
++        Foo::Empty => ().hash(&mut state),
++        Foo::WithValue(x) => x.hash(&mut state),
++    }
++
++    let res = ();
++    res.hash(&mut state);
++
++    #[allow(clippy::unit_arg)]
++    do_nothing().hash(&mut state);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..da276296e0282507b446f629bb5ff051c2f2086f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,27 @@@
++error: this call to `hash` on the unit type will do nothing
++  --> $DIR/unit_hash.rs:18:23
++   |
++LL |         Foo::Empty => ().hash(&mut state),
++   |                       ^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)`
++   |
++   = note: `-D clippy::unit-hash` implied by `-D warnings`
++   = note: the implementation of `Hash` for `()` is a no-op
++
++error: this call to `hash` on the unit type will do nothing
++  --> $DIR/unit_hash.rs:23:5
++   |
++LL |     res.hash(&mut state);
++   |     ^^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)`
++   |
++   = note: the implementation of `Hash` for `()` is a no-op
++
++error: this call to `hash` on the unit type will do nothing
++  --> $DIR/unit_hash.rs:26:5
++   |
++LL |     do_nothing().hash(&mut state);
++   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)`
++   |
++   = note: the implementation of `Hash` for `()` is a no-op
++
++error: aborting due to 3 previous errors
++
index 4f4203f5fdbf67fd59049f85769d322ae2ff73ba,0000000000000000000000000000000000000000..2a3a506a57b1437310918767ad1fa55ab0987052
mode 100644,000000..100644
--- /dev/null
@@@ -1,15 -1,0 +1,14 @@@
- // edition:2018
 +#![warn(clippy::unused_async)]
 +
 +async fn foo() -> i32 {
 +    4
 +}
 +
 +async fn bar() -> i32 {
 +    foo().await
 +}
 +
 +fn main() {
 +    foo();
 +    bar();
 +}
index 8b834d205b176970c8911b5f371c1282de83feb1,0000000000000000000000000000000000000000..cc6096d65d9f351a016e0fcd7423ac12405ba587
mode 100644,000000..100644
--- /dev/null
@@@ -1,13 -1,0 +1,13 @@@
-   --> $DIR/unused_async.rs:4:1
 +error: unused `async` for function with no await statements
++  --> $DIR/unused_async.rs:3:1
 +   |
 +LL | / async fn foo() -> i32 {
 +LL | |     4
 +LL | | }
 +   | |_^
 +   |
 +   = note: `-D clippy::unused-async` implied by `-D warnings`
 +   = help: consider removing the `async` from this function
 +
 +error: aborting due to previous error
 +
index dcf818f80763052c6d4fae4d6e282b0b67c438c2,0000000000000000000000000000000000000000..4e33e343ce0e9c414b42abf6d5e73d6b488392c6
mode 100644,000000..100644
--- /dev/null
@@@ -1,522 -1,0 +1,521 @@@
- // edition:2018
 +// run-rustfix
 +// aux-build:proc_macro_derive.rs
 +
 +#![warn(clippy::use_self)]
 +#![allow(dead_code)]
 +#![allow(
 +    clippy::should_implement_trait,
 +    clippy::upper_case_acronyms,
 +    clippy::from_over_into,
 +    clippy::self_named_constructors
 +)]
 +
 +#[macro_use]
 +extern crate proc_macro_derive;
 +
 +fn main() {}
 +
 +mod use_self {
 +    struct Foo {}
 +
 +    impl Foo {
 +        fn new() -> Self {
 +            Self {}
 +        }
 +        fn test() -> Self {
 +            Self::new()
 +        }
 +    }
 +
 +    impl Default for Foo {
 +        fn default() -> Self {
 +            Self::new()
 +        }
 +    }
 +}
 +
 +mod better {
 +    struct Foo {}
 +
 +    impl Foo {
 +        fn new() -> Self {
 +            Self {}
 +        }
 +        fn test() -> Self {
 +            Self::new()
 +        }
 +    }
 +
 +    impl Default for Foo {
 +        fn default() -> Self {
 +            Self::new()
 +        }
 +    }
 +}
 +
 +mod lifetimes {
 +    struct Foo<'a> {
 +        foo_str: &'a str,
 +    }
 +
 +    impl<'a> Foo<'a> {
 +        // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
 +        // Foo<'b>`
 +        fn foo(s: &str) -> Foo {
 +            Foo { foo_str: s }
 +        }
 +        // cannot replace with `Self`, because that's `Foo<'a>`
 +        fn bar() -> Foo<'static> {
 +            Foo { foo_str: "foo" }
 +        }
 +
 +        // FIXME: the lint does not handle lifetimed struct
 +        // `Self` should be applicable here
 +        fn clone(&self) -> Foo<'a> {
 +            Foo { foo_str: self.foo_str }
 +        }
 +    }
 +}
 +
 +mod issue2894 {
 +    trait IntoBytes {
 +        fn to_bytes(self) -> Vec<u8>;
 +    }
 +
 +    // This should not be linted
 +    impl IntoBytes for u8 {
 +        fn to_bytes(self) -> Vec<u8> {
 +            vec![self]
 +        }
 +    }
 +}
 +
 +mod existential {
 +    struct Foo;
 +
 +    impl Foo {
 +        fn bad(foos: &[Self]) -> impl Iterator<Item = &Self> {
 +            foos.iter()
 +        }
 +
 +        fn good(foos: &[Self]) -> impl Iterator<Item = &Self> {
 +            foos.iter()
 +        }
 +    }
 +}
 +
 +mod tuple_structs {
 +    pub struct TS(i32);
 +
 +    impl TS {
 +        pub fn ts() -> Self {
 +            Self(0)
 +        }
 +    }
 +}
 +
 +mod macros {
 +    macro_rules! use_self_expand {
 +        () => {
 +            fn new() -> Foo {
 +                Foo {}
 +            }
 +        };
 +    }
 +
 +    struct Foo {}
 +
 +    impl Foo {
 +        use_self_expand!(); // Should not lint in local macros
 +    }
 +
 +    #[derive(StructAUseSelf)] // Should not lint in derives
 +    struct A;
 +}
 +
 +mod nesting {
 +    struct Foo {}
 +    impl Foo {
 +        fn foo() {
 +            #[allow(unused_imports)]
 +            use self::Foo; // Can't use Self here
 +            struct Bar {
 +                foo: Foo, // Foo != Self
 +            }
 +
 +            impl Bar {
 +                fn bar() -> Self {
 +                    Self { foo: Foo {} }
 +                }
 +            }
 +
 +            // Can't use Self here
 +            fn baz() -> Foo {
 +                Foo {}
 +            }
 +        }
 +
 +        // Should lint here
 +        fn baz() -> Self {
 +            Self {}
 +        }
 +    }
 +
 +    enum Enum {
 +        A,
 +        B(u64),
 +        C { field: bool },
 +    }
 +    impl Enum {
 +        fn method() {
 +            #[allow(unused_imports)]
 +            use self::Enum::*; // Issue 3425
 +            static STATIC: Enum = Enum::A; // Can't use Self as type
 +        }
 +
 +        fn method2() {
 +            let _ = Self::B(42);
 +            let _ = Self::C { field: true };
 +            let _ = Self::A;
 +        }
 +    }
 +}
 +
 +mod issue3410 {
 +
 +    struct A;
 +    struct B;
 +
 +    trait Trait<T> {
 +        fn a(v: T) -> Self;
 +    }
 +
 +    impl Trait<Vec<A>> for Vec<B> {
 +        fn a(_: Vec<A>) -> Self {
 +            unimplemented!()
 +        }
 +    }
 +
 +    impl<T> Trait<Vec<A>> for Vec<T>
 +    where
 +        T: Trait<B>,
 +    {
 +        fn a(v: Vec<A>) -> Self {
 +            <Vec<B>>::a(v).into_iter().map(Trait::a).collect()
 +        }
 +    }
 +}
 +
 +#[allow(clippy::no_effect, path_statements)]
 +mod rustfix {
 +    mod nested {
 +        pub struct A {}
 +    }
 +
 +    impl nested::A {
 +        const A: bool = true;
 +
 +        fn fun_1() {}
 +
 +        fn fun_2() {
 +            Self::fun_1();
 +            Self::A;
 +
 +            Self {};
 +        }
 +    }
 +}
 +
 +mod issue3567 {
 +    struct TestStruct {}
 +    impl TestStruct {
 +        fn from_something() -> Self {
 +            Self {}
 +        }
 +    }
 +
 +    trait Test {
 +        fn test() -> TestStruct;
 +    }
 +
 +    impl Test for TestStruct {
 +        fn test() -> TestStruct {
 +            Self::from_something()
 +        }
 +    }
 +}
 +
 +mod paths_created_by_lowering {
 +    use std::ops::Range;
 +
 +    struct S {}
 +
 +    impl S {
 +        const A: usize = 0;
 +        const B: usize = 1;
 +
 +        async fn g() -> Self {
 +            Self {}
 +        }
 +
 +        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
 +            &p[Self::A..Self::B]
 +        }
 +    }
 +
 +    trait T {
 +        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8];
 +    }
 +
 +    impl T for Range<u8> {
 +        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
 +            &p[0..1]
 +        }
 +    }
 +}
 +
 +// reused from #1997
 +mod generics {
 +    struct Foo<T> {
 +        value: T,
 +    }
 +
 +    impl<T> Foo<T> {
 +        // `Self` is applicable here
 +        fn foo(value: T) -> Self {
 +            Self { value }
 +        }
 +
 +        // `Cannot` use `Self` as a return type as the generic types are different
 +        fn bar(value: i32) -> Foo<i32> {
 +            Foo { value }
 +        }
 +    }
 +}
 +
 +mod issue4140 {
 +    pub struct Error<From, To> {
 +        _from: From,
 +        _too: To,
 +    }
 +
 +    pub trait From<T> {
 +        type From;
 +        type To;
 +
 +        fn from(value: T) -> Self;
 +    }
 +
 +    pub trait TryFrom<T>
 +    where
 +        Self: Sized,
 +    {
 +        type From;
 +        type To;
 +
 +        fn try_from(value: T) -> Result<Self, Error<Self::From, Self::To>>;
 +    }
 +
 +    // FIXME: Suggested fix results in infinite recursion.
 +    // impl<F, T> TryFrom<F> for T
 +    // where
 +    //     T: From<F>,
 +    // {
 +    //     type From = Self::From;
 +    //     type To = Self::To;
 +
 +    //     fn try_from(value: F) -> Result<Self, Error<Self::From, Self::To>> {
 +    //         Ok(From::from(value))
 +    //     }
 +    // }
 +
 +    impl From<bool> for i64 {
 +        type From = bool;
 +        type To = Self;
 +
 +        fn from(value: bool) -> Self {
 +            if value { 100 } else { 0 }
 +        }
 +    }
 +}
 +
 +mod issue2843 {
 +    trait Foo {
 +        type Bar;
 +    }
 +
 +    impl Foo for usize {
 +        type Bar = u8;
 +    }
 +
 +    impl<T: Foo> Foo for Option<T> {
 +        type Bar = Option<T::Bar>;
 +    }
 +}
 +
 +mod issue3859 {
 +    pub struct Foo;
 +    pub struct Bar([usize; 3]);
 +
 +    impl Foo {
 +        pub const BAR: usize = 3;
 +
 +        pub fn foo() {
 +            const _X: usize = Foo::BAR;
 +            // const _Y: usize = Self::BAR;
 +        }
 +    }
 +}
 +
 +mod issue4305 {
 +    trait Foo: 'static {}
 +
 +    struct Bar;
 +
 +    impl Foo for Bar {}
 +
 +    impl<T: Foo> From<T> for Box<dyn Foo> {
 +        fn from(t: T) -> Self {
 +            Box::new(t)
 +        }
 +    }
 +}
 +
 +mod lint_at_item_level {
 +    struct Foo {}
 +
 +    #[allow(clippy::use_self)]
 +    impl Foo {
 +        fn new() -> Foo {
 +            Foo {}
 +        }
 +    }
 +
 +    #[allow(clippy::use_self)]
 +    impl Default for Foo {
 +        fn default() -> Foo {
 +            Foo::new()
 +        }
 +    }
 +}
 +
 +mod lint_at_impl_item_level {
 +    struct Foo {}
 +
 +    impl Foo {
 +        #[allow(clippy::use_self)]
 +        fn new() -> Foo {
 +            Foo {}
 +        }
 +    }
 +
 +    impl Default for Foo {
 +        #[allow(clippy::use_self)]
 +        fn default() -> Foo {
 +            Foo::new()
 +        }
 +    }
 +}
 +
 +mod issue4734 {
 +    #[repr(C, packed)]
 +    pub struct X {
 +        pub x: u32,
 +    }
 +
 +    impl From<X> for u32 {
 +        fn from(c: X) -> Self {
 +            unsafe { core::mem::transmute(c) }
 +        }
 +    }
 +}
 +
 +mod nested_paths {
 +    use std::convert::Into;
 +    mod submod {
 +        pub struct B {}
 +        pub struct C {}
 +
 +        impl Into<C> for B {
 +            fn into(self) -> C {
 +                C {}
 +            }
 +        }
 +    }
 +
 +    struct A<T> {
 +        t: T,
 +    }
 +
 +    impl<T> A<T> {
 +        fn new<V: Into<T>>(v: V) -> Self {
 +            Self { t: Into::into(v) }
 +        }
 +    }
 +
 +    impl A<submod::C> {
 +        fn test() -> Self {
 +            Self::new::<submod::B>(submod::B {})
 +        }
 +    }
 +}
 +
 +mod issue6818 {
 +    #[derive(serde::Deserialize)]
 +    struct A {
 +        a: i32,
 +    }
 +}
 +
 +mod issue7206 {
 +    struct MyStruct<const C: char>;
 +    impl From<MyStruct<'a'>> for MyStruct<'b'> {
 +        fn from(_s: MyStruct<'a'>) -> Self {
 +            Self
 +        }
 +    }
 +
 +    // keep linting non-`Const` generic args
 +    struct S<'a> {
 +        inner: &'a str,
 +    }
 +
 +    struct S2<T> {
 +        inner: T,
 +    }
 +
 +    impl<T> S2<T> {
 +        fn new() -> Self {
 +            unimplemented!();
 +        }
 +    }
 +
 +    impl<'a> S2<S<'a>> {
 +        fn new_again() -> Self {
 +            Self::new()
 +        }
 +    }
 +}
 +
 +mod self_is_ty_param {
 +    trait Trait {
 +        type Type;
 +        type Hi;
 +
 +        fn test();
 +    }
 +
 +    impl<I> Trait for I
 +    where
 +        I: Iterator,
 +        I::Item: Trait, // changing this to Self would require <Self as Iterator>
 +    {
 +        type Type = I;
 +        type Hi = I::Item;
 +
 +        fn test() {
 +            let _: I::Item;
 +            let _: I; // this could lint, but is questionable
 +        }
 +    }
 +}
index 9da6fef7a380c792781aceadb6ffbb2258395995,0000000000000000000000000000000000000000..7b621ff9bcabf5be14250e8740311b04516047b8
mode 100644,000000..100644
--- /dev/null
@@@ -1,522 -1,0 +1,521 @@@
- // edition:2018
 +// run-rustfix
 +// aux-build:proc_macro_derive.rs
 +
 +#![warn(clippy::use_self)]
 +#![allow(dead_code)]
 +#![allow(
 +    clippy::should_implement_trait,
 +    clippy::upper_case_acronyms,
 +    clippy::from_over_into,
 +    clippy::self_named_constructors
 +)]
 +
 +#[macro_use]
 +extern crate proc_macro_derive;
 +
 +fn main() {}
 +
 +mod use_self {
 +    struct Foo {}
 +
 +    impl Foo {
 +        fn new() -> Foo {
 +            Foo {}
 +        }
 +        fn test() -> Foo {
 +            Foo::new()
 +        }
 +    }
 +
 +    impl Default for Foo {
 +        fn default() -> Foo {
 +            Foo::new()
 +        }
 +    }
 +}
 +
 +mod better {
 +    struct Foo {}
 +
 +    impl Foo {
 +        fn new() -> Self {
 +            Self {}
 +        }
 +        fn test() -> Self {
 +            Self::new()
 +        }
 +    }
 +
 +    impl Default for Foo {
 +        fn default() -> Self {
 +            Self::new()
 +        }
 +    }
 +}
 +
 +mod lifetimes {
 +    struct Foo<'a> {
 +        foo_str: &'a str,
 +    }
 +
 +    impl<'a> Foo<'a> {
 +        // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
 +        // Foo<'b>`
 +        fn foo(s: &str) -> Foo {
 +            Foo { foo_str: s }
 +        }
 +        // cannot replace with `Self`, because that's `Foo<'a>`
 +        fn bar() -> Foo<'static> {
 +            Foo { foo_str: "foo" }
 +        }
 +
 +        // FIXME: the lint does not handle lifetimed struct
 +        // `Self` should be applicable here
 +        fn clone(&self) -> Foo<'a> {
 +            Foo { foo_str: self.foo_str }
 +        }
 +    }
 +}
 +
 +mod issue2894 {
 +    trait IntoBytes {
 +        fn to_bytes(self) -> Vec<u8>;
 +    }
 +
 +    // This should not be linted
 +    impl IntoBytes for u8 {
 +        fn to_bytes(self) -> Vec<u8> {
 +            vec![self]
 +        }
 +    }
 +}
 +
 +mod existential {
 +    struct Foo;
 +
 +    impl Foo {
 +        fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
 +            foos.iter()
 +        }
 +
 +        fn good(foos: &[Self]) -> impl Iterator<Item = &Self> {
 +            foos.iter()
 +        }
 +    }
 +}
 +
 +mod tuple_structs {
 +    pub struct TS(i32);
 +
 +    impl TS {
 +        pub fn ts() -> Self {
 +            TS(0)
 +        }
 +    }
 +}
 +
 +mod macros {
 +    macro_rules! use_self_expand {
 +        () => {
 +            fn new() -> Foo {
 +                Foo {}
 +            }
 +        };
 +    }
 +
 +    struct Foo {}
 +
 +    impl Foo {
 +        use_self_expand!(); // Should not lint in local macros
 +    }
 +
 +    #[derive(StructAUseSelf)] // Should not lint in derives
 +    struct A;
 +}
 +
 +mod nesting {
 +    struct Foo {}
 +    impl Foo {
 +        fn foo() {
 +            #[allow(unused_imports)]
 +            use self::Foo; // Can't use Self here
 +            struct Bar {
 +                foo: Foo, // Foo != Self
 +            }
 +
 +            impl Bar {
 +                fn bar() -> Bar {
 +                    Bar { foo: Foo {} }
 +                }
 +            }
 +
 +            // Can't use Self here
 +            fn baz() -> Foo {
 +                Foo {}
 +            }
 +        }
 +
 +        // Should lint here
 +        fn baz() -> Foo {
 +            Foo {}
 +        }
 +    }
 +
 +    enum Enum {
 +        A,
 +        B(u64),
 +        C { field: bool },
 +    }
 +    impl Enum {
 +        fn method() {
 +            #[allow(unused_imports)]
 +            use self::Enum::*; // Issue 3425
 +            static STATIC: Enum = Enum::A; // Can't use Self as type
 +        }
 +
 +        fn method2() {
 +            let _ = Enum::B(42);
 +            let _ = Enum::C { field: true };
 +            let _ = Enum::A;
 +        }
 +    }
 +}
 +
 +mod issue3410 {
 +
 +    struct A;
 +    struct B;
 +
 +    trait Trait<T> {
 +        fn a(v: T) -> Self;
 +    }
 +
 +    impl Trait<Vec<A>> for Vec<B> {
 +        fn a(_: Vec<A>) -> Self {
 +            unimplemented!()
 +        }
 +    }
 +
 +    impl<T> Trait<Vec<A>> for Vec<T>
 +    where
 +        T: Trait<B>,
 +    {
 +        fn a(v: Vec<A>) -> Self {
 +            <Vec<B>>::a(v).into_iter().map(Trait::a).collect()
 +        }
 +    }
 +}
 +
 +#[allow(clippy::no_effect, path_statements)]
 +mod rustfix {
 +    mod nested {
 +        pub struct A {}
 +    }
 +
 +    impl nested::A {
 +        const A: bool = true;
 +
 +        fn fun_1() {}
 +
 +        fn fun_2() {
 +            nested::A::fun_1();
 +            nested::A::A;
 +
 +            nested::A {};
 +        }
 +    }
 +}
 +
 +mod issue3567 {
 +    struct TestStruct {}
 +    impl TestStruct {
 +        fn from_something() -> Self {
 +            Self {}
 +        }
 +    }
 +
 +    trait Test {
 +        fn test() -> TestStruct;
 +    }
 +
 +    impl Test for TestStruct {
 +        fn test() -> TestStruct {
 +            TestStruct::from_something()
 +        }
 +    }
 +}
 +
 +mod paths_created_by_lowering {
 +    use std::ops::Range;
 +
 +    struct S {}
 +
 +    impl S {
 +        const A: usize = 0;
 +        const B: usize = 1;
 +
 +        async fn g() -> S {
 +            S {}
 +        }
 +
 +        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
 +            &p[S::A..S::B]
 +        }
 +    }
 +
 +    trait T {
 +        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8];
 +    }
 +
 +    impl T for Range<u8> {
 +        fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] {
 +            &p[0..1]
 +        }
 +    }
 +}
 +
 +// reused from #1997
 +mod generics {
 +    struct Foo<T> {
 +        value: T,
 +    }
 +
 +    impl<T> Foo<T> {
 +        // `Self` is applicable here
 +        fn foo(value: T) -> Foo<T> {
 +            Foo::<T> { value }
 +        }
 +
 +        // `Cannot` use `Self` as a return type as the generic types are different
 +        fn bar(value: i32) -> Foo<i32> {
 +            Foo { value }
 +        }
 +    }
 +}
 +
 +mod issue4140 {
 +    pub struct Error<From, To> {
 +        _from: From,
 +        _too: To,
 +    }
 +
 +    pub trait From<T> {
 +        type From;
 +        type To;
 +
 +        fn from(value: T) -> Self;
 +    }
 +
 +    pub trait TryFrom<T>
 +    where
 +        Self: Sized,
 +    {
 +        type From;
 +        type To;
 +
 +        fn try_from(value: T) -> Result<Self, Error<Self::From, Self::To>>;
 +    }
 +
 +    // FIXME: Suggested fix results in infinite recursion.
 +    // impl<F, T> TryFrom<F> for T
 +    // where
 +    //     T: From<F>,
 +    // {
 +    //     type From = Self::From;
 +    //     type To = Self::To;
 +
 +    //     fn try_from(value: F) -> Result<Self, Error<Self::From, Self::To>> {
 +    //         Ok(From::from(value))
 +    //     }
 +    // }
 +
 +    impl From<bool> for i64 {
 +        type From = bool;
 +        type To = Self;
 +
 +        fn from(value: bool) -> Self {
 +            if value { 100 } else { 0 }
 +        }
 +    }
 +}
 +
 +mod issue2843 {
 +    trait Foo {
 +        type Bar;
 +    }
 +
 +    impl Foo for usize {
 +        type Bar = u8;
 +    }
 +
 +    impl<T: Foo> Foo for Option<T> {
 +        type Bar = Option<T::Bar>;
 +    }
 +}
 +
 +mod issue3859 {
 +    pub struct Foo;
 +    pub struct Bar([usize; 3]);
 +
 +    impl Foo {
 +        pub const BAR: usize = 3;
 +
 +        pub fn foo() {
 +            const _X: usize = Foo::BAR;
 +            // const _Y: usize = Self::BAR;
 +        }
 +    }
 +}
 +
 +mod issue4305 {
 +    trait Foo: 'static {}
 +
 +    struct Bar;
 +
 +    impl Foo for Bar {}
 +
 +    impl<T: Foo> From<T> for Box<dyn Foo> {
 +        fn from(t: T) -> Self {
 +            Box::new(t)
 +        }
 +    }
 +}
 +
 +mod lint_at_item_level {
 +    struct Foo {}
 +
 +    #[allow(clippy::use_self)]
 +    impl Foo {
 +        fn new() -> Foo {
 +            Foo {}
 +        }
 +    }
 +
 +    #[allow(clippy::use_self)]
 +    impl Default for Foo {
 +        fn default() -> Foo {
 +            Foo::new()
 +        }
 +    }
 +}
 +
 +mod lint_at_impl_item_level {
 +    struct Foo {}
 +
 +    impl Foo {
 +        #[allow(clippy::use_self)]
 +        fn new() -> Foo {
 +            Foo {}
 +        }
 +    }
 +
 +    impl Default for Foo {
 +        #[allow(clippy::use_self)]
 +        fn default() -> Foo {
 +            Foo::new()
 +        }
 +    }
 +}
 +
 +mod issue4734 {
 +    #[repr(C, packed)]
 +    pub struct X {
 +        pub x: u32,
 +    }
 +
 +    impl From<X> for u32 {
 +        fn from(c: X) -> Self {
 +            unsafe { core::mem::transmute(c) }
 +        }
 +    }
 +}
 +
 +mod nested_paths {
 +    use std::convert::Into;
 +    mod submod {
 +        pub struct B {}
 +        pub struct C {}
 +
 +        impl Into<C> for B {
 +            fn into(self) -> C {
 +                C {}
 +            }
 +        }
 +    }
 +
 +    struct A<T> {
 +        t: T,
 +    }
 +
 +    impl<T> A<T> {
 +        fn new<V: Into<T>>(v: V) -> Self {
 +            Self { t: Into::into(v) }
 +        }
 +    }
 +
 +    impl A<submod::C> {
 +        fn test() -> Self {
 +            A::new::<submod::B>(submod::B {})
 +        }
 +    }
 +}
 +
 +mod issue6818 {
 +    #[derive(serde::Deserialize)]
 +    struct A {
 +        a: i32,
 +    }
 +}
 +
 +mod issue7206 {
 +    struct MyStruct<const C: char>;
 +    impl From<MyStruct<'a'>> for MyStruct<'b'> {
 +        fn from(_s: MyStruct<'a'>) -> Self {
 +            Self
 +        }
 +    }
 +
 +    // keep linting non-`Const` generic args
 +    struct S<'a> {
 +        inner: &'a str,
 +    }
 +
 +    struct S2<T> {
 +        inner: T,
 +    }
 +
 +    impl<T> S2<T> {
 +        fn new() -> Self {
 +            unimplemented!();
 +        }
 +    }
 +
 +    impl<'a> S2<S<'a>> {
 +        fn new_again() -> Self {
 +            S2::new()
 +        }
 +    }
 +}
 +
 +mod self_is_ty_param {
 +    trait Trait {
 +        type Type;
 +        type Hi;
 +
 +        fn test();
 +    }
 +
 +    impl<I> Trait for I
 +    where
 +        I: Iterator,
 +        I::Item: Trait, // changing this to Self would require <Self as Iterator>
 +    {
 +        type Type = I;
 +        type Hi = I::Item;
 +
 +        fn test() {
 +            let _: I::Item;
 +            let _: I; // this could lint, but is questionable
 +        }
 +    }
 +}
index e14368a11aa746eddd1fffeeb88c3bc36c35982d,0000000000000000000000000000000000000000..ecb78b3f9721b0b575a4a153e08e9833f63917b5
mode 100644,000000..100644
--- /dev/null
@@@ -1,172 -1,0 +1,172 @@@
-   --> $DIR/use_self.rs:23:21
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:24:13
++  --> $DIR/use_self.rs:22:21
 +   |
 +LL |         fn new() -> Foo {
 +   |                     ^^^ help: use the applicable keyword: `Self`
 +   |
 +   = note: `-D clippy::use-self` implied by `-D warnings`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:26:22
++  --> $DIR/use_self.rs:23:13
 +   |
 +LL |             Foo {}
 +   |             ^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:27:13
++  --> $DIR/use_self.rs:25:22
 +   |
 +LL |         fn test() -> Foo {
 +   |                      ^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:32:25
++  --> $DIR/use_self.rs:26:13
 +   |
 +LL |             Foo::new()
 +   |             ^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:33:13
++  --> $DIR/use_self.rs:31:25
 +   |
 +LL |         fn default() -> Foo {
 +   |                         ^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:98:24
++  --> $DIR/use_self.rs:32:13
 +   |
 +LL |             Foo::new()
 +   |             ^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:98:55
++  --> $DIR/use_self.rs:97:24
 +   |
 +LL |         fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
 +   |                        ^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:113:13
++  --> $DIR/use_self.rs:97:55
 +   |
 +LL |         fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
 +   |                                                       ^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:148:29
++  --> $DIR/use_self.rs:112:13
 +   |
 +LL |             TS(0)
 +   |             ^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:149:21
++  --> $DIR/use_self.rs:147:29
 +   |
 +LL |                 fn bar() -> Bar {
 +   |                             ^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:160:21
++  --> $DIR/use_self.rs:148:21
 +   |
 +LL |                     Bar { foo: Foo {} }
 +   |                     ^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:161:13
++  --> $DIR/use_self.rs:159:21
 +   |
 +LL |         fn baz() -> Foo {
 +   |                     ^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:178:21
++  --> $DIR/use_self.rs:160:13
 +   |
 +LL |             Foo {}
 +   |             ^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:179:21
++  --> $DIR/use_self.rs:177:21
 +   |
 +LL |             let _ = Enum::B(42);
 +   |                     ^^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:180:21
++  --> $DIR/use_self.rs:178:21
 +   |
 +LL |             let _ = Enum::C { field: true };
 +   |                     ^^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:222:13
++  --> $DIR/use_self.rs:179:21
 +   |
 +LL |             let _ = Enum::A;
 +   |                     ^^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:223:13
++  --> $DIR/use_self.rs:221:13
 +   |
 +LL |             nested::A::fun_1();
 +   |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:225:13
++  --> $DIR/use_self.rs:222:13
 +   |
 +LL |             nested::A::A;
 +   |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:244:13
++  --> $DIR/use_self.rs:224:13
 +   |
 +LL |             nested::A {};
 +   |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:258:25
++  --> $DIR/use_self.rs:243:13
 +   |
 +LL |             TestStruct::from_something()
 +   |             ^^^^^^^^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:259:13
++  --> $DIR/use_self.rs:257:25
 +   |
 +LL |         async fn g() -> S {
 +   |                         ^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:263:16
++  --> $DIR/use_self.rs:258:13
 +   |
 +LL |             S {}
 +   |             ^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:263:22
++  --> $DIR/use_self.rs:262:16
 +   |
 +LL |             &p[S::A..S::B]
 +   |                ^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:286:29
++  --> $DIR/use_self.rs:262:22
 +   |
 +LL |             &p[S::A..S::B]
 +   |                      ^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:287:13
++  --> $DIR/use_self.rs:285:29
 +   |
 +LL |         fn foo(value: T) -> Foo<T> {
 +   |                             ^^^^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:459:13
++  --> $DIR/use_self.rs:286:13
 +   |
 +LL |             Foo::<T> { value }
 +   |             ^^^^^^^^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:496:13
++  --> $DIR/use_self.rs:458:13
 +   |
 +LL |             A::new::<submod::B>(submod::B {})
 +   |             ^ help: use the applicable keyword: `Self`
 +
 +error: unnecessary structure name repetition
++  --> $DIR/use_self.rs:495:13
 +   |
 +LL |             S2::new()
 +   |             ^^ help: use the applicable keyword: `Self`
 +
 +error: aborting due to 28 previous errors
 +
index d8bda7e8f48a7eb32cc22fc54c4cb5d24d1ffea8,0000000000000000000000000000000000000000..21d66d5df79ecfa0a8b1727424d38ffb1134081f
mode 100644,000000..100644
--- /dev/null
@@@ -1,119 -1,0 +1,118 @@@
- // edition:2018
 +// aux-build:proc_macro_derive.rs
 +
 +#![feature(rustc_private)]
 +#![warn(clippy::all)]
 +#![allow(clippy::blacklisted_name, clippy::eq_op)]
 +#![warn(clippy::used_underscore_binding)]
 +
 +#[macro_use]
 +extern crate proc_macro_derive;
 +
 +// This should not trigger the lint. There's underscore binding inside the external derive that
 +// would trigger the `used_underscore_binding` lint.
 +#[derive(DeriveSomething)]
 +struct Baz;
 +
 +macro_rules! test_macro {
 +    () => {{
 +        let _foo = 42;
 +        _foo + 1
 +    }};
 +}
 +
 +/// Tests that we lint if we use a binding with a single leading underscore
 +fn prefix_underscore(_foo: u32) -> u32 {
 +    _foo + 1
 +}
 +
 +/// Tests that we lint if we use a `_`-variable defined outside within a macro expansion
 +fn in_macro_or_desugar(_foo: u32) {
 +    println!("{}", _foo);
 +    assert_eq!(_foo, _foo);
 +
 +    test_macro!() + 1;
 +}
 +
 +// Struct for testing use of fields prefixed with an underscore
 +struct StructFieldTest {
 +    _underscore_field: u32,
 +}
 +
 +/// Tests that we lint the use of a struct field which is prefixed with an underscore
 +fn in_struct_field() {
 +    let mut s = StructFieldTest { _underscore_field: 0 };
 +    s._underscore_field += 1;
 +}
 +
 +/// Tests that we do not lint if the underscore is not a prefix
 +fn non_prefix_underscore(some_foo: u32) -> u32 {
 +    some_foo + 1
 +}
 +
 +/// Tests that we do not lint if we do not use the binding (simple case)
 +fn unused_underscore_simple(_foo: u32) -> u32 {
 +    1
 +}
 +
 +/// Tests that we do not lint if we do not use the binding (complex case). This checks for
 +/// compatibility with the built-in `unused_variables` lint.
 +fn unused_underscore_complex(mut _foo: u32) -> u32 {
 +    _foo += 1;
 +    _foo = 2;
 +    1
 +}
 +
 +/// Test that we do not lint for multiple underscores
 +fn multiple_underscores(__foo: u32) -> u32 {
 +    __foo + 1
 +}
 +
 +// Non-variable bindings with preceding underscore
 +fn _fn_test() {}
 +struct _StructTest;
 +enum _EnumTest {
 +    _Empty,
 +    _Value(_StructTest),
 +}
 +
 +/// Tests that we do not lint for non-variable bindings
 +fn non_variables() {
 +    _fn_test();
 +    let _s = _StructTest;
 +    let _e = match _EnumTest::_Value(_StructTest) {
 +        _EnumTest::_Empty => 0,
 +        _EnumTest::_Value(_st) => 1,
 +    };
 +    let f = _fn_test;
 +    f();
 +}
 +
 +// Tests that we do not lint if the binding comes from await desugaring,
 +// but we do lint the awaited expression. See issue 5360.
 +async fn await_desugaring() {
 +    async fn foo() {}
 +    fn uses_i(_i: i32) {}
 +
 +    foo().await;
 +    ({
 +        let _i = 5;
 +        uses_i(_i);
 +        foo()
 +    })
 +    .await
 +}
 +
 +fn main() {
 +    let foo = 0u32;
 +    // tests of unused_underscore lint
 +    let _ = prefix_underscore(foo);
 +    in_macro_or_desugar(foo);
 +    in_struct_field();
 +    // possible false positives
 +    let _ = non_prefix_underscore(foo);
 +    let _ = unused_underscore_simple(foo);
 +    let _ = unused_underscore_complex(foo);
 +    let _ = multiple_underscores(foo);
 +    non_variables();
 +    await_desugaring();
 +}
index 2cbfc5ca2e2705e0bb618bfad420339277493f22,0000000000000000000000000000000000000000..790b849210c9b35875ff2c9b8c4d47f4c54017cd
mode 100644,000000..100644
--- /dev/null
@@@ -1,40 -1,0 +1,40 @@@
-   --> $DIR/used_underscore_binding.rs:26:5
 +error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
-   --> $DIR/used_underscore_binding.rs:31:20
++  --> $DIR/used_underscore_binding.rs:25:5
 +   |
 +LL |     _foo + 1
 +   |     ^^^^
 +   |
 +   = note: `-D clippy::used-underscore-binding` implied by `-D warnings`
 +
 +error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
-   --> $DIR/used_underscore_binding.rs:32:16
++  --> $DIR/used_underscore_binding.rs:30:20
 +   |
 +LL |     println!("{}", _foo);
 +   |                    ^^^^
 +
 +error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
-   --> $DIR/used_underscore_binding.rs:32:22
++  --> $DIR/used_underscore_binding.rs:31:16
 +   |
 +LL |     assert_eq!(_foo, _foo);
 +   |                ^^^^
 +
 +error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
-   --> $DIR/used_underscore_binding.rs:45:5
++  --> $DIR/used_underscore_binding.rs:31:22
 +   |
 +LL |     assert_eq!(_foo, _foo);
 +   |                      ^^^^
 +
 +error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
-   --> $DIR/used_underscore_binding.rs:100:16
++  --> $DIR/used_underscore_binding.rs:44:5
 +   |
 +LL |     s._underscore_field += 1;
 +   |     ^^^^^^^^^^^^^^^^^^^
 +
 +error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
++  --> $DIR/used_underscore_binding.rs:99:16
 +   |
 +LL |         uses_i(_i);
 +   |                ^^
 +
 +error: aborting due to 6 previous errors
 +
index 98bc1e80731ff3934643d2c565f70ad241ddd7f1,0000000000000000000000000000000000000000..8402c33a4cd5fb695d37116caf003763dcf186bd
mode 100644,000000..100644
--- /dev/null
@@@ -1,241 -1,0 +1,246 @@@
- //#![allow(clippy::redundant_pub_crate)]
++// edition:2015
 +// run-rustfix
 +// aux-build:wildcard_imports_helper.rs
 +
++// the 2015 edition here is needed because edition 2018 changed the module system
++// (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
++// no longer detects some of the cases starting with Rust 2018.
++// FIXME: We should likely add another edition 2021 test case for this lint
++
 +#![warn(clippy::wildcard_imports)]
 +#![allow(unused)]
 +#![allow(clippy::unnecessary_wraps)]
 +#![warn(unused_imports)]
 +
 +extern crate wildcard_imports_helper;
 +
 +use crate::fn_mod::foo;
 +use crate::mod_mod::inner_mod;
 +use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod};
 +#[macro_use]
 +use crate::struct_mod::{A, inner_struct_mod};
 +
 +#[allow(unused_imports)]
 +use wildcard_imports_helper::inner::inner_for_self_import;
 +use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar;
 +use wildcard_imports_helper::{ExternA, extern_foo};
 +
 +use std::io::prelude::*;
 +use wildcard_imports_helper::prelude::v1::*;
 +
 +struct ReadFoo;
 +
 +impl Read for ReadFoo {
 +    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
 +        Ok(0)
 +    }
 +}
 +
 +mod fn_mod {
 +    pub fn foo() {}
 +}
 +
 +mod mod_mod {
 +    pub mod inner_mod {
 +        pub fn foo() {}
 +    }
 +}
 +
 +mod multi_fn_mod {
 +    pub fn multi_foo() {}
 +    pub fn multi_bar() {}
 +    pub fn multi_baz() {}
 +    pub mod multi_inner_mod {
 +        pub fn foo() {}
 +    }
 +}
 +
 +mod struct_mod {
 +    pub struct A;
 +    pub struct B;
 +    pub mod inner_struct_mod {
 +        pub struct C;
 +    }
 +
 +    #[macro_export]
 +    macro_rules! double_struct_import_test {
 +        () => {
 +            let _ = A;
 +        };
 +    }
 +}
 +
 +fn main() {
 +    foo();
 +    multi_foo();
 +    multi_bar();
 +    multi_inner_mod::foo();
 +    inner_mod::foo();
 +    extern_foo();
 +    inner_extern_bar();
 +
 +    let _ = A;
 +    let _ = inner_struct_mod::C;
 +    let _ = ExternA;
 +    let _ = PreludeModAnywhere;
 +
 +    double_struct_import_test!();
 +    double_struct_import_test!();
 +}
 +
 +mod in_fn_test {
 +    pub use self::inner_exported::*;
 +    #[allow(unused_imports)]
 +    pub(crate) use self::inner_exported2::*;
 +
 +    fn test_intern() {
 +        use crate::fn_mod::foo;
 +
 +        foo();
 +    }
 +
 +    fn test_extern() {
 +        use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo};
 +        use wildcard_imports_helper::{ExternA, extern_foo};
 +
 +        inner_for_self_import::inner_extern_foo();
 +        inner_extern_foo();
 +
 +        extern_foo();
 +
 +        let _ = ExternA;
 +    }
 +
 +    fn test_inner_nested() {
 +        use self::{inner::inner_foo, inner2::inner_bar};
 +
 +        inner_foo();
 +        inner_bar();
 +    }
 +
 +    fn test_extern_reexported() {
 +        use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported};
 +
 +        extern_exported();
 +        let _ = ExternExportedStruct;
 +        let _ = ExternExportedEnum::A;
 +    }
 +
 +    mod inner_exported {
 +        pub fn exported() {}
 +        pub struct ExportedStruct;
 +        pub enum ExportedEnum {
 +            A,
 +        }
 +    }
 +
 +    mod inner_exported2 {
 +        pub(crate) fn exported2() {}
 +    }
 +
 +    mod inner {
 +        pub fn inner_foo() {}
 +    }
 +
 +    mod inner2 {
 +        pub fn inner_bar() {}
 +    }
 +}
 +
 +fn test_reexported() {
 +    use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported};
 +
 +    exported();
 +    let _ = ExportedStruct;
 +    let _ = ExportedEnum::A;
 +}
 +
 +#[rustfmt::skip]
 +fn test_weird_formatting() {
 +    use crate:: in_fn_test::exported;
 +    use crate:: fn_mod::foo;
 +
 +    exported();
 +    foo();
 +}
 +
 +mod super_imports {
 +    fn foofoo() {}
 +
 +    mod should_be_replaced {
 +        use super::foofoo;
 +
 +        fn with_super() {
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod test_should_pass {
 +        use super::*;
 +
 +        fn with_super() {
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod test_should_pass_inside_function {
 +        fn with_super_inside_function() {
 +            use super::*;
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod test_should_pass_further_inside {
 +        fn insidefoo() {}
 +        mod inner {
 +            use super::*;
 +            fn with_super() {
 +                let _ = insidefoo();
 +            }
 +        }
 +    }
 +
 +    mod should_be_replaced_futher_inside {
 +        fn insidefoo() {}
 +        mod inner {
 +            use super::insidefoo;
 +            fn with_super() {
 +                let _ = insidefoo();
 +            }
 +        }
 +    }
 +
 +    mod use_explicit_should_be_replaced {
 +        use super_imports::foofoo;
 +
 +        fn with_explicit() {
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod use_double_super_should_be_replaced {
 +        mod inner {
 +            use super::super::foofoo;
 +
 +            fn with_double_super() {
 +                let _ = foofoo();
 +            }
 +        }
 +    }
 +
 +    mod use_super_explicit_should_be_replaced {
 +        use super::super::super_imports::foofoo;
 +
 +        fn with_super_explicit() {
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod attestation_should_be_replaced {
 +        use super::foofoo;
 +
 +        fn with_explicit() {
 +            let _ = foofoo();
 +        }
 +    }
 +}
index 4ef61f9245b58f9420daded6c79a1d84e201edb9,0000000000000000000000000000000000000000..faaeaade9b02bff03b30793a73638ba5a3a560eb
mode 100644,000000..100644
--- /dev/null
@@@ -1,242 -1,0 +1,247 @@@
- //#![allow(clippy::redundant_pub_crate)]
++// edition:2015
 +// run-rustfix
 +// aux-build:wildcard_imports_helper.rs
 +
++// the 2015 edition here is needed because edition 2018 changed the module system
++// (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
++// no longer detects some of the cases starting with Rust 2018.
++// FIXME: We should likely add another edition 2021 test case for this lint
++
 +#![warn(clippy::wildcard_imports)]
 +#![allow(unused)]
 +#![allow(clippy::unnecessary_wraps)]
 +#![warn(unused_imports)]
 +
 +extern crate wildcard_imports_helper;
 +
 +use crate::fn_mod::*;
 +use crate::mod_mod::*;
 +use crate::multi_fn_mod::*;
 +#[macro_use]
 +use crate::struct_mod::*;
 +
 +#[allow(unused_imports)]
 +use wildcard_imports_helper::inner::inner_for_self_import;
 +use wildcard_imports_helper::inner::inner_for_self_import::*;
 +use wildcard_imports_helper::*;
 +
 +use std::io::prelude::*;
 +use wildcard_imports_helper::prelude::v1::*;
 +
 +struct ReadFoo;
 +
 +impl Read for ReadFoo {
 +    fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
 +        Ok(0)
 +    }
 +}
 +
 +mod fn_mod {
 +    pub fn foo() {}
 +}
 +
 +mod mod_mod {
 +    pub mod inner_mod {
 +        pub fn foo() {}
 +    }
 +}
 +
 +mod multi_fn_mod {
 +    pub fn multi_foo() {}
 +    pub fn multi_bar() {}
 +    pub fn multi_baz() {}
 +    pub mod multi_inner_mod {
 +        pub fn foo() {}
 +    }
 +}
 +
 +mod struct_mod {
 +    pub struct A;
 +    pub struct B;
 +    pub mod inner_struct_mod {
 +        pub struct C;
 +    }
 +
 +    #[macro_export]
 +    macro_rules! double_struct_import_test {
 +        () => {
 +            let _ = A;
 +        };
 +    }
 +}
 +
 +fn main() {
 +    foo();
 +    multi_foo();
 +    multi_bar();
 +    multi_inner_mod::foo();
 +    inner_mod::foo();
 +    extern_foo();
 +    inner_extern_bar();
 +
 +    let _ = A;
 +    let _ = inner_struct_mod::C;
 +    let _ = ExternA;
 +    let _ = PreludeModAnywhere;
 +
 +    double_struct_import_test!();
 +    double_struct_import_test!();
 +}
 +
 +mod in_fn_test {
 +    pub use self::inner_exported::*;
 +    #[allow(unused_imports)]
 +    pub(crate) use self::inner_exported2::*;
 +
 +    fn test_intern() {
 +        use crate::fn_mod::*;
 +
 +        foo();
 +    }
 +
 +    fn test_extern() {
 +        use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
 +        use wildcard_imports_helper::*;
 +
 +        inner_for_self_import::inner_extern_foo();
 +        inner_extern_foo();
 +
 +        extern_foo();
 +
 +        let _ = ExternA;
 +    }
 +
 +    fn test_inner_nested() {
 +        use self::{inner::*, inner2::*};
 +
 +        inner_foo();
 +        inner_bar();
 +    }
 +
 +    fn test_extern_reexported() {
 +        use wildcard_imports_helper::*;
 +
 +        extern_exported();
 +        let _ = ExternExportedStruct;
 +        let _ = ExternExportedEnum::A;
 +    }
 +
 +    mod inner_exported {
 +        pub fn exported() {}
 +        pub struct ExportedStruct;
 +        pub enum ExportedEnum {
 +            A,
 +        }
 +    }
 +
 +    mod inner_exported2 {
 +        pub(crate) fn exported2() {}
 +    }
 +
 +    mod inner {
 +        pub fn inner_foo() {}
 +    }
 +
 +    mod inner2 {
 +        pub fn inner_bar() {}
 +    }
 +}
 +
 +fn test_reexported() {
 +    use crate::in_fn_test::*;
 +
 +    exported();
 +    let _ = ExportedStruct;
 +    let _ = ExportedEnum::A;
 +}
 +
 +#[rustfmt::skip]
 +fn test_weird_formatting() {
 +    use crate:: in_fn_test::  * ;
 +    use crate:: fn_mod::
 +        *;
 +
 +    exported();
 +    foo();
 +}
 +
 +mod super_imports {
 +    fn foofoo() {}
 +
 +    mod should_be_replaced {
 +        use super::*;
 +
 +        fn with_super() {
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod test_should_pass {
 +        use super::*;
 +
 +        fn with_super() {
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod test_should_pass_inside_function {
 +        fn with_super_inside_function() {
 +            use super::*;
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod test_should_pass_further_inside {
 +        fn insidefoo() {}
 +        mod inner {
 +            use super::*;
 +            fn with_super() {
 +                let _ = insidefoo();
 +            }
 +        }
 +    }
 +
 +    mod should_be_replaced_futher_inside {
 +        fn insidefoo() {}
 +        mod inner {
 +            use super::*;
 +            fn with_super() {
 +                let _ = insidefoo();
 +            }
 +        }
 +    }
 +
 +    mod use_explicit_should_be_replaced {
 +        use super_imports::*;
 +
 +        fn with_explicit() {
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod use_double_super_should_be_replaced {
 +        mod inner {
 +            use super::super::*;
 +
 +            fn with_double_super() {
 +                let _ = foofoo();
 +            }
 +        }
 +    }
 +
 +    mod use_super_explicit_should_be_replaced {
 +        use super::super::super_imports::*;
 +
 +        fn with_super_explicit() {
 +            let _ = foofoo();
 +        }
 +    }
 +
 +    mod attestation_should_be_replaced {
 +        use super::*;
 +
 +        fn with_explicit() {
 +            let _ = foofoo();
 +        }
 +    }
 +}
index d7af0c046e88694f34a1ff399931fe346cc8904c,0000000000000000000000000000000000000000..7534a65ec9bd56c0878846b81663d05ef269cb92
mode 100644,000000..100644
--- /dev/null
@@@ -1,132 -1,0 +1,132 @@@
-   --> $DIR/wildcard_imports.rs:12:5
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:13:5
++  --> $DIR/wildcard_imports.rs:17:5
 +   |
 +LL | use crate::fn_mod::*;
 +   |     ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
 +   |
 +   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:14:5
++  --> $DIR/wildcard_imports.rs:18:5
 +   |
 +LL | use crate::mod_mod::*;
 +   |     ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:16:5
++  --> $DIR/wildcard_imports.rs:19:5
 +   |
 +LL | use crate::multi_fn_mod::*;
 +   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:20:5
++  --> $DIR/wildcard_imports.rs:21:5
 +   |
 +LL | use crate::struct_mod::*;
 +   |     ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:21:5
++  --> $DIR/wildcard_imports.rs:25:5
 +   |
 +LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:92:13
++  --> $DIR/wildcard_imports.rs:26:5
 +   |
 +LL | use wildcard_imports_helper::*;
 +   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:98:75
++  --> $DIR/wildcard_imports.rs:97:13
 +   |
 +LL |         use crate::fn_mod::*;
 +   |             ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:99:13
++  --> $DIR/wildcard_imports.rs:103:75
 +   |
 +LL |         use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
 +   |                                                                           ^ help: try: `inner_extern_foo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:110:20
++  --> $DIR/wildcard_imports.rs:104:13
 +   |
 +LL |         use wildcard_imports_helper::*;
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:110:30
++  --> $DIR/wildcard_imports.rs:115:20
 +   |
 +LL |         use self::{inner::*, inner2::*};
 +   |                    ^^^^^^^^ help: try: `inner::inner_foo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:117:13
++  --> $DIR/wildcard_imports.rs:115:30
 +   |
 +LL |         use self::{inner::*, inner2::*};
 +   |                              ^^^^^^^^^ help: try: `inner2::inner_bar`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:146:9
++  --> $DIR/wildcard_imports.rs:122:13
 +   |
 +LL |         use wildcard_imports_helper::*;
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:155:9
++  --> $DIR/wildcard_imports.rs:151:9
 +   |
 +LL |     use crate::in_fn_test::*;
 +   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:156:9
++  --> $DIR/wildcard_imports.rs:160:9
 +   |
 +LL |     use crate:: in_fn_test::  * ;
 +   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:167:13
++  --> $DIR/wildcard_imports.rs:161:9
 +   |
 +LL |       use crate:: fn_mod::
 +   |  _________^
 +LL | |         *;
 +   | |_________^ help: try: `crate:: fn_mod::foo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:202:17
++  --> $DIR/wildcard_imports.rs:172:13
 +   |
 +LL |         use super::*;
 +   |             ^^^^^^^^ help: try: `super::foofoo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:210:13
++  --> $DIR/wildcard_imports.rs:207:17
 +   |
 +LL |             use super::*;
 +   |                 ^^^^^^^^ help: try: `super::insidefoo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:219:17
++  --> $DIR/wildcard_imports.rs:215:13
 +   |
 +LL |         use super_imports::*;
 +   |             ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:228:13
++  --> $DIR/wildcard_imports.rs:224:17
 +   |
 +LL |             use super::super::*;
 +   |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
 +
 +error: usage of wildcard import
-   --> $DIR/wildcard_imports.rs:236:13
++  --> $DIR/wildcard_imports.rs:233:13
 +   |
 +LL |         use super::super::super_imports::*;
 +   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
 +
 +error: usage of wildcard import
++  --> $DIR/wildcard_imports.rs:241:13
 +   |
 +LL |         use super::*;
 +   |             ^^^^^^^^ help: try: `super::foofoo`
 +
 +error: aborting due to 21 previous errors
 +
index 151dd0c27d57dbab4f7b4e98f485eb3993e10b3b,0000000000000000000000000000000000000000..1b9da8a55e53fe8796ff7b92ee9b393db29b25bd
mode 100644,000000..100644
--- /dev/null
@@@ -1,191 -1,0 +1,190 @@@
- // edition:2018
 +#![warn(clippy::wrong_self_convention)]
 +#![allow(dead_code)]
 +
 +fn main() {}
 +
 +#[derive(Clone, Copy)]
 +struct Foo;
 +
 +impl Foo {
 +    fn as_i32(self) {}
 +    fn as_u32(&self) {}
 +    fn into_i32(self) {}
 +    fn is_i32(self) {}
 +    fn is_u32(&self) {}
 +    fn to_i32(self) {}
 +    fn from_i32(self) {}
 +
 +    pub fn as_i64(self) {}
 +    pub fn into_i64(self) {}
 +    pub fn is_i64(self) {}
 +    pub fn to_i64(self) {}
 +    pub fn from_i64(self) {}
 +    // check whether the lint can be allowed at the function level
 +    #[allow(clippy::wrong_self_convention)]
 +    pub fn from_cake(self) {}
 +
 +    fn as_x<F: AsRef<Self>>(_: F) {}
 +    fn as_y<F: AsRef<Foo>>(_: F) {}
 +}
 +
 +struct Bar;
 +
 +impl Bar {
 +    fn as_i32(self) {}
 +    fn as_u32(&self) {}
 +    fn into_i32(&self) {}
 +    fn into_u32(self) {}
 +    fn is_i32(self) {}
 +    fn is_u32(&self) {}
 +    fn to_i32(self) {}
 +    fn to_u32(&self) {}
 +    fn from_i32(self) {}
 +
 +    pub fn as_i64(self) {}
 +    pub fn into_i64(&self) {}
 +    pub fn is_i64(self) {}
 +    pub fn to_i64(self) {}
 +    pub fn from_i64(self) {}
 +
 +    // test for false positives
 +    fn as_(self) {}
 +    fn into_(&self) {}
 +    fn is_(self) {}
 +    fn to_(self) {}
 +    fn from_(self) {}
 +    fn to_mut(&mut self) {}
 +}
 +
 +// Allow Box<Self>, Rc<Self>, Arc<Self> for methods that take conventionally take Self by value
 +#[allow(clippy::boxed_local)]
 +mod issue4293 {
 +    use std::rc::Rc;
 +    use std::sync::Arc;
 +
 +    struct T;
 +
 +    impl T {
 +        fn into_s1(self: Box<Self>) {}
 +        fn into_s2(self: Rc<Self>) {}
 +        fn into_s3(self: Arc<Self>) {}
 +
 +        fn into_t1(self: Box<T>) {}
 +        fn into_t2(self: Rc<T>) {}
 +        fn into_t3(self: Arc<T>) {}
 +    }
 +}
 +
 +// False positive for async (see #4037)
 +mod issue4037 {
 +    pub struct Foo;
 +    pub struct Bar;
 +
 +    impl Foo {
 +        pub async fn into_bar(self) -> Bar {
 +            Bar
 +        }
 +    }
 +}
 +
 +// Lint also in trait definition (see #6307)
 +mod issue6307 {
 +    trait T: Sized {
 +        fn as_i32(self) {}
 +        fn as_u32(&self) {}
 +        fn into_i32(self) {}
 +        fn into_i32_ref(&self) {}
 +        fn into_u32(self) {}
 +        fn is_i32(self) {}
 +        fn is_u32(&self) {}
 +        fn to_i32(self) {}
 +        fn to_u32(&self) {}
 +        fn from_i32(self) {}
 +        // check whether the lint can be allowed at the function level
 +        #[allow(clippy::wrong_self_convention)]
 +        fn from_cake(self) {}
 +
 +        // test for false positives
 +        fn as_(self) {}
 +        fn into_(&self) {}
 +        fn is_(self) {}
 +        fn to_(self) {}
 +        fn from_(self) {}
 +        fn to_mut(&mut self) {}
 +    }
 +
 +    trait U {
 +        fn as_i32(self);
 +        fn as_u32(&self);
 +        fn into_i32(self);
 +        fn into_i32_ref(&self);
 +        fn into_u32(self);
 +        fn is_i32(self);
 +        fn is_u32(&self);
 +        fn to_i32(self);
 +        fn to_u32(&self);
 +        fn from_i32(self);
 +        // check whether the lint can be allowed at the function level
 +        #[allow(clippy::wrong_self_convention)]
 +        fn from_cake(self);
 +
 +        // test for false positives
 +        fn as_(self);
 +        fn into_(&self);
 +        fn is_(self);
 +        fn to_(self);
 +        fn from_(self);
 +        fn to_mut(&mut self);
 +    }
 +
 +    trait C: Copy {
 +        fn as_i32(self);
 +        fn as_u32(&self);
 +        fn into_i32(self);
 +        fn into_i32_ref(&self);
 +        fn into_u32(self);
 +        fn is_i32(self);
 +        fn is_u32(&self);
 +        fn to_i32(self);
 +        fn to_u32(&self);
 +        fn from_i32(self);
 +        // check whether the lint can be allowed at the function level
 +        #[allow(clippy::wrong_self_convention)]
 +        fn from_cake(self);
 +
 +        // test for false positives
 +        fn as_(self);
 +        fn into_(&self);
 +        fn is_(self);
 +        fn to_(self);
 +        fn from_(self);
 +        fn to_mut(&mut self);
 +    }
 +}
 +
 +mod issue6727 {
 +    #[derive(Clone, Copy)]
 +    struct FooCopy;
 +
 +    impl FooCopy {
 +        fn to_u64(self) -> u64 {
 +            1
 +        }
 +        // trigger lint
 +        fn to_u64_v2(&self) -> u64 {
 +            1
 +        }
 +    }
 +
 +    struct FooNoCopy;
 +
 +    impl FooNoCopy {
 +        // trigger lint
 +        fn to_u64(self) -> u64 {
 +            2
 +        }
 +        fn to_u64_v2(&self) -> u64 {
 +            2
 +        }
 +    }
 +}
index ce23317abf651f59f66ca971aeb15e1520355cfa,0000000000000000000000000000000000000000..590ee6d9c529d6493b8e29b755c2d3e07f982b2b
mode 100644,000000..100644
--- /dev/null
@@@ -1,195 -1,0 +1,195 @@@
-   --> $DIR/wrong_self_convention.rs:17:17
 +error: methods called `from_*` usually take no `self`
-   --> $DIR/wrong_self_convention.rs:23:21
++  --> $DIR/wrong_self_convention.rs:16:17
 +   |
 +LL |     fn from_i32(self) {}
 +   |                 ^^^^
 +   |
 +   = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `from_*` usually take no `self`
-   --> $DIR/wrong_self_convention.rs:35:15
++  --> $DIR/wrong_self_convention.rs:22:21
 +   |
 +LL |     pub fn from_i64(self) {}
 +   |                     ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-   --> $DIR/wrong_self_convention.rs:37:17
++  --> $DIR/wrong_self_convention.rs:34:15
 +   |
 +LL |     fn as_i32(self) {}
 +   |               ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `into_*` usually take `self` by value
-   --> $DIR/wrong_self_convention.rs:39:15
++  --> $DIR/wrong_self_convention.rs:36:17
 +   |
 +LL |     fn into_i32(&self) {}
 +   |                 ^^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `is_*` usually take `self` by reference or no `self`
-   --> $DIR/wrong_self_convention.rs:41:15
++  --> $DIR/wrong_self_convention.rs:38:15
 +   |
 +LL |     fn is_i32(self) {}
 +   |               ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-   --> $DIR/wrong_self_convention.rs:43:17
++  --> $DIR/wrong_self_convention.rs:40:15
 +   |
 +LL |     fn to_i32(self) {}
 +   |               ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `from_*` usually take no `self`
-   --> $DIR/wrong_self_convention.rs:45:19
++  --> $DIR/wrong_self_convention.rs:42:17
 +   |
 +LL |     fn from_i32(self) {}
 +   |                 ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-   --> $DIR/wrong_self_convention.rs:46:21
++  --> $DIR/wrong_self_convention.rs:44:19
 +   |
 +LL |     pub fn as_i64(self) {}
 +   |                   ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `into_*` usually take `self` by value
-   --> $DIR/wrong_self_convention.rs:47:19
++  --> $DIR/wrong_self_convention.rs:45:21
 +   |
 +LL |     pub fn into_i64(&self) {}
 +   |                     ^^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `is_*` usually take `self` by reference or no `self`
-   --> $DIR/wrong_self_convention.rs:48:19
++  --> $DIR/wrong_self_convention.rs:46:19
 +   |
 +LL |     pub fn is_i64(self) {}
 +   |                   ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-   --> $DIR/wrong_self_convention.rs:49:21
++  --> $DIR/wrong_self_convention.rs:47:19
 +   |
 +LL |     pub fn to_i64(self) {}
 +   |                   ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `from_*` usually take no `self`
-   --> $DIR/wrong_self_convention.rs:94:19
++  --> $DIR/wrong_self_convention.rs:48:21
 +   |
 +LL |     pub fn from_i64(self) {}
 +   |                     ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-   --> $DIR/wrong_self_convention.rs:97:25
++  --> $DIR/wrong_self_convention.rs:93:19
 +   |
 +LL |         fn as_i32(self) {}
 +   |                   ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `into_*` usually take `self` by value
-   --> $DIR/wrong_self_convention.rs:99:19
++  --> $DIR/wrong_self_convention.rs:96:25
 +   |
 +LL |         fn into_i32_ref(&self) {}
 +   |                         ^^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `is_*` usually take `self` by reference or no `self`
-   --> $DIR/wrong_self_convention.rs:103:21
++  --> $DIR/wrong_self_convention.rs:98:19
 +   |
 +LL |         fn is_i32(self) {}
 +   |                   ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `from_*` usually take no `self`
-   --> $DIR/wrong_self_convention.rs:118:19
++  --> $DIR/wrong_self_convention.rs:102:21
 +   |
 +LL |         fn from_i32(self) {}
 +   |                     ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-   --> $DIR/wrong_self_convention.rs:121:25
++  --> $DIR/wrong_self_convention.rs:117:19
 +   |
 +LL |         fn as_i32(self);
 +   |                   ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `into_*` usually take `self` by value
-   --> $DIR/wrong_self_convention.rs:123:19
++  --> $DIR/wrong_self_convention.rs:120:25
 +   |
 +LL |         fn into_i32_ref(&self);
 +   |                         ^^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `is_*` usually take `self` by reference or no `self`
-   --> $DIR/wrong_self_convention.rs:127:21
++  --> $DIR/wrong_self_convention.rs:122:19
 +   |
 +LL |         fn is_i32(self);
 +   |                   ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `from_*` usually take no `self`
-   --> $DIR/wrong_self_convention.rs:145:25
++  --> $DIR/wrong_self_convention.rs:126:21
 +   |
 +LL |         fn from_i32(self);
 +   |                     ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `into_*` usually take `self` by value
-   --> $DIR/wrong_self_convention.rs:151:21
++  --> $DIR/wrong_self_convention.rs:144:25
 +   |
 +LL |         fn into_i32_ref(&self);
 +   |                         ^^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `from_*` usually take no `self`
-   --> $DIR/wrong_self_convention.rs:175:22
++  --> $DIR/wrong_self_convention.rs:150:21
 +   |
 +LL |         fn from_i32(self);
 +   |                     ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value
-   --> $DIR/wrong_self_convention.rs:184:19
++  --> $DIR/wrong_self_convention.rs:174:22
 +   |
 +LL |         fn to_u64_v2(&self) -> u64 {
 +   |                      ^^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
++  --> $DIR/wrong_self_convention.rs:183:19
 +   |
 +LL |         fn to_u64(self) -> u64 {
 +   |                   ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: aborting due to 24 previous errors
 +
index 0d827c1feb3e722c4842684a441f6386ee2f2eb5,0000000000000000000000000000000000000000..a8fe8331133778ebcf934b4b234c07c430f484c9
mode 100644,000000..100644
--- /dev/null
@@@ -1,107 -1,0 +1,106 @@@
- // edition:2018
 +#![warn(clippy::wrong_self_convention)]
 +#![allow(dead_code)]
 +
 +fn main() {}
 +
 +mod issue6983 {
 +    pub struct Thing;
 +    pub trait Trait {
 +        fn to_thing(&self) -> Thing;
 +    }
 +
 +    impl Trait for u8 {
 +        // don't trigger, e.g. `ToString` from `std` requires `&self`
 +        fn to_thing(&self) -> Thing {
 +            Thing
 +        }
 +    }
 +
 +    trait ToU64 {
 +        fn to_u64(self) -> u64;
 +    }
 +
 +    struct FooNoCopy;
 +    // don't trigger
 +    impl ToU64 for FooNoCopy {
 +        fn to_u64(self) -> u64 {
 +            2
 +        }
 +    }
 +}
 +
 +mod issue7032 {
 +    trait Foo {
 +        fn from_usize(x: usize) -> Self;
 +    }
 +    // don't trigger
 +    impl Foo for usize {
 +        fn from_usize(x: usize) -> Self {
 +            x
 +        }
 +    }
 +}
 +
 +mod issue7179 {
 +    pub struct S(i32);
 +
 +    impl S {
 +        // don't trigger (`s` is not `self`)
 +        pub fn from_be(s: Self) -> Self {
 +            S(i32::from_be(s.0))
 +        }
 +
 +        // lint
 +        pub fn from_be_self(self) -> Self {
 +            S(i32::from_be(self.0))
 +        }
 +    }
 +
 +    trait T {
 +        // don't trigger (`s` is not `self`)
 +        fn from_be(s: Self) -> Self;
 +        // lint
 +        fn from_be_self(self) -> Self;
 +    }
 +
 +    trait Foo: Sized {
 +        fn as_byte_slice(slice: &[Self]) -> &[u8];
 +    }
 +}
 +
 +mod issue3414 {
 +    struct CellLikeThing<T>(T);
 +
 +    impl<T> CellLikeThing<T> {
 +        // don't trigger
 +        fn into_inner(this: Self) -> T {
 +            this.0
 +        }
 +    }
 +
 +    impl<T> std::ops::Deref for CellLikeThing<T> {
 +        type Target = T;
 +
 +        fn deref(&self) -> &T {
 +            &self.0
 +        }
 +    }
 +}
 +
 +// don't trigger
 +mod issue4546 {
 +    use std::pin::Pin;
 +
 +    struct S;
 +    impl S {
 +        pub fn as_mut(self: Pin<&mut Self>) {}
 +
 +        pub fn as_other_thingy(self: Pin<&Self>) {}
 +
 +        pub fn is_other_thingy(self: Pin<&Self>) {}
 +
 +        pub fn to_mut(self: Pin<&mut Self>) {}
 +
 +        pub fn to_other_thingy(self: Pin<&Self>) {}
 +    }
 +}
index 0e0d066d656b56a174ff00a9190927ca16abbf70,0000000000000000000000000000000000000000..5bdc47f91f65b42b1376b18a7a661926c6d3805b
mode 100644,000000..100644
--- /dev/null
@@@ -1,19 -1,0 +1,19 @@@
-   --> $DIR/wrong_self_convention2.rs:55:29
 +error: methods called `from_*` usually take no `self`
-   --> $DIR/wrong_self_convention2.rs:64:25
++  --> $DIR/wrong_self_convention2.rs:54:29
 +   |
 +LL |         pub fn from_be_self(self) -> Self {
 +   |                             ^^^^
 +   |
 +   = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods called `from_*` usually take no `self`
++  --> $DIR/wrong_self_convention2.rs:63:25
 +   |
 +LL |         fn from_be_self(self) -> Self;
 +   |                         ^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: aborting due to 2 previous errors
 +
index 486a0d772358531ca75e14eea62e41547ad294dd,0000000000000000000000000000000000000000..5bb2116bd339af9ef01ddc281abb2d70416a5610
mode 100644,000000..100644
--- /dev/null
@@@ -1,30 -1,0 +1,29 @@@
- // edition:2018
 +#![warn(clippy::wrong_self_convention)]
 +#![allow(dead_code)]
 +
 +fn main() {}
 +
 +mod issue6758 {
 +    pub enum Test<T> {
 +        One(T),
 +        Many(Vec<T>),
 +    }
 +
 +    impl<T> Test<T> {
 +        // If a method starts with `to_` and not ends with `_mut` it should expect `&self`
 +        pub fn to_many(&mut self) -> Option<&mut [T]> {
 +            match self {
 +                Self::Many(data) => Some(data),
 +                _ => None,
 +            }
 +        }
 +
 +        // If a method starts with `to_` and ends with `_mut` it should expect `&mut self`
 +        pub fn to_many_mut(&self) -> Option<&[T]> {
 +            match self {
 +                Self::Many(data) => Some(data),
 +                _ => None,
 +            }
 +        }
 +    }
 +}
index 6ce37c5949111bf20d20b66ffc00ad6170029a69,0000000000000000000000000000000000000000..8665d8dc9a9dea4f7b1ed03b3b5a26084fdf11d3
mode 100644,000000..100644
--- /dev/null
@@@ -1,19 -1,0 +1,19 @@@
-   --> $DIR/wrong_self_conventions_mut.rs:15:24
 +error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-   --> $DIR/wrong_self_conventions_mut.rs:23:28
++  --> $DIR/wrong_self_conventions_mut.rs:14:24
 +   |
 +LL |         pub fn to_many(&mut self) -> Option<&mut [T]> {
 +   |                        ^^^^^^^^^
 +   |
 +   = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
 +   = help: consider choosing a less ambiguous name
 +
 +error: methods with the following characteristics: (`to_*` and `*_mut`) usually take `self` by mutable reference
++  --> $DIR/wrong_self_conventions_mut.rs:22:28
 +   |
 +LL |         pub fn to_many_mut(&self) -> Option<&[T]> {
 +   |                            ^^^^^
 +   |
 +   = help: consider choosing a less ambiguous name
 +
 +error: aborting due to 2 previous errors
 +