summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:11:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:11:28 +0000
commit94a0819fe3a0d679c3042a77bfe6a2afc505daea (patch)
tree2b827afe6a05f3538db3f7803a88c4587fe85648 /src/tools/clippy
parentAdding upstream version 1.64.0+dfsg1. (diff)
downloadrustc-94a0819fe3a0d679c3042a77bfe6a2afc505daea.tar.xz
rustc-94a0819fe3a0d679c3042a77bfe6a2afc505daea.zip
Adding upstream version 1.66.0+dfsg1.upstream/1.66.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/clippy')
-rw-r--r--src/tools/clippy/.github/workflows/clippy.yml2
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml2
-rw-r--r--src/tools/clippy/.github/workflows/clippy_dev.yml2
-rw-r--r--src/tools/clippy/CHANGELOG.md333
-rw-r--r--src/tools/clippy/CONTRIBUTING.md33
-rw-r--r--src/tools/clippy/Cargo.toml8
-rw-r--r--src/tools/clippy/README.md46
-rw-r--r--src/tools/clippy/book/src/configuration.md2
-rw-r--r--src/tools/clippy/book/src/development/adding_lints.md24
-rw-r--r--src/tools/clippy/book/src/development/basics.md7
-rw-r--r--src/tools/clippy/book/src/development/common_tools_writing_lints.md17
-rw-r--r--src/tools/clippy/clippy_dev/src/bless.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/fmt.rs14
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs1
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs176
-rw-r--r--src/tools/clippy/clippy_dev/src/serve.rs6
-rw-r--r--src/tools/clippy/clippy_dev/src/setup/git_hook.rs7
-rw-r--r--src/tools/clippy/clippy_dev/src/setup/intellij.rs42
-rw-r--r--src/tools/clippy/clippy_dev/src/setup/vscode.rs19
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs311
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/approx_const.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/as_underscore.rs74
-rw-r--r--src/tools/clippy/clippy_lints/src/asm_syntax.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_constants.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/async_yields_async.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs71
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs121
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs99
-rw-r--r--src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs129
-rw-r--r--src/tools/clippy/clippy_lints/src/bytecount.rs103
-rw-r--r--src/tools/clippy/clippy_lints/src/bytes_count_to_len.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/feature_name.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs86
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/as_underscore.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs63
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs164
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs73
-rw-r--r--src/tools/clippy/clippy_lints/src/checked_conversions.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/comparison_chain.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/copy_iterator.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/create_dir.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs73
-rw-r--r--src/tools/clippy/clippy_lints/src/default_union_representation.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs857
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_macros.rs151
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_methods.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_names.rs (renamed from src/tools/clippy/clippy_lints/src/blacklisted_name.rs)26
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_types.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs110
-rw-r--r--src/tools/clippy/clippy_lints/src/doc_link_with_quotes.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/double_parens.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_forget_ref.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/duplicate_mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_enum.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_variants.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/exhaustive_items.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/exit.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/explicit_write.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs168
-rw-r--r--src/tools/clippy/clippy_lints/src/format.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs372
-rw-r--r--src/tools/clippy/clippy_lints/src/format_impl.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/format_push_string.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/formatting.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs176
-rw-r--r--src/tools/clippy/clippy_lints/src/from_str_radix_10.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs56
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs126
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs94
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/result.rs100
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/get_first.rs68
-rw-r--r--src/tools/clippy/clippy_lints/src/if_let_mutex.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs91
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_return.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs114
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs117
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/int_plus_one.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs97
-rw-r--r--src/tools/clippy/clippy_lints/src/large_stack_arrays.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs69
-rw-r--r--src/tools/clippy/clippy_lints/src/let_if_seq.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_all.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_complexity.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_correctness.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_internal.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_lints.rs105
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_nursery.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_perf.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_restriction.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_style.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs536
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs65
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_find.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_collect.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_assert.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_bits.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_clamp.rs717
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs69
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_ok_or.rs98
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs40
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_string_new.rs135
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/map_clone.rs167
-rw-r--r--src/tools/clippy/clippy_lints/src/map_err_ignore.rs154
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/match_result_ok.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_filter.rs153
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_map.rs318
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_utils.rs277
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/needless_match.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs113
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/try_err.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_replace.rs78
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytecount.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs96
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/err_expect.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_used.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_next.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_first.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_count.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs87
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_nth.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs92
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_clone.rs121
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_flatten.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_identity.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs1113
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/ok_expect.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/open_options.rs (renamed from src/tools/clippy/clippy_lints/src/open_options.rs)54
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/repeat_once.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/search_is_some.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unit_hash.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs82
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs (renamed from src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs)162
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs250
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/useless_asref.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/utils.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mod.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_trait_methods.rs98
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/module_style.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/multi_assignments.rs65
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/mutex_atomic.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs121
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_continue.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_late_init.rs57
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_multiply.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs83
-rw-r--r--src/tools/clippy/clippy_lints/src/octal_escapes.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs823
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic.rs119
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs198
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs83
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/bit_mask.rs40
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/eq_op.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_cmp.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/op_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/self_assignment.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/option_env_unwrap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs173
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/partial_pub_fields.rs81
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_to_none.rs104
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs74
-rw-r--r--src/tools/clippy/clippy_lints/src/precedence.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs81
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs100
-rw-r--r--src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs462
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/ref_option_ref.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/repeat_once.rs89
-rw-r--r--src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs222
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/self_named_constructors.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs145
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/to_digit_is_some.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/trailing_empty_array.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs111
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs476
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/utils.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmuting_null.rs89
-rw-r--r--src/tools/clippy/clippy_lints/src/types/borrowed_box.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/types/box_collection.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/types/rc_buffer.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs55
-rw-r--r--src/tools/clippy/clippy_lints/src/types/vec_box.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unicode.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/uninit_vec.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_hash.rs78
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_peekable.rs232
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_rounding.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_self.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_unit.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap_in_result.rs72
-rw-r--r--src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs148
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs100
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs1446
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs245
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs77
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs164
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs239
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs108
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs342
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs115
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs63
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs343
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/verbose_file_reads.rs88
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs665
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_div_zero.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs7
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml3
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/attrs.rs8
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs329
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs64
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs59
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs30
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs43
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs379
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs894
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs52
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/mod.rs164
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs241
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_origin.rs59
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/transitive_relation.rs29
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs7
-rw-r--r--src/tools/clippy/clippy_utils/src/numeric_literal.rs17
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs45
-rw-r--r--src/tools/clippy/clippy_utils/src/ptr.rs37
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs54
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs36
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs140
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs189
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs77
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs173
-rw-r--r--src/tools/clippy/lintcheck/Cargo.toml2
-rw-r--r--src/tools/clippy/lintcheck/README.md20
-rw-r--r--src/tools/clippy/lintcheck/lintcheck_crates.toml10
-rw-r--r--src/tools/clippy/lintcheck/src/config.rs15
-rw-r--r--src/tools/clippy/lintcheck/src/driver.rs67
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs320
-rw-r--r--src/tools/clippy/lintcheck/src/recursive.rs123
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/rustc_tools_util/Cargo.toml2
-rw-r--r--src/tools/clippy/rustc_tools_util/README.md8
-rw-r--r--src/tools/clippy/rustc_tools_util/src/lib.rs16
-rw-r--r--src/tools/clippy/src/docs.rs606
-rw-r--r--src/tools/clippy/src/docs/absurd_extreme_comparisons.txt25
-rw-r--r--src/tools/clippy/src/docs/alloc_instead_of_core.txt18
-rw-r--r--src/tools/clippy/src/docs/allow_attributes_without_reason.txt22
-rw-r--r--src/tools/clippy/src/docs/almost_complete_letter_range.txt15
-rw-r--r--src/tools/clippy/src/docs/almost_swapped.txt15
-rw-r--r--src/tools/clippy/src/docs/approx_constant.txt24
-rw-r--r--src/tools/clippy/src/docs/arithmetic_side_effects.txt33
-rw-r--r--src/tools/clippy/src/docs/as_conversions.txt32
-rw-r--r--src/tools/clippy/src/docs/as_ptr_cast_mut.txt19
-rw-r--r--src/tools/clippy/src/docs/as_underscore.txt21
-rw-r--r--src/tools/clippy/src/docs/assertions_on_constants.txt14
-rw-r--r--src/tools/clippy/src/docs/assertions_on_result_states.txt14
-rw-r--r--src/tools/clippy/src/docs/assign_op_pattern.txt28
-rw-r--r--src/tools/clippy/src/docs/async_yields_async.txt28
-rw-r--r--src/tools/clippy/src/docs/await_holding_invalid_type.txt29
-rw-r--r--src/tools/clippy/src/docs/await_holding_lock.txt51
-rw-r--r--src/tools/clippy/src/docs/await_holding_refcell_ref.txt47
-rw-r--r--src/tools/clippy/src/docs/bad_bit_mask.txt30
-rw-r--r--src/tools/clippy/src/docs/bind_instead_of_map.txt22
-rw-r--r--src/tools/clippy/src/docs/blanket_clippy_restriction_lints.txt16
-rw-r--r--src/tools/clippy/src/docs/blocks_in_if_conditions.txt21
-rw-r--r--src/tools/clippy/src/docs/bool_assert_comparison.txt16
-rw-r--r--src/tools/clippy/src/docs/bool_comparison.txt18
-rw-r--r--src/tools/clippy/src/docs/bool_to_int_with_if.txt26
-rw-r--r--src/tools/clippy/src/docs/borrow_as_ptr.txt26
-rw-r--r--src/tools/clippy/src/docs/borrow_deref_ref.txt27
-rw-r--r--src/tools/clippy/src/docs/borrow_interior_mutable_const.txt40
-rw-r--r--src/tools/clippy/src/docs/borrowed_box.txt19
-rw-r--r--src/tools/clippy/src/docs/box_collection.txt23
-rw-r--r--src/tools/clippy/src/docs/box_default.txt17
-rw-r--r--src/tools/clippy/src/docs/boxed_local.txt18
-rw-r--r--src/tools/clippy/src/docs/branches_sharing_code.txt32
-rw-r--r--src/tools/clippy/src/docs/builtin_type_shadow.txt15
-rw-r--r--src/tools/clippy/src/docs/bytes_count_to_len.txt18
-rw-r--r--src/tools/clippy/src/docs/bytes_nth.txt16
-rw-r--r--src/tools/clippy/src/docs/cargo_common_metadata.txt33
-rw-r--r--src/tools/clippy/src/docs/case_sensitive_file_extension_comparisons.txt21
-rw-r--r--src/tools/clippy/src/docs/cast_abs_to_unsigned.txt16
-rw-r--r--src/tools/clippy/src/docs/cast_enum_constructor.txt11
-rw-r--r--src/tools/clippy/src/docs/cast_enum_truncation.txt12
-rw-r--r--src/tools/clippy/src/docs/cast_lossless.txt26
-rw-r--r--src/tools/clippy/src/docs/cast_nan_to_int.txt15
-rw-r--r--src/tools/clippy/src/docs/cast_possible_truncation.txt16
-rw-r--r--src/tools/clippy/src/docs/cast_possible_wrap.txt17
-rw-r--r--src/tools/clippy/src/docs/cast_precision_loss.txt19
-rw-r--r--src/tools/clippy/src/docs/cast_ptr_alignment.txt21
-rw-r--r--src/tools/clippy/src/docs/cast_ref_to_mut.txt28
-rw-r--r--src/tools/clippy/src/docs/cast_sign_loss.txt15
-rw-r--r--src/tools/clippy/src/docs/cast_slice_different_sizes.txt38
-rw-r--r--src/tools/clippy/src/docs/cast_slice_from_raw_parts.txt20
-rw-r--r--src/tools/clippy/src/docs/char_lit_as_u8.txt21
-rw-r--r--src/tools/clippy/src/docs/chars_last_cmp.txt17
-rw-r--r--src/tools/clippy/src/docs/chars_next_cmp.txt19
-rw-r--r--src/tools/clippy/src/docs/checked_conversions.txt15
-rw-r--r--src/tools/clippy/src/docs/clone_double_ref.txt16
-rw-r--r--src/tools/clippy/src/docs/clone_on_copy.txt11
-rw-r--r--src/tools/clippy/src/docs/clone_on_ref_ptr.txt21
-rw-r--r--src/tools/clippy/src/docs/cloned_instead_of_copied.txt16
-rw-r--r--src/tools/clippy/src/docs/cmp_nan.txt16
-rw-r--r--src/tools/clippy/src/docs/cmp_null.txt23
-rw-r--r--src/tools/clippy/src/docs/cmp_owned.txt18
-rw-r--r--src/tools/clippy/src/docs/cognitive_complexity.txt13
-rw-r--r--src/tools/clippy/src/docs/collapsible_else_if.txt29
-rw-r--r--src/tools/clippy/src/docs/collapsible_if.txt23
-rw-r--r--src/tools/clippy/src/docs/collapsible_match.txt31
-rw-r--r--src/tools/clippy/src/docs/collapsible_str_replace.txt19
-rw-r--r--src/tools/clippy/src/docs/comparison_chain.txt36
-rw-r--r--src/tools/clippy/src/docs/comparison_to_empty.txt31
-rw-r--r--src/tools/clippy/src/docs/copy_iterator.txt20
-rw-r--r--src/tools/clippy/src/docs/crate_in_macro_def.txt35
-rw-r--r--src/tools/clippy/src/docs/create_dir.txt15
-rw-r--r--src/tools/clippy/src/docs/crosspointer_transmute.txt12
-rw-r--r--src/tools/clippy/src/docs/dbg_macro.txt16
-rw-r--r--src/tools/clippy/src/docs/debug_assert_with_mut_call.txt18
-rw-r--r--src/tools/clippy/src/docs/decimal_literal_representation.txt13
-rw-r--r--src/tools/clippy/src/docs/declare_interior_mutable_const.txt46
-rw-r--r--src/tools/clippy/src/docs/default_instead_of_iter_empty.txt15
-rw-r--r--src/tools/clippy/src/docs/default_numeric_fallback.txt28
-rw-r--r--src/tools/clippy/src/docs/default_trait_access.txt16
-rw-r--r--src/tools/clippy/src/docs/default_union_representation.txt36
-rw-r--r--src/tools/clippy/src/docs/deprecated_cfg_attr.txt24
-rw-r--r--src/tools/clippy/src/docs/deprecated_semver.txt13
-rw-r--r--src/tools/clippy/src/docs/deref_addrof.txt22
-rw-r--r--src/tools/clippy/src/docs/deref_by_slicing.txt17
-rw-r--r--src/tools/clippy/src/docs/derivable_impls.txt35
-rw-r--r--src/tools/clippy/src/docs/derive_hash_xor_eq.txt23
-rw-r--r--src/tools/clippy/src/docs/derive_ord_xor_partial_ord.txt44
-rw-r--r--src/tools/clippy/src/docs/derive_partial_eq_without_eq.txt25
-rw-r--r--src/tools/clippy/src/docs/disallowed_macros.txt36
-rw-r--r--src/tools/clippy/src/docs/disallowed_methods.txt41
-rw-r--r--src/tools/clippy/src/docs/disallowed_names.txt12
-rw-r--r--src/tools/clippy/src/docs/disallowed_script_idents.txt32
-rw-r--r--src/tools/clippy/src/docs/disallowed_types.txt33
-rw-r--r--src/tools/clippy/src/docs/diverging_sub_expression.txt19
-rw-r--r--src/tools/clippy/src/docs/doc_link_with_quotes.txt16
-rw-r--r--src/tools/clippy/src/docs/doc_markdown.txt35
-rw-r--r--src/tools/clippy/src/docs/double_comparisons.txt17
-rw-r--r--src/tools/clippy/src/docs/double_must_use.txt17
-rw-r--r--src/tools/clippy/src/docs/double_neg.txt12
-rw-r--r--src/tools/clippy/src/docs/double_parens.txt24
-rw-r--r--src/tools/clippy/src/docs/drop_copy.txt15
-rw-r--r--src/tools/clippy/src/docs/drop_non_drop.txt13
-rw-r--r--src/tools/clippy/src/docs/drop_ref.txt17
-rw-r--r--src/tools/clippy/src/docs/duplicate_mod.txt31
-rw-r--r--src/tools/clippy/src/docs/duplicate_underscore_argument.txt16
-rw-r--r--src/tools/clippy/src/docs/duration_subsec.txt19
-rw-r--r--src/tools/clippy/src/docs/else_if_without_else.txt27
-rw-r--r--src/tools/clippy/src/docs/empty_drop.txt20
-rw-r--r--src/tools/clippy/src/docs/empty_enum.txt27
-rw-r--r--src/tools/clippy/src/docs/empty_line_after_outer_attr.txt35
-rw-r--r--src/tools/clippy/src/docs/empty_loop.txt27
-rw-r--r--src/tools/clippy/src/docs/empty_structs_with_brackets.txt14
-rw-r--r--src/tools/clippy/src/docs/enum_clike_unportable_variant.txt16
-rw-r--r--src/tools/clippy/src/docs/enum_glob_use.txt24
-rw-r--r--src/tools/clippy/src/docs/enum_variant_names.txt30
-rw-r--r--src/tools/clippy/src/docs/eq_op.txt22
-rw-r--r--src/tools/clippy/src/docs/equatable_if_let.txt23
-rw-r--r--src/tools/clippy/src/docs/erasing_op.txt15
-rw-r--r--src/tools/clippy/src/docs/err_expect.txt16
-rw-r--r--src/tools/clippy/src/docs/excessive_precision.txt18
-rw-r--r--src/tools/clippy/src/docs/exhaustive_enums.txt23
-rw-r--r--src/tools/clippy/src/docs/exhaustive_structs.txt23
-rw-r--r--src/tools/clippy/src/docs/exit.txt12
-rw-r--r--src/tools/clippy/src/docs/expect_fun_call.txt24
-rw-r--r--src/tools/clippy/src/docs/expect_used.txt26
-rw-r--r--src/tools/clippy/src/docs/expl_impl_clone_on_copy.txt20
-rw-r--r--src/tools/clippy/src/docs/explicit_auto_deref.txt16
-rw-r--r--src/tools/clippy/src/docs/explicit_counter_loop.txt21
-rw-r--r--src/tools/clippy/src/docs/explicit_deref_methods.txt24
-rw-r--r--src/tools/clippy/src/docs/explicit_into_iter_loop.txt20
-rw-r--r--src/tools/clippy/src/docs/explicit_iter_loop.txt25
-rw-r--r--src/tools/clippy/src/docs/explicit_write.txt18
-rw-r--r--src/tools/clippy/src/docs/extend_with_drain.txt21
-rw-r--r--src/tools/clippy/src/docs/extra_unused_lifetimes.txt23
-rw-r--r--src/tools/clippy/src/docs/fallible_impl_from.txt32
-rw-r--r--src/tools/clippy/src/docs/field_reassign_with_default.txt23
-rw-r--r--src/tools/clippy/src/docs/filetype_is_file.txt29
-rw-r--r--src/tools/clippy/src/docs/filter_map_identity.txt14
-rw-r--r--src/tools/clippy/src/docs/filter_map_next.txt16
-rw-r--r--src/tools/clippy/src/docs/filter_next.txt16
-rw-r--r--src/tools/clippy/src/docs/flat_map_identity.txt14
-rw-r--r--src/tools/clippy/src/docs/flat_map_option.txt16
-rw-r--r--src/tools/clippy/src/docs/float_arithmetic.txt11
-rw-r--r--src/tools/clippy/src/docs/float_cmp.txt28
-rw-r--r--src/tools/clippy/src/docs/float_cmp_const.txt26
-rw-r--r--src/tools/clippy/src/docs/float_equality_without_abs.txt26
-rw-r--r--src/tools/clippy/src/docs/fn_address_comparisons.txt17
-rw-r--r--src/tools/clippy/src/docs/fn_params_excessive_bools.txt31
-rw-r--r--src/tools/clippy/src/docs/fn_to_numeric_cast.txt21
-rw-r--r--src/tools/clippy/src/docs/fn_to_numeric_cast_any.txt35
-rw-r--r--src/tools/clippy/src/docs/fn_to_numeric_cast_with_truncation.txt26
-rw-r--r--src/tools/clippy/src/docs/for_kv_map.txt22
-rw-r--r--src/tools/clippy/src/docs/forget_copy.txt21
-rw-r--r--src/tools/clippy/src/docs/forget_non_drop.txt13
-rw-r--r--src/tools/clippy/src/docs/forget_ref.txt15
-rw-r--r--src/tools/clippy/src/docs/format_in_format_args.txt16
-rw-r--r--src/tools/clippy/src/docs/format_push_string.txt26
-rw-r--r--src/tools/clippy/src/docs/from_iter_instead_of_collect.txt24
-rw-r--r--src/tools/clippy/src/docs/from_over_into.txt26
-rw-r--r--src/tools/clippy/src/docs/from_str_radix_10.txt25
-rw-r--r--src/tools/clippy/src/docs/future_not_send.txt29
-rw-r--r--src/tools/clippy/src/docs/get_first.txt19
-rw-r--r--src/tools/clippy/src/docs/get_last_with_len.txt26
-rw-r--r--src/tools/clippy/src/docs/get_unwrap.txt30
-rw-r--r--src/tools/clippy/src/docs/identity_op.txt11
-rw-r--r--src/tools/clippy/src/docs/if_let_mutex.txt25
-rw-r--r--src/tools/clippy/src/docs/if_not_else.txt25
-rw-r--r--src/tools/clippy/src/docs/if_same_then_else.txt15
-rw-r--r--src/tools/clippy/src/docs/if_then_some_else_none.txt26
-rw-r--r--src/tools/clippy/src/docs/ifs_same_cond.txt25
-rw-r--r--src/tools/clippy/src/docs/implicit_clone.txt19
-rw-r--r--src/tools/clippy/src/docs/implicit_hasher.txt26
-rw-r--r--src/tools/clippy/src/docs/implicit_return.txt22
-rw-r--r--src/tools/clippy/src/docs/implicit_saturating_add.txt20
-rw-r--r--src/tools/clippy/src/docs/implicit_saturating_sub.txt21
-rw-r--r--src/tools/clippy/src/docs/imprecise_flops.txt23
-rw-r--r--src/tools/clippy/src/docs/inconsistent_digit_grouping.txt17
-rw-r--r--src/tools/clippy/src/docs/inconsistent_struct_constructor.txt40
-rw-r--r--src/tools/clippy/src/docs/index_refutable_slice.txt29
-rw-r--r--src/tools/clippy/src/docs/indexing_slicing.txt33
-rw-r--r--src/tools/clippy/src/docs/ineffective_bit_mask.txt25
-rw-r--r--src/tools/clippy/src/docs/inefficient_to_string.txt17
-rw-r--r--src/tools/clippy/src/docs/infallible_destructuring_match.txt29
-rw-r--r--src/tools/clippy/src/docs/infinite_iter.txt13
-rw-r--r--src/tools/clippy/src/docs/inherent_to_string.txt29
-rw-r--r--src/tools/clippy/src/docs/inherent_to_string_shadow_display.txt37
-rw-r--r--src/tools/clippy/src/docs/init_numbered_fields.txt24
-rw-r--r--src/tools/clippy/src/docs/inline_always.txt23
-rw-r--r--src/tools/clippy/src/docs/inline_asm_x86_att_syntax.txt16
-rw-r--r--src/tools/clippy/src/docs/inline_asm_x86_intel_syntax.txt16
-rw-r--r--src/tools/clippy/src/docs/inline_fn_without_body.txt14
-rw-r--r--src/tools/clippy/src/docs/inspect_for_each.txt23
-rw-r--r--src/tools/clippy/src/docs/int_plus_one.txt15
-rw-r--r--src/tools/clippy/src/docs/integer_arithmetic.txt18
-rw-r--r--src/tools/clippy/src/docs/integer_division.txt19
-rw-r--r--src/tools/clippy/src/docs/into_iter_on_ref.txt18
-rw-r--r--src/tools/clippy/src/docs/invalid_null_ptr_usage.txt16
-rw-r--r--src/tools/clippy/src/docs/invalid_regex.txt12
-rw-r--r--src/tools/clippy/src/docs/invalid_upcast_comparisons.txt18
-rw-r--r--src/tools/clippy/src/docs/invalid_utf8_in_unchecked.txt12
-rw-r--r--src/tools/clippy/src/docs/invisible_characters.txt10
-rw-r--r--src/tools/clippy/src/docs/is_digit_ascii_radix.txt20
-rw-r--r--src/tools/clippy/src/docs/items_after_statements.txt37
-rw-r--r--src/tools/clippy/src/docs/iter_cloned_collect.txt17
-rw-r--r--src/tools/clippy/src/docs/iter_count.txt22
-rw-r--r--src/tools/clippy/src/docs/iter_kv_map.txt22
-rw-r--r--src/tools/clippy/src/docs/iter_next_loop.txt17
-rw-r--r--src/tools/clippy/src/docs/iter_next_slice.txt16
-rw-r--r--src/tools/clippy/src/docs/iter_not_returning_iterator.txt26
-rw-r--r--src/tools/clippy/src/docs/iter_nth.txt20
-rw-r--r--src/tools/clippy/src/docs/iter_nth_zero.txt17
-rw-r--r--src/tools/clippy/src/docs/iter_on_empty_collections.txt25
-rw-r--r--src/tools/clippy/src/docs/iter_on_single_items.txt24
-rw-r--r--src/tools/clippy/src/docs/iter_overeager_cloned.txt22
-rw-r--r--src/tools/clippy/src/docs/iter_skip_next.txt18
-rw-r--r--src/tools/clippy/src/docs/iter_with_drain.txt16
-rw-r--r--src/tools/clippy/src/docs/iterator_step_by_zero.txt13
-rw-r--r--src/tools/clippy/src/docs/just_underscores_and_digits.txt14
-rw-r--r--src/tools/clippy/src/docs/large_const_arrays.txt17
-rw-r--r--src/tools/clippy/src/docs/large_digit_groups.txt12
-rw-r--r--src/tools/clippy/src/docs/large_enum_variant.txt41
-rw-r--r--src/tools/clippy/src/docs/large_include_file.txt21
-rw-r--r--src/tools/clippy/src/docs/large_stack_arrays.txt10
-rw-r--r--src/tools/clippy/src/docs/large_types_passed_by_value.txt24
-rw-r--r--src/tools/clippy/src/docs/len_without_is_empty.txt19
-rw-r--r--src/tools/clippy/src/docs/len_zero.txt28
-rw-r--r--src/tools/clippy/src/docs/let_and_return.txt21
-rw-r--r--src/tools/clippy/src/docs/let_underscore_drop.txt29
-rw-r--r--src/tools/clippy/src/docs/let_underscore_lock.txt20
-rw-r--r--src/tools/clippy/src/docs/let_underscore_must_use.txt17
-rw-r--r--src/tools/clippy/src/docs/let_unit_value.txt13
-rw-r--r--src/tools/clippy/src/docs/linkedlist.txt32
-rw-r--r--src/tools/clippy/src/docs/lossy_float_literal.txt18
-rw-r--r--src/tools/clippy/src/docs/macro_use_imports.txt12
-rw-r--r--src/tools/clippy/src/docs/main_recursion.txt13
-rw-r--r--src/tools/clippy/src/docs/manual_assert.txt18
-rw-r--r--src/tools/clippy/src/docs/manual_async_fn.txt16
-rw-r--r--src/tools/clippy/src/docs/manual_bits.txt15
-rw-r--r--src/tools/clippy/src/docs/manual_clamp.txt46
-rw-r--r--src/tools/clippy/src/docs/manual_filter.txt21
-rw-r--r--src/tools/clippy/src/docs/manual_filter_map.txt19
-rw-r--r--src/tools/clippy/src/docs/manual_find.txt24
-rw-r--r--src/tools/clippy/src/docs/manual_find_map.txt19
-rw-r--r--src/tools/clippy/src/docs/manual_flatten.txt25
-rw-r--r--src/tools/clippy/src/docs/manual_instant_elapsed.txt21
-rw-r--r--src/tools/clippy/src/docs/manual_map.txt17
-rw-r--r--src/tools/clippy/src/docs/manual_memcpy.txt18
-rw-r--r--src/tools/clippy/src/docs/manual_non_exhaustive.txt41
-rw-r--r--src/tools/clippy/src/docs/manual_ok_or.txt19
-rw-r--r--src/tools/clippy/src/docs/manual_range_contains.txt19
-rw-r--r--src/tools/clippy/src/docs/manual_rem_euclid.txt17
-rw-r--r--src/tools/clippy/src/docs/manual_retain.txt15
-rw-r--r--src/tools/clippy/src/docs/manual_saturating_arithmetic.txt18
-rw-r--r--src/tools/clippy/src/docs/manual_split_once.txt29
-rw-r--r--src/tools/clippy/src/docs/manual_str_repeat.txt15
-rw-r--r--src/tools/clippy/src/docs/manual_string_new.txt20
-rw-r--r--src/tools/clippy/src/docs/manual_strip.txt24
-rw-r--r--src/tools/clippy/src/docs/manual_swap.txt22
-rw-r--r--src/tools/clippy/src/docs/manual_unwrap_or.txt20
-rw-r--r--src/tools/clippy/src/docs/many_single_char_names.txt12
-rw-r--r--src/tools/clippy/src/docs/map_clone.txt22
-rw-r--r--src/tools/clippy/src/docs/map_collect_result_unit.txt14
-rw-r--r--src/tools/clippy/src/docs/map_entry.txt28
-rw-r--r--src/tools/clippy/src/docs/map_err_ignore.txt93
-rw-r--r--src/tools/clippy/src/docs/map_flatten.txt21
-rw-r--r--src/tools/clippy/src/docs/map_identity.txt16
-rw-r--r--src/tools/clippy/src/docs/map_unwrap_or.txt22
-rw-r--r--src/tools/clippy/src/docs/match_as_ref.txt23
-rw-r--r--src/tools/clippy/src/docs/match_bool.txt24
-rw-r--r--src/tools/clippy/src/docs/match_like_matches_macro.txt32
-rw-r--r--src/tools/clippy/src/docs/match_on_vec_items.txt29
-rw-r--r--src/tools/clippy/src/docs/match_overlapping_arm.txt16
-rw-r--r--src/tools/clippy/src/docs/match_ref_pats.txt26
-rw-r--r--src/tools/clippy/src/docs/match_result_ok.txt27
-rw-r--r--src/tools/clippy/src/docs/match_same_arms.txt38
-rw-r--r--src/tools/clippy/src/docs/match_single_binding.txt23
-rw-r--r--src/tools/clippy/src/docs/match_str_case_mismatch.txt22
-rw-r--r--src/tools/clippy/src/docs/match_wild_err_arm.txt16
-rw-r--r--src/tools/clippy/src/docs/match_wildcard_for_single_variants.txt27
-rw-r--r--src/tools/clippy/src/docs/maybe_infinite_iter.txt16
-rw-r--r--src/tools/clippy/src/docs/mem_forget.txt12
-rw-r--r--src/tools/clippy/src/docs/mem_replace_option_with_none.txt21
-rw-r--r--src/tools/clippy/src/docs/mem_replace_with_default.txt18
-rw-r--r--src/tools/clippy/src/docs/mem_replace_with_uninit.txt24
-rw-r--r--src/tools/clippy/src/docs/min_max.txt18
-rw-r--r--src/tools/clippy/src/docs/mismatched_target_os.txt24
-rw-r--r--src/tools/clippy/src/docs/mismatching_type_param_order.txt33
-rw-r--r--src/tools/clippy/src/docs/misrefactored_assign_op.txt20
-rw-r--r--src/tools/clippy/src/docs/missing_const_for_fn.txt40
-rw-r--r--src/tools/clippy/src/docs/missing_docs_in_private_items.txt9
-rw-r--r--src/tools/clippy/src/docs/missing_enforced_import_renames.txt22
-rw-r--r--src/tools/clippy/src/docs/missing_errors_doc.txt21
-rw-r--r--src/tools/clippy/src/docs/missing_inline_in_public_items.txt45
-rw-r--r--src/tools/clippy/src/docs/missing_panics_doc.txt24
-rw-r--r--src/tools/clippy/src/docs/missing_safety_doc.txt26
-rw-r--r--src/tools/clippy/src/docs/missing_spin_loop.txt27
-rw-r--r--src/tools/clippy/src/docs/missing_trait_methods.txt40
-rw-r--r--src/tools/clippy/src/docs/mistyped_literal_suffixes.txt15
-rw-r--r--src/tools/clippy/src/docs/mixed_case_hex_literals.txt16
-rw-r--r--src/tools/clippy/src/docs/mixed_read_write_in_expression.txt32
-rw-r--r--src/tools/clippy/src/docs/mod_module_files.txt22
-rw-r--r--src/tools/clippy/src/docs/module_inception.txt24
-rw-r--r--src/tools/clippy/src/docs/module_name_repetitions.txt20
-rw-r--r--src/tools/clippy/src/docs/modulo_arithmetic.txt15
-rw-r--r--src/tools/clippy/src/docs/modulo_one.txt16
-rw-r--r--src/tools/clippy/src/docs/multi_assignments.txt17
-rw-r--r--src/tools/clippy/src/docs/multiple_crate_versions.txt19
-rw-r--r--src/tools/clippy/src/docs/multiple_inherent_impl.txt26
-rw-r--r--src/tools/clippy/src/docs/must_use_candidate.txt23
-rw-r--r--src/tools/clippy/src/docs/must_use_unit.txt13
-rw-r--r--src/tools/clippy/src/docs/mut_from_ref.txt26
-rw-r--r--src/tools/clippy/src/docs/mut_mut.txt12
-rw-r--r--src/tools/clippy/src/docs/mut_mutex_lock.txt29
-rw-r--r--src/tools/clippy/src/docs/mut_range_bound.txt29
-rw-r--r--src/tools/clippy/src/docs/mutable_key_type.txt61
-rw-r--r--src/tools/clippy/src/docs/mutex_atomic.txt22
-rw-r--r--src/tools/clippy/src/docs/mutex_integer.txt22
-rw-r--r--src/tools/clippy/src/docs/naive_bytecount.txt22
-rw-r--r--src/tools/clippy/src/docs/needless_arbitrary_self_type.txt44
-rw-r--r--src/tools/clippy/src/docs/needless_bitwise_bool.txt22
-rw-r--r--src/tools/clippy/src/docs/needless_bool.txt26
-rw-r--r--src/tools/clippy/src/docs/needless_borrow.txt21
-rw-r--r--src/tools/clippy/src/docs/needless_borrowed_reference.txt22
-rw-r--r--src/tools/clippy/src/docs/needless_collect.txt14
-rw-r--r--src/tools/clippy/src/docs/needless_continue.txt61
-rw-r--r--src/tools/clippy/src/docs/needless_doctest_main.txt22
-rw-r--r--src/tools/clippy/src/docs/needless_for_each.txt24
-rw-r--r--src/tools/clippy/src/docs/needless_late_init.txt42
-rw-r--r--src/tools/clippy/src/docs/needless_lifetimes.txt29
-rw-r--r--src/tools/clippy/src/docs/needless_match.txt36
-rw-r--r--src/tools/clippy/src/docs/needless_option_as_deref.txt18
-rw-r--r--src/tools/clippy/src/docs/needless_option_take.txt17
-rw-r--r--src/tools/clippy/src/docs/needless_parens_on_range_literals.txt23
-rw-r--r--src/tools/clippy/src/docs/needless_pass_by_value.txt27
-rw-r--r--src/tools/clippy/src/docs/needless_question_mark.txt43
-rw-r--r--src/tools/clippy/src/docs/needless_range_loop.txt23
-rw-r--r--src/tools/clippy/src/docs/needless_return.txt19
-rw-r--r--src/tools/clippy/src/docs/needless_splitn.txt16
-rw-r--r--src/tools/clippy/src/docs/needless_update.txt30
-rw-r--r--src/tools/clippy/src/docs/neg_cmp_op_on_partial_ord.txt26
-rw-r--r--src/tools/clippy/src/docs/neg_multiply.txt18
-rw-r--r--src/tools/clippy/src/docs/negative_feature_names.txt22
-rw-r--r--src/tools/clippy/src/docs/never_loop.txt15
-rw-r--r--src/tools/clippy/src/docs/new_ret_no_self.txt47
-rw-r--r--src/tools/clippy/src/docs/new_without_default.txt32
-rw-r--r--src/tools/clippy/src/docs/no_effect.txt12
-rw-r--r--src/tools/clippy/src/docs/no_effect_replace.txt11
-rw-r--r--src/tools/clippy/src/docs/no_effect_underscore_binding.txt16
-rw-r--r--src/tools/clippy/src/docs/non_ascii_literal.txt19
-rw-r--r--src/tools/clippy/src/docs/non_octal_unix_permissions.txt23
-rw-r--r--src/tools/clippy/src/docs/non_send_fields_in_send_ty.txt36
-rw-r--r--src/tools/clippy/src/docs/nonminimal_bool.txt23
-rw-r--r--src/tools/clippy/src/docs/nonsensical_open_options.txt14
-rw-r--r--src/tools/clippy/src/docs/nonstandard_macro_braces.txt15
-rw-r--r--src/tools/clippy/src/docs/not_unsafe_ptr_arg_deref.txt30
-rw-r--r--src/tools/clippy/src/docs/obfuscated_if_else.txt21
-rw-r--r--src/tools/clippy/src/docs/octal_escapes.txt33
-rw-r--r--src/tools/clippy/src/docs/ok_expect.txt19
-rw-r--r--src/tools/clippy/src/docs/only_used_in_recursion.txt58
-rw-r--r--src/tools/clippy/src/docs/op_ref.txt17
-rw-r--r--src/tools/clippy/src/docs/option_as_ref_deref.txt15
-rw-r--r--src/tools/clippy/src/docs/option_env_unwrap.txt19
-rw-r--r--src/tools/clippy/src/docs/option_filter_map.txt15
-rw-r--r--src/tools/clippy/src/docs/option_if_let_else.txt46
-rw-r--r--src/tools/clippy/src/docs/option_map_or_none.txt19
-rw-r--r--src/tools/clippy/src/docs/option_map_unit_fn.txt27
-rw-r--r--src/tools/clippy/src/docs/option_option.txt32
-rw-r--r--src/tools/clippy/src/docs/or_fun_call.txt27
-rw-r--r--src/tools/clippy/src/docs/or_then_unwrap.txt22
-rw-r--r--src/tools/clippy/src/docs/out_of_bounds_indexing.txt22
-rw-r--r--src/tools/clippy/src/docs/overflow_check_conditional.txt11
-rw-r--r--src/tools/clippy/src/docs/overly_complex_bool_expr.txt20
-rw-r--r--src/tools/clippy/src/docs/panic.txt10
-rw-r--r--src/tools/clippy/src/docs/panic_in_result_fn.txt22
-rw-r--r--src/tools/clippy/src/docs/panicking_unwrap.txt18
-rw-r--r--src/tools/clippy/src/docs/partial_pub_fields.txt27
-rw-r--r--src/tools/clippy/src/docs/partialeq_ne_impl.txt18
-rw-r--r--src/tools/clippy/src/docs/partialeq_to_none.txt24
-rw-r--r--src/tools/clippy/src/docs/path_buf_push_overwrite.txt25
-rw-r--r--src/tools/clippy/src/docs/pattern_type_mismatch.txt64
-rw-r--r--src/tools/clippy/src/docs/possible_missing_comma.txt14
-rw-r--r--src/tools/clippy/src/docs/precedence.txt17
-rw-r--r--src/tools/clippy/src/docs/print_in_format_impl.txt34
-rw-r--r--src/tools/clippy/src/docs/print_literal.txt16
-rw-r--r--src/tools/clippy/src/docs/print_stderr.txt15
-rw-r--r--src/tools/clippy/src/docs/print_stdout.txt15
-rw-r--r--src/tools/clippy/src/docs/print_with_newline.txt16
-rw-r--r--src/tools/clippy/src/docs/println_empty_string.txt16
-rw-r--r--src/tools/clippy/src/docs/ptr_arg.txt29
-rw-r--r--src/tools/clippy/src/docs/ptr_as_ptr.txt22
-rw-r--r--src/tools/clippy/src/docs/ptr_eq.txt22
-rw-r--r--src/tools/clippy/src/docs/ptr_offset_with_cast.txt30
-rw-r--r--src/tools/clippy/src/docs/pub_use.txt28
-rw-r--r--src/tools/clippy/src/docs/question_mark.txt18
-rw-r--r--src/tools/clippy/src/docs/range_minus_one.txt27
-rw-r--r--src/tools/clippy/src/docs/range_plus_one.txt36
-rw-r--r--src/tools/clippy/src/docs/range_zip_with_len.txt16
-rw-r--r--src/tools/clippy/src/docs/rc_buffer.txt27
-rw-r--r--src/tools/clippy/src/docs/rc_clone_in_vec_init.txt29
-rw-r--r--src/tools/clippy/src/docs/rc_mutex.txt26
-rw-r--r--src/tools/clippy/src/docs/read_zero_byte_vec.txt30
-rw-r--r--src/tools/clippy/src/docs/recursive_format_impl.txt32
-rw-r--r--src/tools/clippy/src/docs/redundant_allocation.txt17
-rw-r--r--src/tools/clippy/src/docs/redundant_clone.txt23
-rw-r--r--src/tools/clippy/src/docs/redundant_closure.txt25
-rw-r--r--src/tools/clippy/src/docs/redundant_closure_call.txt17
-rw-r--r--src/tools/clippy/src/docs/redundant_closure_for_method_calls.txt15
-rw-r--r--src/tools/clippy/src/docs/redundant_else.txt30
-rw-r--r--src/tools/clippy/src/docs/redundant_feature_names.txt23
-rw-r--r--src/tools/clippy/src/docs/redundant_field_names.txt22
-rw-r--r--src/tools/clippy/src/docs/redundant_pattern.txt22
-rw-r--r--src/tools/clippy/src/docs/redundant_pattern_matching.txt45
-rw-r--r--src/tools/clippy/src/docs/redundant_pub_crate.txt21
-rw-r--r--src/tools/clippy/src/docs/redundant_slicing.txt24
-rw-r--r--src/tools/clippy/src/docs/redundant_static_lifetimes.txt19
-rw-r--r--src/tools/clippy/src/docs/ref_binding_to_reference.txt21
-rw-r--r--src/tools/clippy/src/docs/ref_option_ref.txt19
-rw-r--r--src/tools/clippy/src/docs/repeat_once.txt25
-rw-r--r--src/tools/clippy/src/docs/rest_pat_in_fully_bound_structs.txt24
-rw-r--r--src/tools/clippy/src/docs/result_large_err.txt36
-rw-r--r--src/tools/clippy/src/docs/result_map_or_into_option.txt16
-rw-r--r--src/tools/clippy/src/docs/result_map_unit_fn.txt26
-rw-r--r--src/tools/clippy/src/docs/result_unit_err.txt40
-rw-r--r--src/tools/clippy/src/docs/return_self_not_must_use.txt46
-rw-r--r--src/tools/clippy/src/docs/reversed_empty_ranges.txt26
-rw-r--r--src/tools/clippy/src/docs/same_functions_in_if_condition.txt41
-rw-r--r--src/tools/clippy/src/docs/same_item_push.txt29
-rw-r--r--src/tools/clippy/src/docs/same_name_method.txt23
-rw-r--r--src/tools/clippy/src/docs/search_is_some.txt24
-rw-r--r--src/tools/clippy/src/docs/self_assignment.txt32
-rw-r--r--src/tools/clippy/src/docs/self_named_constructors.txt26
-rw-r--r--src/tools/clippy/src/docs/self_named_module_files.txt22
-rw-r--r--src/tools/clippy/src/docs/semicolon_if_nothing_returned.txt20
-rw-r--r--src/tools/clippy/src/docs/separated_literal_suffix.txt17
-rw-r--r--src/tools/clippy/src/docs/serde_api_misuse.txt10
-rw-r--r--src/tools/clippy/src/docs/shadow_reuse.txt20
-rw-r--r--src/tools/clippy/src/docs/shadow_same.txt18
-rw-r--r--src/tools/clippy/src/docs/shadow_unrelated.txt22
-rw-r--r--src/tools/clippy/src/docs/short_circuit_statement.txt14
-rw-r--r--src/tools/clippy/src/docs/should_implement_trait.txt22
-rw-r--r--src/tools/clippy/src/docs/significant_drop_in_scrutinee.txt43
-rw-r--r--src/tools/clippy/src/docs/similar_names.txt16
-rw-r--r--src/tools/clippy/src/docs/single_char_add_str.txt18
-rw-r--r--src/tools/clippy/src/docs/single_char_lifetime_names.txt28
-rw-r--r--src/tools/clippy/src/docs/single_char_pattern.txt20
-rw-r--r--src/tools/clippy/src/docs/single_component_path_imports.txt21
-rw-r--r--src/tools/clippy/src/docs/single_element_loop.txt21
-rw-r--r--src/tools/clippy/src/docs/single_match.txt21
-rw-r--r--src/tools/clippy/src/docs/single_match_else.txt29
-rw-r--r--src/tools/clippy/src/docs/size_of_in_element_count.txt16
-rw-r--r--src/tools/clippy/src/docs/skip_while_next.txt16
-rw-r--r--src/tools/clippy/src/docs/slow_vector_initialization.txt24
-rw-r--r--src/tools/clippy/src/docs/stable_sort_primitive.txt31
-rw-r--r--src/tools/clippy/src/docs/std_instead_of_alloc.txt18
-rw-r--r--src/tools/clippy/src/docs/std_instead_of_core.txt18
-rw-r--r--src/tools/clippy/src/docs/str_to_string.txt18
-rw-r--r--src/tools/clippy/src/docs/string_add.txt27
-rw-r--r--src/tools/clippy/src/docs/string_add_assign.txt17
-rw-r--r--src/tools/clippy/src/docs/string_extend_chars.txt23
-rw-r--r--src/tools/clippy/src/docs/string_from_utf8_as_bytes.txt15
-rw-r--r--src/tools/clippy/src/docs/string_lit_as_bytes.txt39
-rw-r--r--src/tools/clippy/src/docs/string_slice.txt17
-rw-r--r--src/tools/clippy/src/docs/string_to_string.txt19
-rw-r--r--src/tools/clippy/src/docs/strlen_on_c_strings.txt20
-rw-r--r--src/tools/clippy/src/docs/struct_excessive_bools.txt29
-rw-r--r--src/tools/clippy/src/docs/suboptimal_flops.txt50
-rw-r--r--src/tools/clippy/src/docs/suspicious_arithmetic_impl.txt17
-rw-r--r--src/tools/clippy/src/docs/suspicious_assignment_formatting.txt12
-rw-r--r--src/tools/clippy/src/docs/suspicious_else_formatting.txt30
-rw-r--r--src/tools/clippy/src/docs/suspicious_map.txt13
-rw-r--r--src/tools/clippy/src/docs/suspicious_op_assign_impl.txt15
-rw-r--r--src/tools/clippy/src/docs/suspicious_operation_groupings.txt41
-rw-r--r--src/tools/clippy/src/docs/suspicious_splitn.txt22
-rw-r--r--src/tools/clippy/src/docs/suspicious_to_owned.txt39
-rw-r--r--src/tools/clippy/src/docs/suspicious_unary_op_formatting.txt18
-rw-r--r--src/tools/clippy/src/docs/swap_ptr_to_ref.txt23
-rw-r--r--src/tools/clippy/src/docs/tabs_in_doc_comments.txt44
-rw-r--r--src/tools/clippy/src/docs/temporary_assignment.txt12
-rw-r--r--src/tools/clippy/src/docs/to_digit_is_some.txt15
-rw-r--r--src/tools/clippy/src/docs/to_string_in_format_args.txt17
-rw-r--r--src/tools/clippy/src/docs/todo.txt10
-rw-r--r--src/tools/clippy/src/docs/too_many_arguments.txt14
-rw-r--r--src/tools/clippy/src/docs/too_many_lines.txt17
-rw-r--r--src/tools/clippy/src/docs/toplevel_ref_arg.txt28
-rw-r--r--src/tools/clippy/src/docs/trailing_empty_array.txt22
-rw-r--r--src/tools/clippy/src/docs/trait_duplication_in_bounds.txt37
-rw-r--r--src/tools/clippy/src/docs/transmute_bytes_to_str.txt27
-rw-r--r--src/tools/clippy/src/docs/transmute_float_to_int.txt16
-rw-r--r--src/tools/clippy/src/docs/transmute_int_to_bool.txt16
-rw-r--r--src/tools/clippy/src/docs/transmute_int_to_char.txt27
-rw-r--r--src/tools/clippy/src/docs/transmute_int_to_float.txt16
-rw-r--r--src/tools/clippy/src/docs/transmute_num_to_bytes.txt16
-rw-r--r--src/tools/clippy/src/docs/transmute_ptr_to_ptr.txt21
-rw-r--r--src/tools/clippy/src/docs/transmute_ptr_to_ref.txt21
-rw-r--r--src/tools/clippy/src/docs/transmute_undefined_repr.txt22
-rw-r--r--src/tools/clippy/src/docs/transmutes_expressible_as_ptr_casts.txt16
-rw-r--r--src/tools/clippy/src/docs/transmuting_null.txt15
-rw-r--r--src/tools/clippy/src/docs/trim_split_whitespace.txt14
-rw-r--r--src/tools/clippy/src/docs/trivial_regex.txt18
-rw-r--r--src/tools/clippy/src/docs/trivially_copy_pass_by_ref.txt43
-rw-r--r--src/tools/clippy/src/docs/try_err.txt28
-rw-r--r--src/tools/clippy/src/docs/type_complexity.txt14
-rw-r--r--src/tools/clippy/src/docs/type_repetition_in_bounds.txt16
-rw-r--r--src/tools/clippy/src/docs/undocumented_unsafe_blocks.txt43
-rw-r--r--src/tools/clippy/src/docs/undropped_manually_drops.txt22
-rw-r--r--src/tools/clippy/src/docs/unicode_not_nfc.txt12
-rw-r--r--src/tools/clippy/src/docs/unimplemented.txt10
-rw-r--r--src/tools/clippy/src/docs/uninit_assumed_init.txt28
-rw-r--r--src/tools/clippy/src/docs/uninit_vec.txt41
-rw-r--r--src/tools/clippy/src/docs/uninlined_format_args.txt36
-rw-r--r--src/tools/clippy/src/docs/unit_arg.txt14
-rw-r--r--src/tools/clippy/src/docs/unit_cmp.txt33
-rw-r--r--src/tools/clippy/src/docs/unit_hash.txt20
-rw-r--r--src/tools/clippy/src/docs/unit_return_expecting_ord.txt20
-rw-r--r--src/tools/clippy/src/docs/unnecessary_cast.txt19
-rw-r--r--src/tools/clippy/src/docs/unnecessary_filter_map.txt23
-rw-r--r--src/tools/clippy/src/docs/unnecessary_find_map.txt23
-rw-r--r--src/tools/clippy/src/docs/unnecessary_fold.txt17
-rw-r--r--src/tools/clippy/src/docs/unnecessary_join.txt25
-rw-r--r--src/tools/clippy/src/docs/unnecessary_lazy_evaluations.txt32
-rw-r--r--src/tools/clippy/src/docs/unnecessary_mut_passed.txt17
-rw-r--r--src/tools/clippy/src/docs/unnecessary_operation.txt12
-rw-r--r--src/tools/clippy/src/docs/unnecessary_owned_empty_strings.txt16
-rw-r--r--src/tools/clippy/src/docs/unnecessary_self_imports.txt19
-rw-r--r--src/tools/clippy/src/docs/unnecessary_sort_by.txt21
-rw-r--r--src/tools/clippy/src/docs/unnecessary_to_owned.txt24
-rw-r--r--src/tools/clippy/src/docs/unnecessary_unwrap.txt20
-rw-r--r--src/tools/clippy/src/docs/unnecessary_wraps.txt36
-rw-r--r--src/tools/clippy/src/docs/unneeded_field_pattern.txt26
-rw-r--r--src/tools/clippy/src/docs/unneeded_wildcard_pattern.txt28
-rw-r--r--src/tools/clippy/src/docs/unnested_or_patterns.txt22
-rw-r--r--src/tools/clippy/src/docs/unreachable.txt10
-rw-r--r--src/tools/clippy/src/docs/unreadable_literal.txt16
-rw-r--r--src/tools/clippy/src/docs/unsafe_derive_deserialize.txt27
-rw-r--r--src/tools/clippy/src/docs/unsafe_removed_from_name.txt15
-rw-r--r--src/tools/clippy/src/docs/unseparated_literal_suffix.txt18
-rw-r--r--src/tools/clippy/src/docs/unsound_collection_transmute.txt25
-rw-r--r--src/tools/clippy/src/docs/unused_async.txt23
-rw-r--r--src/tools/clippy/src/docs/unused_format_specs.txt24
-rw-r--r--src/tools/clippy/src/docs/unused_io_amount.txt31
-rw-r--r--src/tools/clippy/src/docs/unused_peekable.txt26
-rw-r--r--src/tools/clippy/src/docs/unused_rounding.txt17
-rw-r--r--src/tools/clippy/src/docs/unused_self.txt23
-rw-r--r--src/tools/clippy/src/docs/unused_unit.txt18
-rw-r--r--src/tools/clippy/src/docs/unusual_byte_groupings.txt12
-rw-r--r--src/tools/clippy/src/docs/unwrap_in_result.txt39
-rw-r--r--src/tools/clippy/src/docs/unwrap_or_else_default.txt18
-rw-r--r--src/tools/clippy/src/docs/unwrap_used.txt37
-rw-r--r--src/tools/clippy/src/docs/upper_case_acronyms.txt25
-rw-r--r--src/tools/clippy/src/docs/use_debug.txt12
-rw-r--r--src/tools/clippy/src/docs/use_self.txt31
-rw-r--r--src/tools/clippy/src/docs/used_underscore_binding.txt19
-rw-r--r--src/tools/clippy/src/docs/useless_asref.txt17
-rw-r--r--src/tools/clippy/src/docs/useless_attribute.txt36
-rw-r--r--src/tools/clippy/src/docs/useless_conversion.txt17
-rw-r--r--src/tools/clippy/src/docs/useless_format.txt22
-rw-r--r--src/tools/clippy/src/docs/useless_let_if_seq.txt39
-rw-r--r--src/tools/clippy/src/docs/useless_transmute.txt12
-rw-r--r--src/tools/clippy/src/docs/useless_vec.txt18
-rw-r--r--src/tools/clippy/src/docs/vec_box.txt26
-rw-r--r--src/tools/clippy/src/docs/vec_init_then_push.txt23
-rw-r--r--src/tools/clippy/src/docs/vec_resize_to_zero.txt15
-rw-r--r--src/tools/clippy/src/docs/verbose_bit_mask.txt15
-rw-r--r--src/tools/clippy/src/docs/verbose_file_reads.txt17
-rw-r--r--src/tools/clippy/src/docs/vtable_address_comparisons.txt17
-rw-r--r--src/tools/clippy/src/docs/while_immutable_condition.txt20
-rw-r--r--src/tools/clippy/src/docs/while_let_loop.txt25
-rw-r--r--src/tools/clippy/src/docs/while_let_on_iterator.txt20
-rw-r--r--src/tools/clippy/src/docs/wildcard_dependencies.txt13
-rw-r--r--src/tools/clippy/src/docs/wildcard_enum_match_arm.txt25
-rw-r--r--src/tools/clippy/src/docs/wildcard_imports.txt45
-rw-r--r--src/tools/clippy/src/docs/wildcard_in_or_patterns.txt22
-rw-r--r--src/tools/clippy/src/docs/write_literal.txt17
-rw-r--r--src/tools/clippy/src/docs/write_with_newline.txt18
-rw-r--r--src/tools/clippy/src/docs/writeln_empty_string.txt16
-rw-r--r--src/tools/clippy/src/docs/wrong_self_convention.txt39
-rw-r--r--src/tools/clippy/src/docs/wrong_transmute.txt15
-rw-r--r--src/tools/clippy/src/docs/zero_divided_by_zero.txt15
-rw-r--r--src/tools/clippy/src/docs/zero_prefixed_literal.txt32
-rw-r--r--src/tools/clippy/src/docs/zero_ptr.txt16
-rw-r--r--src/tools/clippy/src/docs/zero_sized_map_values.txt24
-rw-r--r--src/tools/clippy/src/docs/zst_offset.txt11
-rw-r--r--src/tools/clippy/src/driver.rs8
-rw-r--r--src/tools/clippy/src/main.rs19
-rw-r--r--src/tools/clippy/tests/check-fmt.rs2
-rw-r--r--src/tools/clippy/tests/compile-test.rs40
-rw-r--r--src/tools/clippy/tests/dogfood.rs13
-rw-r--r--src/tools/clippy/tests/integration.rs27
-rw-r--r--src/tools/clippy/tests/lint_message_convention.rs6
-rw-r--r--src/tools/clippy/tests/missing-test-files.rs2
-rw-r--r--src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr2
-rw-r--r--src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.stderr4
-rw-r--r--src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/main.stderr2
-rw-r--r--src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/Cargo.toml9
-rw-r--r--src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/bad.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/bad/inner.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs7
-rw-r--r--src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.stderr11
-rw-r--r--src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/main.stderr2
-rw-r--r--src/tools/clippy/tests/ui-internal/auxiliary/paths.rs2
-rw-r--r--src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr6
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.stderr2
-rw-r--r--src/tools/clippy/tests/ui-internal/if_chain_style.stderr2
-rw-r--r--src/tools/clippy/tests/ui-internal/invalid_paths.rs2
-rw-r--r--src/tools/clippy/tests/ui-internal/match_type_on_diag_item.rs39
-rw-r--r--src/tools/clippy/tests/ui-internal/match_type_on_diag_item.stderr27
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed62
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs62
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr101
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs16
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr27
-rw-r--r--src/tools/clippy/tests/ui-toml/arithmetic_allowed/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs (renamed from src/tools/clippy/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs)2
-rw-r--r--src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml2
-rw-r--r--src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr16
-rw-r--r--src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr10
-rw-r--r--src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml5
-rw-r--r--src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs12
-rw-r--r--src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr15
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_macros/auxiliary/macros.rs32
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_macros/clippy.toml11
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs39
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr84
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs (renamed from src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs)4
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr16
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs (renamed from src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs)4
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr10
-rw-r--r--src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml5
-rw-r--r--src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs1
-rw-r--r--src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr8
-rw-r--r--src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/fn_params_excessive_bools/test.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed62
-rw-r--r--src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr77
-rw-r--r--src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr46
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs (renamed from src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs)2
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr46
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_methods/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs6
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr24
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr5
-rw-r--r--src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr2
-rw-r--r--src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr2
-rw-r--r--src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr2
-rw-r--r--src/tools/clippy/tests/ui/almost_complete_letter_range.fixed13
-rw-r--r--src/tools/clippy/tests/ui/almost_complete_letter_range.rs13
-rw-r--r--src/tools/clippy/tests/ui/almost_complete_letter_range.stderr39
-rw-r--r--src/tools/clippy/tests/ui/approx_const.stderr2
-rw-r--r--src/tools/clippy/tests/ui/arithmetic.fixed27
-rw-r--r--src/tools/clippy/tests/ui/arithmetic.rs27
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.rs224
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.stderr352
-rw-r--r--src/tools/clippy/tests/ui/as_conversions.stderr2
-rw-r--r--src/tools/clippy/tests/ui/as_ptr_cast_mut.rs37
-rw-r--r--src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr16
-rw-r--r--src/tools/clippy/tests/ui/asm_syntax.stderr4
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_constants.stderr2
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_result_states.fixed14
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_result_states.rs14
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_result_states.stderr18
-rw-r--r--src/tools/clippy/tests/ui/assign_ops2.rs2
-rw-r--r--src/tools/clippy/tests/ui/assign_ops2.stderr20
-rw-r--r--src/tools/clippy/tests/ui/author.stdout24
-rw-r--r--src/tools/clippy/tests/ui/author/blocks.stdout116
-rw-r--r--src/tools/clippy/tests/ui/author/call.stdout28
-rw-r--r--src/tools/clippy/tests/ui/author/if.stdout92
-rw-r--r--src/tools/clippy/tests/ui/author/issue_3849.stdout24
-rw-r--r--src/tools/clippy/tests/ui/author/loop.stdout202
-rw-r--r--src/tools/clippy/tests/ui/author/matches.stdout72
-rw-r--r--src/tools/clippy/tests/ui/author/repeat.stdout20
-rw-r--r--src/tools/clippy/tests/ui/author/struct.rs7
-rw-r--r--src/tools/clippy/tests/ui/author/struct.stdout112
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/macro_rules.rs7
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs2
-rw-r--r--src/tools/clippy/tests/ui/await_holding_lock.stderr2
-rw-r--r--src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr2
-rw-r--r--src/tools/clippy/tests/ui/bind_instead_of_map.fixed1
-rw-r--r--src/tools/clippy/tests/ui/bind_instead_of_map.rs1
-rw-r--r--src/tools/clippy/tests/ui/bind_instead_of_map.stderr6
-rw-r--r--src/tools/clippy/tests/ui/blacklisted_name.stderr88
-rw-r--r--src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr2
-rw-r--r--src/tools/clippy/tests/ui/bool_to_int_with_if.fixed91
-rw-r--r--src/tools/clippy/tests/ui/bool_to_int_with_if.rs123
-rw-r--r--src/tools/clippy/tests/ui/bool_to_int_with_if.stderr109
-rw-r--r--src/tools/clippy/tests/ui/borrow_box.rs5
-rw-r--r--src/tools/clippy/tests/ui/borrow_box.stderr20
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr2
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr2
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr2
-rw-r--r--src/tools/clippy/tests/ui/box_collection.rs6
-rw-r--r--src/tools/clippy/tests/ui/box_collection.stderr2
-rw-r--r--src/tools/clippy/tests/ui/box_default.fixed57
-rw-r--r--src/tools/clippy/tests/ui/box_default.rs57
-rw-r--r--src/tools/clippy/tests/ui/box_default.stderr88
-rw-r--r--src/tools/clippy/tests/ui/box_default_no_std.rs33
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs3
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr22
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs5
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr32
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs3
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr30
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs5
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr30
-rw-r--r--src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs10
-rw-r--r--src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr14
-rw-r--r--src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed19
-rw-r--r--src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs19
-rw-r--r--src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr46
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_bool.fixed13
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_bool.rs13
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_bool.stderr34
-rw-r--r--src/tools/clippy/tests/ui/cast_nan_to_int.rs18
-rw-r--r--src/tools/clippy/tests/ui/cast_nan_to_int.stderr51
-rw-r--r--src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed24
-rw-r--r--src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs24
-rw-r--r--src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr46
-rw-r--r--src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed16
-rw-r--r--src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs16
-rw-r--r--src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr8
-rw-r--r--src/tools/clippy/tests/ui/char_lit_as_u8.stderr2
-rw-r--r--src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr2
-rw-r--r--src/tools/clippy/tests/ui/checked_conversions.fixed16
-rw-r--r--src/tools/clippy/tests/ui/checked_conversions.rs16
-rw-r--r--src/tools/clippy/tests/ui/checked_conversions.stderr40
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr2
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy.fixed7
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy.rs7
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy.stderr8
-rw-r--r--src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed24
-rw-r--r--src/tools/clippy/tests/ui/cloned_instead_of_copied.rs24
-rw-r--r--src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr30
-rw-r--r--src/tools/clippy/tests/ui/cognitive_complexity.stderr2
-rw-r--r--src/tools/clippy/tests/ui/cognitive_complexity_attr_used.stderr2
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if.fixed3
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if.rs5
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if.stderr10
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match.rs24
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match.stderr76
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match2.stderr2
-rw-r--r--src/tools/clippy/tests/ui/collapsible_str_replace.fixed73
-rw-r--r--src/tools/clippy/tests/ui/collapsible_str_replace.rs76
-rw-r--r--src/tools/clippy/tests/ui/collapsible_str_replace.stderr86
-rw-r--r--src/tools/clippy/tests/ui/comparison_chain.stderr2
-rw-r--r--src/tools/clippy/tests/ui/copy_iterator.stderr2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2760.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3462.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-360.stderr2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-4775.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6254.stderr2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-7126.rs6
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-7868.stderr2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-7869.stderr2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9405.rs11
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9405.stderr11
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9414.rs8
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9445.rs3
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9459.rs5
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9463.rs5
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9463.stderr29
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9625.rs4
-rw-r--r--src/tools/clippy/tests/ui/crashes/regressions.rs2
-rw-r--r--src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.stderr2
-rw-r--r--src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr2
-rw-r--r--src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.stderr2
-rw-r--r--src/tools/clippy/tests/ui/def_id_nocore.rs1
-rw-r--r--src/tools/clippy/tests/ui/def_id_nocore.stderr4
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed9
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs9
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr34
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed10
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs10
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr34
-rw-r--r--src/tools/clippy/tests/ui/default_trait_access.fixed10
-rw-r--r--src/tools/clippy/tests/ui/default_trait_access.rs10
-rw-r--r--src/tools/clippy/tests/ui/default_trait_access.stderr18
-rw-r--r--src/tools/clippy/tests/ui/default_union_representation.stderr2
-rw-r--r--src/tools/clippy/tests/ui/derivable_impls.fixed213
-rw-r--r--src/tools/clippy/tests/ui/derivable_impls.rs4
-rw-r--r--src/tools/clippy/tests/ui/derivable_impls.stderr56
-rw-r--r--src/tools/clippy/tests/ui/derive.stderr2
-rw-r--r--src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr2
-rw-r--r--src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr2
-rw-r--r--src/tools/clippy/tests/ui/disallowed_names.rs (renamed from src/tools/clippy/tests/ui/blacklisted_name.rs)4
-rw-r--r--src/tools/clippy/tests/ui/disallowed_names.stderr88
-rw-r--r--src/tools/clippy/tests/ui/diverging_sub_expression.rs2
-rw-r--r--src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr2
-rw-r--r--src/tools/clippy/tests/ui/doc_link_with_quotes.rs7
-rw-r--r--src/tools/clippy/tests/ui/doc_link_with_quotes.stderr6
-rw-r--r--src/tools/clippy/tests/ui/double_must_use.stderr2
-rw-r--r--src/tools/clippy/tests/ui/drop_forget_copy.rs20
-rw-r--r--src/tools/clippy/tests/ui/drop_forget_copy.stderr42
-rw-r--r--src/tools/clippy/tests/ui/drop_non_drop.stderr2
-rw-r--r--src/tools/clippy/tests/ui/drop_ref.stderr2
-rw-r--r--src/tools/clippy/tests/ui/else_if_without_else.stderr2
-rw-r--r--src/tools/clippy/tests/ui/empty_enum.stderr2
-rw-r--r--src/tools/clippy/tests/ui/empty_loop.stderr2
-rw-r--r--src/tools/clippy/tests/ui/empty_loop_no_std.rs1
-rw-r--r--src/tools/clippy/tests/ui/empty_loop_no_std.stderr6
-rw-r--r--src/tools/clippy/tests/ui/entry.fixed1
-rw-r--r--src/tools/clippy/tests/ui/entry.rs1
-rw-r--r--src/tools/clippy/tests/ui/entry.stderr20
-rw-r--r--src/tools/clippy/tests/ui/eprint_with_newline.rs10
-rw-r--r--src/tools/clippy/tests/ui/eprint_with_newline.stderr18
-rw-r--r--src/tools/clippy/tests/ui/err_expect.fixed17
-rw-r--r--src/tools/clippy/tests/ui/err_expect.rs17
-rw-r--r--src/tools/clippy/tests/ui/err_expect.stderr10
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed25
-rw-r--r--src/tools/clippy/tests/ui/eta.rs25
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr20
-rw-r--r--src/tools/clippy/tests/ui/expect.rs3
-rw-r--r--src/tools/clippy/tests/ui/expect.stderr12
-rw-r--r--src/tools/clippy/tests/ui/expect_fun_call.fixed9
-rw-r--r--src/tools/clippy/tests/ui/expect_fun_call.rs9
-rw-r--r--src/tools/clippy/tests/ui/expect_fun_call.stderr40
-rw-r--r--src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs4
-rw-r--r--src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr4
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.fixed51
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.rs51
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.stderr144
-rw-r--r--src/tools/clippy/tests/ui/explicit_counter_loop.rs1
-rw-r--r--src/tools/clippy/tests/ui/explicit_counter_loop.stderr18
-rw-r--r--src/tools/clippy/tests/ui/explicit_deref_methods.fixed10
-rw-r--r--src/tools/clippy/tests/ui/explicit_deref_methods.rs10
-rw-r--r--src/tools/clippy/tests/ui/explicit_write.fixed5
-rw-r--r--src/tools/clippy/tests/ui/explicit_write.rs5
-rw-r--r--src/tools/clippy/tests/ui/explicit_write.stderr32
-rw-r--r--src/tools/clippy/tests/ui/fallible_impl_from.rs1
-rw-r--r--src/tools/clippy/tests/ui/fallible_impl_from.stderr26
-rw-r--r--src/tools/clippy/tests/ui/field_reassign_with_default.stderr2
-rw-r--r--src/tools/clippy/tests/ui/filetype_is_file.stderr2
-rw-r--r--src/tools/clippy/tests/ui/filter_map_next_fixable.fixed16
-rw-r--r--src/tools/clippy/tests/ui/filter_map_next_fixable.rs16
-rw-r--r--src/tools/clippy/tests/ui/filter_map_next_fixable.stderr10
-rw-r--r--src/tools/clippy/tests/ui/float_cmp.stderr2
-rw-r--r--src/tools/clippy/tests/ui/float_cmp_const.stderr2
-rw-r--r--src/tools/clippy/tests/ui/floating_point_exp.fixed2
-rw-r--r--src/tools/clippy/tests/ui/floating_point_exp.rs2
-rw-r--r--src/tools/clippy/tests/ui/floating_point_exp.stderr16
-rw-r--r--src/tools/clippy/tests/ui/floating_point_log.fixed3
-rw-r--r--src/tools/clippy/tests/ui/floating_point_log.rs3
-rw-r--r--src/tools/clippy/tests/ui/floating_point_log.stderr54
-rw-r--r--src/tools/clippy/tests/ui/floating_point_logbase.fixed2
-rw-r--r--src/tools/clippy/tests/ui/floating_point_logbase.rs2
-rw-r--r--src/tools/clippy/tests/ui/floating_point_logbase.stderr16
-rw-r--r--src/tools/clippy/tests/ui/floating_point_mul_add.fixed2
-rw-r--r--src/tools/clippy/tests/ui/floating_point_mul_add.rs2
-rw-r--r--src/tools/clippy/tests/ui/floating_point_mul_add.stderr30
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powf.fixed9
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powf.rs9
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powf.stderr92
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powi.fixed4
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powi.rs4
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powi.stderr28
-rw-r--r--src/tools/clippy/tests/ui/floating_point_rad.fixed5
-rw-r--r--src/tools/clippy/tests/ui/floating_point_rad.rs5
-rw-r--r--src/tools/clippy/tests/ui/floating_point_rad.stderr28
-rw-r--r--src/tools/clippy/tests/ui/fn_params_excessive_bools.stderr2
-rw-r--r--src/tools/clippy/tests/ui/for_loop_fixable.fixed2
-rw-r--r--src/tools/clippy/tests/ui/for_loop_fixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/for_loop_unfixable.rs1
-rw-r--r--src/tools/clippy/tests/ui/for_loop_unfixable.stderr2
-rw-r--r--src/tools/clippy/tests/ui/for_loops_over_fallibles.rs72
-rw-r--r--src/tools/clippy/tests/ui/for_loops_over_fallibles.stderr95
-rw-r--r--src/tools/clippy/tests/ui/forget_non_drop.stderr2
-rw-r--r--src/tools/clippy/tests/ui/forget_ref.stderr2
-rw-r--r--src/tools/clippy/tests/ui/format.fixed12
-rw-r--r--src/tools/clippy/tests/ui/format.rs12
-rw-r--r--src/tools/clippy/tests/ui/format.stderr44
-rw-r--r--src/tools/clippy/tests/ui/format_args.fixed64
-rw-r--r--src/tools/clippy/tests/ui/format_args.rs64
-rw-r--r--src/tools/clippy/tests/ui/format_args.stderr68
-rw-r--r--src/tools/clippy/tests/ui/format_args_unfixable.rs6
-rw-r--r--src/tools/clippy/tests/ui/format_args_unfixable.stderr38
-rw-r--r--src/tools/clippy/tests/ui/format_push_string.stderr2
-rw-r--r--src/tools/clippy/tests/ui/formatting.stderr4
-rw-r--r--src/tools/clippy/tests/ui/from_over_into.fixed87
-rw-r--r--src/tools/clippy/tests/ui/from_over_into.rs66
-rw-r--r--src/tools/clippy/tests/ui/from_over_into.stderr70
-rw-r--r--src/tools/clippy/tests/ui/from_over_into_unfixable.rs35
-rw-r--r--src/tools/clippy/tests/ui/from_over_into_unfixable.stderr29
-rw-r--r--src/tools/clippy/tests/ui/functions.rs4
-rw-r--r--src/tools/clippy/tests/ui/future_not_send.stderr2
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.stderr2
-rw-r--r--src/tools/clippy/tests/ui/identity_op.fixed6
-rw-r--r--src/tools/clippy/tests/ui/identity_op.rs6
-rw-r--r--src/tools/clippy/tests/ui/if_let_mutex.rs8
-rw-r--r--src/tools/clippy/tests/ui/if_let_mutex.stderr32
-rw-r--r--src/tools/clippy/tests/ui/if_not_else.stderr2
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else.rs2
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else.stderr2
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else2.rs2
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else2.stderr2
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.stderr10
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.rs4
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.stderr2
-rw-r--r--src/tools/clippy/tests/ui/impl.stderr2
-rw-r--r--src/tools/clippy/tests/ui/implicit_saturating_add.fixed106
-rw-r--r--src/tools/clippy/tests/ui/implicit_saturating_add.rs154
-rw-r--r--src/tools/clippy/tests/ui/implicit_saturating_add.stderr197
-rw-r--r--src/tools/clippy/tests/ui/implicit_saturating_sub.fixed50
-rw-r--r--src/tools/clippy/tests/ui/implicit_saturating_sub.rs50
-rw-r--r--src/tools/clippy/tests/ui/implicit_saturating_sub.stderr46
-rw-r--r--src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs1
-rw-r--r--src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.stderr20
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_index.rs2
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_index.stderr10
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_slice.stderr2
-rw-r--r--src/tools/clippy/tests/ui/inefficient_to_string.stderr10
-rw-r--r--src/tools/clippy/tests/ui/infinite_iter.rs2
-rw-r--r--src/tools/clippy/tests/ui/infinite_iter.stderr32
-rw-r--r--src/tools/clippy/tests/ui/infinite_loop.stderr2
-rw-r--r--src/tools/clippy/tests/ui/inherent_to_string.stderr4
-rw-r--r--src/tools/clippy/tests/ui/inspect_for_each.stderr2
-rw-r--r--src/tools/clippy/tests/ui/integer_division.stderr2
-rw-r--r--src/tools/clippy/tests/ui/issue_2356.fixed1
-rw-r--r--src/tools/clippy/tests/ui/issue_2356.rs1
-rw-r--r--src/tools/clippy/tests/ui/issue_2356.stderr2
-rw-r--r--src/tools/clippy/tests/ui/issue_4266.rs1
-rw-r--r--src/tools/clippy/tests/ui/issue_4266.stderr8
-rw-r--r--src/tools/clippy/tests/ui/item_after_statement.rs1
-rw-r--r--src/tools/clippy/tests/ui/item_after_statement.stderr6
-rw-r--r--src/tools/clippy/tests/ui/iter_kv_map.fixed64
-rw-r--r--src/tools/clippy/tests/ui/iter_kv_map.rs64
-rw-r--r--src/tools/clippy/tests/ui/iter_kv_map.stderr136
-rw-r--r--src/tools/clippy/tests/ui/iter_nth.stderr2
-rw-r--r--src/tools/clippy/tests/ui/iter_on_empty_collections.fixed63
-rw-r--r--src/tools/clippy/tests/ui/iter_on_empty_collections.rs63
-rw-r--r--src/tools/clippy/tests/ui/iter_on_empty_collections.stderr40
-rw-r--r--src/tools/clippy/tests/ui/iter_on_single_items.fixed63
-rw-r--r--src/tools/clippy/tests/ui/iter_on_single_items.rs63
-rw-r--r--src/tools/clippy/tests/ui/iter_on_single_items.stderr40
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next.fixed2
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next.rs2
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr2
-rw-r--r--src/tools/clippy/tests/ui/large_enum_variant.rs28
-rw-r--r--src/tools/clippy/tests/ui/large_enum_variant.stderr264
-rw-r--r--src/tools/clippy/tests/ui/large_stack_arrays.rs6
-rw-r--r--src/tools/clippy/tests/ui/large_stack_arrays.stderr10
-rw-r--r--src/tools/clippy/tests/ui/len_without_is_empty.rs2
-rw-r--r--src/tools/clippy/tests/ui/len_without_is_empty.stderr2
-rw-r--r--src/tools/clippy/tests/ui/let_if_seq.rs2
-rw-r--r--src/tools/clippy/tests/ui/let_if_seq.stderr2
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_drop.stderr2
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_lock.stderr2
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_must_use.stderr2
-rw-r--r--src/tools/clippy/tests/ui/linkedlist.stderr2
-rw-r--r--src/tools/clippy/tests/ui/literals.rs7
-rw-r--r--src/tools/clippy/tests/ui/literals.stderr35
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2018.fixed45
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2018.stderr58
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2021.fixed20
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2021.stderr51
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.fixed45
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.rs21
-rw-r--r--src/tools/clippy/tests/ui/manual_bits.fixed3
-rw-r--r--src/tools/clippy/tests/ui/manual_bits.rs3
-rw-r--r--src/tools/clippy/tests/ui/manual_bits.stderr58
-rw-r--r--src/tools/clippy/tests/ui/manual_clamp.rs331
-rw-r--r--src/tools/clippy/tests/ui/manual_clamp.stderr390
-rw-r--r--src/tools/clippy/tests/ui/manual_filter.fixed119
-rw-r--r--src/tools/clippy/tests/ui/manual_filter.rs243
-rw-r--r--src/tools/clippy/tests/ui/manual_filter.stderr191
-rw-r--r--src/tools/clippy/tests/ui/manual_find.stderr2
-rw-r--r--src/tools/clippy/tests/ui/manual_find_fixable.fixed4
-rw-r--r--src/tools/clippy/tests/ui/manual_find_fixable.rs4
-rw-r--r--src/tools/clippy/tests/ui/manual_flatten.rs2
-rw-r--r--src/tools/clippy/tests/ui/manual_flatten.stderr2
-rw-r--r--src/tools/clippy/tests/ui/manual_instant_elapsed.fixed27
-rw-r--r--src/tools/clippy/tests/ui/manual_instant_elapsed.rs27
-rw-r--r--src/tools/clippy/tests/ui/manual_instant_elapsed.stderr16
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option.rs2
-rw-r--r--src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr2
-rw-r--r--src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr2
-rw-r--r--src/tools/clippy/tests/ui/manual_ok_or.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_ok_or.rs2
-rw-r--r--src/tools/clippy/tests/ui/manual_rem_euclid.fixed30
-rw-r--r--src/tools/clippy/tests/ui/manual_rem_euclid.rs30
-rw-r--r--src/tools/clippy/tests/ui/manual_rem_euclid.stderr30
-rw-r--r--src/tools/clippy/tests/ui/manual_string_new.fixed63
-rw-r--r--src/tools/clippy/tests/ui/manual_string_new.rs63
-rw-r--r--src/tools/clippy/tests/ui/manual_string_new.stderr58
-rw-r--r--src/tools/clippy/tests/ui/manual_strip.rs19
-rw-r--r--src/tools/clippy/tests/ui/manual_strip.stderr49
-rw-r--r--src/tools/clippy/tests/ui/map_err.stderr2
-rw-r--r--src/tools/clippy/tests/ui/map_unwrap_or.rs18
-rw-r--r--src/tools/clippy/tests/ui/map_unwrap_or.stderr30
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed41
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs44
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr38
-rw-r--r--src/tools/clippy/tests/ui/match_overlapping_arm.rs1
-rw-r--r--src/tools/clippy/tests/ui/match_overlapping_arm.stderr34
-rw-r--r--src/tools/clippy/tests/ui/match_ref_pats.fixed3
-rw-r--r--src/tools/clippy/tests/ui/match_ref_pats.rs3
-rw-r--r--src/tools/clippy/tests/ui/match_ref_pats.stderr10
-rw-r--r--src/tools/clippy/tests/ui/match_result_ok.fixed3
-rw-r--r--src/tools/clippy/tests/ui/match_result_ok.rs3
-rw-r--r--src/tools/clippy/tests/ui/match_result_ok.stderr6
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms.stderr2
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.rs6
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.stderr48
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.fixed13
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.rs12
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.stderr19
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding2.fixed2
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding2.rs2
-rw-r--r--src/tools/clippy/tests/ui/match_wild_err_arm.edition2018.stderr35
-rw-r--r--src/tools/clippy/tests/ui/match_wild_err_arm.rs3
-rw-r--r--src/tools/clippy/tests/ui/match_wild_err_arm.stderr (renamed from src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr)16
-rw-r--r--src/tools/clippy/tests/ui/mem_replace.fixed18
-rw-r--r--src/tools/clippy/tests/ui/mem_replace.rs18
-rw-r--r--src/tools/clippy/tests/ui/mem_replace.stderr46
-rw-r--r--src/tools/clippy/tests/ui/methods.rs2
-rw-r--r--src/tools/clippy/tests/ui/min_max.rs1
-rw-r--r--src/tools/clippy/tests/ui/min_max.stderr26
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_attr.rs227
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_attr.stderr46
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs14
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr44
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.rs11
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.stderr38
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_no_patch.rs14
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_outer_attr.rs4
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_outer_attr.stderr8
-rw-r--r--src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr2
-rw-r--r--src/tools/clippy/tests/ui/mismatching_type_param_order.rs2
-rw-r--r--src/tools/clippy/tests/ui/mismatching_type_param_order.stderr2
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs9
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs12
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr12
-rw-r--r--src/tools/clippy/tests/ui/missing_doc.rs (renamed from src/tools/clippy/tests/ui/missing-doc.rs)14
-rw-r--r--src/tools/clippy/tests/ui/missing_doc.stderr (renamed from src/tools/clippy/tests/ui/missing-doc.stderr)48
-rw-r--r--src/tools/clippy/tests/ui/missing_doc_crate.rs (renamed from src/tools/clippy/tests/ui/missing-doc-crate.rs)0
-rw-r--r--src/tools/clippy/tests/ui/missing_doc_crate_missing.rs (renamed from src/tools/clippy/tests/ui/missing-doc-crate-missing.rs)0
-rw-r--r--src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr (renamed from src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr)2
-rw-r--r--src/tools/clippy/tests/ui/missing_doc_impl.rs (renamed from src/tools/clippy/tests/ui/missing-doc-impl.rs)15
-rw-r--r--src/tools/clippy/tests/ui/missing_doc_impl.stderr (renamed from src/tools/clippy/tests/ui/missing-doc-impl.stderr)30
-rw-r--r--src/tools/clippy/tests/ui/missing_panics_doc.stderr2
-rw-r--r--src/tools/clippy/tests/ui/missing_trait_methods.rs50
-rw-r--r--src/tools/clippy/tests/ui/missing_trait_methods.stderr27
-rw-r--r--src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed6
-rw-r--r--src/tools/clippy/tests/ui/mistyped_literal_suffix.rs6
-rw-r--r--src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr32
-rw-r--r--src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs2
-rw-r--r--src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr2
-rw-r--r--src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr2
-rw-r--r--src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr2
-rw-r--r--src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr2
-rw-r--r--src/tools/clippy/tests/ui/multi_assignments.rs9
-rw-r--r--src/tools/clippy/tests/ui/multi_assignments.stderr40
-rw-r--r--src/tools/clippy/tests/ui/mut_from_ref.stderr2
-rw-r--r--src/tools/clippy/tests/ui/mut_mut.rs4
-rw-r--r--src/tools/clippy/tests/ui/mut_mutex_lock.fixed7
-rw-r--r--src/tools/clippy/tests/ui/mut_mutex_lock.rs7
-rw-r--r--src/tools/clippy/tests/ui/mut_range_bound.stderr2
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.fixed208
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.rs208
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.stderr124
-rw-r--r--src/tools/clippy/tests/ui/needless_borrowed_ref.fixed41
-rw-r--r--src/tools/clippy/tests/ui/needless_borrowed_ref.rs41
-rw-r--r--src/tools/clippy/tests/ui/needless_borrowed_ref.stderr121
-rw-r--r--src/tools/clippy/tests/ui/needless_collect_indirect.rs191
-rw-r--r--src/tools/clippy/tests/ui/needless_collect_indirect.stderr137
-rw-r--r--src/tools/clippy/tests/ui/needless_continue.rs1
-rw-r--r--src/tools/clippy/tests/ui/needless_continue.stderr18
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_fixable.fixed7
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_fixable.rs7
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_fixable.stderr16
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_unfixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.fixed5
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.rs5
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.stderr32
-rw-r--r--src/tools/clippy/tests/ui/needless_match.fixed39
-rw-r--r--src/tools/clippy/tests/ui/needless_match.rs46
-rw-r--r--src/tools/clippy/tests/ui/needless_match.stderr23
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_value.rs9
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_value.stderr52
-rw-r--r--src/tools/clippy/tests/ui/needless_range_loop.rs1
-rw-r--r--src/tools/clippy/tests/ui/needless_range_loop.stderr28
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed46
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs46
-rw-r--r--src/tools/clippy/tests/ui/needless_return.stderr279
-rw-r--r--src/tools/clippy/tests/ui/never_loop.rs26
-rw-r--r--src/tools/clippy/tests/ui/never_loop.stderr15
-rw-r--r--src/tools/clippy/tests/ui/no_effect.rs6
-rw-r--r--src/tools/clippy/tests/ui/no_effect.stderr60
-rw-r--r--src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr2
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.rs6
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.stderr8
-rw-r--r--src/tools/clippy/tests/ui/octal_escapes.stderr2
-rw-r--r--src/tools/clippy/tests/ui/ok_expect.stderr2
-rw-r--r--src/tools/clippy/tests/ui/only_used_in_recursion.rs133
-rw-r--r--src/tools/clippy/tests/ui/only_used_in_recursion.stderr193
-rw-r--r--src/tools/clippy/tests/ui/only_used_in_recursion2.rs91
-rw-r--r--src/tools/clippy/tests/ui/only_used_in_recursion2.stderr63
-rw-r--r--src/tools/clippy/tests/ui/op_ref.rs2
-rw-r--r--src/tools/clippy/tests/ui/option_as_ref_deref.fixed17
-rw-r--r--src/tools/clippy/tests/ui/option_as_ref_deref.rs17
-rw-r--r--src/tools/clippy/tests/ui/option_as_ref_deref.stderr42
-rw-r--r--src/tools/clippy/tests/ui/option_env_unwrap.stderr2
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed9
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.rs21
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.stderr48
-rw-r--r--src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed3
-rw-r--r--src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs3
-rw-r--r--src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr38
-rw-r--r--src/tools/clippy/tests/ui/option_take_on_temporary.fixed15
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed26
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.rs18
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr76
-rw-r--r--src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.rs2
-rw-r--r--src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.rs2
-rw-r--r--src/tools/clippy/tests/ui/overly_complex_bool_expr.rs (renamed from src/tools/clippy/tests/ui/logic_bug.rs)4
-rw-r--r--src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr (renamed from src/tools/clippy/tests/ui/logic_bug.stderr)22
-rw-r--r--src/tools/clippy/tests/ui/panic_in_result_fn.stderr2
-rw-r--r--src/tools/clippy/tests/ui/panic_in_result_fn_assertions.rs2
-rw-r--r--src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr2
-rw-r--r--src/tools/clippy/tests/ui/panic_in_result_fn_debug_assertions.rs2
-rw-r--r--src/tools/clippy/tests/ui/partial_pub_fields.rs40
-rw-r--r--src/tools/clippy/tests/ui/partial_pub_fields.stderr35
-rw-r--r--src/tools/clippy/tests/ui/partialeq_to_none.fixed74
-rw-r--r--src/tools/clippy/tests/ui/partialeq_to_none.rs74
-rw-r--r--src/tools/clippy/tests/ui/partialeq_to_none.stderr110
-rw-r--r--src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr2
-rw-r--r--src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr2
-rw-r--r--src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr2
-rw-r--r--src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr2
-rw-r--r--src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr2
-rw-r--r--src/tools/clippy/tests/ui/patterns.fixed3
-rw-r--r--src/tools/clippy/tests/ui/patterns.rs3
-rw-r--r--src/tools/clippy/tests/ui/patterns.stderr6
-rw-r--r--src/tools/clippy/tests/ui/print_literal.rs3
-rw-r--r--src/tools/clippy/tests/ui/print_literal.stderr56
-rw-r--r--src/tools/clippy/tests/ui/print_with_newline.rs10
-rw-r--r--src/tools/clippy/tests/ui/print_with_newline.stderr18
-rw-r--r--src/tools/clippy/tests/ui/println_empty_string.stderr24
-rw-r--r--src/tools/clippy/tests/ui/proc_macro.stderr2
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.rs30
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.stderr20
-rw-r--r--src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed1
-rw-r--r--src/tools/clippy/tests/ui/ptr_offset_with_cast.rs1
-rw-r--r--src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr4
-rw-r--r--src/tools/clippy/tests/ui/pub_use.stderr2
-rw-r--r--src/tools/clippy/tests/ui/question_mark.fixed24
-rw-r--r--src/tools/clippy/tests/ui/question_mark.rs24
-rw-r--r--src/tools/clippy/tests/ui/range_contains.fixed26
-rw-r--r--src/tools/clippy/tests/ui/range_contains.rs26
-rw-r--r--src/tools/clippy/tests/ui/range_contains.stderr48
-rw-r--r--src/tools/clippy/tests/ui/range_plus_minus_one.fixed19
-rw-r--r--src/tools/clippy/tests/ui/range_plus_minus_one.rs19
-rw-r--r--src/tools/clippy/tests/ui/range_plus_minus_one.stderr18
-rw-r--r--src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr2
-rw-r--r--src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr2
-rw-r--r--src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.stderr2
-rw-r--r--src/tools/clippy/tests/ui/rc_mutex.rs2
-rw-r--r--src/tools/clippy/tests/ui/rc_mutex.stderr2
-rw-r--r--src/tools/clippy/tests/ui/recursive_format_impl.rs5
-rw-r--r--src/tools/clippy/tests/ui/recursive_format_impl.stderr20
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation.rs12
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation.stderr42
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed2
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation_fixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr2
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.fixed4
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.rs4
-rw-r--r--src/tools/clippy/tests/ui/redundant_clone.stderr2
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed20
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs20
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr50
-rw-r--r--src/tools/clippy/tests/ui/redundant_else.stderr2
-rw-r--r--src/tools/clippy/tests/ui/redundant_field_names.fixed16
-rw-r--r--src/tools/clippy/tests/ui/redundant_field_names.rs16
-rw-r--r--src/tools/clippy/tests/ui/redundant_field_names.stderr22
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr2
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed11
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs11
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr36
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed11
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs11
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr44
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed13
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes.rs13
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr40
-rw-r--r--src/tools/clippy/tests/ui/ref_option_ref.rs5
-rw-r--r--src/tools/clippy/tests/ui/regex.rs2
-rw-r--r--src/tools/clippy/tests/ui/regex.stderr2
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed13
-rw-r--r--src/tools/clippy/tests/ui/rename.rs9
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr108
-rw-r--r--src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr2
-rw-r--r--src/tools/clippy/tests/ui/result_large_err.rs99
-rw-r--r--src/tools/clippy/tests/ui/result_large_err.stderr91
-rw-r--r--src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed2
-rw-r--r--src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/result_unit_error.stderr2
-rw-r--r--src/tools/clippy/tests/ui/return_self_not_must_use.stderr2
-rw-r--r--src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed1
-rw-r--r--src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs1
-rw-r--r--src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr8
-rw-r--r--src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed1
-rw-r--r--src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.rs1
-rw-r--r--src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr12
-rw-r--r--src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.rs1
-rw-r--r--src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.stderr4
-rw-r--r--src/tools/clippy/tests/ui/same_functions_in_if_condition.rs16
-rw-r--r--src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr34
-rw-r--r--src/tools/clippy/tests/ui/same_item_push.rs1
-rw-r--r--src/tools/clippy/tests/ui/same_item_push.stderr2
-rw-r--r--src/tools/clippy/tests/ui/same_name_method.stderr2
-rw-r--r--src/tools/clippy/tests/ui/search_is_some.stderr2
-rw-r--r--src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs4
-rw-r--r--src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr10
-rw-r--r--src/tools/clippy/tests/ui/shadow.stderr6
-rw-r--r--src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr14
-rw-r--r--src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr2
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs7
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr54
-rw-r--r--src/tools/clippy/tests/ui/similar_names.stderr2
-rw-r--r--src/tools/clippy/tests/ui/single_char_lifetime_names.stderr2
-rw-r--r--src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr2
-rw-r--r--src/tools/clippy/tests/ui/single_match.rs1
-rw-r--r--src/tools/clippy/tests/ui/single_match.stderr32
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.rs4
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.stderr10
-rw-r--r--src/tools/clippy/tests/ui/size_of_in_element_count/expressions.stderr2
-rw-r--r--src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr2
-rw-r--r--src/tools/clippy/tests/ui/skip_while_next.rs2
-rw-r--r--src/tools/clippy/tests/ui/skip_while_next.stderr2
-rw-r--r--src/tools/clippy/tests/ui/stable_sort_primitive.stderr2
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.rs6
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.stderr22
-rw-r--r--src/tools/clippy/tests/ui/str_to_string.stderr2
-rw-r--r--src/tools/clippy/tests/ui/string_add.rs4
-rw-r--r--src/tools/clippy/tests/ui/string_add_assign.fixed4
-rw-r--r--src/tools/clippy/tests/ui/string_add_assign.rs4
-rw-r--r--src/tools/clippy/tests/ui/string_to_string.stderr2
-rw-r--r--src/tools/clippy/tests/ui/struct_excessive_bools.stderr2
-rw-r--r--src/tools/clippy/tests/ui/suspicious_else_formatting.stderr2
-rw-r--r--src/tools/clippy/tests/ui/suspicious_map.stderr2
-rw-r--r--src/tools/clippy/tests/ui/suspicious_splitn.stderr2
-rw-r--r--src/tools/clippy/tests/ui/suspicious_to_owned.rs62
-rw-r--r--src/tools/clippy/tests/ui/suspicious_to_owned.stderr42
-rw-r--r--src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr2
-rw-r--r--src/tools/clippy/tests/ui/swap.fixed2
-rw-r--r--src/tools/clippy/tests/ui/swap.rs2
-rw-r--r--src/tools/clippy/tests/ui/swap.stderr4
-rw-r--r--src/tools/clippy/tests/ui/toplevel_ref_arg.fixed2
-rw-r--r--src/tools/clippy/tests/ui/toplevel_ref_arg.rs2
-rw-r--r--src/tools/clippy/tests/ui/trailing_empty_array.stderr2
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed112
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs218
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr165
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.rs166
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.stderr71
-rw-r--r--src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr4
-rw-r--r--src/tools/clippy/tests/ui/transmute_undefined_repr.rs12
-rw-r--r--src/tools/clippy/tests/ui/transmute_undefined_repr.stderr38
-rw-r--r--src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed2
-rw-r--r--src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs2
-rw-r--r--src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs7
-rw-r--r--src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr38
-rw-r--r--src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr2
-rw-r--r--src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr2
-rw-r--r--src/tools/clippy/tests/ui/undropped_manually_drops.stderr2
-rw-r--r--src/tools/clippy/tests/ui/unicode.fixed48
-rw-r--r--src/tools/clippy/tests/ui/unicode.rs48
-rw-r--r--src/tools/clippy/tests/ui/unicode.stderr46
-rw-r--r--src/tools/clippy/tests/ui/uninit.rs2
-rw-r--r--src/tools/clippy/tests/ui/uninit_vec.rs6
-rw-r--r--src/tools/clippy/tests/ui/uninit_vec.stderr2
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args.fixed182
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args.rs182
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args.stderr879
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed29
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.stderr15
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed29
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr51
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args_panic.rs29
-rw-r--r--src/tools/clippy/tests/ui/unit_arg.rs21
-rw-r--r--src/tools/clippy/tests/ui/unit_arg.stderr20
-rw-r--r--src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed3
-rw-r--r--src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs3
-rw-r--r--src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unit_hash.stderr2
-rw-r--r--src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr2
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.fixed27
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.rs27
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.stderr32
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_clone.rs4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_join.fixed2
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_join.rs2
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed21
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs21
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr68
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.fixed1
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.rs1
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.stderr2
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_self_imports.stderr2
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.fixed99
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.rs99
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.stderr10
-rw-r--r--src/tools/clippy/tests/ui/unneeded_field_pattern.stderr2
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns.fixed16
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns.rs16
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns.stderr13
-rw-r--r--src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr2
-rw-r--r--src/tools/clippy/tests/ui/unsafe_removed_from_name.rs3
-rw-r--r--src/tools/clippy/tests/ui/unused_async.stderr2
-rw-r--r--src/tools/clippy/tests/ui/unused_format_specs.fixed18
-rw-r--r--src/tools/clippy/tests/ui/unused_format_specs.rs18
-rw-r--r--src/tools/clippy/tests/ui/unused_format_specs.stderr54
-rw-r--r--src/tools/clippy/tests/ui/unused_format_specs_unfixable.rs30
-rw-r--r--src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr69
-rw-r--r--src/tools/clippy/tests/ui/unused_io_amount.stderr2
-rw-r--r--src/tools/clippy/tests/ui/unused_peekable.rs169
-rw-r--r--src/tools/clippy/tests/ui/unused_peekable.stderr67
-rw-r--r--src/tools/clippy/tests/ui/unused_self.stderr2
-rw-r--r--src/tools/clippy/tests/ui/unwrap.rs3
-rw-r--r--src/tools/clippy/tests/ui/unwrap.stderr12
-rw-r--r--src/tools/clippy/tests/ui/unwrap_expect_used.rs35
-rw-r--r--src/tools/clippy/tests/ui/unwrap_expect_used.stderr52
-rw-r--r--src/tools/clippy/tests/ui/unwrap_in_result.stderr2
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or_else_default.fixed3
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or_else_default.rs3
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or_else_default.stderr8
-rw-r--r--src/tools/clippy/tests/ui/upper_case_acronyms.rs9
-rw-r--r--src/tools/clippy/tests/ui/upper_case_acronyms.stderr14
-rw-r--r--src/tools/clippy/tests/ui/use_self.fixed42
-rw-r--r--src/tools/clippy/tests/ui/use_self.rs42
-rw-r--r--src/tools/clippy/tests/ui/use_self.stderr90
-rw-r--r--src/tools/clippy/tests/ui/used_underscore_binding.rs3
-rw-r--r--src/tools/clippy/tests/ui/used_underscore_binding.stderr12
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.fixed3
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.rs3
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.stderr24
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.stderr2
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion_try.rs4
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion_try.stderr4
-rw-r--r--src/tools/clippy/tests/ui/vec.fixed2
-rw-r--r--src/tools/clippy/tests/ui/vec.rs2
-rw-r--r--src/tools/clippy/tests/ui/vec_resize_to_zero.rs12
-rw-r--r--src/tools/clippy/tests/ui/vec_resize_to_zero.stderr12
-rw-r--r--src/tools/clippy/tests/ui/verbose_file_reads.rs2
-rw-r--r--src/tools/clippy/tests/ui/verbose_file_reads.stderr2
-rw-r--r--src/tools/clippy/tests/ui/vtable_address_comparisons.stderr2
-rw-r--r--src/tools/clippy/tests/ui/while_let_loop.rs1
-rw-r--r--src/tools/clippy/tests/ui/while_let_loop.stderr10
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.fixed10
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.rs10
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.stderr52
-rw-r--r--src/tools/clippy/tests/ui/wild_in_or_pats.stderr2
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed10
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs10
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr14
-rw-r--r--src/tools/clippy/tests/ui/write_literal.rs4
-rw-r--r--src/tools/clippy/tests/ui/write_literal.stderr56
-rw-r--r--src/tools/clippy/tests/ui/write_literal_2.rs9
-rw-r--r--src/tools/clippy/tests/ui/write_literal_2.stderr80
-rw-r--r--src/tools/clippy/tests/ui/write_with_newline.rs8
-rw-r--r--src/tools/clippy/tests/ui/write_with_newline.stderr38
-rw-r--r--src/tools/clippy/tests/ui/writeln_empty_string.stderr12
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention.stderr2
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention2.stderr2
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr2
-rw-r--r--src/tools/clippy/tests/ui/zero_div_zero.stderr2
-rw-r--r--src/tools/clippy/tests/ui/zero_sized_btreemap_values.stderr2
-rw-r--r--src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr2
-rw-r--r--src/tools/clippy/tests/versioncheck.rs8
-rw-r--r--src/tools/clippy/tests/workspace.rs14
1871 files changed, 47050 insertions, 15314 deletions
diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml
index 0e27cc927..b99213011 100644
--- a/src/tools/clippy/.github/workflows/clippy.yml
+++ b/src/tools/clippy/.github/workflows/clippy.yml
@@ -24,6 +24,8 @@ env:
RUST_BACKTRACE: 1
CARGO_TARGET_DIR: '${{ github.workspace }}/target'
NO_FMT_TEST: 1
+ CARGO_INCREMENTAL: 0
+ CARGO_UNSTABLE_SPARSE_REGISTRY: true
jobs:
base:
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 97453303c..6448b2d40 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -10,6 +10,8 @@ env:
RUST_BACKTRACE: 1
CARGO_TARGET_DIR: '${{ github.workspace }}/target'
NO_FMT_TEST: 1
+ CARGO_INCREMENTAL: 0
+ CARGO_UNSTABLE_SPARSE_REGISTRY: true
defaults:
run:
diff --git a/src/tools/clippy/.github/workflows/clippy_dev.yml b/src/tools/clippy/.github/workflows/clippy_dev.yml
index 22051093c..14f20212a 100644
--- a/src/tools/clippy/.github/workflows/clippy_dev.yml
+++ b/src/tools/clippy/.github/workflows/clippy_dev.yml
@@ -15,6 +15,8 @@ on:
env:
RUST_BACKTRACE: 1
+ CARGO_INCREMENTAL: 0
+ CARGO_UNSTABLE_SPARSE_REGISTRY: true
jobs:
clippy_dev:
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 2278a8dc1..2d7bda27e 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,307 @@ document.
## Unreleased / In Rust Nightly
-[7c21f91b...master](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...master)
+[3c7e7dbc...master](https://github.com/rust-lang/rust-clippy/compare/3c7e7dbc...master)
+
+## Rust 1.64
+
+Current stable, released 2022-09-22
+
+[d7b5cbf0...3c7e7dbc](https://github.com/rust-lang/rust-clippy/compare/d7b5cbf0...3c7e7dbc)
+
+### New Lints
+
+* [`arithmetic_side_effects`]
+ [#9130](https://github.com/rust-lang/rust-clippy/pull/9130)
+* [`invalid_utf8_in_unchecked`]
+ [#9105](https://github.com/rust-lang/rust-clippy/pull/9105)
+* [`assertions_on_result_states`]
+ [#9225](https://github.com/rust-lang/rust-clippy/pull/9225)
+* [`manual_find`]
+ [#8649](https://github.com/rust-lang/rust-clippy/pull/8649)
+* [`manual_retain`]
+ [#8972](https://github.com/rust-lang/rust-clippy/pull/8972)
+* [`default_instead_of_iter_empty`]
+ [#8989](https://github.com/rust-lang/rust-clippy/pull/8989)
+* [`manual_rem_euclid`]
+ [#9031](https://github.com/rust-lang/rust-clippy/pull/9031)
+* [`obfuscated_if_else`]
+ [#9148](https://github.com/rust-lang/rust-clippy/pull/9148)
+* [`std_instead_of_core`]
+ [#9103](https://github.com/rust-lang/rust-clippy/pull/9103)
+* [`std_instead_of_alloc`]
+ [#9103](https://github.com/rust-lang/rust-clippy/pull/9103)
+* [`alloc_instead_of_core`]
+ [#9103](https://github.com/rust-lang/rust-clippy/pull/9103)
+* [`explicit_auto_deref`]
+ [#8355](https://github.com/rust-lang/rust-clippy/pull/8355)
+
+
+### Moves and Deprecations
+
+* Moved [`format_push_string`] to `restriction` (now allow-by-default)
+ [#9161](https://github.com/rust-lang/rust-clippy/pull/9161)
+
+### Enhancements
+
+* [`significant_drop_in_scrutinee`]: Now gives more context in the lint message
+ [#8981](https://github.com/rust-lang/rust-clippy/pull/8981)
+* [`single_match`], [`single_match_else`]: Now catches more `Option` cases
+ [#8985](https://github.com/rust-lang/rust-clippy/pull/8985)
+* [`unused_async`]: Now works for async methods
+ [#9025](https://github.com/rust-lang/rust-clippy/pull/9025)
+* [`manual_filter_map`], [`manual_find_map`]: Now lint more expressions
+ [#8958](https://github.com/rust-lang/rust-clippy/pull/8958)
+* [`question_mark`]: Now works for simple `if let` expressions
+ [#8356](https://github.com/rust-lang/rust-clippy/pull/8356)
+* [`undocumented_unsafe_blocks`]: Now finds comments before the start of closures
+ [#9117](https://github.com/rust-lang/rust-clippy/pull/9117)
+* [`trait_duplication_in_bounds`]: Now catches duplicate bounds in where clauses
+ [#8703](https://github.com/rust-lang/rust-clippy/pull/8703)
+* [`shadow_reuse`], [`shadow_same`], [`shadow_unrelated`]: Now lint in const blocks
+ [#9124](https://github.com/rust-lang/rust-clippy/pull/9124)
+* [`slow_vector_initialization`]: Now detects cases with `vec.capacity()`
+ [#8953](https://github.com/rust-lang/rust-clippy/pull/8953)
+* [`unused_self`]: Now respects the `avoid-breaking-exported-api` config option
+ [#9199](https://github.com/rust-lang/rust-clippy/pull/9199)
+* [`box_collection`]: Now supports all std collections
+ [#9170](https://github.com/rust-lang/rust-clippy/pull/9170)
+
+### False Positive Fixes
+
+* [`significant_drop_in_scrutinee`]: Now ignores calls to `IntoIterator::into_iter`
+ [#9140](https://github.com/rust-lang/rust-clippy/pull/9140)
+* [`while_let_loop`]: Now ignores cases when the significant drop order would change
+ [#8981](https://github.com/rust-lang/rust-clippy/pull/8981)
+* [`branches_sharing_code`]: Now ignores cases where moved variables have a significant
+ drop or variable modifications can affect the conditions
+ [#9138](https://github.com/rust-lang/rust-clippy/pull/9138)
+* [`let_underscore_lock`]: Now ignores bindings that aren't locked
+ [#8990](https://github.com/rust-lang/rust-clippy/pull/8990)
+* [`trivially_copy_pass_by_ref`]: Now tracks lifetimes and ignores cases where unsafe
+ pointers are used
+ [#8639](https://github.com/rust-lang/rust-clippy/pull/8639)
+* [`let_unit_value`]: No longer ignores `#[allow]` attributes on the value
+ [#9082](https://github.com/rust-lang/rust-clippy/pull/9082)
+* [`declare_interior_mutable_const`]: Now ignores the `thread_local!` macro
+ [#9015](https://github.com/rust-lang/rust-clippy/pull/9015)
+* [`if_same_then_else`]: Now ignores branches with `todo!` and `unimplemented!`
+ [#9006](https://github.com/rust-lang/rust-clippy/pull/9006)
+* [`enum_variant_names`]: Now ignores names with `_` prefixes
+ [#9032](https://github.com/rust-lang/rust-clippy/pull/9032)
+* [`let_unit_value`]: Now ignores cases, where the unit type is manually specified
+ [#9056](https://github.com/rust-lang/rust-clippy/pull/9056)
+* [`match_same_arms`]: Now ignores branches with `todo!`
+ [#9207](https://github.com/rust-lang/rust-clippy/pull/9207)
+* [`assign_op_pattern`]: Ignores cases that break borrowing rules
+ [#9214](https://github.com/rust-lang/rust-clippy/pull/9214)
+* [`extra_unused_lifetimes`]: No longer triggers in derive macros
+ [#9037](https://github.com/rust-lang/rust-clippy/pull/9037)
+* [`mismatching_type_param_order`]: Now ignores complicated generic parameters
+ [#9146](https://github.com/rust-lang/rust-clippy/pull/9146)
+* [`equatable_if_let`]: No longer lints in macros
+ [#9074](https://github.com/rust-lang/rust-clippy/pull/9074)
+* [`new_without_default`]: Now ignores generics and lifetime parameters on `fn new`
+ [#9115](https://github.com/rust-lang/rust-clippy/pull/9115)
+* [`needless_borrow`]: Now ignores cases that result in the execution of different traits
+ [#9096](https://github.com/rust-lang/rust-clippy/pull/9096)
+* [`declare_interior_mutable_const`]: No longer triggers in thread-local initializers
+ [#9246](https://github.com/rust-lang/rust-clippy/pull/9246)
+
+### Suggestion Fixes/Improvements
+
+* [`type_repetition_in_bounds`]: The suggestion now works with maybe bounds
+ [#9132](https://github.com/rust-lang/rust-clippy/pull/9132)
+* [`transmute_ptr_to_ref`]: Now suggests `pointer::cast` when possible
+ [#8939](https://github.com/rust-lang/rust-clippy/pull/8939)
+* [`useless_format`]: Now suggests the correct variable name
+ [#9237](https://github.com/rust-lang/rust-clippy/pull/9237)
+* [`or_fun_call`]: The lint emission will now only span over the `unwrap_or` call
+ [#9144](https://github.com/rust-lang/rust-clippy/pull/9144)
+* [`neg_multiply`]: Now suggests adding parentheses around suggestion if needed
+ [#9026](https://github.com/rust-lang/rust-clippy/pull/9026)
+* [`unnecessary_lazy_evaluations`]: Now suggest for `bool::then_some` for lazy evaluation
+ [#9099](https://github.com/rust-lang/rust-clippy/pull/9099)
+* [`manual_flatten`]: Improved message for long code snippets
+ [#9156](https://github.com/rust-lang/rust-clippy/pull/9156)
+* [`explicit_counter_loop`]: The suggestion is now machine applicable
+ [#9149](https://github.com/rust-lang/rust-clippy/pull/9149)
+* [`needless_borrow`]: Now keeps parentheses around fields, when needed
+ [#9210](https://github.com/rust-lang/rust-clippy/pull/9210)
+* [`while_let_on_iterator`]: The suggestion now works in `FnOnce` closures
+ [#9134](https://github.com/rust-lang/rust-clippy/pull/9134)
+
+### ICE Fixes
+
+* Fix ICEs related to `#![feature(generic_const_exprs)]` usage
+ [#9241](https://github.com/rust-lang/rust-clippy/pull/9241)
+* Fix ICEs related to reference lints
+ [#9093](https://github.com/rust-lang/rust-clippy/pull/9093)
+* [`question_mark`]: Fix ICE on zero field tuple structs
+ [#9244](https://github.com/rust-lang/rust-clippy/pull/9244)
+
+### Documentation Improvements
+
+* [`needless_option_take`]: Now includes a "What it does" and "Why is this bad?" section.
+ [#9022](https://github.com/rust-lang/rust-clippy/pull/9022)
+
+### Others
+
+* Using `--cap-lints=allow` and only `--force-warn`ing some will now work with Clippy's driver
+ [#9036](https://github.com/rust-lang/rust-clippy/pull/9036)
+* Clippy now tries to read the `rust-version` from `Cargo.toml` to identify the
+ minimum supported rust version
+ [#8774](https://github.com/rust-lang/rust-clippy/pull/8774)
+
+## Rust 1.63
+
+Released 2022-08-11
+
+[7c21f91b...d7b5cbf0](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...d7b5cbf0)
+
+### New Lints
+
+* [`borrow_deref_ref`]
+ [#7930](https://github.com/rust-lang/rust-clippy/pull/7930)
+* [`doc_link_with_quotes`]
+ [#8385](https://github.com/rust-lang/rust-clippy/pull/8385)
+* [`no_effect_replace`]
+ [#8754](https://github.com/rust-lang/rust-clippy/pull/8754)
+* [`rc_clone_in_vec_init`]
+ [#8769](https://github.com/rust-lang/rust-clippy/pull/8769)
+* [`derive_partial_eq_without_eq`]
+ [#8796](https://github.com/rust-lang/rust-clippy/pull/8796)
+* [`mismatching_type_param_order`]
+ [#8831](https://github.com/rust-lang/rust-clippy/pull/8831)
+* [`duplicate_mod`] [#8832](https://github.com/rust-lang/rust-clippy/pull/8832)
+* [`unused_rounding`]
+ [#8866](https://github.com/rust-lang/rust-clippy/pull/8866)
+* [`get_first`] [#8882](https://github.com/rust-lang/rust-clippy/pull/8882)
+* [`swap_ptr_to_ref`]
+ [#8916](https://github.com/rust-lang/rust-clippy/pull/8916)
+* [`almost_complete_letter_range`]
+ [#8918](https://github.com/rust-lang/rust-clippy/pull/8918)
+* [`needless_parens_on_range_literals`]
+ [#8933](https://github.com/rust-lang/rust-clippy/pull/8933)
+* [`as_underscore`] [#8934](https://github.com/rust-lang/rust-clippy/pull/8934)
+
+### Moves and Deprecations
+
+* Rename `eval_order_dependence` to [`mixed_read_write_in_expression`], move to
+ `nursery` [#8621](https://github.com/rust-lang/rust-clippy/pull/8621)
+
+### Enhancements
+
+* [`undocumented_unsafe_blocks`]: Now also lints on unsafe trait implementations
+ [#8761](https://github.com/rust-lang/rust-clippy/pull/8761)
+* [`empty_line_after_outer_attr`]: Now also lints on argumentless macros
+ [#8790](https://github.com/rust-lang/rust-clippy/pull/8790)
+* [`expect_used`]: Now can be disabled in tests with the `allow-expect-in-tests`
+ option [#8802](https://github.com/rust-lang/rust-clippy/pull/8802)
+* [`unwrap_used`]: Now can be disabled in tests with the `allow-unwrap-in-tests`
+ option [#8802](https://github.com/rust-lang/rust-clippy/pull/8802)
+* [`disallowed_methods`]: Now also lints indirect usages
+ [#8852](https://github.com/rust-lang/rust-clippy/pull/8852)
+* [`get_last_with_len`]: Now also lints `VecDeque` and any deref to slice
+ [#8862](https://github.com/rust-lang/rust-clippy/pull/8862)
+* [`manual_range_contains`]: Now also lints on chains of `&&` and `||`
+ [#8884](https://github.com/rust-lang/rust-clippy/pull/8884)
+* [`rc_clone_in_vec_init`]: Now also lints on `Weak`
+ [#8885](https://github.com/rust-lang/rust-clippy/pull/8885)
+* [`dbg_macro`]: Introduce `allow-dbg-in-tests` config option
+ [#8897](https://github.com/rust-lang/rust-clippy/pull/8897)
+* [`use_self`]: Now also lints on `TupleStruct` and `Struct` patterns
+ [#8899](https://github.com/rust-lang/rust-clippy/pull/8899)
+* [`manual_find_map`] and [`manual_filter_map`]: Now also lints on more complex
+ method chains inside `map`
+ [#8930](https://github.com/rust-lang/rust-clippy/pull/8930)
+* [`needless_return`]: Now also lints on macro expressions in return statements
+ [#8932](https://github.com/rust-lang/rust-clippy/pull/8932)
+* [`doc_markdown`]: Users can now indicate, that the `doc-valid-idents` config
+ should extend the default and not replace it
+ [#8944](https://github.com/rust-lang/rust-clippy/pull/8944)
+* [`disallowed_names`]: Users can now indicate, that the `disallowed-names`
+ config should extend the default and not replace it
+ [#8944](https://github.com/rust-lang/rust-clippy/pull/8944)
+* [`never_loop`]: Now checks for `continue` in struct expression
+ [#9002](https://github.com/rust-lang/rust-clippy/pull/9002)
+
+### False Positive Fixes
+
+* [`useless_transmute`]: No longer lints on types with erased regions
+ [#8564](https://github.com/rust-lang/rust-clippy/pull/8564)
+* [`vec_init_then_push`]: No longer lints when further extended
+ [#8699](https://github.com/rust-lang/rust-clippy/pull/8699)
+* [`cmp_owned`]: No longer lints on `From::from` for `Copy` types
+ [#8807](https://github.com/rust-lang/rust-clippy/pull/8807)
+* [`redundant_allocation`]: No longer lints on fat pointers that would become
+ thin pointers [#8813](https://github.com/rust-lang/rust-clippy/pull/8813)
+* [`derive_partial_eq_without_eq`]:
+ * Handle differing predicates applied by `#[derive(PartialEq)]` and
+ `#[derive(Eq)]`
+ [#8869](https://github.com/rust-lang/rust-clippy/pull/8869)
+ * No longer lints on non-public types and better handles generics
+ [#8950](https://github.com/rust-lang/rust-clippy/pull/8950)
+* [`empty_line_after_outer_attr`]: No longer lints empty lines in inner
+ string values [#8892](https://github.com/rust-lang/rust-clippy/pull/8892)
+* [`branches_sharing_code`]: No longer lints when using different binding names
+ [#8901](https://github.com/rust-lang/rust-clippy/pull/8901)
+* [`significant_drop_in_scrutinee`]: No longer lints on Try `?` and `await`
+ desugared expressions [#8902](https://github.com/rust-lang/rust-clippy/pull/8902)
+* [`checked_conversions`]: No longer lints in `const` contexts
+ [#8907](https://github.com/rust-lang/rust-clippy/pull/8907)
+* [`iter_overeager_cloned`]: No longer lints on `.cloned().flatten()` when
+ `T::Item` doesn't implement `IntoIterator`
+ [#8960](https://github.com/rust-lang/rust-clippy/pull/8960)
+
+### Suggestion Fixes/Improvements
+
+* [`vec_init_then_push`]: Suggest to remove `mut` binding when possible
+ [#8699](https://github.com/rust-lang/rust-clippy/pull/8699)
+* [`manual_range_contains`]: Fix suggestion for integers with different signs
+ [#8763](https://github.com/rust-lang/rust-clippy/pull/8763)
+* [`identity_op`]: Add parenthesis to suggestions where required
+ [#8786](https://github.com/rust-lang/rust-clippy/pull/8786)
+* [`cast_lossless`]: No longer gives wrong suggestion on `usize`/`isize`->`f64`
+ [#8778](https://github.com/rust-lang/rust-clippy/pull/8778)
+* [`rc_clone_in_vec_init`]: Add suggestion
+ [#8814](https://github.com/rust-lang/rust-clippy/pull/8814)
+* The "unknown field" error messages for config files now wraps the field names
+ [#8823](https://github.com/rust-lang/rust-clippy/pull/8823)
+* [`cast_abs_to_unsigned`]: Do not remove cast if it's required
+ [#8876](https://github.com/rust-lang/rust-clippy/pull/8876)
+* [`significant_drop_in_scrutinee`]: Improve lint message for types that are not
+ references and not trivially clone-able
+ [#8902](https://github.com/rust-lang/rust-clippy/pull/8902)
+* [`for_loops_over_fallibles`]: Now suggests the correct variant of `iter()`,
+ `iter_mut()` or `into_iter()`
+ [#8941](https://github.com/rust-lang/rust-clippy/pull/8941)
+
+### ICE Fixes
+
+* Fix ICE in [`let_unit_value`] when calling a `static`/`const` callable type
+ [#8835](https://github.com/rust-lang/rust-clippy/pull/8835)
+* Fix ICEs on callable `static`/`const`s
+ [#8896](https://github.com/rust-lang/rust-clippy/pull/8896)
+* [`needless_late_init`]
+ [#8912](https://github.com/rust-lang/rust-clippy/pull/8912)
+* Fix ICE in shadow lints
+ [#8913](https://github.com/rust-lang/rust-clippy/pull/8913)
+
+### Documentation Improvements
+
+* Clippy has a [Book](https://doc.rust-lang.org/nightly/clippy/) now!
+ [#7359](https://github.com/rust-lang/rust-clippy/pull/7359)
+* Add a *copy lint name*-button to Clippy's lint list
+ [#8839](https://github.com/rust-lang/rust-clippy/pull/8839)
+* Display past names of renamed lints on Clippy's lint list
+ [#8843](https://github.com/rust-lang/rust-clippy/pull/8843)
+* Add the ability to show the lint output in the lint list
+ [#8947](https://github.com/rust-lang/rust-clippy/pull/8947)
## Rust 1.62
-Current stable, released 2022-06-30
+Released 2022-06-30
[d0cf3481...7c21f91b](https://github.com/rust-lang/rust-clippy/compare/d0cf3481...7c21f91b)
@@ -965,7 +1261,7 @@ Released 2021-09-09
[#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
+* [`disallowed_names`]: Now allows disallowed 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)
@@ -2066,7 +2362,7 @@ Released 2020-08-27
[#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
+* [`disallowed_names`]: 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)
@@ -3437,8 +3733,9 @@ Released 2018-09-13
[`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range
[`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
-[`arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic
+[`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects
[`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
+[`as_ptr_cast_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_ptr_cast_mut
[`as_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore
[`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
[`assertions_on_result_states`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_result_states
@@ -3457,11 +3754,13 @@ Released 2018-09-13
[`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
+[`bool_to_int_with_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_to_int_with_if
[`borrow_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr
[`borrow_deref_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_deref_ref
[`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
+[`box_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_default
[`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
[`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
@@ -3474,6 +3773,7 @@ Released 2018-09-13
[`cast_enum_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_enum_constructor
[`cast_enum_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_enum_truncation
[`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless
+[`cast_nan_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_nan_to_int
[`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
@@ -3481,6 +3781,7 @@ Released 2018-09-13
[`cast_ref_to_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ref_to_mut
[`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss
[`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes
+[`cast_slice_from_raw_parts`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_from_raw_parts
[`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
@@ -3496,6 +3797,7 @@ Released 2018-09-13
[`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
+[`collapsible_str_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace
[`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
[`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
@@ -3520,8 +3822,10 @@ Released 2018-09-13
[`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
[`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq
+[`disallowed_macros`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros
[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
[`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
+[`disallowed_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names
[`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
[`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
@@ -3616,6 +3920,7 @@ Released 2018-09-13
[`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_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_add
[`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
@@ -3650,11 +3955,14 @@ Released 2018-09-13
[`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_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map
[`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_on_empty_collections`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_empty_collections
+[`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items
[`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned
[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
[`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain
@@ -3681,10 +3989,13 @@ Released 2018-09-13
[`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
[`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits
+[`manual_clamp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp
+[`manual_filter`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter
[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
[`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find
[`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_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed
[`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
@@ -3695,6 +4006,7 @@ Released 2018-09-13
[`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_string_new`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_string_new
[`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
@@ -3737,6 +4049,7 @@ Released 2018-09-13
[`missing_panics_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc
[`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc
[`missing_spin_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_spin_loop
+[`missing_trait_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_trait_methods
[`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
[`mixed_read_write_in_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_read_write_in_expression
@@ -3745,6 +4058,7 @@ Released 2018-09-13
[`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
+[`multi_assignments`]: https://rust-lang.github.io/rust-clippy/master/index.html#multi_assignments
[`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
@@ -3816,13 +4130,17 @@ Released 2018-09-13
[`or_then_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_then_unwrap
[`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
[`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
+[`overly_complex_bool_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#overly_complex_bool_expr
[`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic
[`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
[`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
+[`partial_pub_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#partial_pub_fields
[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
+[`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none
[`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
+[`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters
[`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
[`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
[`print_in_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_in_format_impl
@@ -3868,6 +4186,7 @@ Released 2018-09-13
[`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_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used
+[`result_large_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err
[`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_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else
@@ -3926,6 +4245,7 @@ Released 2018-09-13
[`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_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_to_owned
[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
[`swap_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_ptr_to_ref
[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
@@ -3963,6 +4283,7 @@ Released 2018-09-13
[`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
+[`uninlined_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
[`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
@@ -3996,8 +4317,10 @@ Released 2018-09-13
[`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_format_specs`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_format_specs
[`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
[`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
+[`unused_peekable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_peekable
[`unused_rounding`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_rounding
[`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
diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md
index 6e15133d2..85f94a74a 100644
--- a/src/tools/clippy/CONTRIBUTING.md
+++ b/src/tools/clippy/CONTRIBUTING.md
@@ -29,11 +29,11 @@ All contributors are expected to follow the [Rust Code of Conduct].
## The Clippy book
-If you're new to Clippy and don't know where to start the [Clippy book] includes
-a developer guide and is a good place to start your journey.
+If you're new to Clippy and don't know where to start, the [Clippy book] includes
+a [developer guide] and is a good place to start your journey.
-<!-- FIXME: Link to the deployed book, once it is deployed through CI -->
-[Clippy book]: book/src
+[Clippy book]: https://doc.rust-lang.org/nightly/clippy/index.html
+[developer guide]: https://doc.rust-lang.org/nightly/clippy/development/index.html
## High level approach
@@ -110,23 +110,28 @@ Just make sure to remove the dependencies again before finally making a pull req
[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 Clippy's `Cargo.toml.`
-You will require a `nightly` toolchain with the `rustc-dev` component installed.
-Make sure that in the `rust-analyzer` configuration, you set
+For [`rust-analyzer`][ra_homepage] to work correctly make sure that in the `rust-analyzer` configuration you set
+
```json
{ "rust-analyzer.rustc.source": "discover" }
```
-and
-```json
-{ "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.
+
+To have `rust-analyzer` also work in the `clippy_dev` and `lintcheck` crates, add the following configuration
+
+```json
+{
+ "rust-analyzer.linkedProjects": [
+ "./Cargo.toml",
+ "clippy_dev/Cargo.toml",
+ "lintcheck/Cargo.toml",
+ ]
+}
+```
[ra_homepage]: https://rust-analyzer.github.io/
-[6869]: https://github.com/rust-lang/rust-clippy/pull/6869
## How Clippy works
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 1c875c3ad..60200a88b 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy"
-version = "0.1.64"
+version = "0.1.66"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@@ -23,12 +23,12 @@ path = "src/driver.rs"
[dependencies]
clippy_lints = { path = "clippy_lints" }
semver = "1.0"
-rustc_tools_util = { path = "rustc_tools_util" }
+rustc_tools_util = "0.2.1"
tempfile = { version = "3.2", optional = true }
termize = "0.1"
[dev-dependencies]
-compiletest_rs = { version = "0.8", features = ["tmp"] }
+compiletest_rs = { version = "0.9", features = ["tmp"] }
tester = "0.9"
regex = "1.5"
toml = "0.5"
@@ -55,7 +55,7 @@ tokio = { version = "1", features = ["io-util"] }
rustc-semver = "1.1"
[build-dependencies]
-rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
+rustc_tools_util = "0.2.1"
[features]
deny-warnings = ["clippy_lints/deny-warnings"]
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index 2c3defeaa..a8a6b86d2 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -139,25 +139,6 @@ line. (You can swap `clippy::all` with the specific lint category you are target
## Configuration
-Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml`. It contains a basic `variable =
-value` mapping e.g.
-
-```toml
-avoid-breaking-exported-api = false
-blacklisted-names = ["toto", "tata", "titi"]
-cognitive-complexity-threshold = 30
-```
-
-See the [list of lints](https://rust-lang.github.io/rust-clippy/master/index.html) for more information about which
-lints can be configured and the meaning of the variables.
-
-Note that configuration changes will not apply for code that has already been compiled and cached under `./target/`;
-for example, adding a new string to `doc-valid-idents` may still result in Clippy flagging that string. To be sure that
-any configuration changes are applied, you may want to run `cargo clean` and re-compile your crate from scratch.
-
-To deactivate the “for further information visit *lint-link*” message you can
-define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable.
-
### Allowing/denying lints
You can add options to your code to `allow`/`warn`/`deny` Clippy lints:
@@ -205,6 +186,33 @@ the lint(s) you are interested in:
cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::...
```
+### Configure the behavior of some lints
+
+Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml`. It contains a basic `variable =
+value` mapping e.g.
+
+```toml
+avoid-breaking-exported-api = false
+disallowed-names = ["toto", "tata", "titi"]
+cognitive-complexity-threshold = 30
+```
+
+See the [list of lints](https://rust-lang.github.io/rust-clippy/master/index.html) for more information about which
+lints can be configured and the meaning of the variables.
+
+> **Note**
+>
+> `clippy.toml` or `.clippy.toml` cannot be used to allow/deny lints.
+
+> **Note**
+>
+> Configuration changes will not apply for code that has already been compiled and cached under `./target/`;
+> for example, adding a new string to `doc-valid-idents` may still result in Clippy flagging that string. To be sure
+> that any configuration changes are applied, you may want to run `cargo clean` and re-compile your crate from scratch.
+
+To deactivate the “for further information visit *lint-link*” message you can
+define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable.
+
### Specifying the minimum supported Rust version
Projects that intend to support old versions of Rust can disable lints pertaining to newer features by
diff --git a/src/tools/clippy/book/src/configuration.md b/src/tools/clippy/book/src/configuration.md
index 6e295ac31..77f1d2e87 100644
--- a/src/tools/clippy/book/src/configuration.md
+++ b/src/tools/clippy/book/src/configuration.md
@@ -7,7 +7,7 @@ basic `variable = value` mapping eg.
```toml
avoid-breaking-exported-api = false
-blacklisted-names = ["toto", "tata", "titi"]
+disallowed-names = ["toto", "tata", "titi"]
cognitive-complexity-threshold = 30
```
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index da781eb97..3c3f368a5 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -90,6 +90,7 @@ We start by opening the test file created at `tests/ui/foo_functions.rs`.
Update the file with some examples to get started:
```rust
+#![allow(unused)]
#![warn(clippy::foo_functions)]
// Impl methods
@@ -477,8 +478,27 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
```
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.
+the lint's test file, `tests/ui/manual_strip.rs` in this example. It should
+have a case for the version below the MSRV and one with the same contents but
+for the MSRV version itself.
+
+```rust
+#![feature(custom_inner_attributes)]
+
+...
+
+fn msrv_1_44() {
+ #![clippy::msrv = "1.44"]
+
+ /* something that would trigger the lint */
+}
+
+fn msrv_1_45() {
+ #![clippy::msrv = "1.45"]
+
+ /* something that would trigger the lint */
+}
+```
As a last step, the lint should be added to the lint documentation. This is done
in `clippy_lints/src/utils/conf.rs`:
diff --git a/src/tools/clippy/book/src/development/basics.md b/src/tools/clippy/book/src/development/basics.md
index 44ba6e327..6fb53236e 100644
--- a/src/tools/clippy/book/src/development/basics.md
+++ b/src/tools/clippy/book/src/development/basics.md
@@ -69,7 +69,7 @@ the reference file with:
cargo dev bless
```
-For example, this is necessary, if you fix a typo in an error message of a lint
+For example, this is necessary if you fix a typo in an error message of a lint,
or if you modify a test file to add a test case.
> _Note:_ This command may update more files than you intended. In that case
@@ -101,8 +101,9 @@ cargo dev setup intellij
cargo dev dogfood
```
-More about intellij command usage and reasons
-[here](https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md#intellij-rust)
+More about [intellij] command usage and reasons.
+
+[intellij]: https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md#intellij-rust
## lintcheck
diff --git a/src/tools/clippy/book/src/development/common_tools_writing_lints.md b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
index 15e00c7d7..f5aa06e4b 100644
--- a/src/tools/clippy/book/src/development/common_tools_writing_lints.md
+++ b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
@@ -66,7 +66,7 @@ Starting with an `expr`, you can check whether it is calling a specific method
impl<'tcx> LateLintPass<'tcx> for MyStructLint {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
// Check our expr is calling a method
- if let hir::ExprKind::MethodCall(path, _, [_self_arg, ..]) = &expr.kind
+ if let hir::ExprKind::MethodCall(path, _, _self_arg, ..) = &expr.kind
// Check the name of this method is `some_method`
&& path.ident.name == sym!(some_method)
// Optionally, check the type of the self argument.
@@ -123,7 +123,8 @@ There are three ways to do this, depending on if the target trait has a
diagnostic item, lang item or neither.
```rust
-use clippy_utils::{implements_trait, is_trait_method, match_trait_method, paths};
+use clippy_utils::ty::implements_trait;
+use clippy_utils::is_trait_method;
use rustc_span::symbol::sym;
impl LateLintPass<'_> for MyStructLint {
@@ -143,13 +144,6 @@ impl LateLintPass<'_> for MyStructLint {
.map_or(false, |id| implements_trait(cx, ty, id, &[])) {
// `expr` implements `Drop` trait
}
-
- // 3. Using the type path with the expression
- // we use `match_trait_method` function from Clippy's utils
- // (This method should be avoided if possible)
- if match_trait_method(cx, expr, &paths::INTO) {
- // `expr` implements `Into` trait
- }
}
}
```
@@ -233,8 +227,9 @@ functions to deal with macros:
crates
```rust
- #[macro_use]
- extern crate a_crate_with_macros;
+ use rustc_middle::lint::in_external_macro;
+
+ use a_crate_with_macros::foo;
// `foo` is defined in `a_crate_with_macros`
foo!("bar");
diff --git a/src/tools/clippy/clippy_dev/src/bless.rs b/src/tools/clippy/clippy_dev/src/bless.rs
index f5c51b947..92b2771f3 100644
--- a/src/tools/clippy/clippy_dev/src/bless.rs
+++ b/src/tools/clippy/clippy_dev/src/bless.rs
@@ -37,7 +37,7 @@ fn update_reference_file(test_output_entry: &DirEntry, ignore_timestamp: bool) {
return;
}
- let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file");
+ let test_output_file = fs::read(test_output_path).expect("Unable to read test output file");
let reference_file = fs::read(&reference_file_path).unwrap_or_default();
if test_output_file != reference_file {
diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs
index 3b27f061e..256231441 100644
--- a/src/tools/clippy/clippy_dev/src/fmt.rs
+++ b/src/tools/clippy/clippy_dev/src/fmt.rs
@@ -46,7 +46,7 @@ pub fn run(check: bool, verbose: bool) {
// dependency
if fs::read_to_string(project_root.join("Cargo.toml"))
.expect("Failed to read clippy Cargo.toml")
- .contains(&"[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
+ .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
{
return Err(CliError::IntellijSetupActive);
}
@@ -82,16 +82,16 @@ pub fn run(check: bool, verbose: bool) {
fn output_err(err: CliError) {
match err {
CliError::CommandFailed(command, stderr) => {
- eprintln!("error: A command failed! `{}`\nstderr: {}", command, stderr);
+ eprintln!("error: A command failed! `{command}`\nstderr: {stderr}");
},
CliError::IoError(err) => {
- eprintln!("error: {}", err);
+ eprintln!("error: {err}");
},
CliError::RustfmtNotInstalled => {
eprintln!("error: rustfmt nightly is not installed.");
},
CliError::WalkDirError(err) => {
- eprintln!("error: {}", err);
+ eprintln!("error: {err}");
},
CliError::IntellijSetupActive => {
eprintln!(
@@ -193,10 +193,10 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
let args = &["--version"];
if context.verbose {
- println!("{}", format_command(&program, &dir, args));
+ println!("{}", format_command(program, &dir, args));
}
- let output = Command::new(&program).current_dir(&dir).args(args.iter()).output()?;
+ let output = Command::new(program).current_dir(&dir).args(args.iter()).output()?;
if output.status.success() {
Ok(())
@@ -207,7 +207,7 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
Err(CliError::RustfmtNotInstalled)
} else {
Err(CliError::CommandFailed(
- format_command(&program, &dir, args),
+ format_command(program, &dir, args),
std::str::from_utf8(&output.stderr).unwrap_or("").to_string(),
))
}
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 82574a8e6..80bb83af4 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -1,5 +1,4 @@
#![feature(let_chains)]
-#![feature(let_else)]
#![feature(once_cell)]
#![feature(rustc_private)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index a417d3dd8..d3e036692 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -41,7 +41,7 @@ fn main() {
matches.contains_id("msrv"),
) {
Ok(_) => update_lints::update(update_lints::UpdateMode::Change),
- Err(e) => eprintln!("Unable to create lint: {}", e),
+ Err(e) => eprintln!("Unable to create lint: {e}"),
}
},
Some(("setup", sub_command)) => match sub_command.subcommand() {
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index 03d2ef3d1..9e15f1504 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -1,5 +1,5 @@
use crate::clippy_project_root;
-use indoc::{indoc, writedoc};
+use indoc::{formatdoc, writedoc};
use std::fmt::Write as _;
use std::fs::{self, OpenOptions};
use std::io::prelude::*;
@@ -23,7 +23,7 @@ impl<T> Context for io::Result<T> {
match self {
Ok(t) => Ok(t),
Err(e) => {
- let message = format!("{}: {}", text.as_ref(), e);
+ let message = format!("{}: {e}", text.as_ref());
Err(io::Error::new(ErrorKind::Other, message))
},
}
@@ -72,7 +72,7 @@ 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())?;
- println!("Generated lint file: `{}`", lint_path);
+ println!("Generated lint file: `{lint_path}`");
Ok(())
}
@@ -86,7 +86,7 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
path.push("src");
fs::create_dir(&path)?;
- let header = format!("// compile-flags: --crate-name={}", lint_name);
+ let header = format!("// compile-flags: --crate-name={lint_name}");
write_file(path.join("main.rs"), get_test_file_contents(lint_name, Some(&header)))?;
Ok(())
@@ -106,7 +106,7 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
let test_contents = get_test_file_contents(lint.name, None);
write_file(lint.project_root.join(&test_path), test_contents)?;
- println!("Generated test file: `{}`", test_path);
+ println!("Generated test file: `{test_path}`");
}
Ok(())
@@ -120,15 +120,17 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
let new_lint = if enable_msrv {
format!(
- "store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n ",
+ "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv)));\n ",
lint_pass = lint.pass,
+ ctor_arg = if lint.pass == "late" { "_" } else { "" },
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 ",
+ "store.register_{lint_pass}_pass(|{ctor_arg}| Box::new({module_name}::{camel_name}));\n ",
lint_pass = lint.pass,
+ ctor_arg = if lint.pass == "late" { "_" } else { "" },
module_name = lint.name,
camel_name = to_camel_case(lint.name),
)
@@ -155,7 +157,7 @@ fn to_camel_case(name: &str) -> String {
name.split('_')
.map(|s| {
if s.is_empty() {
- String::from("")
+ String::new()
} else {
[&s[0..1].to_uppercase(), &s[1..]].concat()
}
@@ -184,37 +186,36 @@ pub(crate) fn get_stabilization_version() -> String {
}
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
+ let mut contents = formatdoc!(
+ r#"
+ #![allow(unused)]
+ #![warn(clippy::{lint_name})]
+
+ fn main() {{
+ // test code goes here
+ }}
+ "#
);
if let Some(header) = header_commands {
- contents = format!("{}\n{}", header, contents);
+ contents = format!("{header}\n{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
+ formatdoc!(
+ r#"
+ # {hint}
+
+ [package]
+ name = "{lint_name}"
+ version = "0.1.0"
+ publish = false
+
+ [workspace]
+ "#
)
}
@@ -235,76 +236,61 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
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}};
+ formatdoc!(
+ r#"
+ 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
+ formatdoc!(
+ r#"
+ {pass_import}
+ use rustc_lint::{{{context_import}, {pass_type}}};
+ use rustc_session::{{declare_lint_pass, declare_tool_lint}};
+
+ "#
)
});
let _ = write!(result, "{}", get_lint_declaration(&name_upper, category));
result.push_str(&if enable_msrv {
- format!(
- indoc! {"
- pub struct {name_camel} {{
- msrv: Option<RustcVersion>,
- }}
+ formatdoc!(
+ r#"
+ pub struct {name_camel} {{
+ msrv: Option<RustcVersion>,
+ }}
- impl {name_camel} {{
- #[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {{
- Self {{ msrv }}
- }}
+ impl {name_camel} {{
+ #[must_use]
+ pub fn new(msrv: Option<RustcVersion>) -> Self {{
+ Self {{ msrv }}
}}
+ }}
- impl_lint_pass!({name_camel} => [{name_upper}]);
+ impl_lint_pass!({name_camel} => [{name_upper}]);
- impl {pass_type}{pass_lifetimes} for {name_camel} {{
- extract_msrv_attr!({context_import});
- }}
+ impl {pass_type}{pass_lifetimes} for {name_camel} {{
+ extract_msrv_attr!({context_import});
+ }}
- // TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed.
- // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`.
- // TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
- "},
- pass_type = pass_type,
- pass_lifetimes = pass_lifetimes,
- name_upper = name_upper,
- name_camel = name_camel,
- context_import = context_import,
+ // 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`
+ "#
)
} else {
- format!(
- indoc! {"
- declare_lint_pass!({name_camel} => [{name_upper}]);
+ formatdoc!(
+ r#"
+ declare_lint_pass!({name_camel} => [{name_upper}]);
- impl {pass_type}{pass_lifetimes} for {name_camel} {{}}
- "},
- pass_type = pass_type,
- pass_lifetimes = pass_lifetimes,
- name_upper = name_upper,
- name_camel = name_camel,
+ impl {pass_type}{pass_lifetimes} for {name_camel} {{}}
+ "#
)
});
@@ -312,8 +298,8 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
}
fn get_lint_declaration(name_upper: &str, category: &str) -> String {
- format!(
- indoc! {r#"
+ formatdoc!(
+ r#"
declare_clippy_lint! {{
/// ### What it does
///
@@ -327,15 +313,13 @@ fn get_lint_declaration(name_upper: &str, category: &str) -> String {
/// ```rust
/// // example code which does not raise clippy warning
/// ```
- #[clippy::version = "{version}"]
+ #[clippy::version = "{}"]
pub {name_upper},
{category},
"default lint description"
}}
- "#},
- version = get_stabilization_version(),
- name_upper = name_upper,
- category = category,
+ "#,
+ get_stabilization_version(),
)
}
@@ -349,7 +333,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
_ => {},
}
- let ty_dir = lint.project_root.join(format!("clippy_lints/src/{}", ty));
+ let ty_dir = lint.project_root.join(format!("clippy_lints/src/{ty}"));
assert!(
ty_dir.exists() && ty_dir.is_dir(),
"Directory `{}` does not exist!",
@@ -409,10 +393,10 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
}
write_file(lint_file_path.as_path(), lint_file_contents)?;
- println!("Generated lint file: `clippy_lints/src/{}/{}.rs`", ty, lint.name);
+ println!("Generated lint file: `clippy_lints/src/{ty}/{}.rs`", lint.name);
println!(
- "Be sure to add a call to `{}::check` in `clippy_lints/src/{}/mod.rs`!",
- lint.name, ty
+ "Be sure to add a call to `{}::check` in `clippy_lints/src/{ty}/mod.rs`!",
+ lint.name
);
Ok(())
@@ -438,7 +422,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
let mut lint_context = None;
let mut iter = rustc_lexer::tokenize(&file_contents).map(|t| {
- let range = offset..offset + t.len;
+ let range = offset..offset + t.len as usize;
offset = range.end;
LintDeclSearchResult {
@@ -539,7 +523,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
.chain(std::iter::once(&*lint_name_upper))
.filter(|s| !s.is_empty())
{
- let _ = write!(new_arr_content, "\n {},", ident);
+ let _ = write!(new_arr_content, "\n {ident},");
}
new_arr_content.push('\n');
diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs
index f15f24da9..535c25e69 100644
--- a/src/tools/clippy/clippy_dev/src/serve.rs
+++ b/src/tools/clippy/clippy_dev/src/serve.rs
@@ -10,8 +10,8 @@ use std::time::{Duration, SystemTime};
/// Panics if the python commands could not be spawned
pub fn run(port: u16, lint: Option<&String>) -> ! {
let mut url = Some(match lint {
- None => format!("http://localhost:{}", port),
- Some(lint) => format!("http://localhost:{}/#{}", port, lint),
+ None => format!("http://localhost:{port}"),
+ Some(lint) => format!("http://localhost:{port}/#{lint}"),
});
loop {
@@ -49,7 +49,7 @@ fn mtime(path: impl AsRef<Path>) -> SystemTime {
.into_iter()
.flatten()
.flatten()
- .map(|entry| mtime(&entry.path()))
+ .map(|entry| mtime(entry.path()))
.max()
.unwrap_or(SystemTime::UNIX_EPOCH)
} else {
diff --git a/src/tools/clippy/clippy_dev/src/setup/git_hook.rs b/src/tools/clippy/clippy_dev/src/setup/git_hook.rs
index 3fbb77d59..1de5b1940 100644
--- a/src/tools/clippy/clippy_dev/src/setup/git_hook.rs
+++ b/src/tools/clippy/clippy_dev/src/setup/git_hook.rs
@@ -30,10 +30,7 @@ pub fn install_hook(force_override: bool) {
println!("info: the hook can be removed with `cargo dev remove git-hook`");
println!("git hook successfully installed");
},
- Err(err) => eprintln!(
- "error: unable to copy `{}` to `{}` ({})",
- HOOK_SOURCE_FILE, HOOK_TARGET_FILE, err
- ),
+ Err(err) => eprintln!("error: unable to copy `{HOOK_SOURCE_FILE}` to `{HOOK_TARGET_FILE}` ({err})"),
}
}
@@ -77,7 +74,7 @@ pub fn remove_hook() {
fn delete_git_hook_file(path: &Path) -> bool {
if let Err(err) = fs::remove_file(path) {
- eprintln!("error: unable to delete existing pre-commit git hook ({})", err);
+ eprintln!("error: unable to delete existing pre-commit git hook ({err})");
false
} else {
true
diff --git a/src/tools/clippy/clippy_dev/src/setup/intellij.rs b/src/tools/clippy/clippy_dev/src/setup/intellij.rs
index bf741e6d1..efdb158c2 100644
--- a/src/tools/clippy/clippy_dev/src/setup/intellij.rs
+++ b/src/tools/clippy/clippy_dev/src/setup/intellij.rs
@@ -36,9 +36,8 @@ impl ClippyProjectInfo {
}
pub fn setup_rustc_src(rustc_path: &str) {
- let rustc_source_dir = match check_and_get_rustc_dir(rustc_path) {
- Ok(path) => path,
- Err(_) => return,
+ let Ok(rustc_source_dir) = check_and_get_rustc_dir(rustc_path) else {
+ return
};
for project in CLIPPY_PROJECTS {
@@ -60,7 +59,7 @@ fn check_and_get_rustc_dir(rustc_path: &str) -> Result<PathBuf, ()> {
path = absolute_path;
},
Err(err) => {
- eprintln!("error: unable to get the absolute path of rustc ({})", err);
+ eprintln!("error: unable to get the absolute path of rustc ({err})");
return Err(());
},
};
@@ -103,14 +102,14 @@ fn inject_deps_into_project(rustc_source_dir: &Path, project: &ClippyProjectInfo
fn read_project_file(file_path: &str) -> Result<String, ()> {
let path = Path::new(file_path);
if !path.exists() {
- eprintln!("error: unable to find the file `{}`", file_path);
+ eprintln!("error: unable to find the file `{file_path}`");
return Err(());
}
match fs::read_to_string(path) {
Ok(content) => Ok(content),
Err(err) => {
- eprintln!("error: the file `{}` could not be read ({})", file_path, err);
+ eprintln!("error: the file `{file_path}` could not be read ({err})");
Err(())
},
}
@@ -124,10 +123,7 @@ fn inject_deps_into_manifest(
) -> std::io::Result<()> {
// do not inject deps if we have already done so
if cargo_toml.contains(RUSTC_PATH_SECTION) {
- eprintln!(
- "warn: dependencies are already setup inside {}, skipping file",
- manifest_path
- );
+ eprintln!("warn: dependencies are already setup inside {manifest_path}, skipping file");
return Ok(());
}
@@ -142,11 +138,7 @@ fn inject_deps_into_manifest(
let new_deps = extern_crates.map(|dep| {
// format the dependencies that are going to be put inside the Cargo.toml
- format!(
- "{dep} = {{ path = \"{source_path}/{dep}\" }}\n",
- dep = dep,
- source_path = rustc_source_dir.display()
- )
+ format!("{dep} = {{ path = \"{}/{dep}\" }}\n", rustc_source_dir.display())
});
// format a new [dependencies]-block with the new deps we need to inject
@@ -163,11 +155,11 @@ fn inject_deps_into_manifest(
// etc
let new_manifest = cargo_toml.replacen("[dependencies]\n", &all_deps, 1);
- // println!("{}", new_manifest);
+ // println!("{new_manifest}");
let mut file = File::create(manifest_path)?;
file.write_all(new_manifest.as_bytes())?;
- println!("info: successfully setup dependencies inside {}", manifest_path);
+ println!("info: successfully setup dependencies inside {manifest_path}");
Ok(())
}
@@ -179,14 +171,10 @@ pub fn remove_rustc_src() {
}
fn remove_rustc_src_from_project(project: &ClippyProjectInfo) -> bool {
- let mut cargo_content = if let Ok(content) = read_project_file(project.cargo_file) {
- content
- } else {
+ let Ok(mut cargo_content) = read_project_file(project.cargo_file) else {
return false;
};
- let section_start = if let Some(section_start) = cargo_content.find(RUSTC_PATH_SECTION) {
- section_start
- } else {
+ let Some(section_start) = cargo_content.find(RUSTC_PATH_SECTION) else {
println!(
"info: dependencies could not be found in `{}` for {}, skipping file",
project.cargo_file, project.name
@@ -194,9 +182,7 @@ fn remove_rustc_src_from_project(project: &ClippyProjectInfo) -> bool {
return true;
};
- let end_point = if let Some(end_point) = cargo_content.find(DEPENDENCIES_SECTION) {
- end_point
- } else {
+ let Some(end_point) = cargo_content.find(DEPENDENCIES_SECTION) else {
eprintln!(
"error: the end of the rustc dependencies section could not be found in `{}`",
project.cargo_file
@@ -214,8 +200,8 @@ fn remove_rustc_src_from_project(project: &ClippyProjectInfo) -> bool {
},
Err(err) => {
eprintln!(
- "error: unable to open file `{}` to remove rustc dependencies for {} ({})",
- project.cargo_file, project.name, err
+ "error: unable to open file `{}` to remove rustc dependencies for {} ({err})",
+ project.cargo_file, project.name
);
false
},
diff --git a/src/tools/clippy/clippy_dev/src/setup/vscode.rs b/src/tools/clippy/clippy_dev/src/setup/vscode.rs
index d59001b2c..dbcdc9b59 100644
--- a/src/tools/clippy/clippy_dev/src/setup/vscode.rs
+++ b/src/tools/clippy/clippy_dev/src/setup/vscode.rs
@@ -17,10 +17,7 @@ pub fn install_tasks(force_override: bool) {
println!("info: the task file can be removed with `cargo dev remove vscode-tasks`");
println!("vscode tasks successfully installed");
},
- Err(err) => eprintln!(
- "error: unable to copy `{}` to `{}` ({})",
- TASK_SOURCE_FILE, TASK_TARGET_FILE, err
- ),
+ Err(err) => eprintln!("error: unable to copy `{TASK_SOURCE_FILE}` to `{TASK_TARGET_FILE}` ({err})"),
}
}
@@ -44,23 +41,17 @@ fn check_install_precondition(force_override: bool) -> bool {
return delete_vs_task_file(path);
}
- eprintln!(
- "error: there is already a `task.json` file inside the `{}` directory",
- VSCODE_DIR
- );
+ eprintln!("error: there is already a `task.json` file inside the `{VSCODE_DIR}` directory");
println!("info: use the `--force-override` flag to override the existing `task.json` file");
return false;
}
} else {
match fs::create_dir(vs_dir_path) {
Ok(_) => {
- println!("info: created `{}` directory for clippy", VSCODE_DIR);
+ println!("info: created `{VSCODE_DIR}` directory for clippy");
},
Err(err) => {
- eprintln!(
- "error: the task target directory `{}` could not be created ({})",
- VSCODE_DIR, err
- );
+ eprintln!("error: the task target directory `{VSCODE_DIR}` could not be created ({err})");
},
}
}
@@ -82,7 +73,7 @@ pub fn remove_tasks() {
fn delete_vs_task_file(path: &Path) -> bool {
if let Err(err) = fs::remove_file(path) {
- eprintln!("error: unable to delete the existing `tasks.json` file ({})", err);
+ eprintln!("error: unable to delete the existing `tasks.json` file ({err})");
return false;
}
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index aed38bc28..e690bc369 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -3,7 +3,7 @@ use aho_corasick::AhoCorasickBuilder;
use indoc::writedoc;
use itertools::Itertools;
use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
-use std::collections::{HashMap, HashSet};
+use std::collections::{BTreeSet, HashMap, HashSet};
use std::ffi::OsStr;
use std::fmt::Write;
use std::fs::{self, OpenOptions};
@@ -45,9 +45,8 @@ fn generate_lint_files(
renamed_lints: &[RenamedLint],
) {
let internal_lints = Lint::internal_lints(lints);
- let usable_lints = Lint::usable_lints(lints);
- let mut sorted_usable_lints = usable_lints.clone();
- sorted_usable_lints.sort_by_key(|lint| lint.name.clone());
+ let mut usable_lints = Lint::usable_lints(lints);
+ usable_lints.sort_by_key(|lint| lint.name.clone());
replace_region_in_file(
update_mode,
@@ -86,7 +85,7 @@ fn generate_lint_files(
)
.sorted()
{
- writeln!(res, "[`{}`]: {}#{}", lint, DOCS_LINK, lint).unwrap();
+ writeln!(res, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap();
}
},
);
@@ -99,7 +98,7 @@ fn generate_lint_files(
"// end lints modules, do not remove this comment, it’s used in `update_lints`",
|res| {
for lint_mod in usable_lints.iter().map(|l| &l.module).unique().sorted() {
- writeln!(res, "mod {};", lint_mod).unwrap();
+ writeln!(res, "mod {lint_mod};").unwrap();
}
},
);
@@ -124,10 +123,12 @@ fn generate_lint_files(
let content = gen_lint_group_list("all", all_group_lints);
process_file("clippy_lints/src/lib.register_all.rs", update_mode, &content);
+ update_docs(update_mode, &usable_lints);
+
for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) {
let content = gen_lint_group_list(&lint_group, lints.iter());
process_file(
- &format!("clippy_lints/src/lib.register_{}.rs", lint_group),
+ format!("clippy_lints/src/lib.register_{lint_group}.rs"),
update_mode,
&content,
);
@@ -140,6 +141,62 @@ fn generate_lint_files(
process_file("tests/ui/rename.rs", update_mode, &content);
}
+fn update_docs(update_mode: UpdateMode, usable_lints: &[Lint]) {
+ replace_region_in_file(update_mode, Path::new("src/docs.rs"), "docs! {\n", "\n}\n", |res| {
+ for name in usable_lints.iter().map(|lint| lint.name.clone()).sorted() {
+ writeln!(res, r#" "{name}","#).unwrap();
+ }
+ });
+
+ if update_mode == UpdateMode::Check {
+ let mut extra = BTreeSet::new();
+ let mut lint_names = usable_lints
+ .iter()
+ .map(|lint| lint.name.clone())
+ .collect::<BTreeSet<_>>();
+ for file in std::fs::read_dir("src/docs").unwrap() {
+ let filename = file.unwrap().file_name().into_string().unwrap();
+ if let Some(name) = filename.strip_suffix(".txt") {
+ if !lint_names.remove(name) {
+ extra.insert(name.to_string());
+ }
+ }
+ }
+
+ let failed = print_lint_names("extra lint docs:", &extra) | print_lint_names("missing lint docs:", &lint_names);
+
+ if failed {
+ exit_with_failure();
+ }
+ } else {
+ if std::fs::remove_dir_all("src/docs").is_err() {
+ eprintln!("could not remove src/docs directory");
+ }
+ if std::fs::create_dir("src/docs").is_err() {
+ eprintln!("could not recreate src/docs directory");
+ }
+ }
+ for lint in usable_lints {
+ process_file(
+ Path::new("src/docs").join(lint.name.clone() + ".txt"),
+ update_mode,
+ &lint.documentation,
+ );
+ }
+}
+
+fn print_lint_names(header: &str, lints: &BTreeSet<String>) -> bool {
+ if lints.is_empty() {
+ return false;
+ }
+ println!("{header}");
+ for lint in lints.iter().sorted() {
+ println!(" {lint}");
+ }
+ println!();
+ true
+}
+
pub fn print_lints() {
let (lint_list, _, _) = gather_all();
let usable_lints = Lint::usable_lints(&lint_list);
@@ -147,16 +204,16 @@ pub fn print_lints() {
let grouped_by_lint_group = Lint::by_lint_group(usable_lints.into_iter());
for (lint_group, mut lints) in grouped_by_lint_group {
- println!("\n## {}", lint_group);
+ println!("\n## {lint_group}");
lints.sort_by_key(|l| l.name.clone());
for lint in lints {
- println!("* [{}]({}#{}) ({})", lint.name, DOCS_LINK, lint.name, lint.desc);
+ println!("* [{}]({DOCS_LINK}#{}) ({})", lint.name, lint.name, lint.desc);
}
}
- println!("there are {} lints", usable_lint_count);
+ println!("there are {usable_lint_count} lints");
}
/// Runs the `rename_lint` command.
@@ -177,10 +234,10 @@ pub fn print_lints() {
#[allow(clippy::too_many_lines)]
pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
if let Some((prefix, _)) = old_name.split_once("::") {
- panic!("`{}` should not contain the `{}` prefix", old_name, prefix);
+ panic!("`{old_name}` should not contain the `{prefix}` prefix");
}
if let Some((prefix, _)) = new_name.split_once("::") {
- panic!("`{}` should not contain the `{}` prefix", new_name, prefix);
+ panic!("`{new_name}` should not contain the `{prefix}` prefix");
}
let (mut lints, deprecated_lints, mut renamed_lints) = gather_all();
@@ -193,14 +250,14 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
found_new_name = true;
}
}
- let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{}`", old_name));
+ let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{old_name}`"));
let lint = RenamedLint {
- old_name: format!("clippy::{}", old_name),
+ old_name: format!("clippy::{old_name}"),
new_name: if uplift {
new_name.into()
} else {
- format!("clippy::{}", new_name)
+ format!("clippy::{new_name}")
},
};
@@ -208,13 +265,11 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
// case.
assert!(
!renamed_lints.iter().any(|l| lint.old_name == l.old_name),
- "`{}` has already been renamed",
- old_name
+ "`{old_name}` has already been renamed"
);
assert!(
!deprecated_lints.iter().any(|l| lint.old_name == l.name),
- "`{}` has already been deprecated",
- old_name
+ "`{old_name}` has already been deprecated"
);
// Update all lint level attributes. (`clippy::lint_name`)
@@ -251,14 +306,12 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
if uplift {
write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints));
println!(
- "`{}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually.",
- old_name
+ "`{old_name}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually."
);
} else if found_new_name {
write_file(Path::new("tests/ui/rename.rs"), &gen_renamed_lints_test(&renamed_lints));
println!(
- "`{}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually.",
- new_name
+ "`{new_name}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually."
);
} else {
// Rename the lint struct and source files sharing a name with the lint.
@@ -269,16 +322,16 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
// Rename test files. only rename `.stderr` and `.fixed` files if the new test name doesn't exist.
if try_rename_file(
- Path::new(&format!("tests/ui/{}.rs", old_name)),
- Path::new(&format!("tests/ui/{}.rs", new_name)),
+ Path::new(&format!("tests/ui/{old_name}.rs")),
+ Path::new(&format!("tests/ui/{new_name}.rs")),
) {
try_rename_file(
- Path::new(&format!("tests/ui/{}.stderr", old_name)),
- Path::new(&format!("tests/ui/{}.stderr", new_name)),
+ Path::new(&format!("tests/ui/{old_name}.stderr")),
+ Path::new(&format!("tests/ui/{new_name}.stderr")),
);
try_rename_file(
- Path::new(&format!("tests/ui/{}.fixed", old_name)),
- Path::new(&format!("tests/ui/{}.fixed", new_name)),
+ Path::new(&format!("tests/ui/{old_name}.fixed")),
+ Path::new(&format!("tests/ui/{new_name}.fixed")),
);
}
@@ -286,8 +339,8 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
let replacements;
let replacements = if lint.module == old_name
&& try_rename_file(
- Path::new(&format!("clippy_lints/src/{}.rs", old_name)),
- Path::new(&format!("clippy_lints/src/{}.rs", new_name)),
+ Path::new(&format!("clippy_lints/src/{old_name}.rs")),
+ Path::new(&format!("clippy_lints/src/{new_name}.rs")),
) {
// Edit the module name in the lint list. Note there could be multiple lints.
for lint in lints.iter_mut().filter(|l| l.module == old_name) {
@@ -298,14 +351,14 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
} else if !lint.module.contains("::")
// Catch cases like `methods/lint_name.rs` where the lint is stored in `methods/mod.rs`
&& try_rename_file(
- Path::new(&format!("clippy_lints/src/{}/{}.rs", lint.module, old_name)),
- Path::new(&format!("clippy_lints/src/{}/{}.rs", lint.module, new_name)),
+ Path::new(&format!("clippy_lints/src/{}/{old_name}.rs", lint.module)),
+ Path::new(&format!("clippy_lints/src/{}/{new_name}.rs", lint.module)),
)
{
// Edit the module name in the lint list. Note there could be multiple lints, or none.
- let renamed_mod = format!("{}::{}", lint.module, old_name);
+ let renamed_mod = format!("{}::{old_name}", lint.module);
for lint in lints.iter_mut().filter(|l| l.module == renamed_mod) {
- lint.module = format!("{}::{}", lint.module, new_name);
+ lint.module = format!("{}::{new_name}", lint.module);
}
replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)];
replacements.as_slice()
@@ -321,7 +374,7 @@ pub fn rename(old_name: &str, new_name: &str, uplift: bool) {
}
generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
- println!("{} has been successfully renamed", old_name);
+ println!("{old_name} has been successfully renamed");
}
println!("note: `cargo uitest` still needs to be run to update the test results");
@@ -350,7 +403,7 @@ pub fn deprecate(name: &str, reason: Option<&String>) {
});
generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
- println!("info: `{}` has successfully been deprecated", name);
+ println!("info: `{name}` has successfully been deprecated");
if reason == DEFAULT_DEPRECATION_REASON {
println!("note: the deprecation reason must be updated in `clippy_lints/src/deprecated_lints.rs`");
@@ -363,7 +416,7 @@ pub fn deprecate(name: &str, reason: Option<&String>) {
let name_upper = name.to_uppercase();
let (mut lints, deprecated_lints, renamed_lints) = gather_all();
- let Some(lint) = lints.iter().find(|l| l.name == name_lower) else { eprintln!("error: failed to find lint `{}`", name); return; };
+ let Some(lint) = lints.iter().find(|l| l.name == name_lower) else { eprintln!("error: failed to find lint `{name}`"); return; };
let mod_path = {
let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module));
@@ -392,7 +445,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
}
fn remove_test_assets(name: &str) {
- let test_file_stem = format!("tests/ui/{}", name);
+ let test_file_stem = format!("tests/ui/{name}");
let path = Path::new(&test_file_stem);
// Some lints have their own directories, delete them
@@ -418,7 +471,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
.expect("failed to find `impl_lint_pass` terminator");
impl_lint_pass_end += impl_lint_pass_start;
- if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(&lint_name_upper) {
+ if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(lint_name_upper) {
let mut lint_name_end = impl_lint_pass_start + (lint_name_pos + lint_name_upper.len());
for c in content[lint_name_end..impl_lint_pass_end].chars() {
// Remove trailing whitespace
@@ -451,11 +504,10 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
}
let mut content =
- fs::read_to_string(&path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy()));
+ fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy()));
eprintln!(
- "warn: you will have to manually remove any code related to `{}` from `{}`",
- name,
+ "warn: you will have to manually remove any code related to `{name}` from `{}`",
path.display()
);
@@ -470,7 +522,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
content.replace_range(lint.declaration_range.clone(), "");
// Remove the module declaration (mod xyz;)
- let mod_decl = format!("\nmod {};", name);
+ let mod_decl = format!("\nmod {name};");
content = content.replacen(&mod_decl, "", 1);
remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content);
@@ -563,13 +615,13 @@ fn round_to_fifty(count: usize) -> usize {
fn process_file(path: impl AsRef<Path>, update_mode: UpdateMode, content: &str) {
if update_mode == UpdateMode::Check {
let old_content =
- fs::read_to_string(&path).unwrap_or_else(|e| panic!("Cannot read from {}: {}", path.as_ref().display(), e));
+ fs::read_to_string(&path).unwrap_or_else(|e| panic!("Cannot read from {}: {e}", path.as_ref().display()));
if content != old_content {
exit_with_failure();
}
} else {
fs::write(&path, content.as_bytes())
- .unwrap_or_else(|e| panic!("Cannot write to {}: {}", path.as_ref().display(), e));
+ .unwrap_or_else(|e| panic!("Cannot write to {}: {e}", path.as_ref().display()));
}
}
@@ -589,17 +641,26 @@ struct Lint {
desc: String,
module: String,
declaration_range: Range<usize>,
+ documentation: String,
}
impl Lint {
#[must_use]
- fn new(name: &str, group: &str, desc: &str, module: &str, declaration_range: Range<usize>) -> Self {
+ fn new(
+ name: &str,
+ group: &str,
+ desc: &str,
+ module: &str,
+ declaration_range: Range<usize>,
+ documentation: String,
+ ) -> Self {
Self {
name: name.to_lowercase(),
group: group.into(),
desc: remove_line_splices(desc),
module: module.into(),
declaration_range,
+ documentation,
}
}
@@ -664,11 +725,10 @@ fn gen_lint_group_list<'a>(group_name: &str, lints: impl Iterator<Item = &'a Lin
let _ = writeln!(
output,
- "store.register_group(true, \"clippy::{0}\", Some(\"clippy_{0}\"), vec![",
- group_name
+ "store.register_group(true, \"clippy::{group_name}\", Some(\"clippy_{group_name}\"), vec![",
);
for (module, name) in details {
- let _ = writeln!(output, " LintId::of({}::{}),", module, name);
+ let _ = writeln!(output, " LintId::of({module}::{name}),");
}
output.push_str("])\n");
@@ -716,7 +776,7 @@ fn gen_register_lint_list<'a>(
if !is_public {
output.push_str(" #[cfg(feature = \"internal\")]\n");
}
- let _ = writeln!(output, " {}::{},", module_name, lint_name);
+ let _ = writeln!(output, " {module_name}::{lint_name},");
}
output.push_str("])\n");
@@ -774,7 +834,7 @@ fn gather_all() -> (Vec<Lint>, Vec<DeprecatedLint>, Vec<RenamedLint>) {
for (rel_path, file) in clippy_lints_src_files() {
let path = file.path();
let contents =
- fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {}", path.display(), e));
+ fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display()));
let module = rel_path
.components()
.map(|c| c.as_os_str().to_str().unwrap())
@@ -809,13 +869,11 @@ fn clippy_lints_src_files() -> impl Iterator<Item = (PathBuf, DirEntry)> {
macro_rules! match_tokens {
($iter:ident, $($token:ident $({$($fields:tt)*})? $(($capture:ident))?)*) => {
{
- $($(let $capture =)? if let Some(LintDeclSearchResult {
+ $(#[allow(clippy::redundant_pattern)] let Some(LintDeclSearchResult {
token_kind: TokenKind::$token $({$($fields)*})?,
- content: _x,
+ content: $($capture @)? _,
..
- }) = $iter.next() {
- _x
- } else {
+ }) = $iter.next() else {
continue;
};)*
#[allow(clippy::unused_unit)]
@@ -836,7 +894,7 @@ pub(crate) struct LintDeclSearchResult<'a> {
fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
let mut offset = 0usize;
let mut iter = tokenize(contents).map(|t| {
- let range = offset..offset + t.len;
+ let range = offset..offset + t.len as usize;
offset = range.end;
LintDeclSearchResult {
@@ -852,27 +910,35 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
}| token_kind == &TokenKind::Ident && *content == "declare_clippy_lint",
) {
let start = range.start;
-
- let mut iter = iter
- .by_ref()
- .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
+ let mut docs = String::with_capacity(128);
+ let mut iter = iter.by_ref().filter(|t| !matches!(t.token_kind, TokenKind::Whitespace));
// matches `!{`
match_tokens!(iter, Bang OpenBrace);
- match iter.next() {
- // #[clippy::version = "version"] pub
- Some(LintDeclSearchResult {
- token_kind: TokenKind::Pound,
- ..
- }) => {
- match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident);
- },
- // pub
- Some(LintDeclSearchResult {
- token_kind: TokenKind::Ident,
- ..
- }) => (),
- _ => continue,
+ let mut in_code = false;
+ while let Some(t) = iter.next() {
+ match t.token_kind {
+ TokenKind::LineComment { .. } => {
+ if let Some(line) = t.content.strip_prefix("/// ").or_else(|| t.content.strip_prefix("///")) {
+ if line.starts_with("```") {
+ docs += "```\n";
+ in_code = !in_code;
+ } else if !(in_code && line.starts_with("# ")) {
+ docs += line;
+ docs.push('\n');
+ }
+ }
+ },
+ TokenKind::Pound => {
+ match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident);
+ break;
+ },
+ TokenKind::Ident => {
+ break;
+ },
+ _ => {},
+ }
}
+ docs.pop(); // remove final newline
let (name, group, desc) = match_tokens!(
iter,
@@ -890,7 +956,7 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
..
}) = iter.next()
{
- lints.push(Lint::new(name, group, desc, module, start..range.end));
+ lints.push(Lint::new(name, group, desc, module, start..range.end, docs));
}
}
}
@@ -899,7 +965,7 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
fn parse_deprecated_contents(contents: &str, lints: &mut Vec<DeprecatedLint>) {
let mut offset = 0usize;
let mut iter = tokenize(contents).map(|t| {
- let range = offset..offset + t.len;
+ let range = offset..offset + t.len as usize;
offset = range.end;
LintDeclSearchResult {
@@ -946,7 +1012,7 @@ fn parse_renamed_contents(contents: &str, lints: &mut Vec<RenamedLint>) {
for line in contents.lines() {
let mut offset = 0usize;
let mut iter = tokenize(line).map(|t| {
- let range = offset..offset + t.len;
+ let range = offset..offset + t.len as usize;
offset = range.end;
LintDeclSearchResult {
@@ -975,9 +1041,13 @@ fn remove_line_splices(s: &str) -> String {
.trim_matches('#')
.strip_prefix('"')
.and_then(|s| s.strip_suffix('"'))
- .unwrap_or_else(|| panic!("expected quoted string, found `{}`", s));
+ .unwrap_or_else(|| panic!("expected quoted string, found `{s}`"));
let mut res = String::with_capacity(s.len());
- unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, _| res.push_str(&s[range]));
+ unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, ch| {
+ if ch.is_ok() {
+ res.push_str(&s[range]);
+ }
+ });
res
}
@@ -997,10 +1067,10 @@ fn replace_region_in_file(
end: &str,
write_replacement: impl FnMut(&mut String),
) {
- let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {}", path.display(), e));
+ let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display()));
let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) {
Ok(x) => x,
- Err(delim) => panic!("Couldn't find `{}` in file `{}`", delim, path.display()),
+ Err(delim) => panic!("Couldn't find `{delim}` in file `{}`", path.display()),
};
match update_mode {
@@ -1008,7 +1078,7 @@ fn replace_region_in_file(
UpdateMode::Check => (),
UpdateMode::Change => {
if let Err(e) = fs::write(path, new_contents.as_bytes()) {
- panic!("Cannot write to `{}`: {}", path.display(), e);
+ panic!("Cannot write to `{}`: {e}", path.display());
}
},
}
@@ -1056,7 +1126,7 @@ fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
#[allow(clippy::needless_pass_by_value)]
fn panic_file(error: io::Error, name: &Path, action: &str) -> ! {
- panic!("failed to {} file `{}`: {}", action, name.display(), error)
+ panic!("failed to {action} file `{}`: {error}", name.display())
}
fn rewrite_file(path: &Path, f: impl FnOnce(&str) -> Option<String>) {
@@ -1116,6 +1186,7 @@ mod tests {
"\"really long text\"",
"module_name",
Range::default(),
+ String::new(),
),
Lint::new(
"doc_markdown",
@@ -1123,6 +1194,7 @@ mod tests {
"\"single line\"",
"module_name",
Range::default(),
+ String::new(),
),
];
assert_eq!(expected, result);
@@ -1162,6 +1234,7 @@ mod tests {
"\"abc\"",
"module_name",
Range::default(),
+ String::new(),
),
Lint::new(
"should_assert_eq2",
@@ -1169,6 +1242,7 @@ mod tests {
"\"abc\"",
"module_name",
Range::default(),
+ String::new(),
),
Lint::new(
"should_assert_eq2",
@@ -1176,6 +1250,7 @@ mod tests {
"\"abc\"",
"module_name",
Range::default(),
+ String::new(),
),
];
let expected = vec![Lint::new(
@@ -1184,6 +1259,7 @@ mod tests {
"\"abc\"",
"module_name",
Range::default(),
+ String::new(),
)];
assert_eq!(expected, Lint::usable_lints(&lints));
}
@@ -1191,22 +1267,51 @@ mod tests {
#[test]
fn test_by_lint_group() {
let lints = vec![
- Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
+ Lint::new(
+ "should_assert_eq",
+ "group1",
+ "\"abc\"",
+ "module_name",
+ Range::default(),
+ String::new(),
+ ),
Lint::new(
"should_assert_eq2",
"group2",
"\"abc\"",
"module_name",
Range::default(),
+ String::new(),
+ ),
+ Lint::new(
+ "incorrect_match",
+ "group1",
+ "\"abc\"",
+ "module_name",
+ Range::default(),
+ String::new(),
),
- Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
];
let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
expected.insert(
"group1".to_string(),
vec![
- Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
- Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
+ Lint::new(
+ "should_assert_eq",
+ "group1",
+ "\"abc\"",
+ "module_name",
+ Range::default(),
+ String::new(),
+ ),
+ Lint::new(
+ "incorrect_match",
+ "group1",
+ "\"abc\"",
+ "module_name",
+ Range::default(),
+ String::new(),
+ ),
],
);
expected.insert(
@@ -1217,6 +1322,7 @@ mod tests {
"\"abc\"",
"module_name",
Range::default(),
+ String::new(),
)],
);
assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
@@ -1255,9 +1361,30 @@ mod tests {
#[test]
fn test_gen_lint_group_list() {
let lints = vec![
- Lint::new("abc", "group1", "\"abc\"", "module_name", Range::default()),
- Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
- Lint::new("internal", "internal_style", "\"abc\"", "module_name", Range::default()),
+ Lint::new(
+ "abc",
+ "group1",
+ "\"abc\"",
+ "module_name",
+ Range::default(),
+ String::new(),
+ ),
+ Lint::new(
+ "should_assert_eq",
+ "group1",
+ "\"abc\"",
+ "module_name",
+ Range::default(),
+ String::new(),
+ ),
+ Lint::new(
+ "internal",
+ "internal_style",
+ "\"abc\"",
+ "module_name",
+ Range::default(),
+ String::new(),
+ ),
];
let expected = GENERATED_FILE_COMMENT.to_string()
+ &[
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 79a56dc40..6fbd6401e 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy_lints"
-version = "0.1.64"
+version = "0.1.66"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs
index 59a7c5354..073e4af13 100644
--- a/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs
+++ b/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs
@@ -4,6 +4,7 @@ use clippy_utils::{meets_msrv, msrvs};
use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
@@ -79,6 +80,7 @@ fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg
(LitKind::Byte(b'a') | LitKind::Char('a'), LitKind::Byte(b'z') | LitKind::Char('z'))
| (LitKind::Byte(b'A') | LitKind::Char('A'), LitKind::Byte(b'Z') | LitKind::Char('Z'))
)
+ && !in_external_macro(cx.sess(), span)
{
span_lint_and_then(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index 159f3b0cd..724490fb4 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -92,7 +92,7 @@ impl ApproxConstant {
cx,
APPROX_CONSTANT,
e.span,
- &format!("approximate value of `{}::consts::{}` found", module, &name),
+ &format!("approximate value of `{module}::consts::{}` found", &name),
None,
"consider using the constant directly",
);
@@ -126,7 +126,7 @@ fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool {
// The value is a truncated constant
true
} else {
- let round_const = format!("{:.*}", value.len() - 2, constant);
+ let round_const = format!("{constant:.*}", value.len() - 2);
value == round_const
}
}
diff --git a/src/tools/clippy/clippy_lints/src/as_underscore.rs b/src/tools/clippy/clippy_lints/src/as_underscore.rs
deleted file mode 100644
index 0bdef9d0a..000000000
--- a/src/tools/clippy/clippy_lints/src/as_underscore.rs
+++ /dev/null
@@ -1,74 +0,0 @@
-use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, TyKind};
-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};
-
-declare_clippy_lint! {
- /// ### What it does
- /// Check for the usage of `as _` conversion using inferred type.
- ///
- /// ### Why is this bad?
- /// The conversion might include lossy conversion and dangerous cast that might go
- /// undetected du to the type being inferred.
- ///
- /// The lint is allowed by default as using `_` is less wordy than always specifying the type.
- ///
- /// ### Example
- /// ```rust
- /// fn foo(n: usize) {}
- /// let n: u16 = 256;
- /// foo(n as _);
- /// ```
- /// Use instead:
- /// ```rust
- /// fn foo(n: usize) {}
- /// let n: u16 = 256;
- /// foo(n as usize);
- /// ```
- #[clippy::version = "1.63.0"]
- pub AS_UNDERSCORE,
- restriction,
- "detects `as _` conversion"
-}
-declare_lint_pass!(AsUnderscore => [AS_UNDERSCORE]);
-
-impl<'tcx> LateLintPass<'tcx> for AsUnderscore {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
- if in_external_macro(cx.sess(), expr.span) {
- return;
- }
-
- if let ExprKind::Cast(_, ty) = expr.kind && let TyKind::Infer = ty.kind {
-
- let ty_resolved = cx.typeck_results().expr_ty(expr);
- if let ty::Error(_) = ty_resolved.kind() {
- span_lint_and_help(
- cx,
- AS_UNDERSCORE,
- expr.span,
- "using `as _` conversion",
- None,
- "consider giving the type explicitly",
- );
- } else {
- span_lint_and_then(
- cx,
- AS_UNDERSCORE,
- expr.span,
- "using `as _` conversion",
- |diag| {
- diag.span_suggestion(
- ty.span,
- "consider giving the type explicitly",
- ty_resolved,
- Applicability::MachineApplicable,
- );
- }
- );
- }
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/asm_syntax.rs b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
index f419781db..9717aa9e9 100644
--- a/src/tools/clippy/clippy_lints/src/asm_syntax.rs
+++ b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
@@ -44,7 +44,7 @@ fn check_expr_asm_syntax(lint: &'static Lint, cx: &EarlyContext<'_>, expr: &Expr
cx,
lint,
expr.span,
- &format!("{} x86 assembly syntax used", style),
+ &format!("{style} x86 assembly syntax used"),
None,
&format!("use {} x86 assembly syntax", !style),
);
@@ -64,6 +64,7 @@ declare_clippy_lint! {
///
/// ```rust,no_run
/// # #![feature(asm)]
+ /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
/// # unsafe { let ptr = "".as_ptr();
/// # use std::arch::asm;
/// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
@@ -72,6 +73,7 @@ declare_clippy_lint! {
/// Use instead:
/// ```rust,no_run
/// # #![feature(asm)]
+ /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
/// # unsafe { let ptr = "".as_ptr();
/// # use std::arch::asm;
/// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
@@ -103,6 +105,7 @@ declare_clippy_lint! {
///
/// ```rust,no_run
/// # #![feature(asm)]
+ /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
/// # unsafe { let ptr = "".as_ptr();
/// # use std::arch::asm;
/// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
@@ -111,6 +114,7 @@ declare_clippy_lint! {
/// Use instead:
/// ```rust,no_run
/// # #![feature(asm)]
+ /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
/// # unsafe { let ptr = "".as_ptr();
/// # use std::arch::asm;
/// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
index 2705ffffd..a36df55d0 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -60,9 +60,9 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
cx,
ASSERTIONS_ON_CONSTANTS,
macro_call.span,
- &format!("`assert!(false{})` should probably be replaced", assert_arg),
+ &format!("`assert!(false{assert_arg})` should probably be replaced"),
None,
- &format!("use `panic!({})` or `unreachable!({0})`", panic_arg),
+ &format!("use `panic!({panic_arg})` or `unreachable!({panic_arg})`"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
index 4caab6230..f6d6c23bb 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
@@ -1,9 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
-use clippy_utils::path_res;
use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item};
+use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item};
use clippy_utils::usage::local_used_after_expr;
+use clippy_utils::{is_expr_final_block_expr, path_res};
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{Expr, ExprKind};
@@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
&& matches!(cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::assert_macro))
&& let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn)
&& matches!(panic_expn, PanicExpn::Empty)
- && let ExprKind::MethodCall(method_segment, [recv], _) = condition.kind
+ && let ExprKind::MethodCall(method_segment, recv, [], _) = condition.kind
&& let result_type_with_refs = cx.typeck_results().expr_ty(recv)
&& let result_type = result_type_with_refs.peel_refs()
&& is_type_diagnostic_item(cx, result_type, sym::Result)
@@ -53,13 +53,15 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
if result_type_with_refs != result_type {
return;
} else if let Res::Local(binding_id) = path_res(cx, recv)
- && local_used_after_expr(cx, binding_id, recv) {
+ && local_used_after_expr(cx, binding_id, recv)
+ {
return;
}
}
+ let semicolon = if is_expr_final_block_expr(cx.tcx, e) {";"} else {""};
let mut app = Applicability::MachineApplicable;
match method_segment.ident.as_str() {
- "is_ok" if has_debug_impl(cx, substs.type_at(1)) => {
+ "is_ok" if type_suitable_to_unwrap(cx, substs.type_at(1)) => {
span_lint_and_sugg(
cx,
ASSERTIONS_ON_RESULT_STATES,
@@ -67,13 +69,13 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
"called `assert!` with `Result::is_ok`",
"replace with",
format!(
- "{}.unwrap()",
+ "{}.unwrap(){semicolon}",
snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
),
app,
);
}
- "is_err" if has_debug_impl(cx, substs.type_at(0)) => {
+ "is_err" if type_suitable_to_unwrap(cx, substs.type_at(0)) => {
span_lint_and_sugg(
cx,
ASSERTIONS_ON_RESULT_STATES,
@@ -81,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
"called `assert!` with `Result::is_err`",
"replace with",
format!(
- "{}.unwrap_err()",
+ "{}.unwrap_err(){semicolon}",
snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
),
app,
@@ -93,9 +95,6 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
}
}
-/// This checks whether a given type is known to implement Debug.
-fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
- cx.tcx
- .get_diagnostic_item(sym::Debug)
- .map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
+fn type_suitable_to_unwrap<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+ has_debug_impl(cx, ty) && !ty.is_unit() && !ty.is_never()
}
diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
index 27c2896e1..9464694a3 100644
--- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs
+++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
hir_id: body.value.hir_id,
};
let typeck_results = cx.tcx.typeck_body(body_id);
- let expr_ty = typeck_results.expr_ty(&body.value);
+ let expr_ty = typeck_results.expr_ty(body.value);
if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
let return_expr_span = match &body.value.kind {
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index 4bcbeacf9..0bd1f8b78 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -357,7 +357,8 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
"wildcard_imports"
| "enum_glob_use"
| "redundant_pub_crate"
- | "macro_use_imports",
+ | "macro_use_imports"
+ | "unsafe_removed_from_name",
)
})
{
@@ -475,7 +476,7 @@ fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem
fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
if let ItemKind::Fn(_, _, eid) = item.kind {
- is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value)
+ is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value)
} else {
true
}
@@ -483,7 +484,7 @@ fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
fn is_relevant_impl(cx: &LateContext<'_>, item: &ImplItem<'_>) -> bool {
match item.kind {
- ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value),
+ ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value),
_ => false,
}
}
@@ -492,7 +493,7 @@ fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool {
match item.kind {
TraitItemKind::Fn(_, TraitFn::Required(_)) => true,
TraitItemKind::Fn(_, TraitFn::Provided(eid)) => {
- is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value)
+ is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value)
},
_ => false,
}
@@ -541,10 +542,7 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribut
cx,
INLINE_ALWAYS,
attr.span,
- &format!(
- "you have declared `#[inline(always)]` on `{}`. This is usually a bad idea",
- name
- ),
+ &format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"),
);
}
}
@@ -720,7 +718,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
let mut unix_suggested = false;
for (os, span) in mismatched {
- let sugg = format!("target_os = \"{}\"", os);
+ let sugg = format!("target_os = \"{os}\"");
diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect);
if !unix_suggested && is_unix(os) {
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index 1761360fb..347178118 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -1,14 +1,15 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{match_def_path, paths};
use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def::{Namespace, Res};
use rustc_hir::def_id::DefId;
-use rustc_hir::{def::Res, AsyncGeneratorKind, Body, BodyId, GeneratorKind};
+use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::GeneratorInteriorTypeCause;
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
-use crate::utils::conf::DisallowedType;
+use crate::utils::conf::DisallowedPath;
declare_clippy_lint! {
/// ### What it does
@@ -171,12 +172,12 @@ impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF,
#[derive(Debug)]
pub struct AwaitHolding {
- conf_invalid_types: Vec<DisallowedType>,
- def_ids: FxHashMap<DefId, DisallowedType>,
+ conf_invalid_types: Vec<DisallowedPath>,
+ def_ids: FxHashMap<DefId, DisallowedPath>,
}
impl AwaitHolding {
- pub(crate) fn new(conf_invalid_types: Vec<DisallowedType>) -> Self {
+ pub(crate) fn new(conf_invalid_types: Vec<DisallowedPath>) -> Self {
Self {
conf_invalid_types,
def_ids: FxHashMap::default(),
@@ -187,11 +188,8 @@ impl AwaitHolding {
impl LateLintPass<'_> for AwaitHolding {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for conf in &self.conf_invalid_types {
- let path = match conf {
- DisallowedType::Simple(path) | DisallowedType::WithReason { path, .. } => path,
- };
- let segs: Vec<_> = path.split("::").collect();
- if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs) {
+ let segs: Vec<_> = conf.path().split("::").collect();
+ if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
self.def_ids.insert(id, conf.clone());
}
}
@@ -256,29 +254,27 @@ impl AwaitHolding {
}
}
-fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedType) {
- let (type_name, reason) = match disallowed {
- DisallowedType::Simple(path) => (path, &None),
- DisallowedType::WithReason { path, reason } => (path, reason),
- };
-
+fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPath) {
span_lint_and_then(
cx,
AWAIT_HOLDING_INVALID_TYPE,
span,
- &format!("`{type_name}` may not be held across an `await` point per `clippy.toml`",),
+ &format!(
+ "`{}` may not be held across an `await` point per `clippy.toml`",
+ disallowed.path()
+ ),
|diag| {
- if let Some(reason) = reason {
- diag.note(reason.clone());
+ if let Some(reason) = disallowed.reason() {
+ diag.note(reason);
}
},
);
}
fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool {
- match_def_path(cx, def_id, &paths::MUTEX_GUARD)
- || match_def_path(cx, def_id, &paths::RWLOCK_READ_GUARD)
- || match_def_path(cx, def_id, &paths::RWLOCK_WRITE_GUARD)
+ cx.tcx.is_diagnostic_item(sym::MutexGuard, def_id)
+ || cx.tcx.is_diagnostic_item(sym::RwLockReadGuard, def_id)
+ || cx.tcx.is_diagnostic_item(sym::RwLockWriteGuard, def_id)
|| match_def_path(cx, def_id, &paths::PARKING_LOT_MUTEX_GUARD)
|| match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_READ_GUARD)
|| match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_WRITE_GUARD)
diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
index ad206b5fb..9c0532474 100644
--- a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
+++ b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
@@ -3,10 +3,11 @@ use clippy_utils::get_parent_expr;
use clippy_utils::higher;
use clippy_utils::source::snippet_block_with_applicability;
use clippy_utils::ty::implements_trait;
+use clippy_utils::visitors::{for_each_expr, Descend};
+use core::ops::ControlFlow;
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{BlockCheckMode, Closure, Expr, ExprKind};
+use rustc_hir::{BlockCheckMode, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -44,39 +45,6 @@ declare_clippy_lint! {
declare_lint_pass!(BlocksInIfConditions => [BLOCKS_IN_IF_CONDITIONS]);
-struct ExVisitor<'a, 'tcx> {
- found_block: Option<&'tcx Expr<'tcx>>,
- cx: &'a LateContext<'tcx>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
- fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
- if let ExprKind::Closure(&Closure { body, .. }) = expr.kind {
- // do not lint if the closure is called using an iterator (see #1141)
- if_chain! {
- if let Some(parent) = get_parent_expr(self.cx, expr);
- if let ExprKind::MethodCall(_, [self_arg, ..], _) = &parent.kind;
- let caller = self.cx.typeck_results().expr_ty(self_arg);
- if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator);
- if implements_trait(self.cx, caller, iter_id, &[]);
- then {
- return;
- }
- }
-
- let body = self.cx.tcx.hir().body(body);
- let ex = &body.value;
- if let ExprKind::Block(block, _) = ex.kind {
- if !body.value.span.from_expansion() && !block.stmts.is_empty() {
- self.found_block = Some(ex);
- return;
- }
- }
- }
- walk_expr(self, expr);
- }
-}
-
const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition";
const COMPLEX_BLOCK_MESSAGE: &str = "in an `if` condition, avoid complex blocks or closures with blocks; \
instead, move the block or closure higher and bind it with a `let`";
@@ -117,7 +85,8 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
);
}
} else {
- let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
+ let span =
+ block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
if span.from_expansion() || expr.span.from_expansion() {
return;
}
@@ -144,11 +113,31 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
}
}
} else {
- let mut visitor = ExVisitor { found_block: None, cx };
- walk_expr(&mut visitor, cond);
- if let Some(block) = visitor.found_block {
- span_lint(cx, BLOCKS_IN_IF_CONDITIONS, block.span, COMPLEX_BLOCK_MESSAGE);
- }
+ let _: Option<!> = for_each_expr(cond, |e| {
+ if let ExprKind::Closure(closure) = e.kind {
+ // do not lint if the closure is called using an iterator (see #1141)
+ if_chain! {
+ if let Some(parent) = get_parent_expr(cx, e);
+ if let ExprKind::MethodCall(_, self_arg, _, _) = &parent.kind;
+ let caller = cx.typeck_results().expr_ty(self_arg);
+ if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
+ if implements_trait(cx, caller, iter_id, &[]);
+ then {
+ return ControlFlow::Continue(Descend::No);
+ }
+ }
+
+ let body = cx.tcx.hir().body(closure.body);
+ let ex = &body.value;
+ if let ExprKind::Block(block, _) = ex.kind {
+ if !body.value.span.from_expansion() && !block.stmts.is_empty() {
+ span_lint(cx, BLOCKS_IN_IF_CONDITIONS, ex.span, COMPLEX_BLOCK_MESSAGE);
+ return ControlFlow::Continue(Descend::No);
+ }
+ }
+ }
+ ControlFlow::Continue(Descend::Yes)
+ });
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index 95abe8aa5..4bd55c142 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -98,9 +98,9 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
cx,
BOOL_ASSERT_COMPARISON,
macro_call.span,
- &format!("used `{}!` with a literal bool", macro_name),
+ &format!("used `{macro_name}!` with a literal bool"),
"replace it with",
- format!("{}!(..)", non_eq_mac),
+ format!("{non_eq_mac}!(..)"),
Applicability::MaybeIncorrect,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
new file mode 100644
index 000000000..001d74c26
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
@@ -0,0 +1,121 @@
+use rustc_ast::LitKind;
+use rustc_hir::{Block, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+use clippy_utils::{diagnostics::span_lint_and_then, is_else_clause, is_integer_literal, sugg::Sugg};
+use rustc_errors::Applicability;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Instead of using an if statement to convert a bool to an int,
+ /// this lint suggests using a `from()` function or an `as` coercion.
+ ///
+ /// ### Why is this bad?
+ /// Coercion or `from()` is idiomatic way to convert bool to a number.
+ /// Both methods are guaranteed to return 1 for true, and 0 for false.
+ ///
+ /// See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E
+ ///
+ /// ### Example
+ /// ```rust
+ /// # let condition = false;
+ /// if condition {
+ /// 1_i64
+ /// } else {
+ /// 0
+ /// };
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # let condition = false;
+ /// i64::from(condition);
+ /// ```
+ /// or
+ /// ```rust
+ /// # let condition = false;
+ /// condition as i64;
+ /// ```
+ #[clippy::version = "1.65.0"]
+ pub BOOL_TO_INT_WITH_IF,
+ style,
+ "using if to convert bool to int"
+}
+declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]);
+
+impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
+ fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
+ if !expr.span.from_expansion() {
+ check_if_else(ctx, expr);
+ }
+ }
+}
+
+fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
+ if let ExprKind::If(check, then, Some(else_)) = expr.kind
+ && let Some(then_lit) = int_literal(then)
+ && let Some(else_lit) = int_literal(else_)
+ {
+ let inverted = if is_integer_literal(then_lit, 1) && is_integer_literal(else_lit, 0) {
+ false
+ } else if is_integer_literal(then_lit, 0) && is_integer_literal(else_lit, 1) {
+ true
+ } else {
+ // Expression isn't boolean, exit
+ return;
+ };
+ let mut applicability = Applicability::MachineApplicable;
+ let snippet = {
+ let mut sugg = Sugg::hir_with_applicability(ctx, check, "..", &mut applicability);
+ if inverted {
+ sugg = !sugg;
+ }
+ sugg
+ };
+
+ let ty = ctx.typeck_results().expr_ty(then_lit); // then and else must be of same type
+
+ let suggestion = {
+ let wrap_in_curly = is_else_clause(ctx.tcx, expr);
+ let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into());
+ if wrap_in_curly {
+ s = s.blockify();
+ }
+ s
+ }; // when used in else clause if statement should be wrapped in curly braces
+
+ let into_snippet = snippet.clone().maybe_par();
+ let as_snippet = snippet.as_ty(ty);
+
+ span_lint_and_then(ctx,
+ BOOL_TO_INT_WITH_IF,
+ expr.span,
+ "boolean to int conversion using if",
+ |diag| {
+ diag.span_suggestion(
+ expr.span,
+ "replace with from",
+ suggestion,
+ applicability,
+ );
+ diag.note(format!("`{as_snippet}` or `{into_snippet}.into()` can also be valid options"));
+ });
+ };
+}
+
+// If block contains only a int literal expression, return literal expression
+fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> {
+ if let ExprKind::Block(block, _) = expr.kind
+ && let Block {
+ stmts: [], // Shouldn't lint if statements with side effects
+ expr: Some(expr),
+ ..
+ } = block
+ && let ExprKind::Lit(lit) = &expr.kind
+ && let LitKind::Int(_, _) = lit.node
+ {
+ Some(expr)
+ } else {
+ None
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 526ee2f89..08164c0b6 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
+use clippy_utils::eq_expr_value;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{eq_expr_value, get_trait_def_id, paths};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
@@ -64,7 +64,7 @@ declare_clippy_lint! {
/// if a {}
/// ```
#[clippy::version = "pre 1.29.0"]
- pub LOGIC_BUG,
+ pub OVERLY_COMPLEX_BOOL_EXPR,
correctness,
"boolean expressions that contain terminals which can be eliminated"
}
@@ -72,7 +72,7 @@ declare_clippy_lint! {
// For each pairs, both orders are considered.
const METHODS_WITH_NEGATION: [(&str, &str); 2] = [("is_some", "is_none"), ("is_err", "is_ok")];
-declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, LOGIC_BUG]);
+declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]);
impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
fn check_fn(
@@ -237,7 +237,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
}
},
&Term(n) => {
- let snip = snippet_opt(self.cx, self.terminals[n as usize].span)?;
+ let snip = snippet_opt(self.cx, self.terminals[n as usize].span.source_callsite())?;
self.output.push_str(&snip);
},
}
@@ -263,15 +263,14 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
}
.and_then(|op| {
Some(format!(
- "{}{}{}",
+ "{}{op}{}",
snippet_opt(cx, lhs.span)?,
- op,
snippet_opt(cx, rhs.span)?
))
})
},
- ExprKind::MethodCall(path, args, _) if args.len() == 1 => {
- let type_of_receiver = cx.typeck_results().expr_ty(&args[0]);
+ ExprKind::MethodCall(path, receiver, [], _) => {
+ let type_of_receiver = cx.typeck_results().expr_ty(receiver);
if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option)
&& !is_type_diagnostic_item(cx, type_of_receiver, sym::Result)
{
@@ -285,7 +284,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
let path: &str = path.ident.name.as_str();
a == path
})
- .and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, args[0].span)?, neg_method)))
+ .and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", snippet_opt(cx, receiver.span)?)))
},
_ => None,
}
@@ -396,7 +395,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 {
span_lint_hir_and_then(
self.cx,
- LOGIC_BUG,
+ OVERLY_COMPLEX_BOOL_EXPR,
e.hir_id,
e.span,
"this boolean expression contains a logic bug",
@@ -484,7 +483,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
fn implements_ord<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
let ty = cx.typeck_results().expr_ty(expr);
- get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]))
+ cx.tcx
+ .get_diagnostic_item(sym::Ord)
+ .map_or(false, |id| implements_trait(cx, ty, id, &[]))
}
struct NotSimplificationVisitor<'a, 'tcx> {
diff --git a/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs
deleted file mode 100644
index 0993adbae..000000000
--- a/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_no_std_crate;
-use clippy_utils::source::snippet_opt;
-use clippy_utils::{meets_msrv, msrvs};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, TyKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_semver::RustcVersion;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for the usage of `&expr as *const T` or
- /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or
- /// `ptr::addr_of_mut` instead.
- ///
- /// ### Why is this bad?
- /// This would improve readability and avoid creating a reference
- /// that points to an uninitialized value or unaligned place.
- /// Read the `ptr::addr_of` docs for more information.
- ///
- /// ### Example
- /// ```rust
- /// let val = 1;
- /// let p = &val as *const i32;
- ///
- /// let mut val_mut = 1;
- /// let p_mut = &mut val_mut as *mut i32;
- /// ```
- /// Use instead:
- /// ```rust
- /// let val = 1;
- /// let p = std::ptr::addr_of!(val);
- ///
- /// let mut val_mut = 1;
- /// let p_mut = std::ptr::addr_of_mut!(val_mut);
- /// ```
- #[clippy::version = "1.60.0"]
- pub BORROW_AS_PTR,
- pedantic,
- "borrowing just to cast to a raw pointer"
-}
-
-impl_lint_pass!(BorrowAsPtr => [BORROW_AS_PTR]);
-
-pub struct BorrowAsPtr {
- msrv: Option<RustcVersion>,
-}
-
-impl BorrowAsPtr {
- #[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
- Self { msrv }
- }
-}
-
-impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if !meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) {
- return;
- }
-
- if expr.span.from_expansion() {
- return;
- }
-
- if_chain! {
- if let ExprKind::Cast(left_expr, ty) = &expr.kind;
- if let TyKind::Ptr(_) = ty.kind;
- if let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = &left_expr.kind;
-
- then {
- let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
- let macro_name = match mutability {
- Mutability::Not => "addr_of",
- Mutability::Mut => "addr_of_mut",
- };
-
- span_lint_and_sugg(
- cx,
- BORROW_AS_PTR,
- expr.span,
- "borrow as raw pointer",
- "try",
- format!(
- "{}::ptr::{}!({})",
- core_or_std,
- macro_name,
- snippet_opt(cx, e.span).unwrap()
- ),
- Applicability::MachineApplicable,
- );
- }
- }
- }
-
- extract_msrv_attr!(LateContext);
-}
diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
index 937765b66..c4520d003 100644
--- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
@@ -29,22 +29,17 @@ declare_clippy_lint! {
///
/// ### Example
/// ```rust
- /// fn foo(_x: &str) {}
- ///
/// let s = &String::new();
///
/// let a: &String = &* s;
- /// foo(&*s);
/// ```
///
/// Use instead:
/// ```rust
- /// # fn foo(_x: &str) {}
/// # let s = &String::new();
/// let a: &String = s;
- /// foo(&**s);
/// ```
- #[clippy::version = "1.59.0"]
+ #[clippy::version = "1.63.0"]
pub BORROW_DEREF_REF,
complexity,
"deref on an immutable reference returns the same type as itself"
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
new file mode 100644
index 000000000..36daceabe
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -0,0 +1,129 @@
+use clippy_utils::{
+ diagnostics::span_lint_and_sugg, get_parent_node, is_default_equivalent, macros::macro_backtrace, match_path,
+ path_def_id, paths, ty::expr_sig,
+};
+use rustc_errors::Applicability;
+use rustc_hir::{
+ intravisit::{walk_ty, Visitor},
+ Block, Expr, ExprKind, Local, Node, QPath, TyKind,
+};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// checks for `Box::new(T::default())`, which is better written as
+ /// `Box::<T>::default()`.
+ ///
+ /// ### Why is this bad?
+ /// First, it's more complex, involving two calls instead of one.
+ /// Second, `Box::default()` can be faster
+ /// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box).
+ ///
+ /// ### Example
+ /// ```rust
+ /// let x: Box<String> = Box::new(Default::default());
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let x: Box<String> = Box::default();
+ /// ```
+ #[clippy::version = "1.65.0"]
+ pub BOX_DEFAULT,
+ perf,
+ "Using Box::new(T::default()) instead of Box::default()"
+}
+
+declare_lint_pass!(BoxDefault => [BOX_DEFAULT]);
+
+impl LateLintPass<'_> for BoxDefault {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if let ExprKind::Call(box_new, [arg]) = expr.kind
+ && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_new.kind
+ && let ExprKind::Call(arg_path, ..) = arg.kind
+ && !in_external_macro(cx.sess(), expr.span)
+ && (expr.span.eq_ctxt(arg.span) || is_vec_expn(cx, arg))
+ && seg.ident.name == sym::new
+ && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box())
+ && is_default_equivalent(cx, arg)
+ {
+ let arg_ty = cx.typeck_results().expr_ty(arg);
+ span_lint_and_sugg(
+ cx,
+ BOX_DEFAULT,
+ expr.span,
+ "`Box::new(_)` of default value",
+ "try",
+ if is_plain_default(arg_path) || given_type(cx, expr) {
+ "Box::default()".into()
+ } else {
+ format!("Box::<{arg_ty}>::default()")
+ },
+ Applicability::MachineApplicable
+ );
+ }
+ }
+}
+
+fn is_plain_default(arg_path: &Expr<'_>) -> bool {
+ // we need to match the actual path so we don't match e.g. "u8::default"
+ if let ExprKind::Path(QPath::Resolved(None, path)) = &arg_path.kind {
+ // avoid generic parameters
+ match_path(path, &paths::DEFAULT_TRAIT_METHOD) && path.segments.iter().all(|seg| seg.args.is_none())
+ } else {
+ false
+ }
+}
+
+fn is_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ macro_backtrace(expr.span)
+ .next()
+ .map_or(false, |call| cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id))
+}
+
+#[derive(Default)]
+struct InferVisitor(bool);
+
+impl<'tcx> Visitor<'tcx> for InferVisitor {
+ fn visit_ty(&mut self, t: &rustc_hir::Ty<'_>) {
+ self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..));
+ if !self.0 {
+ walk_ty(self, t);
+ }
+ }
+}
+
+fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ match get_parent_node(cx.tcx, expr.hir_id) {
+ Some(Node::Local(Local { ty: Some(ty), .. })) => {
+ let mut v = InferVisitor::default();
+ v.visit_ty(ty);
+ !v.0
+ },
+ Some(
+ Node::Expr(Expr {
+ kind: ExprKind::Call(path, args),
+ ..
+ }) | Node::Block(Block {
+ expr:
+ Some(Expr {
+ kind: ExprKind::Call(path, args),
+ ..
+ }),
+ ..
+ }),
+ ) => {
+ if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) &&
+ let Some(sig) = expr_sig(cx, path) &&
+ let Some(input) = sig.input(index)
+ {
+ input.no_bound_vars().is_some()
+ } else {
+ false
+ }
+ },
+ _ => false,
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/bytecount.rs b/src/tools/clippy/clippy_lints/src/bytecount.rs
deleted file mode 100644
index 326ce3408..000000000
--- a/src/tools/clippy/clippy_lints/src/bytecount.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::match_type;
-use clippy_utils::visitors::is_local_used;
-use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, UintTy};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for naive byte counts
- ///
- /// ### Why is this bad?
- /// The [`bytecount`](https://crates.io/crates/bytecount)
- /// crate has methods to count your bytes faster, especially for large slices.
- ///
- /// ### Known problems
- /// If you have predominantly small slices, the
- /// `bytecount::count(..)` method may actually be slower. However, if you can
- /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be
- /// faster in those cases.
- ///
- /// ### Example
- /// ```rust
- /// # let vec = vec![1_u8];
- /// let count = vec.iter().filter(|x| **x == 0u8).count();
- /// ```
- ///
- /// Use instead:
- /// ```rust,ignore
- /// # let vec = vec![1_u8];
- /// let count = bytecount::count(&vec, 0u8);
- /// ```
- #[clippy::version = "pre 1.29.0"]
- pub NAIVE_BYTECOUNT,
- pedantic,
- "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values"
-}
-
-declare_lint_pass!(ByteCount => [NAIVE_BYTECOUNT]);
-
-impl<'tcx> LateLintPass<'tcx> for ByteCount {
- fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- if_chain! {
- if let ExprKind::MethodCall(count, [count_recv], _) = expr.kind;
- if count.ident.name == sym::count;
- if let ExprKind::MethodCall(filter, [filter_recv, filter_arg], _) = count_recv.kind;
- if filter.ident.name == sym!(filter);
- if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind;
- let body = cx.tcx.hir().body(body);
- if let [param] = body.params;
- if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind;
- if let ExprKind::Binary(ref op, l, r) = body.value.kind;
- if op.node == BinOpKind::Eq;
- if match_type(cx,
- cx.typeck_results().expr_ty(filter_recv).peel_refs(),
- &paths::SLICE_ITER);
- let operand_is_arg = |expr| {
- let expr = peel_ref_operators(cx, peel_blocks(expr));
- path_to_local_id(expr, arg_id)
- };
- let needle = if operand_is_arg(l) {
- r
- } else if operand_is_arg(r) {
- l
- } else {
- return;
- };
- if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
- if !is_local_used(cx, needle, arg_id);
- then {
- let haystack = if let ExprKind::MethodCall(path, args, _) =
- filter_recv.kind {
- let p = path.ident.name;
- if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
- &args[0]
- } else {
- filter_recv
- }
- } else {
- filter_recv
- };
- let mut applicability = Applicability::MaybeIncorrect;
- span_lint_and_sugg(
- cx,
- NAIVE_BYTECOUNT,
- expr.span,
- "you appear to be counting bytes the naive way",
- "consider using the bytecount crate",
- format!("bytecount::count({}, {})",
- snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
- snippet_with_applicability(cx, needle.span, "..", &mut applicability)),
- applicability,
- );
- }
- };
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/bytes_count_to_len.rs b/src/tools/clippy/clippy_lints/src/bytes_count_to_len.rs
deleted file mode 100644
index d70dbf5b2..000000000
--- a/src/tools/clippy/clippy_lints/src/bytes_count_to_len.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{match_def_path, paths};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
- /// ### What it does
- /// It checks for `str::bytes().count()` and suggests replacing it with
- /// `str::len()`.
- ///
- /// ### Why is this bad?
- /// `str::bytes().count()` is longer and may not be as performant as using
- /// `str::len()`.
- ///
- /// ### Example
- /// ```rust
- /// "hello".bytes().count();
- /// String::from("hello").bytes().count();
- /// ```
- /// Use instead:
- /// ```rust
- /// "hello".len();
- /// String::from("hello").len();
- /// ```
- #[clippy::version = "1.62.0"]
- pub BYTES_COUNT_TO_LEN,
- complexity,
- "Using `bytes().count()` when `len()` performs the same functionality"
-}
-
-declare_lint_pass!(BytesCountToLen => [BYTES_COUNT_TO_LEN]);
-
-impl<'tcx> LateLintPass<'tcx> for BytesCountToLen {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if_chain! {
- if let hir::ExprKind::MethodCall(_, expr_args, _) = &expr.kind;
- if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if match_def_path(cx, expr_def_id, &paths::ITER_COUNT);
-
- if let [bytes_expr] = &**expr_args;
- if let hir::ExprKind::MethodCall(_, bytes_args, _) = &bytes_expr.kind;
- if let Some(bytes_def_id) = cx.typeck_results().type_dependent_def_id(bytes_expr.hir_id);
- if match_def_path(cx, bytes_def_id, &paths::STR_BYTES);
-
- if let [str_expr] = &**bytes_args;
- let ty = cx.typeck_results().expr_ty(str_expr).peel_refs();
-
- if is_type_diagnostic_item(cx, ty, sym::String) || ty.kind() == &ty::Str;
- then {
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- BYTES_COUNT_TO_LEN,
- expr.span,
- "using long and hard to read `.bytes().count()`",
- "consider calling `.len()` instead",
- format!("{}.len()", snippet_with_applicability(cx, str_expr.span, "..", &mut applicability)),
- applicability
- );
- }
- };
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs
index e0442dda4..805121bcc 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs
@@ -40,7 +40,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, ignore_publish: b
}
fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) {
- let message = format!("package `{}` is missing `{}` metadata", package.name, field);
+ let message = format!("package `{}` is missing `{field}` metadata", package.name);
span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message);
}
diff --git a/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs b/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs
index 79a469a42..37c169dbd 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs
@@ -57,10 +57,8 @@ fn lint(cx: &LateContext<'_>, feature: &str, substring: &str, is_prefix: bool) {
},
DUMMY_SP,
&format!(
- "the \"{}\" {} in the feature name \"{}\" is {}",
- substring,
+ "the \"{substring}\" {} in the feature name \"{feature}\" is {}",
if is_prefix { "prefix" } else { "suffix" },
- feature,
if is_negative { "negative" } else { "redundant" }
),
None,
diff --git a/src/tools/clippy/clippy_lints/src/cargo/mod.rs b/src/tools/clippy/clippy_lints/src/cargo/mod.rs
index 9f45db86a..3a872e54c 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/mod.rs
@@ -196,7 +196,7 @@ impl LateLintPass<'_> for Cargo {
},
Err(e) => {
for lint in NO_DEPS_LINTS {
- span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {}", e));
+ span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}"));
}
},
}
@@ -212,7 +212,7 @@ impl LateLintPass<'_> for Cargo {
},
Err(e) => {
for lint in WITH_DEPS_LINTS {
- span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {}", e));
+ span_lint(cx, lint, DUMMY_SP, &format!("could not read cargo metadata: {e}"));
}
},
}
diff --git a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs
index 76fd0819a..f9b17d45e 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs
@@ -37,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) {
cx,
MULTIPLE_CRATE_VERSIONS,
DUMMY_SP,
- &format!("multiple versions for dependency `{}`: {}", name, versions),
+ &format!("multiple versions for dependency `{name}`: {versions}"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
deleted file mode 100644
index 7eff71d50..000000000
--- a/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
-use rustc_hir::{Expr, ExprKind, PathSegment};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{source_map::Spanned, symbol::sym, Span};
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for calls to `ends_with` with possible file extensions
- /// and suggests to use a case-insensitive approach instead.
- ///
- /// ### Why is this bad?
- /// `ends_with` is case-sensitive and may not detect files with a valid extension.
- ///
- /// ### Example
- /// ```rust
- /// fn is_rust_file(filename: &str) -> bool {
- /// filename.ends_with(".rs")
- /// }
- /// ```
- /// Use instead:
- /// ```rust
- /// fn is_rust_file(filename: &str) -> bool {
- /// let filename = std::path::Path::new(filename);
- /// filename.extension()
- /// .map(|ext| ext.eq_ignore_ascii_case("rs"))
- /// .unwrap_or(false)
- /// }
- /// ```
- #[clippy::version = "1.51.0"]
- pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
- pedantic,
- "Checks for calls to ends_with with case-sensitive file extensions"
-}
-
-declare_lint_pass!(CaseSensitiveFileExtensionComparisons => [CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS]);
-
-fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Span> {
- if_chain! {
- if let ExprKind::MethodCall(PathSegment { ident, .. }, [obj, extension, ..], span) = expr.kind;
- if ident.as_str() == "ends_with";
- if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = extension.kind;
- if (2..=6).contains(&ext_literal.as_str().len());
- if ext_literal.as_str().starts_with('.');
- if ext_literal.as_str().chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit())
- || ext_literal.as_str().chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit());
- then {
- let mut ty = ctx.typeck_results().expr_ty(obj);
- ty = match ty.kind() {
- ty::Ref(_, ty, ..) => *ty,
- _ => ty
- };
-
- match ty.kind() {
- ty::Str => {
- return Some(span);
- },
- ty::Adt(def, _) => {
- if ctx.tcx.is_diagnostic_item(sym::String, def.did()) {
- return Some(span);
- }
- },
- _ => { return None; }
- }
- }
- }
- None
-}
-
-impl<'tcx> LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons {
- fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if let Some(span) = check_case_sensitive_file_extension_comparison(ctx, expr) {
- span_lint_and_help(
- ctx,
- CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
- span,
- "case-sensitive file extension comparison",
- None,
- "consider using a case-insensitive comparison instead",
- );
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
new file mode 100644
index 000000000..9409f4844
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
@@ -0,0 +1,38 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_opt;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::{
+ mir::Mutability,
+ ty::{self, Ty, TypeAndMut},
+};
+
+use super::AS_PTR_CAST_MUT;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>) {
+ if let ty::RawPtr(ptrty @ TypeAndMut { mutbl: Mutability::Mut, .. }) = cast_to.kind()
+ && let ty::RawPtr(TypeAndMut { mutbl: Mutability::Not, .. }) =
+ cx.typeck_results().node_type(cast_expr.hir_id).kind()
+ && let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind
+ && method_name.ident.name == rustc_span::sym::as_ptr
+ && let Some(as_ptr_did) = cx.typeck_results().type_dependent_def_id(cast_expr.peel_blocks().hir_id)
+ && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did)
+ && let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next()
+ && let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind()
+ && let Some(recv) = snippet_opt(cx, receiver.span)
+ {
+ // `as_mut_ptr` might not exist
+ let applicability = Applicability::MaybeIncorrect;
+
+ span_lint_and_sugg(
+ cx,
+ AS_PTR_CAST_MUT,
+ expr.span,
+ &format!("casting the result of `as_ptr` to *{ptrty}"),
+ "replace with",
+ format!("{recv}.as_mut_ptr()"),
+ applicability
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs b/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs
new file mode 100644
index 000000000..56e894c62
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs
@@ -0,0 +1,25 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, Ty, TyKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+
+use super::AS_UNDERSCORE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ty: &'tcx Ty<'_>) {
+ if matches!(ty.kind, TyKind::Infer) {
+ span_lint_and_then(cx, AS_UNDERSCORE, expr.span, "using `as _` conversion", |diag| {
+ let ty_resolved = cx.typeck_results().expr_ty(expr);
+ if let ty::Error(_) = ty_resolved.kind() {
+ diag.help("consider giving the type explicitly");
+ } else {
+ diag.span_suggestion(
+ ty.span,
+ "consider giving the type explicitly",
+ ty_resolved,
+ Applicability::MachineApplicable,
+ );
+ }
+ });
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
new file mode 100644
index 000000000..294d22d34
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
@@ -0,0 +1,37 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_no_std_crate;
+use clippy_utils::source::snippet_with_context;
+use rustc_errors::Applicability;
+use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind};
+use rustc_lint::LateContext;
+
+use super::BORROW_AS_PTR;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ cast_expr: &'tcx Expr<'_>,
+ cast_to: &'tcx Ty<'_>,
+) {
+ if matches!(cast_to.kind, TyKind::Ptr(_))
+ && let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind
+ {
+ let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
+ let macro_name = match mutability {
+ Mutability::Not => "addr_of",
+ Mutability::Mut => "addr_of_mut",
+ };
+ let mut app = Applicability::MachineApplicable;
+ let snip = snippet_with_context(cx, e.span, cast_expr.span.ctxt(), "..", &mut app).0;
+
+ span_lint_and_sugg(
+ cx,
+ BORROW_AS_PTR,
+ expr.span,
+ "borrow as raw pointer",
+ "try",
+ format!("{core_or_std}::ptr::{macro_name}!({snip})"),
+ Applicability::MachineApplicable,
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
index 64ea326b7..3f1edabe6 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
@@ -20,7 +20,7 @@ pub(super) fn check(
if meets_msrv(msrv, msrvs::UNSIGNED_ABS)
&& let ty::Int(from) = cast_from.kind()
&& let ty::Uint(to) = cast_to.kind()
- && let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind
+ && let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind
&& method_path.ident.name.as_str() == "abs"
{
let span = if from.bit_width() == to.bit_width() {
@@ -37,7 +37,7 @@ pub(super) fn check(
span,
&format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
"replace with",
- format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")),
+ format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()),
Applicability::MachineApplicable,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
index 938458e30..13c403234 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
@@ -41,15 +41,9 @@ pub(super) fn check(
);
let message = if cast_from.is_bool() {
- format!(
- "casting `{0:}` to `{1:}` is more cleanly stated with `{1:}::from(_)`",
- cast_from, cast_to
- )
+ format!("casting `{cast_from:}` to `{cast_to:}` is more cleanly stated with `{cast_to:}::from(_)`")
} else {
- format!(
- "casting `{}` to `{}` may become silently lossy if you later change the type",
- cast_from, cast_to
- )
+ format!("casting `{cast_from}` to `{cast_to}` may become silently lossy if you later change the type")
};
span_lint_and_sugg(
@@ -58,7 +52,7 @@ pub(super) fn check(
expr.span,
&message,
"try",
- format!("{}::from({})", cast_to, sugg),
+ format!("{cast_to}::from({sugg})"),
applicability,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs
new file mode 100644
index 000000000..322dc41b3
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs
@@ -0,0 +1,28 @@
+use super::CAST_NAN_TO_INT;
+
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_note;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, from_ty: Ty<'_>, to_ty: Ty<'_>) {
+ if from_ty.is_floating_point() && to_ty.is_integral() && is_known_nan(cx, cast_expr) {
+ span_lint_and_note(
+ cx,
+ CAST_NAN_TO_INT,
+ expr.span,
+ &format!("casting a known NaN to {to_ty}"),
+ None,
+ "this always evaluates to 0",
+ );
+ }
+}
+
+fn is_known_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
+ match constant(cx, cx.typeck_results(), e) {
+ Some((Constant::F64(n), _)) => n.is_nan(),
+ Some((Constant::F32(n), _)) => n.is_nan(),
+ _ => false,
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index 64f87c80f..88deb4565 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -44,7 +44,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
.saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))),
_ => nbits,
},
- ExprKind::MethodCall(method, [left, right], _) => {
+ ExprKind::MethodCall(method, left, [right], _) => {
if signed {
return nbits;
}
@@ -55,7 +55,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
};
apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
},
- ExprKind::MethodCall(method, [_, lo, hi], _) => {
+ 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)) {
@@ -64,7 +64,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
}
nbits
},
- ExprKind::MethodCall(method, [_value], _) => {
+ ExprKind::MethodCall(method, _value, [], _) => {
if method.ident.name.as_str() == "signum" {
0 // do not lint if cast comes from a `signum` function
} else {
@@ -103,10 +103,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
return;
}
- format!(
- "casting `{}` to `{}` may truncate the value{}",
- cast_from, cast_to, suffix,
- )
+ format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",)
},
(ty::Adt(def, _), true) if def.is_enum() => {
@@ -142,20 +139,17 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
CAST_ENUM_TRUNCATION,
expr.span,
&format!(
- "casting `{}::{}` to `{}` will truncate the value{}",
- cast_from, variant.name, cast_to, suffix,
+ "casting `{cast_from}::{}` to `{cast_to}` will truncate the value{suffix}",
+ variant.name,
),
);
return;
}
- format!(
- "casting `{}` to `{}` may truncate the value{}",
- cast_from, cast_to, suffix,
- )
+ format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",)
},
(ty::Float(_), true) => {
- format!("casting `{}` to `{}` may truncate the value", cast_from, cast_to)
+ format!("casting `{cast_from}` to `{cast_to}` may truncate the value")
},
(ty::Float(FloatTy::F64), false) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => {
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
index 2c5c1d7cb..28ecdea7e 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
@@ -35,10 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
cx,
CAST_POSSIBLE_WRAP,
expr.span,
- &format!(
- "casting `{}` to `{}` may wrap around the value{}",
- cast_from, cast_to, suffix,
- ),
+ &format!("casting `{cast_from}` to `{cast_to}` may wrap around the value{suffix}",),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index d476a1a76..97054a0d1 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
cx.typeck_results().expr_ty(expr),
);
lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
- } else if let ExprKind::MethodCall(method_path, [self_arg, ..], _) = &expr.kind {
+ } else if let ExprKind::MethodCall(method_path, self_arg, ..) = &expr.kind {
if method_path.ident.name == sym!(cast)
&& let Some(generic_args) = method_path.args
&& let [GenericArg::Type(cast_to)] = generic_args.args
@@ -49,9 +49,7 @@ fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_f
CAST_PTR_ALIGNMENT,
expr.span,
&format!(
- "casting from `{}` to a more-strictly-aligned pointer (`{}`) ({} < {} bytes)",
- cast_from,
- cast_to,
+ "casting from `{cast_from}` to a more-strictly-aligned pointer (`{cast_to}`) ({} < {} bytes)",
from_layout.align.abi.bytes(),
to_layout.align.abi.bytes(),
),
@@ -64,7 +62,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
return false;
};
match parent.kind {
- ExprKind::MethodCall(name, [self_arg, ..], _) if self_arg.hir_id == e.hir_id => {
+ ExprKind::MethodCall(name, self_arg, ..) if self_arg.hir_id == e.hir_id => {
if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned")
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
&& let Some(def_id) = cx.tcx.impl_of_method(def_id)
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index 75f70b77e..a20a97d4e 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -14,10 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, c
cx,
CAST_SIGN_LOSS,
expr.span,
- &format!(
- "casting `{}` to `{}` may lose the sign of the value",
- cast_from, cast_to
- ),
+ &format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"),
);
}
}
@@ -41,14 +38,14 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast
}
// Don't lint for the result of methods that always return non-negative values.
- if let ExprKind::MethodCall(path, _, _) = cast_op.kind {
+ if let ExprKind::MethodCall(path, ..) = cast_op.kind {
let mut method_name = path.ident.name.as_str();
let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
if_chain! {
if method_name == "unwrap";
if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]);
- if let ExprKind::MethodCall(inner_path, _, _) = &arglist[0][0].kind;
+ if let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind;
then {
method_name = inner_path.ident.name.as_str();
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
index 027c660ce..d31d10d22 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
@@ -35,8 +35,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Optio
CAST_SLICE_DIFFERENT_SIZES,
expr.span,
&format!(
- "casting between raw pointers to `[{}]` (element size {}) and `[{}]` (element size {}) does not adjust the count",
- start_ty.ty, from_size, end_ty.ty, to_size,
+ "casting between raw pointers to `[{}]` (element size {from_size}) and `[{}]` (element size {to_size}) does not adjust the count",
+ start_ty.ty, end_ty.ty,
),
|diag| {
let ptr_snippet = source::snippet(cx, left_cast.span, "..");
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
new file mode 100644
index 000000000..284ef1659
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
@@ -0,0 +1,63 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{match_def_path, meets_msrv, msrvs, paths};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{def_id::DefId, Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty};
+use rustc_semver::RustcVersion;
+
+use super::CAST_SLICE_FROM_RAW_PARTS;
+
+enum RawPartsKind {
+ Immutable,
+ Mutable,
+}
+
+fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option<RawPartsKind> {
+ if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS) {
+ Some(RawPartsKind::Immutable)
+ } else if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS_MUT) {
+ Some(RawPartsKind::Mutable)
+ } else {
+ None
+ }
+}
+
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ cast_expr: &Expr<'_>,
+ cast_to: Ty<'_>,
+ msrv: Option<RustcVersion>,
+) {
+ if_chain! {
+ if meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS);
+ if let ty::RawPtr(ptrty) = cast_to.kind();
+ if let ty::Slice(_) = ptrty.ty.kind();
+ if let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().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 let Some(rpk) = raw_parts_kind(cx, fun_def_id);
+ then {
+ let func = match rpk {
+ RawPartsKind::Immutable => "from_raw_parts",
+ RawPartsKind::Mutable => "from_raw_parts_mut"
+ };
+ let span = expr.span;
+ let mut applicability = Applicability::MachineApplicable;
+ let ptr = snippet_with_applicability(cx, ptr_arg.span, "ptr", &mut applicability);
+ let len = snippet_with_applicability(cx, len_arg.span, "len", &mut applicability);
+ span_lint_and_sugg(
+ cx,
+ CAST_SLICE_FROM_RAW_PARTS,
+ span,
+ &format!("casting the result of `{func}` to {cast_to}"),
+ "replace with",
+ format!("core::ptr::slice_{func}({ptr}, {len})"),
+ applicability
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs b/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs
index 7cc406018..82e07c98a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs
@@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
diag.span_suggestion(
expr.span,
"use a byte literal instead",
- format!("b{}", snippet),
+ format!("b{snippet}"),
applicability,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
index 35350d8a2..a26bfab4e 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
@@ -25,9 +25,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
cx,
FN_TO_NUMERIC_CAST,
expr.span,
- &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to),
+ &format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
"try",
- format!("{} as usize", from_snippet),
+ format!("{from_snippet} as usize"),
applicability,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
index 03621887a..756541294 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
@@ -23,9 +23,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
cx,
FN_TO_NUMERIC_CAST_ANY,
expr.span,
- &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to),
+ &format!("casting function pointer `{from_snippet}` to `{cast_to}`"),
"did you mean to invoke the function?",
- format!("{}() as {}", from_snippet, cast_to),
+ format!("{from_snippet}() as {cast_to}"),
applicability,
);
},
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
index 6287f479b..556be1d15 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
@@ -24,12 +24,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
cx,
FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
expr.span,
- &format!(
- "casting function pointer `{}` to `{}`, which truncates the value",
- from_snippet, cast_to
- ),
+ &format!("casting function pointer `{from_snippet}` to `{cast_to}`, which truncates the value"),
"try",
- format!("{} as usize", from_snippet),
+ format!("{from_snippet} as usize"),
applicability,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index af3798a0c..b72c4c772 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -1,6 +1,10 @@
+mod as_ptr_cast_mut;
+mod as_underscore;
+mod borrow_as_ptr;
mod cast_abs_to_unsigned;
mod cast_enum_constructor;
mod cast_lossless;
+mod cast_nan_to_int;
mod cast_possible_truncation;
mod cast_possible_wrap;
mod cast_precision_loss;
@@ -8,6 +12,7 @@ mod cast_ptr_alignment;
mod cast_ref_to_mut;
mod cast_sign_loss;
mod cast_slice_different_sizes;
+mod cast_slice_from_raw_parts;
mod char_lit_as_u8;
mod fn_to_numeric_cast;
mod fn_to_numeric_cast_any;
@@ -16,7 +21,7 @@ mod ptr_as_ptr;
mod unnecessary_cast;
mod utils;
-use clippy_utils::is_hir_ty_cfg_dependant;
+use clippy_utils::{is_hir_ty_cfg_dependant, meets_msrv, msrvs};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
@@ -506,6 +511,142 @@ declare_clippy_lint! {
"casting the result of `abs()` to an unsigned integer can panic"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Check for the usage of `as _` conversion using inferred type.
+ ///
+ /// ### Why is this bad?
+ /// The conversion might include lossy conversion and dangerous cast that might go
+ /// undetected due to the type being inferred.
+ ///
+ /// The lint is allowed by default as using `_` is less wordy than always specifying the type.
+ ///
+ /// ### Example
+ /// ```rust
+ /// fn foo(n: usize) {}
+ /// let n: u16 = 256;
+ /// foo(n as _);
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// fn foo(n: usize) {}
+ /// let n: u16 = 256;
+ /// foo(n as usize);
+ /// ```
+ #[clippy::version = "1.63.0"]
+ pub AS_UNDERSCORE,
+ restriction,
+ "detects `as _` conversion"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for the usage of `&expr as *const T` or
+ /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or
+ /// `ptr::addr_of_mut` instead.
+ ///
+ /// ### Why is this bad?
+ /// This would improve readability and avoid creating a reference
+ /// that points to an uninitialized value or unaligned place.
+ /// Read the `ptr::addr_of` docs for more information.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let val = 1;
+ /// let p = &val as *const i32;
+ ///
+ /// let mut val_mut = 1;
+ /// let p_mut = &mut val_mut as *mut i32;
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let val = 1;
+ /// let p = std::ptr::addr_of!(val);
+ ///
+ /// let mut val_mut = 1;
+ /// let p_mut = std::ptr::addr_of_mut!(val_mut);
+ /// ```
+ #[clippy::version = "1.60.0"]
+ pub BORROW_AS_PTR,
+ pedantic,
+ "borrowing just to cast to a raw pointer"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for a raw slice being cast to a slice pointer
+ ///
+ /// ### Why is this bad?
+ /// This can result in multiple `&mut` references to the same location when only a pointer is
+ /// required.
+ /// `ptr::slice_from_raw_parts` is a safe alternative that doesn't require
+ /// the same [safety requirements] to be upheld.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _;
+ /// let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _;
+ /// ```
+ /// Use instead:
+ /// ```rust,ignore
+ /// let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len);
+ /// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len);
+ /// ```
+ /// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety
+ #[clippy::version = "1.64.0"]
+ pub CAST_SLICE_FROM_RAW_PARTS,
+ suspicious,
+ "casting a slice created from a pointer and length to a slice pointer"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer
+ ///
+ /// ### Why is this bad?
+ /// Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior
+ /// mutability is used, making it unlikely that having it as a mutable pointer is correct.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let string = String::with_capacity(1);
+ /// let ptr = string.as_ptr() as *mut u8;
+ /// unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let mut string = String::with_capacity(1);
+ /// let ptr = string.as_mut_ptr();
+ /// unsafe { ptr.write(4) };
+ /// ```
+ #[clippy::version = "1.66.0"]
+ pub AS_PTR_CAST_MUT,
+ nursery,
+ "casting the result of the `&self`-taking `as_ptr` to a mutabe pointer"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for a known NaN float being cast to an integer
+ ///
+ /// ### Why is this bad?
+ /// NaNs are cast into zero, so one could simply use this and make the
+ /// code more readable. The lint could also hint at a programmer error.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// let _: (0.0_f32 / 0.0) as u64;
+ /// ```
+ /// Use instead:
+ /// ```rust,ignore
+ /// let _: = 0_u64;
+ /// ```
+ #[clippy::version = "1.64.0"]
+ pub CAST_NAN_TO_INT,
+ suspicious,
+ "casting a known floating-point NaN into an integer"
+}
+
pub struct Casts {
msrv: Option<RustcVersion>,
}
@@ -534,7 +675,12 @@ impl_lint_pass!(Casts => [
PTR_AS_PTR,
CAST_ENUM_TRUNCATION,
CAST_ENUM_CONSTRUCTOR,
- CAST_ABS_TO_UNSIGNED
+ CAST_ABS_TO_UNSIGNED,
+ AS_UNDERSCORE,
+ BORROW_AS_PTR,
+ CAST_SLICE_FROM_RAW_PARTS,
+ AS_PTR_CAST_MUT,
+ CAST_NAN_TO_INT,
]);
impl<'tcx> LateLintPass<'tcx> for Casts {
@@ -547,8 +693,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
return;
}
- if let ExprKind::Cast(cast_expr, cast_to) = expr.kind {
- if is_hir_ty_cfg_dependant(cx, cast_to) {
+ if let ExprKind::Cast(cast_expr, cast_to_hir) = expr.kind {
+ if is_hir_ty_cfg_dependant(cx, cast_to_hir) {
return;
}
let (cast_from, cast_to) = (
@@ -559,7 +705,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
return;
}
-
+ cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, self.msrv);
+ as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to);
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);
@@ -571,10 +718,17 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
cast_precision_loss::check(cx, expr, cast_from, cast_to);
cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
+ cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to);
}
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
}
+
+ as_underscore::check(cx, expr, cast_to_hir);
+
+ if meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) {
+ borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
+ }
}
cast_ref_to_mut::check(cx, expr);
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index 46d45d096..b9509ca65 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -26,14 +26,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option<RustcVer
(Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut));
// The `U` in `pointer::cast` have to be `Sized`
// as explained here: https://github.com/rust-lang/rust/issues/60602.
- if to_pointee_ty.is_sized(cx.tcx.at(expr.span), cx.param_env);
+ if to_pointee_ty.is_sized(cx.tcx, cx.param_env);
then {
let mut applicability = Applicability::MachineApplicable;
let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut applicability);
let turbofish = match &cast_to_hir_ty.kind {
TyKind::Infer => Cow::Borrowed(""),
TyKind::Ptr(mut_ty) if matches!(mut_ty.ty.kind, TyKind::Infer) => Cow::Borrowed(""),
- _ => Cow::Owned(format!("::<{}>", to_pointee_ty)),
+ _ => Cow::Owned(format!("::<{to_pointee_ty}>")),
};
span_lint_and_sugg(
cx,
@@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option<RustcVer
expr.span,
"`as` casting between raw pointers without changing its mutability",
"try `pointer::cast`, a safer alternative",
- format!("{}.cast{}()", cast_expr_sugg.maybe_par(), turbofish),
+ format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()),
applicability,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index fff7da8e3..c8596987e 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -1,4 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::get_parent_expr;
use clippy_utils::numeric_literal::NumericLiteral;
use clippy_utils::source::snippet_opt;
use if_chain::if_chain;
@@ -30,8 +31,10 @@ pub(super) fn check<'tcx>(
}
}
+ let cast_str = snippet_opt(cx, cast_expr.span).unwrap_or_default();
+
if let Some(lit) = get_numeric_literal(cast_expr) {
- let literal_str = snippet_opt(cx, cast_expr.span).unwrap_or_default();
+ let literal_str = &cast_str;
if_chain! {
if let LitKind::Int(n, _) = lit.node;
@@ -49,12 +52,13 @@ pub(super) fn check<'tcx>(
match lit.node {
LitKind::Int(_, LitIntType::Unsuffixed) if cast_to.is_integral() => {
- lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
+ lint_unnecessary_cast(cx, expr, literal_str, cast_from, cast_to);
+ return false;
},
LitKind::Float(_, LitFloatType::Unsuffixed) if cast_to.is_floating_point() => {
- lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
+ lint_unnecessary_cast(cx, expr, literal_str, cast_from, cast_to);
+ return false;
},
- LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => {},
LitKind::Int(_, LitIntType::Signed(_) | LitIntType::Unsigned(_))
| LitKind::Float(_, LitFloatType::Suffixed(_))
if cast_from.kind() == cast_to.kind() =>
@@ -62,41 +66,62 @@ pub(super) fn check<'tcx>(
if let Some(src) = snippet_opt(cx, cast_expr.span) {
if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) {
lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
+ return true;
}
}
},
- _ => {
- if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
- span_lint_and_sugg(
- cx,
- UNNECESSARY_CAST,
- expr.span,
- &format!(
- "casting to the same type is unnecessary (`{}` -> `{}`)",
- cast_from, cast_to
- ),
- "try",
- literal_str,
- Applicability::MachineApplicable,
- );
- return true;
- }
- },
+ _ => {},
}
}
+ if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_CAST,
+ expr.span,
+ &format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
+ "try",
+ cast_str,
+ Applicability::MachineApplicable,
+ );
+ return true;
+ }
+
false
}
-fn lint_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &str, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+fn lint_unnecessary_cast(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ raw_literal_str: &str,
+ cast_from: Ty<'_>,
+ cast_to: Ty<'_>,
+) {
let literal_kind_name = if cast_from.is_integral() { "integer" } else { "float" };
+ // first we remove all matches so `-(1)` become `-1`, and remove trailing dots, so `1.` become `1`
+ let literal_str = raw_literal_str
+ .replace(['(', ')'], "")
+ .trim_end_matches('.')
+ .to_string();
+ // we know need to check if the parent is a method call, to add parenthesis accordingly (eg:
+ // (-1).foo() instead of -1.foo())
+ let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr)
+ && let ExprKind::MethodCall(..) = parent_expr.kind
+ && literal_str.starts_with('-')
+ {
+ format!("({literal_str}_{cast_to})")
+
+ } else {
+ format!("{literal_str}_{cast_to}")
+ };
+
span_lint_and_sugg(
cx,
UNNECESSARY_CAST,
expr.span,
- &format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to),
+ &format!("casting {literal_kind_name} literal to `{cast_to}` is unnecessary"),
"try",
- format!("{}_{}", literal_str.trim_end_matches('.'), cast_to),
+ sugg,
Applicability::MachineApplicable,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index 17fc81951..78e9921f0 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -2,9 +2,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{in_constant, meets_msrv, msrvs, SpanlessEq};
+use clippy_utils::{in_constant, is_integer_literal, meets_msrv, msrvs, SpanlessEq};
use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -82,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
item.span,
"checked cast can be simplified",
"try",
- format!("{}::try_from({}).is_ok()", to_type, snippet),
+ format!("{to_type}::try_from({snippet}).is_ok()"),
applicability,
);
}
@@ -223,16 +222,7 @@ fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
/// Check for `expr >= 0`
fn check_lower_bound_zero<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> {
- if_chain! {
- if let ExprKind::Lit(ref lit) = &check.kind;
- if let LitKind::Int(0, _) = &lit.node;
-
- then {
- Some(Conversion::new_any(candidate))
- } else {
- None
- }
- }
+ is_integer_literal(check, 0).then(|| Conversion::new_any(candidate))
}
/// Check for `expr >= (to_type::MIN as from_type)`
@@ -270,10 +260,7 @@ fn get_types_from_cast<'a>(
let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| {
if_chain! {
// `from_type::from, to_type::max_value()`
- if let ExprKind::Call(from_func, args) = &expr.kind;
- // `to_type::max_value()`
- if args.len() == 1;
- if let limit = &args[0];
+ if let ExprKind::Call(from_func, [limit]) = &expr.kind;
// `from_type::from`
if let ExprKind::Path(ref path) = &from_func.kind;
if let Some(from_sym) = get_implementing_type(path, INTS, "from");
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 33c44f8b2..77af3b53d 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -3,10 +3,12 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::for_each_expr;
use clippy_utils::LimitStack;
+use core::ops::ControlFlow;
use rustc_ast::ast::Attribute;
-use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId};
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Body, ExprKind, FnDecl, HirId};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
@@ -61,11 +63,27 @@ impl CognitiveComplexity {
return;
}
- let expr = &body.value;
+ let expr = body.value;
+
+ let mut cc = 1u64;
+ let mut returns = 0u64;
+ let _: Option<!> = for_each_expr(expr, |e| {
+ match e.kind {
+ ExprKind::If(_, _, _) => {
+ cc += 1;
+ },
+ ExprKind::Match(_, arms, _) => {
+ if arms.len() > 1 {
+ cc += 1;
+ }
+ cc += arms.iter().filter(|arm| arm.guard.is_some()).count() as u64;
+ },
+ ExprKind::Ret(_) => returns += 1,
+ _ => {},
+ }
+ ControlFlow::Continue(())
+ });
- let mut helper = CcHelper { cc: 1, returns: 0 };
- helper.visit_expr(expr);
- let CcHelper { cc, returns } = helper;
let ret_ty = cx.typeck_results().node_type(expr.hir_id);
let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::Result) {
returns
@@ -74,13 +92,12 @@ impl CognitiveComplexity {
(returns / 2)
};
- let mut rust_cc = cc;
// prevent degenerate cases where unreachable code contains `return` statements
- if rust_cc >= ret_adjust {
- rust_cc -= ret_adjust;
+ if cc >= ret_adjust {
+ cc -= ret_adjust;
}
- if rust_cc > self.limit.limit() {
+ if cc > self.limit.limit() {
let fn_span = match kind {
FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span,
FnKind::Closure => {
@@ -107,8 +124,7 @@ impl CognitiveComplexity {
COGNITIVE_COMPLEXITY,
fn_span,
&format!(
- "the function has a cognitive complexity of ({}/{})",
- rust_cc,
+ "the function has a cognitive complexity of ({cc}/{})",
self.limit.limit()
),
None,
@@ -141,27 +157,3 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity {
self.limit.pop_attrs(cx.sess(), attrs, "cognitive_complexity");
}
}
-
-struct CcHelper {
- cc: u64,
- returns: u64,
-}
-
-impl<'tcx> Visitor<'tcx> for CcHelper {
- fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
- walk_expr(self, e);
- match e.kind {
- ExprKind::If(_, _, _) => {
- self.cc += 1;
- },
- ExprKind::Match(_, arms, _) => {
- if arms.len() > 1 {
- self.cc += 1;
- }
- self.cc += arms.iter().filter(|arm| arm.guard.is_some()).count() as u64;
- },
- ExprKind::Ret(_) => self.returns += 1,
- _ => {},
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
index a05b41eb3..0fe973b49 100644
--- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs
+++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
@@ -1,9 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_trait_def_id, if_sequence, in_constant, is_else_clause, paths, SpanlessEq};
+use clippy_utils::{if_sequence, in_constant, is_else_clause, SpanlessEq};
use rustc_hir::{BinOpKind, 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
@@ -106,7 +107,10 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
// Check that the type being compared implements `core::cmp::Ord`
let ty = cx.typeck_results().expr_ty(lhs1);
- let is_ord = get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]));
+ let is_ord = cx
+ .tcx
+ .get_diagnostic_item(sym::Ord)
+ .map_or(false, |id| implements_trait(cx, ty, id, &[]));
if !is_ord {
return;
diff --git a/src/tools/clippy/clippy_lints/src/copy_iterator.rs b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
index 026683f60..e38f77268 100644
--- a/src/tools/clippy/clippy_lints/src/copy_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
@@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for CopyIterator {
of_trait: Some(ref trait_ref),
..
}) = item.kind;
- let ty = cx.tcx.type_of(item.def_id);
+ let ty = cx.tcx.type_of(item.owner_id);
if is_copy(cx, ty);
if let Some(trait_id) = trait_ref.trait_def_id();
if cx.tcx.is_diagnostic_item(sym::Iterator, trait_id);
diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
index 454ec2338..20cc330e0 100644
--- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
+++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
@@ -74,8 +74,8 @@ impl EarlyLintPass for CrateInMacroDef {
fn is_macro_export(attr: &Attribute) -> bool {
if_chain! {
- if let AttrKind::Normal(attr_item, _) = &attr.kind;
- if let [segment] = attr_item.path.segments.as_slice();
+ if let AttrKind::Normal(normal) = &attr.kind;
+ if let [segment] = normal.item.path.segments.as_slice();
then {
segment.ident.name == sym::macro_export
} else {
diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs
index 18d34370a..878248a6b 100644
--- a/src/tools/clippy/clippy_lints/src/create_dir.rs
+++ b/src/tools/clippy/clippy_lints/src/create_dir.rs
@@ -34,7 +34,7 @@ declare_lint_pass!(CreateDir => [CREATE_DIR]);
impl LateLintPass<'_> for CreateDir {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
- if let ExprKind::Call(func, args) = expr.kind;
+ if let ExprKind::Call(func, [arg, ..]) = expr.kind;
if let ExprKind::Path(ref path) = func.kind;
if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR);
@@ -45,7 +45,7 @@ impl LateLintPass<'_> for CreateDir {
expr.span,
"calling `std::fs::create_dir` where there may be a better way",
"consider calling `std::fs::create_dir_all` instead",
- format!("create_dir_all({})", snippet(cx, args[0].span, "..")),
+ format!("create_dir_all({})", snippet(cx, arg.span, "..")),
Applicability::MaybeIncorrect,
)
}
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index d99a1aa29..7f937de1d 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -1,7 +1,9 @@
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
use clippy_utils::source::snippet_with_macro_callsite;
use clippy_utils::ty::{has_drop, is_copy};
-use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, match_def_path, paths};
+use clippy_utils::{
+ any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths,
+};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@@ -94,6 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
if let QPath::Resolved(None, _path) = qpath;
let expr_ty = cx.typeck_results().expr_ty(expr);
if let ty::Adt(def, ..) = expr_ty.kind();
+ if !is_from_proc_macro(cx, expr);
then {
// TODO: Work out a way to put "whatever the imported way of referencing
// this type in this file" rather than a fully-qualified type.
@@ -102,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
cx,
DEFAULT_TRAIT_ACCESS,
expr.span,
- &format!("calling `{}` is more clear than this expression", replacement),
+ &format!("calling `{replacement}` is more clear than this expression"),
"try",
replacement,
Applicability::Unspecified, // First resolve the TODO above
@@ -139,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
if adt.is_struct();
let variant = adt.non_enum_variant();
if adt.did().is_local() || !variant.is_field_list_non_exhaustive();
- let module_did = cx.tcx.parent_module(stmt.hir_id).to_def_id();
+ let module_did = cx.tcx.parent_module(stmt.hir_id);
if variant
.fields
.iter()
@@ -207,7 +210,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
.map(|(field, rhs)| {
// extract and store the assigned value for help message
let value_snippet = snippet_with_macro_callsite(cx, rhs.span, "..");
- format!("{}: {}", field, value_snippet)
+ format!("{field}: {value_snippet}")
})
.collect::<Vec<String>>()
.join(", ");
@@ -224,7 +227,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(", ");
- format!("{}::<{}>", adt_def_ty_name, &tys_str)
+ format!("{adt_def_ty_name}::<{}>", &tys_str)
} else {
binding_type.to_string()
}
@@ -232,12 +235,12 @@ impl<'tcx> LateLintPass<'tcx> for Default {
let sugg = if ext_with_default {
if field_list.is_empty() {
- format!("{}::default()", binding_type)
+ format!("{binding_type}::default()")
} else {
- format!("{} {{ {}, ..Default::default() }}", binding_type, field_list)
+ format!("{binding_type} {{ {field_list}, ..Default::default() }}")
}
} else {
- format!("{} {{ {} }}", binding_type, field_list)
+ format!("{binding_type} {{ {field_list} }}")
};
// span lint once per statement that binds default
@@ -247,10 +250,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
first_assign.unwrap().span,
"field assignment outside of initializer for an instance created with Default::default()",
Some(local.span),
- &format!(
- "consider initializing the variable with `{}` and removing relevant reassignments",
- sugg
- ),
+ &format!("consider initializing the variable with `{sugg}` and removing relevant reassignments"),
);
self.reassigned_linted.insert(span);
}
diff --git a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
index 3c996d3d2..1ad929864 100644
--- a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
+++ b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
@@ -23,7 +23,7 @@ declare_clippy_lint! {
/// let _ = std::iter::empty::<usize>();
/// let iter: std::iter::Empty<usize> = std::iter::empty();
/// ```
- #[clippy::version = "1.63.0"]
+ #[clippy::version = "1.64.0"]
pub DEFAULT_INSTEAD_OF_ITER_EMPTY,
style,
"check `std::iter::Empty::default()` and replace with `std::iter::empty()`"
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index fb418a325..03460689e 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -1,12 +1,12 @@
use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::numeric_literal;
use clippy_utils::source::snippet_opt;
+use clippy_utils::{get_parent_node, numeric_literal};
use if_chain::if_chain;
use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::{
intravisit::{walk_expr, walk_stmt, Visitor},
- Body, Expr, ExprKind, HirId, Lit, Stmt, StmtKind,
+ Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::{
@@ -55,22 +55,31 @@ declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]);
impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback {
fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
- let mut visitor = NumericFallbackVisitor::new(cx);
+ let is_parent_const = if let Some(Node::Item(item)) = get_parent_node(cx.tcx, body.id().hir_id) {
+ matches!(item.kind, ItemKind::Const(..))
+ } else {
+ false
+ };
+ let mut visitor = NumericFallbackVisitor::new(cx, is_parent_const);
visitor.visit_body(body);
}
}
struct NumericFallbackVisitor<'a, 'tcx> {
/// Stack manages type bound of exprs. The top element holds current expr type.
- ty_bounds: Vec<TyBound<'tcx>>,
+ ty_bounds: Vec<ExplicitTyBound>,
cx: &'a LateContext<'tcx>,
}
impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
- fn new(cx: &'a LateContext<'tcx>) -> Self {
+ fn new(cx: &'a LateContext<'tcx>, is_parent_const: bool) -> Self {
Self {
- ty_bounds: vec![TyBound::Nothing],
+ ty_bounds: vec![if is_parent_const {
+ ExplicitTyBound(true)
+ } else {
+ ExplicitTyBound(false)
+ }],
cx,
}
}
@@ -79,10 +88,9 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) {
if_chain! {
if !in_external_macro(self.cx.sess(), lit.span);
- if let Some(ty_bound) = self.ty_bounds.last();
+ if matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false)));
if matches!(lit.node,
LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed));
- if !ty_bound.is_numeric();
then {
let (suffix, is_float) = match lit_ty.kind() {
ty::Int(IntTy::I32) => ("i32", false),
@@ -95,8 +103,8 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
src
} else {
match lit.node {
- LitKind::Int(src, _) => format!("{}", src),
- LitKind::Float(src, _) => format!("{}", src),
+ LitKind::Int(src, _) => format!("{src}"),
+ LitKind::Float(src, _) => format!("{src}"),
_ => return,
}
};
@@ -123,7 +131,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
if let Some(fn_sig) = fn_sig_opt(self.cx, func.hir_id) {
for (expr, bound) in iter::zip(*args, fn_sig.skip_binder().inputs()) {
// Push found arg type, then visit arg.
- self.ty_bounds.push(TyBound::Ty(*bound));
+ self.ty_bounds.push((*bound).into());
self.visit_expr(expr);
self.ty_bounds.pop();
}
@@ -131,11 +139,11 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
}
},
- ExprKind::MethodCall(_, args, _) => {
+ ExprKind::MethodCall(_, receiver, args, _) => {
if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
- for (expr, bound) in iter::zip(*args, fn_sig.inputs()) {
- self.ty_bounds.push(TyBound::Ty(*bound));
+ for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) {
+ self.ty_bounds.push((*bound).into());
self.visit_expr(expr);
self.ty_bounds.pop();
}
@@ -169,7 +177,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
// Visit base with no bound.
if let Some(base) = base {
- self.ty_bounds.push(TyBound::Nothing);
+ self.ty_bounds.push(ExplicitTyBound(false));
self.visit_expr(base);
self.ty_bounds.pop();
}
@@ -192,15 +200,10 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
match stmt.kind {
- StmtKind::Local(local) => {
- if local.ty.is_some() {
- self.ty_bounds.push(TyBound::Any);
- } else {
- self.ty_bounds.push(TyBound::Nothing);
- }
- },
+ // we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric`
+ StmtKind::Local(local) => self.ty_bounds.push(ExplicitTyBound(local.ty.is_some())),
- _ => self.ty_bounds.push(TyBound::Nothing),
+ _ => self.ty_bounds.push(ExplicitTyBound(false)),
}
walk_stmt(self, stmt);
@@ -218,28 +221,18 @@ fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<'
}
}
+/// Wrapper around a `bool` to make the meaning of the value clearer
#[derive(Debug, Clone, Copy)]
-enum TyBound<'tcx> {
- Any,
- Ty(Ty<'tcx>),
- Nothing,
-}
+struct ExplicitTyBound(pub bool);
-impl<'tcx> TyBound<'tcx> {
- fn is_numeric(self) -> bool {
- match self {
- TyBound::Any => true,
- TyBound::Ty(t) => t.is_numeric(),
- TyBound::Nothing => false,
- }
+impl<'tcx> From<Ty<'tcx>> for ExplicitTyBound {
+ fn from(v: Ty<'tcx>) -> Self {
+ Self(v.is_numeric())
}
}
-impl<'tcx> From<Option<Ty<'tcx>>> for TyBound<'tcx> {
+impl<'tcx> From<Option<Ty<'tcx>>> for ExplicitTyBound {
fn from(v: Option<Ty<'tcx>>) -> Self {
- match v {
- Some(t) => TyBound::Ty(t),
- None => TyBound::Nothing,
- }
+ Self(v.map_or(false, Ty::is_numeric))
}
}
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
index d559ad423..dec357ab7 100644
--- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_hir::{self as hir, HirId, Item, ItemKind};
+use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
-use rustc_typeck::hir_ty_to_ty;
declare_clippy_lint! {
/// ### What it does
@@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation {
None,
&format!(
"consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout",
- cx.tcx.def_path_str(item.def_id.to_def_id())
+ cx.tcx.def_path_str(item.owner_id.to_def_id())
),
);
}
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 514661589..a37ee82d4 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1,24 +1,38 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
+use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap};
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, variant_of_res};
-use clippy_utils::{get_parent_expr, is_lint_allowed, path_to_local, walk_to_expr_usage};
+use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res};
+use clippy_utils::{
+ fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, meets_msrv, msrvs, path_to_local,
+ walk_to_expr_usage,
+};
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_ty, Visitor};
use rustc_hir::{
- self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId,
- ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem,
+ self as hir,
+ def_id::{DefId, LocalDefId},
+ BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId, ImplItem,
+ ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem,
TraitItemKind, TyKind, UnOp,
};
+use rustc_index::bit_set::BitSet;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::mir::{Rvalue, StatementKind};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults};
+use rustc_middle::ty::{
+ self, Binder, BoundVariableKind, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind,
+ ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults,
+};
+use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{symbol::sym, Span, Symbol};
-use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
+use std::collections::VecDeque;
declare_clippy_lint! {
/// ### What it does
@@ -125,13 +139,13 @@ declare_clippy_lint! {
/// let x = String::new();
/// let y: &str = &x;
/// ```
- #[clippy::version = "1.60.0"]
+ #[clippy::version = "1.64.0"]
pub EXPLICIT_AUTO_DEREF,
- nursery,
+ complexity,
"dereferencing when the compiler would automatically dereference"
}
-impl_lint_pass!(Dereferencing => [
+impl_lint_pass!(Dereferencing<'_> => [
EXPLICIT_DEREF_METHODS,
NEEDLESS_BORROW,
REF_BINDING_TO_REFERENCE,
@@ -139,7 +153,7 @@ impl_lint_pass!(Dereferencing => [
]);
#[derive(Default)]
-pub struct Dereferencing {
+pub struct Dereferencing<'tcx> {
state: Option<(State, StateData)>,
// While parsing a `deref` method call in ufcs form, the path to the function is itself an
@@ -151,6 +165,7 @@ pub struct Dereferencing {
/// 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
@@ -158,8 +173,27 @@ pub struct Dereferencing {
///
/// e.g. `m!(x) | Foo::Bar(ref x)`
ref_locals: FxIndexMap<HirId, Option<RefPat>>,
+
+ /// Stack of (body owner, `PossibleBorrowerMap`) pairs. Used by
+ /// `needless_borrow_impl_arg_position` to determine when a borrowed expression can instead
+ /// be moved.
+ possible_borrowers: Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
+
+ // `IntoIterator` for arrays requires Rust 1.53.
+ msrv: Option<RustcVersion>,
}
+impl<'tcx> Dereferencing<'tcx> {
+ #[must_use]
+ pub fn new(msrv: Option<RustcVersion>) -> Self {
+ Self {
+ msrv,
+ ..Dereferencing::default()
+ }
+ }
+}
+
+#[derive(Debug)]
struct StateData {
/// Span of the top level expression
span: Span,
@@ -167,11 +201,14 @@ struct StateData {
position: Position,
}
+#[derive(Debug)]
struct DerefedBorrow {
count: usize,
msg: &'static str,
+ snip_expr: Option<HirId>,
}
+#[derive(Debug)]
enum State {
// Any number of deref method calls.
DerefMethod {
@@ -183,24 +220,24 @@ enum State {
},
DerefedBorrow(DerefedBorrow),
ExplicitDeref {
- // Span and id of the top-level deref expression if the parent expression is a borrow.
- deref_span_id: Option<(Span, HirId)>,
+ mutability: Option<Mutability>,
},
ExplicitDerefField {
name: Symbol,
},
Reborrow {
- deref_span: Span,
- deref_hir_id: HirId,
+ mutability: Mutability,
+ },
+ Borrow {
+ mutability: Mutability,
},
- Borrow,
}
// A reference operation considered by this lint pass
enum RefOp {
Method(Mutability),
Deref,
- AddrOf,
+ AddrOf(Mutability),
}
struct RefPat {
@@ -216,7 +253,7 @@ struct RefPat {
hir_id: HirId,
}
-impl<'tcx> LateLintPass<'tcx> for Dereferencing {
+impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
#[expect(clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// Skip path expressions from deref calls. e.g. `Deref::deref(e)`
@@ -250,11 +287,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
match (self.state.take(), kind) {
(None, kind) => {
let expr_ty = typeck.expr_ty(expr);
- let (position, adjustments) = walk_parents(cx, expr);
-
+ let (position, adjustments) = walk_parents(cx, &mut self.possible_borrowers, expr, self.msrv);
match kind {
RefOp::Deref => {
- if let Position::FieldAccess(name) = position
+ if let Position::FieldAccess {
+ name,
+ of_union: false,
+ } = position
&& !ty_contains_field(typeck.expr_ty(sub_expr), name)
{
self.state = Some((
@@ -263,7 +302,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
));
} else if position.is_deref_stable() {
self.state = Some((
- State::ExplicitDeref { deref_span_id: None },
+ State::ExplicitDeref { mutability: None },
StateData { span: expr.span, hir_id: expr.hir_id, position },
));
}
@@ -272,13 +311,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
&& position.lint_explicit_deref() =>
{
+ let ty_changed_count = usize::from(!deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)));
self.state = Some((
State::DerefMethod {
- ty_changed_count: if deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)) {
- 0
- } else {
- 1
- },
+ ty_changed_count,
is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
target_mut,
},
@@ -289,7 +325,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
},
));
},
- RefOp::AddrOf => {
+ RefOp::AddrOf(mutability) => {
// Find the number of times the borrow is auto-derefed.
let mut iter = adjustments.iter();
let mut deref_count = 0usize;
@@ -331,20 +367,23 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
let deref_msg =
"this expression creates a reference which is immediately dereferenced by the compiler";
let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
+ let impl_msg = "the borrowed expression implements the required traits";
- let (required_refs, msg) = if position.can_auto_borrow() {
- (1, if deref_count == 1 { borrow_msg } else { deref_msg })
+ let (required_refs, msg, snip_expr) = if position.can_auto_borrow() {
+ (1, if deref_count == 1 { borrow_msg } else { deref_msg }, None)
+ } else if let Position::ImplArg(hir_id) = position {
+ (0, impl_msg, Some(hir_id))
} else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) =
next_adjust.map(|a| &a.kind)
{
if matches!(mutability, AutoBorrowMutability::Mut { .. }) && !position.is_reborrow_stable()
{
- (3, deref_msg)
+ (3, deref_msg, None)
} else {
- (2, deref_msg)
+ (2, deref_msg, None)
}
} else {
- (2, deref_msg)
+ (2, deref_msg, None)
};
if deref_count >= required_refs {
@@ -354,12 +393,17 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
// can't be removed without breaking the code. See earlier comment.
count: deref_count - required_refs,
msg,
+ snip_expr,
}),
StateData { span: expr.span, hir_id: expr.hir_id, position },
));
- } else if position.is_deref_stable() {
+ } else if position.is_deref_stable()
+ // Auto-deref doesn't combine with other adjustments
+ && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
+ && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
+ {
self.state = Some((
- State::Borrow,
+ State::Borrow { mutability },
StateData {
span: expr.span,
hir_id: expr.hir_id,
@@ -395,7 +439,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
data,
));
},
- (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) if state.count != 0 => {
+ (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(_)) if state.count != 0 => {
self.state = Some((
State::DerefedBorrow(DerefedBorrow {
count: state.count - 1,
@@ -404,12 +448,12 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
data,
));
},
- (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) => {
+ (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => {
let position = data.position;
report(cx, expr, State::DerefedBorrow(state), data);
if position.is_deref_stable() {
self.state = Some((
- State::Borrow,
+ State::Borrow { mutability },
StateData {
span: expr.span,
hir_id: expr.hir_id,
@@ -421,7 +465,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
(Some((State::DerefedBorrow(state), data)), RefOp::Deref) => {
let position = data.position;
report(cx, expr, State::DerefedBorrow(state), data);
- if let Position::FieldAccess(name) = position
+ if let Position::FieldAccess{name, ..} = position
&& !ty_contains_field(typeck.expr_ty(sub_expr), name)
{
self.state = Some((
@@ -430,43 +474,28 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
));
} else if position.is_deref_stable() {
self.state = Some((
- State::ExplicitDeref { deref_span_id: None },
+ State::ExplicitDeref { mutability: None },
StateData { span: expr.span, hir_id: expr.hir_id, position },
));
}
},
- (Some((State::Borrow, data)), RefOp::Deref) => {
+ (Some((State::Borrow { mutability }, data)), RefOp::Deref) => {
if typeck.expr_ty(sub_expr).is_ref() {
- self.state = Some((
- State::Reborrow {
- deref_span: expr.span,
- deref_hir_id: expr.hir_id,
- },
- data,
- ));
+ self.state = Some((State::Reborrow { mutability }, data));
} else {
self.state = Some((
State::ExplicitDeref {
- deref_span_id: Some((expr.span, expr.hir_id)),
+ mutability: Some(mutability),
},
data,
));
}
},
- (
- Some((
- State::Reborrow {
- deref_span,
- deref_hir_id,
- },
- data,
- )),
- RefOp::Deref,
- ) => {
+ (Some((State::Reborrow { mutability }, data)), RefOp::Deref) => {
self.state = Some((
State::ExplicitDeref {
- deref_span_id: Some((deref_span, deref_hir_id)),
+ mutability: Some(mutability),
},
data,
));
@@ -485,7 +514,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
}
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
- if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind {
+ 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 {
@@ -521,7 +550,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
spans: vec![pat.span],
app,
replacements: vec![(pat.span, snip.into())],
- hir_id: pat.hir_id
+ hir_id: pat.hir_id,
}),
);
}
@@ -530,6 +559,12 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
}
fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
+ if self.possible_borrowers.last().map_or(false, |&(local_def_id, _)| {
+ local_def_id == cx.tcx.hir().body_owner_def_id(body.id())
+ }) {
+ self.possible_borrowers.pop();
+ }
+
if Some(body.id()) == self.current_body {
for pat in self.ref_locals.drain(..).filter_map(|(_, x)| x) {
let replacements = pat.replacements;
@@ -553,6 +588,8 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
self.current_body = None;
}
}
+
+ extract_msrv_attr!(LateContext);
}
fn try_parse_ref_op<'tcx>(
@@ -561,7 +598,7 @@ fn try_parse_ref_op<'tcx>(
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::MethodCall(_, arg, [], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
ExprKind::Call(
Expr {
kind: ExprKind::Path(path),
@@ -573,7 +610,7 @@ fn try_parse_ref_op<'tcx>(
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)),
+ ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => return Some((RefOp::AddrOf(mutability), sub_expr)),
_ => return None,
};
if tcx.is_diagnostic_item(sym::deref_method, def_id) {
@@ -599,36 +636,46 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
}
/// The position of an expression relative to it's parent.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
enum Position {
MethodReceiver,
/// The method is defined on a reference type. e.g. `impl Foo for &T`
MethodReceiverRefImpl,
Callee,
- FieldAccess(Symbol),
+ ImplArg(HirId),
+ FieldAccess {
+ name: Symbol,
+ of_union: bool,
+ }, // union fields cannot be auto borrowed
Postfix,
Deref,
/// Any other location which will trigger auto-deref to a specific time.
- DerefStable(i8),
+ /// Contains the precedence of the parent expression and whether the target type is sized.
+ DerefStable(i8, bool),
/// Any other location which will trigger auto-reborrowing.
+ /// Contains the precedence of the parent expression.
ReborrowStable(i8),
+ /// Contains the precedence of the parent expression.
Other(i8),
}
impl Position {
fn is_deref_stable(self) -> bool {
- matches!(self, Self::DerefStable(_))
+ matches!(self, Self::DerefStable(..))
}
fn is_reborrow_stable(self) -> bool {
- matches!(self, Self::DerefStable(_) | Self::ReborrowStable(_))
+ matches!(self, Self::DerefStable(..) | Self::ReborrowStable(_))
}
fn can_auto_borrow(self) -> bool {
- matches!(self, Self::MethodReceiver | Self::FieldAccess(_) | Self::Callee)
+ matches!(
+ self,
+ Self::MethodReceiver | Self::FieldAccess { of_union: false, .. } | Self::Callee
+ )
}
fn lint_explicit_deref(self) -> bool {
- matches!(self, Self::Other(_) | Self::DerefStable(_) | Self::ReborrowStable(_))
+ matches!(self, Self::Other(_) | Self::DerefStable(..) | Self::ReborrowStable(_))
}
fn precedence(self) -> i8 {
@@ -636,10 +683,10 @@ impl Position {
Self::MethodReceiver
| Self::MethodReceiverRefImpl
| Self::Callee
- | Self::FieldAccess(_)
+ | Self::FieldAccess { .. }
| Self::Postfix => PREC_POSTFIX,
- Self::Deref => PREC_PREFIX,
- Self::DerefStable(p) | Self::ReborrowStable(p) | Self::Other(p) => p,
+ Self::ImplArg(_) | Self::Deref => PREC_PREFIX,
+ Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p,
}
}
}
@@ -647,8 +694,13 @@ impl Position {
/// Walks up the parent expressions attempting to determine both how stable the auto-deref result
/// is, and which adjustments will be applied to it. Note this will not consider auto-borrow
/// locations as those follow different rules.
-#[allow(clippy::too_many_lines)]
-fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &'tcx [Adjustment<'tcx>]) {
+#[expect(clippy::too_many_lines)]
+fn walk_parents<'tcx>(
+ cx: &LateContext<'tcx>,
+ possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
+ e: &'tcx Expr<'_>,
+ msrv: Option<RustcVersion>,
+) -> (Position, &'tcx [Adjustment<'tcx>]) {
let mut adjustments = [].as_slice();
let mut precedence = 0i8;
let ctxt = e.span.ctxt();
@@ -659,91 +711,93 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
}
match parent {
Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => {
- Some(binding_ty_auto_deref_stability(ty, precedence))
+ Some(binding_ty_auto_deref_stability(cx, ty, precedence, List::empty()))
},
Node::Item(&Item {
kind: ItemKind::Static(..) | ItemKind::Const(..),
- def_id,
+ owner_id,
span,
..
})
| Node::TraitItem(&TraitItem {
kind: TraitItemKind::Const(..),
- def_id,
+ owner_id,
span,
..
})
| Node::ImplItem(&ImplItem {
kind: ImplItemKind::Const(..),
- def_id,
+ owner_id,
span,
..
}) if span.ctxt() == ctxt => {
- let ty = cx.tcx.type_of(def_id);
- Some(if ty.is_ref() {
- Position::DerefStable(precedence)
- } else {
- Position::Other(precedence)
- })
+ let ty = cx.tcx.type_of(owner_id.def_id);
+ Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx))
},
Node::Item(&Item {
kind: ItemKind::Fn(..),
- def_id,
+ owner_id,
span,
..
})
| Node::TraitItem(&TraitItem {
kind: TraitItemKind::Fn(..),
- def_id,
+ owner_id,
span,
..
})
| Node::ImplItem(&ImplItem {
kind: ImplItemKind::Fn(..),
- def_id,
+ owner_id,
span,
..
}) if span.ctxt() == ctxt => {
- let output = cx.tcx.fn_sig(def_id.to_def_id()).skip_binder().output();
- Some(if !output.is_ref() {
- Position::Other(precedence)
- } else if output.has_placeholders() || output.has_opaque_types() {
- Position::ReborrowStable(precedence)
- } else {
- Position::DerefStable(precedence)
- })
+ let output = cx
+ .tcx
+ .erase_late_bound_regions(cx.tcx.fn_sig(owner_id.to_def_id()).output());
+ Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx))
+ },
+
+ Node::ExprField(field) if field.span.ctxt() == ctxt => match get_parent_expr_for_hir(cx, field.hir_id) {
+ Some(Expr {
+ hir_id,
+ kind: ExprKind::Struct(path, ..),
+ ..
+ }) => variant_of_res(cx, cx.qpath_res(path, *hir_id))
+ .and_then(|variant| variant.fields.iter().find(|f| f.name == field.ident.name))
+ .map(|field_def| {
+ ty_auto_deref_stability(cx, cx.tcx.type_of(field_def.did), precedence).position_for_arg()
+ }),
+ _ => None,
},
Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
ExprKind::Ret(_) => {
let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap());
Some(
- if let Node::Expr(Expr {
- kind: ExprKind::Closure(&Closure { fn_decl, .. }),
- ..
- }) = cx.tcx.hir().get(owner_id)
+ if let Node::Expr(
+ closure_expr @ Expr {
+ kind: ExprKind::Closure(closure),
+ ..
+ },
+ ) = cx.tcx.hir().get(owner_id)
{
- match fn_decl.output {
- FnRetTy::Return(ty) => binding_ty_auto_deref_stability(ty, precedence),
- FnRetTy::DefaultReturn(_) => Position::Other(precedence),
- }
+ closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence)
} else {
let output = cx
.tcx
- .fn_sig(cx.tcx.hir().local_def_id(owner_id))
- .skip_binder()
- .output();
- if !output.is_ref() {
- Position::Other(precedence)
- } else if output.has_placeholders() || output.has_opaque_types() {
- Position::ReborrowStable(precedence)
- } else {
- Position::DerefStable(precedence)
- }
+ .erase_late_bound_regions(cx.tcx.fn_sig(cx.tcx.hir().local_def_id(owner_id)).output());
+ ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)
},
)
},
+ ExprKind::Closure(closure) => Some(closure_result_position(
+ cx,
+ closure,
+ cx.typeck_results().expr_ty(parent),
+ precedence,
+ )),
ExprKind::Call(func, _) if func.hir_id == child_id => {
(child_id == e.hir_id).then_some(Position::Callee)
},
@@ -751,66 +805,93 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
.iter()
.position(|arg| arg.hir_id == child_id)
.zip(expr_sig(cx, func))
- .and_then(|(i, sig)| sig.input_with_hir(i))
- .map(|(hir_ty, ty)| match hir_ty {
- // Type inference for closures can depend on how they're called. Only go by the explicit
- // types here.
- Some(ty) => binding_ty_auto_deref_stability(ty, precedence),
- None => param_auto_deref_stability(ty.skip_binder(), precedence),
+ .and_then(|(i, sig)| {
+ sig.input_with_hir(i).map(|(hir_ty, ty)| match hir_ty {
+ // Type inference for closures can depend on how they're called. Only go by the explicit
+ // types here.
+ Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()),
+ None => {
+ if let ty::Param(param_ty) = ty.skip_binder().kind() {
+ needless_borrow_impl_arg_position(
+ cx,
+ possible_borrowers,
+ parent,
+ i,
+ *param_ty,
+ e,
+ precedence,
+ msrv,
+ )
+ } else {
+ ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
+ .position_for_arg()
+ }
+ },
+ })
}),
- ExprKind::MethodCall(_, args, _) => {
+ ExprKind::MethodCall(_, receiver, args, _) => {
let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
- args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
- if i == 0 {
- // Check for calls to trait methods where the trait is implemented on a reference.
- // Two cases need to be handled:
- // * `self` methods on `&T` will never have auto-borrow
- // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
- // priority.
- if e.hir_id != child_id {
- Position::ReborrowStable(precedence)
- } else if let Some(trait_id) = cx.tcx.trait_of_item(id)
- && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
- && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
- && let subs = match cx
- .typeck_results()
- .node_substs_opt(parent.hir_id)
- .and_then(|subs| subs.get(1..))
- {
- Some(subs) => cx.tcx.mk_substs(subs.iter().copied()),
- None => cx.tcx.mk_substs([].iter()),
- } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
- // Trait methods taking `&self`
- sub_ty
- } else {
- // Trait methods taking `self`
- arg_ty
- } && impl_ty.is_ref()
- && cx.tcx.infer_ctxt().enter(|infcx|
- infcx
- .type_implements_trait(trait_id, impl_ty, subs, cx.param_env)
- .must_apply_modulo_regions()
- )
+ if receiver.hir_id == child_id {
+ // Check for calls to trait methods where the trait is implemented on a reference.
+ // Two cases need to be handled:
+ // * `self` methods on `&T` will never have auto-borrow
+ // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
+ // priority.
+ if e.hir_id != child_id {
+ return Some(Position::ReborrowStable(precedence))
+ } else if let Some(trait_id) = cx.tcx.trait_of_item(id)
+ && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
+ && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
+ && let subs = match cx
+ .typeck_results()
+ .node_substs_opt(parent.hir_id)
+ .and_then(|subs| subs.get(1..))
{
- Position::MethodReceiverRefImpl
+ Some(subs) => cx.tcx.mk_substs(subs.iter().copied()),
+ None => cx.tcx.mk_substs(std::iter::empty::<ty::subst::GenericArg<'_>>()),
+ } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
+ // Trait methods taking `&self`
+ sub_ty
} else {
- Position::MethodReceiver
- }
+ // Trait methods taking `self`
+ arg_ty
+ } && impl_ty.is_ref()
+ && let infcx = cx.tcx.infer_ctxt().build()
+ && infcx
+ .type_implements_trait(trait_id, impl_ty, subs, cx.param_env)
+ .must_apply_modulo_regions()
+ {
+ return Some(Position::MethodReceiverRefImpl)
+ }
+ return Some(Position::MethodReceiver);
+ }
+ args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
+ let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
+ if let ty::Param(param_ty) = ty.kind() {
+ needless_borrow_impl_arg_position(
+ cx,
+ possible_borrowers,
+ parent,
+ i + 1,
+ *param_ty,
+ e,
+ precedence,
+ msrv,
+ )
} else {
- param_auto_deref_stability(cx.tcx.fn_sig(id).skip_binder().inputs()[i], precedence)
+ ty_auto_deref_stability(
+ cx,
+ cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
+ precedence,
+ )
+ .position_for_arg()
}
})
},
- ExprKind::Struct(path, fields, _) => {
- let variant = variant_of_res(cx, cx.qpath_res(path, parent.hir_id));
- fields
- .iter()
- .find(|f| f.expr.hir_id == child_id)
- .zip(variant)
- .and_then(|(field, variant)| variant.fields.iter().find(|f| f.name == field.ident.name))
- .map(|field| param_auto_deref_stability(cx.tcx.type_of(field.did), precedence))
- },
- ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)),
+ ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess {
+ name: name.name,
+ of_union: is_union(cx.typeck_results(), child),
+ }),
ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
ExprKind::Match(child, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
| ExprKind::Index(child, _)
@@ -831,6 +912,33 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
(position, adjustments)
}
+fn is_union<'tcx>(typeck: &'tcx TypeckResults<'_>, path_expr: &'tcx Expr<'_>) -> bool {
+ typeck
+ .expr_ty_adjusted(path_expr)
+ .ty_adt_def()
+ .map_or(false, rustc_middle::ty::AdtDef::is_union)
+}
+
+fn closure_result_position<'tcx>(
+ cx: &LateContext<'tcx>,
+ closure: &'tcx Closure<'_>,
+ ty: Ty<'tcx>,
+ precedence: i8,
+) -> Position {
+ match closure.fn_decl.output {
+ FnRetTy::Return(hir_ty) => {
+ if let Some(sig) = ty_sig(cx, ty)
+ && let Some(output) = sig.output()
+ {
+ binding_ty_auto_deref_stability(cx, hir_ty, precedence, output.bound_vars())
+ } else {
+ Position::Other(precedence)
+ }
+ },
+ FnRetTy::DefaultReturn(_) => Position::Other(precedence),
+ }
+}
+
// Checks the stability of auto-deref when assigned to a binding with the given explicit type.
//
// e.g.
@@ -840,7 +948,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
//
// Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
// switching to auto-dereferencing.
-fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position {
+fn binding_ty_auto_deref_stability<'tcx>(
+ cx: &LateContext<'tcx>,
+ ty: &'tcx hir::Ty<'_>,
+ precedence: i8,
+ binder_args: &'tcx List<BoundVariableKind>,
+) -> Position {
let TyKind::Rptr(_, ty) = &ty.kind else {
return Position::Other(precedence);
};
@@ -870,21 +983,33 @@ fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position
{
Position::ReborrowStable(precedence)
} else {
- Position::DerefStable(precedence)
+ Position::DerefStable(
+ precedence,
+ cx.tcx
+ .erase_late_bound_regions(Binder::bind_with_vars(
+ cx.typeck_results().node_type(ty.ty.hir_id),
+ binder_args,
+ ))
+ .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
+ )
}
},
- TyKind::Slice(_)
- | TyKind::Array(..)
- | TyKind::BareFn(_)
- | TyKind::Never
+ TyKind::Slice(_) => Position::DerefStable(precedence, false),
+ TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) => Position::DerefStable(precedence, true),
+ TyKind::Never
| TyKind::Tup(_)
- | TyKind::Ptr(_)
- | TyKind::TraitObject(..)
- | TyKind::Path(_) => Position::DerefStable(precedence),
- TyKind::OpaqueDef(..)
- | TyKind::Infer
- | TyKind::Typeof(..)
- | TyKind::Err => Position::ReborrowStable(precedence),
+ | TyKind::Path(_) => Position::DerefStable(
+ precedence,
+ cx.tcx
+ .erase_late_bound_regions(Binder::bind_with_vars(
+ cx.typeck_results().node_type(ty.ty.hir_id),
+ binder_args,
+ ))
+ .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
+ ),
+ TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
+ Position::ReborrowStable(precedence)
+ },
};
}
}
@@ -920,10 +1045,272 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
v.0
}
+// Checks whether:
+// * child is an expression of the form `&e` in an argument position requiring an `impl Trait`
+// * `e`'s type implements `Trait` and is copyable
+// If the conditions are met, returns `Some(Position::ImplArg(..))`; otherwise, returns `None`.
+// The "is copyable" condition is to avoid the case where removing the `&` means `e` would have to
+// be moved, but it cannot be.
+#[expect(clippy::too_many_arguments)]
+fn needless_borrow_impl_arg_position<'tcx>(
+ cx: &LateContext<'tcx>,
+ possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
+ parent: &Expr<'tcx>,
+ arg_index: usize,
+ param_ty: ParamTy,
+ mut expr: &Expr<'tcx>,
+ precedence: i8,
+ msrv: Option<RustcVersion>,
+) -> Position {
+ let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
+ let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
+
+ let Some(callee_def_id) = fn_def_id(cx, parent) else { return Position::Other(precedence) };
+ let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+ let substs_with_expr_ty = cx
+ .typeck_results()
+ .node_substs(if let ExprKind::Call(callee, _) = parent.kind {
+ callee.hir_id
+ } else {
+ parent.hir_id
+ });
+
+ let predicates = cx.tcx.param_env(callee_def_id).caller_bounds();
+ let projection_predicates = predicates
+ .iter()
+ .filter_map(|predicate| {
+ if let PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
+ Some(projection_predicate)
+ } else {
+ None
+ }
+ })
+ .collect::<Vec<_>>();
+
+ let mut trait_with_ref_mut_self_method = false;
+
+ // If no traits were found, or only the `Destruct`, `Sized`, or `Any` traits were found, return.
+ if predicates
+ .iter()
+ .filter_map(|predicate| {
+ if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder()
+ && trait_predicate.trait_ref.self_ty() == param_ty.to_ty(cx.tcx)
+ {
+ Some(trait_predicate.trait_ref.def_id)
+ } else {
+ None
+ }
+ })
+ .inspect(|trait_def_id| {
+ trait_with_ref_mut_self_method |= has_ref_mut_self_method(cx, *trait_def_id);
+ })
+ .all(|trait_def_id| {
+ Some(trait_def_id) == destruct_trait_def_id
+ || Some(trait_def_id) == sized_trait_def_id
+ || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id)
+ })
+ {
+ return Position::Other(precedence);
+ }
+
+ // `substs_with_referent_ty` can be constructed outside of `check_referent` because the same
+ // elements are modified each time `check_referent` is called.
+ let mut substs_with_referent_ty = substs_with_expr_ty.to_vec();
+
+ let mut check_reference_and_referent = |reference, referent| {
+ let referent_ty = cx.typeck_results().expr_ty(referent);
+
+ if !is_copy(cx, referent_ty)
+ && (referent_ty.has_significant_drop(cx.tcx, cx.param_env)
+ || !referent_used_exactly_once(cx, possible_borrowers, reference))
+ {
+ return false;
+ }
+
+ // https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321
+ if trait_with_ref_mut_self_method && !matches!(referent_ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
+ return false;
+ }
+
+ if !replace_types(
+ cx,
+ param_ty,
+ referent_ty,
+ fn_sig,
+ arg_index,
+ &projection_predicates,
+ &mut substs_with_referent_ty,
+ ) {
+ return false;
+ }
+
+ predicates.iter().all(|predicate| {
+ if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder()
+ && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id)
+ && let ty::Param(param_ty) = trait_predicate.self_ty().kind()
+ && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack()
+ && ty.is_array()
+ && !meets_msrv(msrv, msrvs::ARRAY_INTO_ITERATOR)
+ {
+ return false;
+ }
+
+ let predicate = EarlyBinder(predicate).subst(cx.tcx, &substs_with_referent_ty);
+ let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate);
+ let infcx = cx.tcx.infer_ctxt().build();
+ infcx.predicate_must_hold_modulo_regions(&obligation)
+ })
+ };
+
+ let mut needless_borrow = false;
+ while let ExprKind::AddrOf(_, _, referent) = expr.kind {
+ if !check_reference_and_referent(expr, referent) {
+ break;
+ }
+ expr = referent;
+ needless_borrow = true;
+ }
+
+ if needless_borrow {
+ Position::ImplArg(expr.hir_id)
+ } else {
+ Position::Other(precedence)
+ }
+}
+
+fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
+ cx.tcx
+ .associated_items(trait_def_id)
+ .in_definition_order()
+ .any(|assoc_item| {
+ if assoc_item.fn_has_self_parameter {
+ let self_ty = cx.tcx.fn_sig(assoc_item.def_id).skip_binder().inputs()[0];
+ matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Mut))
+ } else {
+ false
+ }
+ })
+}
+
+fn referent_used_exactly_once<'tcx>(
+ cx: &LateContext<'tcx>,
+ possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
+ reference: &Expr<'tcx>,
+) -> bool {
+ let mir = enclosing_mir(cx.tcx, reference.hir_id);
+ if let Some(local) = expr_local(cx.tcx, reference)
+ && let [location] = *local_assignments(mir, local).as_slice()
+ && let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index)
+ && let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
+ && !place.has_deref()
+ {
+ let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id);
+ if possible_borrowers
+ .last()
+ .map_or(true, |&(local_def_id, _)| local_def_id != body_owner_local_def_id)
+ {
+ possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
+ }
+ let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
+ // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
+ // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
+ // itself. See the comment in that method for an explanation as to why.
+ possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
+ && used_exactly_once(mir, place.local).unwrap_or(false)
+ } else {
+ false
+ }
+}
+
+// Iteratively replaces `param_ty` with `new_ty` in `substs`, and similarly for each resulting
+// projected type that is a type parameter. Returns `false` if replacing the types would have an
+// effect on the function signature beyond substituting `new_ty` for `param_ty`.
+// See: https://github.com/rust-lang/rust-clippy/pull/9136#discussion_r927212757
+fn replace_types<'tcx>(
+ cx: &LateContext<'tcx>,
+ param_ty: ParamTy,
+ new_ty: Ty<'tcx>,
+ fn_sig: FnSig<'tcx>,
+ arg_index: usize,
+ projection_predicates: &[ProjectionPredicate<'tcx>],
+ substs: &mut [ty::GenericArg<'tcx>],
+) -> bool {
+ let mut replaced = BitSet::new_empty(substs.len());
+
+ let mut deque = VecDeque::with_capacity(substs.len());
+ deque.push_back((param_ty, new_ty));
+
+ while let Some((param_ty, new_ty)) = deque.pop_front() {
+ // If `replaced.is_empty()`, then `param_ty` and `new_ty` are those initially passed in.
+ if !fn_sig
+ .inputs_and_output
+ .iter()
+ .enumerate()
+ .all(|(i, ty)| (replaced.is_empty() && i == arg_index) || !ty.contains(param_ty.to_ty(cx.tcx)))
+ {
+ return false;
+ }
+
+ substs[param_ty.index as usize] = ty::GenericArg::from(new_ty);
+
+ // The `replaced.insert(...)` check provides some protection against infinite loops.
+ if replaced.insert(param_ty.index) {
+ for projection_predicate in projection_predicates {
+ if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx)
+ && let Some(term_ty) = projection_predicate.term.ty()
+ && let ty::Param(term_param_ty) = term_ty.kind()
+ {
+ let item_def_id = projection_predicate.projection_ty.item_def_id;
+ let assoc_item = cx.tcx.associated_item(item_def_id);
+ let projection = cx.tcx
+ .mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, &[]));
+
+ if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection)
+ && substs[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty)
+ {
+ deque.push_back((*term_param_ty, projected_ty));
+ }
+ }
+ }
+ }
+ }
+
+ true
+}
+
+struct TyPosition<'tcx> {
+ position: Position,
+ ty: Option<Ty<'tcx>>,
+}
+impl From<Position> for TyPosition<'_> {
+ fn from(position: Position) -> Self {
+ Self { position, ty: None }
+ }
+}
+impl<'tcx> TyPosition<'tcx> {
+ fn new_deref_stable_for_result(precedence: i8, ty: Ty<'tcx>) -> Self {
+ Self {
+ position: Position::ReborrowStable(precedence),
+ ty: Some(ty),
+ }
+ }
+ fn position_for_result(self, cx: &LateContext<'tcx>) -> Position {
+ match (self.position, self.ty) {
+ (Position::ReborrowStable(precedence), Some(ty)) => {
+ Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env))
+ },
+ (position, _) => position,
+ }
+ }
+ fn position_for_arg(self) -> Position {
+ self.position
+ }
+}
+
// Checks whether a type is stable when switching to auto dereferencing,
-fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position {
+fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> TyPosition<'tcx> {
let ty::Ref(_, mut ty, _) = *ty.kind() else {
- return Position::Other(precedence);
+ return Position::Other(precedence).into();
};
loop {
@@ -932,35 +1319,38 @@ fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position {
ty = ref_ty;
continue;
},
- ty::Infer(_)
- | ty::Error(_)
- | ty::Param(_)
- | ty::Bound(..)
- | ty::Opaque(..)
- | ty::Placeholder(_)
- | ty::Dynamic(..) => Position::ReborrowStable(precedence),
- ty::Adt(..) if ty.has_placeholders() || ty.has_param_types_or_consts() => {
- Position::ReborrowStable(precedence)
+ ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
+ ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Opaque(..) | ty::Placeholder(_) | ty::Dynamic(..) => {
+ Position::ReborrowStable(precedence).into()
},
- ty::Adt(..)
- | ty::Bool
+ ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
+ Position::ReborrowStable(precedence).into()
+ },
+ ty::Adt(_, substs) if substs.has_non_region_param() => {
+ TyPosition::new_deref_stable_for_result(precedence, ty)
+ },
+ ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
- | ty::Float(_)
- | ty::Foreign(_)
- | ty::Str
| ty::Array(..)
- | ty::Slice(..)
+ | ty::Float(_)
| ty::RawPtr(..)
+ | ty::FnPtr(_) => Position::DerefStable(precedence, true).into(),
+ ty::Str | ty::Slice(..) => Position::DerefStable(precedence, false).into(),
+ ty::Adt(..)
+ | ty::Foreign(_)
| ty::FnDef(..)
- | ty::FnPtr(_)
- | ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
+ | ty::Closure(..)
| ty::Never
| ty::Tuple(_)
- | ty::Projection(_) => Position::DerefStable(precedence),
+ | ty::Projection(_) => Position::DerefStable(
+ precedence,
+ ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
+ )
+ .into(),
};
}
}
@@ -1006,7 +1396,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
};
let expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX {
- format!("({})", expr_str)
+ format!("({expr_str})")
} else {
expr_str.into_owned()
};
@@ -1020,54 +1410,85 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
Mutability::Mut => "explicit `deref_mut` method call",
},
"try this",
- format!("{}{}{}", addr_of_str, deref_str, expr_str),
+ format!("{addr_of_str}{deref_str}{expr_str}"),
app,
);
},
State::DerefedBorrow(state) => {
let mut app = Applicability::MachineApplicable;
- let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
+ let snip_expr = state.snip_expr.map_or(expr, |hir_id| cx.tcx.hir().expect_expr(hir_id));
+ let (snip, snip_is_macro) = snippet_with_context(cx, snip_expr.span, data.span.ctxt(), "..", &mut app);
span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, state.msg, |diag| {
let calls_field = matches!(expr.kind, ExprKind::Field(..)) && matches!(data.position, Position::Callee);
let sugg = if !snip_is_macro
&& !has_enclosing_paren(&snip)
&& (expr.precedence().order() < data.position.precedence() || calls_field)
{
- format!("({})", snip)
+ format!("({snip})")
} else {
snip.into()
};
diag.span_suggestion(data.span, "change this to", sugg, app);
});
},
- State::ExplicitDeref { deref_span_id } => {
- let (span, hir_id, precedence) = if let Some((span, hir_id)) = deref_span_id
+ State::ExplicitDeref { mutability } => {
+ if matches!(
+ expr.kind,
+ ExprKind::Block(..)
+ | ExprKind::ConstBlock(_)
+ | ExprKind::If(..)
+ | ExprKind::Loop(..)
+ | ExprKind::Match(..)
+ ) && matches!(data.position, Position::DerefStable(_, true))
+ {
+ // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
+ return;
+ }
+
+ let (prefix, precedence) = if let Some(mutability) = mutability
&& !cx.typeck_results().expr_ty(expr).is_ref()
{
- (span, hir_id, PREC_PREFIX)
+ let prefix = match mutability {
+ Mutability::Not => "&",
+ Mutability::Mut => "&mut ",
+ };
+ (prefix, 0)
} else {
- (data.span, data.hir_id, data.position.precedence())
+ ("", data.position.precedence())
};
span_lint_hir_and_then(
cx,
EXPLICIT_AUTO_DEREF,
- hir_id,
- span,
+ data.hir_id,
+ data.span,
"deref which would be done by auto-deref",
|diag| {
let mut app = Applicability::MachineApplicable;
- let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, span.ctxt(), "..", &mut app);
+ let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
let sugg =
if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) {
- format!("({})", snip)
+ format!("{prefix}({snip})")
} else {
- snip.into()
+ format!("{prefix}{snip}")
};
- diag.span_suggestion(span, "try this", sugg, app);
+ diag.span_suggestion(data.span, "try this", sugg, app);
},
);
},
State::ExplicitDerefField { .. } => {
+ if matches!(
+ expr.kind,
+ ExprKind::Block(..)
+ | ExprKind::ConstBlock(_)
+ | ExprKind::If(..)
+ | ExprKind::Loop(..)
+ | ExprKind::Match(..)
+ ) && matches!(data.position, Position::DerefStable(_, true))
+ {
+ // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
+ return;
+ }
+
span_lint_hir_and_then(
cx,
EXPLICIT_AUTO_DEREF,
@@ -1081,12 +1502,12 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
},
);
},
- State::Borrow | State::Reborrow { .. } => (),
+ State::Borrow { .. } | State::Reborrow { .. } => (),
}
}
-impl Dereferencing {
- fn check_local_usage<'tcx>(&mut self, cx: &LateContext<'tcx>, e: &Expr<'tcx>, local: HirId) {
+impl<'tcx> Dereferencing<'tcx> {
+ fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &Expr<'tcx>, local: HirId) {
if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
if let Some(pat) = outer_pat {
// Check for auto-deref
@@ -1127,14 +1548,14 @@ impl Dereferencing {
} 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)));
+ pat.replacements.push((e.span, format!("&{snip}")));
}
},
_ if !e.span.from_expansion() => {
// 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)));
+ 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
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index 4d7f4076d..ae8f6b794 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -1,5 +1,6 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{is_default_equivalent, peel_blocks};
+use rustc_errors::Applicability;
use rustc_hir::{
def::{DefKind, Res},
Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
@@ -40,7 +41,7 @@ declare_clippy_lint! {
///
/// ### Known problems
/// Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925)
- /// in generic types and the user defined `impl` maybe is more generalized or
+ /// in generic types and the user defined `impl` may be more generalized or
/// specialized than what derive will produce. This lint can't detect the manual `impl`
/// has exactly equal bounds, and therefore this lint is disabled for types with
/// generic parameters.
@@ -69,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
self_ty,
..
}) = item.kind;
- if !cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
+ if !cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived);
if !item.span.from_expansion();
if let Some(def_id) = trait_ref.trait_def_id();
if cx.tcx.is_diagnostic_item(sym::Default, def_id);
@@ -77,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
if let ImplItemKind::Fn(_, b) = &impl_item.kind;
if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
- if let Some(adt_def) = cx.tcx.type_of(item.def_id).ty_adt_def();
+ if let Some(adt_def) = cx.tcx.type_of(item.owner_id).ty_adt_def();
if let attrs = cx.tcx.hir().attrs(item.hir_id());
if !attrs.iter().any(|attr| attr.doc_str().is_some());
if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
@@ -100,15 +101,28 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)),
_ => false,
};
+
if should_emit {
- let path_string = cx.tcx.def_path_str(adt_def.did());
- span_lint_and_help(
+ let struct_span = cx.tcx.def_span(adt_def.did());
+ span_lint_and_then(
cx,
DERIVABLE_IMPLS,
item.span,
"this `impl` can be derived",
- None,
- &format!("try annotating `{}` with `#[derive(Default)]`", path_string),
+ |diag| {
+ diag.span_suggestion_hidden(
+ item.span,
+ "remove the manual implementation...",
+ String::new(),
+ Applicability::MachineApplicable
+ );
+ diag.span_suggestion(
+ struct_span.shrink_to_lo(),
+ "...and instead derive it",
+ "#[derive(Default)]\n".to_string(),
+ Applicability::MachineApplicable
+ );
+ }
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index a982990e4..102a02138 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -15,7 +15,7 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::traits::Reveal;
use rustc_middle::ty::{
self, Binder, BoundConstness, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, TraitRef,
- Ty, TyCtxt, Visibility,
+ Ty, TyCtxt,
};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
@@ -191,7 +191,7 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "1.63.0"]
pub DERIVE_PARTIAL_EQ_WITHOUT_EQ,
- style,
+ nursery,
"deriving `PartialEq` on a type that can implement `Eq`, without implementing `Eq`"
}
@@ -210,8 +210,8 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
..
}) = item.kind
{
- let ty = cx.tcx.type_of(item.def_id);
- let is_automatically_derived = cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
+ let ty = cx.tcx.type_of(item.owner_id);
+ let is_automatically_derived = cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived);
check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
@@ -339,10 +339,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h
Some(id) if trait_ref.trait_def_id() == Some(id) => id,
_ => return,
};
- let copy_id = match cx.tcx.lang_items().copy_trait() {
- Some(id) => id,
- None => return,
- };
+ let Some(copy_id) = cx.tcx.lang_items().copy_trait() else { return };
let (ty_adt, ty_subs) = match *ty.kind() {
// Unions can't derive clone.
ty::Adt(adt, subs) if !adt.is_union() => (adt, subs),
@@ -425,7 +422,7 @@ struct UnsafeVisitor<'a, 'tcx> {
impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
type NestedFilter = nested_filter::All;
- fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, span: Span, id: HirId) {
+ fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: HirId) {
if self.has_unsafe {
return;
}
@@ -438,7 +435,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
}
}
- walk_fn(self, kind, decl, body_id, span, id);
+ walk_fn(self, kind, decl, body_id, id);
}
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
@@ -464,7 +461,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
if_chain! {
if let ty::Adt(adt, substs) = ty.kind();
- if cx.tcx.visibility(adt.did()) == Visibility::Public;
+ if cx.tcx.visibility(adt.did()).is_public();
if let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq);
if let Some(def_id) = trait_ref.trait_def_id();
if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id);
@@ -516,7 +513,10 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain(
params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
tcx.mk_predicate(Binder::dummy(PredicateKind::Trait(TraitPredicate {
- trait_ref: TraitRef::new(eq_trait_id, tcx.mk_substs([tcx.mk_param_from_def(param)].into_iter())),
+ trait_ref: TraitRef::new(
+ eq_trait_id,
+ tcx.mk_substs(std::iter::once(tcx.mk_param_from_def(param))),
+ ),
constness: BoundConstness::NotConst,
polarity: ImplPolarity::Positive,
})))
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
new file mode 100644
index 000000000..5ab7144e2
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -0,0 +1,151 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::macro_backtrace;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::def::{Namespace, Res};
+use rustc_hir::def_id::DefIdMap;
+use rustc_hir::{Expr, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{ExpnId, Span};
+
+use crate::utils::conf;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Denies the configured macros in clippy.toml
+ ///
+ /// Note: Even though this lint is warn-by-default, it will only trigger if
+ /// macros are defined in the clippy.toml file.
+ ///
+ /// ### Why is this bad?
+ /// Some macros are undesirable in certain contexts, and it's beneficial to
+ /// lint for them as needed.
+ ///
+ /// ### Example
+ /// An example clippy.toml configuration:
+ /// ```toml
+ /// # clippy.toml
+ /// disallowed-macros = [
+ /// # Can use a string as the path of the disallowed macro.
+ /// "std::print",
+ /// # Can also use an inline table with a `path` key.
+ /// { path = "std::println" },
+ /// # When using an inline table, can add a `reason` for why the macro
+ /// # is disallowed.
+ /// { path = "serde::Serialize", reason = "no serializing" },
+ /// ]
+ /// ```
+ /// ```
+ /// use serde::Serialize;
+ ///
+ /// // Example code where clippy issues a warning
+ /// println!("warns");
+ ///
+ /// // The diagnostic will contain the message "no serializing"
+ /// #[derive(Serialize)]
+ /// struct Data {
+ /// name: String,
+ /// value: usize,
+ /// }
+ /// ```
+ #[clippy::version = "1.65.0"]
+ pub DISALLOWED_MACROS,
+ style,
+ "use of a disallowed macro"
+}
+
+pub struct DisallowedMacros {
+ conf_disallowed: Vec<conf::DisallowedPath>,
+ disallowed: DefIdMap<usize>,
+ seen: FxHashSet<ExpnId>,
+}
+
+impl DisallowedMacros {
+ pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
+ Self {
+ conf_disallowed,
+ disallowed: DefIdMap::default(),
+ seen: FxHashSet::default(),
+ }
+ }
+
+ fn check(&mut self, cx: &LateContext<'_>, span: Span) {
+ if self.conf_disallowed.is_empty() {
+ return;
+ }
+
+ for mac in macro_backtrace(span) {
+ if !self.seen.insert(mac.expn) {
+ return;
+ }
+
+ if let Some(&index) = self.disallowed.get(&mac.def_id) {
+ let conf = &self.conf_disallowed[index];
+
+ span_lint_and_then(
+ cx,
+ DISALLOWED_MACROS,
+ mac.span,
+ &format!("use of a disallowed macro `{}`", conf.path()),
+ |diag| {
+ if let Some(reason) = conf.reason() {
+ diag.note(&format!("{reason} (from clippy.toml)"));
+ }
+ },
+ );
+ }
+ }
+ }
+}
+
+impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]);
+
+impl LateLintPass<'_> for DisallowedMacros {
+ fn check_crate(&mut self, cx: &LateContext<'_>) {
+ for (index, conf) in self.conf_disallowed.iter().enumerate() {
+ let segs: Vec<_> = conf.path().split("::").collect();
+ if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::MacroNS)) {
+ self.disallowed.insert(id, index);
+ }
+ }
+ }
+
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ self.check(cx, expr.span);
+ }
+
+ fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
+ self.check(cx, stmt.span);
+ }
+
+ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &Ty<'_>) {
+ self.check(cx, ty.span);
+ }
+
+ fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) {
+ self.check(cx, pat.span);
+ }
+
+ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+ self.check(cx, item.span);
+ self.check(cx, item.vis_span);
+ }
+
+ fn check_foreign_item(&mut self, cx: &LateContext<'_>, item: &ForeignItem<'_>) {
+ self.check(cx, item.span);
+ self.check(cx, item.vis_span);
+ }
+
+ fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &ImplItem<'_>) {
+ self.check(cx, item.span);
+ self.check(cx, item.vis_span);
+ }
+
+ fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
+ self.check(cx, item.span);
+ }
+
+ fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, _: HirId) {
+ self.check(cx, path.span);
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index 53973ab79..6ac85606d 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -1,7 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
-use rustc_hir::{def::Res, def_id::DefIdMap, Expr, ExprKind};
+use rustc_hir::def::{Namespace, Res};
+use rustc_hir::def_id::DefIdMap;
+use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -58,12 +60,12 @@ declare_clippy_lint! {
#[derive(Clone, Debug)]
pub struct DisallowedMethods {
- conf_disallowed: Vec<conf::DisallowedMethod>,
+ conf_disallowed: Vec<conf::DisallowedPath>,
disallowed: DefIdMap<usize>,
}
impl DisallowedMethods {
- pub fn new(conf_disallowed: Vec<conf::DisallowedMethod>) -> Self {
+ pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
Self {
conf_disallowed,
disallowed: DefIdMap::default(),
@@ -77,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for (index, conf) in self.conf_disallowed.iter().enumerate() {
let segs: Vec<_> = conf.path().split("::").collect();
- if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs) {
+ if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::ValueNS)) {
self.disallowed.insert(id, index);
}
}
@@ -92,9 +94,8 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
} else {
path_def_id(cx, expr)
};
- let def_id = match uncalled_path.or_else(|| fn_def_id(cx, expr)) {
- Some(def_id) => def_id,
- None => return,
+ let Some(def_id) = uncalled_path.or_else(|| fn_def_id(cx, expr)) else {
+ return
};
let conf = match self.disallowed.get(&def_id) {
Some(&index) => &self.conf_disallowed[index],
@@ -102,11 +103,8 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
};
let msg = format!("use of a disallowed method `{}`", conf.path());
span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| {
- if let conf::DisallowedMethod::WithReason {
- reason: Some(reason), ..
- } = conf
- {
- diag.note(&format!("{} (from clippy.toml)", reason));
+ if let Some(reason) = conf.reason() {
+ diag.note(&format!("{reason} (from clippy.toml)"));
}
});
}
diff --git a/src/tools/clippy/clippy_lints/src/blacklisted_name.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
index 1600fb25d..6e6615f08 100644
--- a/src/tools/clippy/clippy_lints/src/blacklisted_name.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
@@ -6,7 +6,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! {
/// ### What it does
- /// Checks for usage of blacklisted names for variables, such
+ /// Checks for usage of disallowed names for variables, such
/// as `foo`.
///
/// ### Why is this bad?
@@ -18,21 +18,21 @@ declare_clippy_lint! {
/// let foo = 3.14;
/// ```
#[clippy::version = "pre 1.29.0"]
- pub BLACKLISTED_NAME,
+ pub DISALLOWED_NAMES,
style,
- "usage of a blacklisted/placeholder name"
+ "usage of a disallowed/placeholder name"
}
#[derive(Clone, Debug)]
-pub struct BlacklistedName {
- blacklist: FxHashSet<String>,
+pub struct DisallowedNames {
+ disallow: FxHashSet<String>,
test_modules_deep: u32,
}
-impl BlacklistedName {
- pub fn new(blacklist: FxHashSet<String>) -> Self {
+impl DisallowedNames {
+ pub fn new(disallow: FxHashSet<String>) -> Self {
Self {
- blacklist,
+ disallow,
test_modules_deep: 0,
}
}
@@ -42,9 +42,9 @@ impl BlacklistedName {
}
}
-impl_lint_pass!(BlacklistedName => [BLACKLISTED_NAME]);
+impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]);
-impl<'tcx> LateLintPass<'tcx> for BlacklistedName {
+impl<'tcx> LateLintPass<'tcx> for DisallowedNames {
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
if is_test_module_or_function(cx.tcx, item) {
self.test_modules_deep = self.test_modules_deep.saturating_add(1);
@@ -58,12 +58,12 @@ impl<'tcx> LateLintPass<'tcx> for BlacklistedName {
}
if let PatKind::Binding(.., ident, _) = pat.kind {
- if self.blacklist.contains(&ident.name.to_string()) {
+ if self.disallow.contains(&ident.name.to_string()) {
span_lint(
cx,
- BLACKLISTED_NAME,
+ DISALLOWED_NAMES,
ident.span,
- &format!("use of a blacklisted/placeholder name `{}`", ident.name),
+ &format!("use of a disallowed/placeholder name `{}`", ident.name),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
index 0c27c3f92..084190f00 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
@@ -99,8 +99,7 @@ impl EarlyLintPass for DisallowedScriptIdents {
DISALLOWED_SCRIPT_IDENTS,
span,
&format!(
- "identifier `{}` has a Unicode script that is not allowed by configuration: {}",
- symbol_str,
+ "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}",
script.full_name()
),
);
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
index 14f89edce..c7131fc16 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -1,9 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_then;
use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::{
- def::Res, def_id::DefId, Item, ItemKind, PolyTraitRef, PrimTy, TraitBoundModifier, Ty, TyKind, UseKind,
-};
+use rustc_hir::def::{Namespace, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
@@ -52,13 +52,13 @@ declare_clippy_lint! {
}
#[derive(Clone, Debug)]
pub struct DisallowedTypes {
- conf_disallowed: Vec<conf::DisallowedType>,
+ conf_disallowed: Vec<conf::DisallowedPath>,
def_ids: FxHashMap<DefId, Option<String>>,
prim_tys: FxHashMap<PrimTy, Option<String>>,
}
impl DisallowedTypes {
- pub fn new(conf_disallowed: Vec<conf::DisallowedType>) -> Self {
+ pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
Self {
conf_disallowed,
def_ids: FxHashMap::default(),
@@ -88,15 +88,9 @@ impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for conf in &self.conf_disallowed {
- let (path, reason) = match conf {
- conf::DisallowedType::Simple(path) => (path, None),
- conf::DisallowedType::WithReason { path, reason } => (
- path,
- reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)),
- ),
- };
- let segs: Vec<_> = path.split("::").collect();
- match clippy_utils::def_path_res(cx, &segs) {
+ let segs: Vec<_> = conf.path().split("::").collect();
+ let reason = conf.reason().map(|reason| format!("{reason} (from clippy.toml)"));
+ match clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
Res::Def(_, id) => {
self.def_ids.insert(id, reason);
},
@@ -120,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
}
}
- fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>, _: TraitBoundModifier) {
+ fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) {
self.check_res_emit(cx, &poly.trait_ref.path.res, poly.trait_ref.path.span);
}
}
@@ -130,7 +124,7 @@ fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) {
cx,
DISALLOWED_TYPES,
span,
- &format!("`{}` is not allowed according to config", name),
+ &format!("`{name}` is not allowed according to config"),
|diag| {
if let Some(reason) = reason {
diag.note(reason);
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index da111e737..24d6a6951 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -198,6 +198,29 @@ declare_clippy_lint! {
"presence of `fn main() {` in code examples"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks)
+ /// outside of code blocks
+ /// ### Why is this bad?
+ /// It is likely a typo when defining an intra-doc link
+ ///
+ /// ### Example
+ /// ```rust
+ /// /// See also: ['foo']
+ /// fn bar() {}
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// /// See also: [`foo`]
+ /// fn bar() {}
+ /// ```
+ #[clippy::version = "1.63.0"]
+ pub DOC_LINK_WITH_QUOTES,
+ pedantic,
+ "possible typo for an intra-doc link"
+}
+
#[expect(clippy::module_name_repetitions)]
#[derive(Clone)]
pub struct DocMarkdown {
@@ -214,9 +237,14 @@ impl DocMarkdown {
}
}
-impl_lint_pass!(DocMarkdown =>
- [DOC_MARKDOWN, MISSING_SAFETY_DOC, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, NEEDLESS_DOCTEST_MAIN]
-);
+impl_lint_pass!(DocMarkdown => [
+ DOC_LINK_WITH_QUOTES,
+ 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>) {
@@ -229,15 +257,23 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
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)) {
+ if !(is_entrypoint_fn(cx, item.owner_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),
+ typeck_results: cx.tcx.typeck(item.owner_id.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);
+ fpu.visit_expr(body.value);
+ lint_for_missing_headers(
+ cx,
+ item.owner_id.def_id,
+ item.span,
+ sig,
+ headers,
+ Some(body_id),
+ fpu.panic_span,
+ );
}
},
hir::ItemKind::Impl(impl_) => {
@@ -268,7 +304,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
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);
+ lint_for_missing_headers(cx, item.owner_id.def_id, item.span, sig, headers, None, None);
}
}
}
@@ -283,11 +319,19 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
let body = cx.tcx.hir().body(body_id);
let mut fpu = FindPanicUnwrap {
cx,
- typeck_results: cx.tcx.typeck(item.def_id),
+ typeck_results: cx.tcx.typeck(item.owner_id.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);
+ fpu.visit_expr(body.value);
+ lint_for_missing_headers(
+ cx,
+ item.owner_id.def_id,
+ item.span,
+ sig,
+ headers,
+ Some(body_id),
+ fpu.panic_span,
+ );
}
}
}
@@ -301,7 +345,7 @@ fn lint_for_missing_headers<'tcx>(
body_id: Option<hir::BodyId>,
panic_span: Option<Span>,
) {
- if !cx.access_levels.is_exported(def_id) {
+ if !cx.effective_visibilities.is_exported(def_id) {
return; // Private functions do not require doc comments
}
@@ -348,7 +392,7 @@ fn lint_for_missing_headers<'tcx>(
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);
+ 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();
@@ -416,7 +460,7 @@ pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span:
(no_stars, sizes)
}
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Default)]
struct DocHeaders {
safety: bool,
errors: bool,
@@ -460,11 +504,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
}
if doc.is_empty() {
- return DocHeaders {
- safety: false,
- errors: false,
- panics: false,
- };
+ return DocHeaders::default();
}
let mut cb = fake_broken_link_callback;
@@ -505,11 +545,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
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 headers = DocHeaders::default();
let mut in_code = false;
let mut in_link = None;
let mut in_heading = false;
@@ -596,6 +632,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
check_code(cx, &text, edition, span);
}
} else {
+ check_link_quotes(cx, in_link.is_some(), trimmed_text, span, &range, begin, text.len());
// 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));
@@ -606,6 +643,27 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
headers
}
+fn check_link_quotes(
+ cx: &LateContext<'_>,
+ in_link: bool,
+ trimmed_text: &str,
+ span: Span,
+ range: &Range<usize>,
+ begin: usize,
+ text_len: usize,
+) {
+ if in_link && trimmed_text.starts_with('\'') && trimmed_text.ends_with('\'') {
+ // fix the span to only point at the text within the link
+ let lo = span.lo() + BytePos::from_usize(range.start - begin);
+ span_lint(
+ cx,
+ DOC_LINK_WITH_QUOTES,
+ span.with_lo(lo).with_hi(lo + BytePos::from_usize(text_len)),
+ "possible intra-doc link using quotes instead of backticks",
+ );
+ }
+}
+
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,
@@ -790,7 +848,7 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
diag.span_suggestion_with_style(
span,
"try",
- format!("`{}`", snippet),
+ format!("`{snippet}`"),
applicability,
// always show the suggestion in a separate line, since the
// inline presentation adds another pair of backticks
@@ -828,7 +886,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
// 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();
+ 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)
{
diff --git a/src/tools/clippy/clippy_lints/src/doc_link_with_quotes.rs b/src/tools/clippy/clippy_lints/src/doc_link_with_quotes.rs
deleted file mode 100644
index cb07f57e8..000000000
--- a/src/tools/clippy/clippy_lints/src/doc_link_with_quotes.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-use clippy_utils::diagnostics::span_lint;
-use itertools::Itertools;
-use rustc_ast::{AttrKind, Attribute};
-use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
- /// ### What it does
- /// Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks)
- /// outside of code blocks
- /// ### Why is this bad?
- /// It is likely a typo when defining an intra-doc link
- ///
- /// ### Example
- /// ```rust
- /// /// See also: ['foo']
- /// fn bar() {}
- /// ```
- /// Use instead:
- /// ```rust
- /// /// See also: [`foo`]
- /// fn bar() {}
- /// ```
- #[clippy::version = "1.60.0"]
- pub DOC_LINK_WITH_QUOTES,
- pedantic,
- "possible typo for an intra-doc link"
-}
-declare_lint_pass!(DocLinkWithQuotes => [DOC_LINK_WITH_QUOTES]);
-
-impl EarlyLintPass for DocLinkWithQuotes {
- fn check_attribute(&mut self, ctx: &EarlyContext<'_>, attr: &Attribute) {
- if let AttrKind::DocComment(_, symbol) = attr.kind {
- if contains_quote_link(symbol.as_str()) {
- span_lint(
- ctx,
- DOC_LINK_WITH_QUOTES,
- attr.span,
- "possible intra-doc link using quotes instead of backticks",
- );
- }
- }
- }
-}
-
-fn contains_quote_link(s: &str) -> bool {
- let mut in_backticks = false;
- let mut found_opening = false;
-
- for c in s.chars().tuple_windows::<(char, char)>() {
- match c {
- ('`', _) => in_backticks = !in_backticks,
- ('[', '\'') if !in_backticks => found_opening = true,
- ('\'', ']') if !in_backticks && found_opening => return true,
- _ => {},
- }
- }
-
- false
-}
diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs
index a33ef5ce6..0f1d70186 100644
--- a/src/tools/clippy/clippy_lints/src/double_parens.rs
+++ b/src/tools/clippy/clippy_lints/src/double_parens.rs
@@ -61,9 +61,8 @@ impl EarlyLintPass for DoubleParens {
}
}
},
- ExprKind::MethodCall(_, ref params, _) => {
- if params.len() == 2 {
- let param = &params[1];
+ ExprKind::MethodCall(_, _, ref params, _) => {
+ if let [ref param] = params[..] {
if let ExprKind::Paren(_) = param.kind {
span_lint(cx, DOUBLE_PARENS, param.span, msg);
}
diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
index b35f0b8ca..4721a7b37 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -1,7 +1,8 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note};
+use clippy_utils::get_parent_node;
use clippy_utils::is_must_use_func_call;
use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item};
-use rustc_hir::{Expr, ExprKind, LangItem};
+use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
@@ -202,11 +203,13 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
&& let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id)
{
let arg_ty = cx.typeck_results().expr_ty(arg);
+ let is_copy = is_copy(cx, arg_ty);
+ let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
let (lint, msg) = match fn_name {
sym::mem_drop if arg_ty.is_ref() => (DROP_REF, DROP_REF_SUMMARY),
sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY),
- sym::mem_drop if is_copy(cx, arg_ty) => (DROP_COPY, DROP_COPY_SUMMARY),
- sym::mem_forget if is_copy(cx, arg_ty) => (FORGET_COPY, FORGET_COPY_SUMMARY),
+ sym::mem_drop if is_copy && !drop_is_single_call_in_arm => (DROP_COPY, DROP_COPY_SUMMARY),
+ sym::mem_forget if is_copy => (FORGET_COPY, FORGET_COPY_SUMMARY),
sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => {
span_lint_and_help(
cx,
@@ -221,7 +224,9 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
sym::mem_drop
if !(arg_ty.needs_drop(cx.tcx, cx.param_env)
|| is_must_use_func_call(cx, arg)
- || is_must_use_ty(cx, arg_ty)) =>
+ || is_must_use_ty(cx, arg_ty)
+ || drop_is_single_call_in_arm
+ ) =>
{
(DROP_NON_DROP, DROP_NON_DROP_SUMMARY)
},
@@ -236,8 +241,23 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
expr.span,
msg,
Some(arg.span),
- &format!("argument has type `{}`", arg_ty),
+ &format!("argument has type `{arg_ty}`"),
);
}
}
}
+
+// dropping returned value of a function like in the following snippet is considered idiomatic, see
+// #9482 for examples match <var> {
+// <pat> => drop(fn_with_side_effect_and_returning_some_value()),
+// ..
+// }
+fn is_single_call_in_arm<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'_>, drop_expr: &'tcx Expr<'_>) -> bool {
+ if matches!(arg.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)) {
+ let parent_node = get_parent_node(cx.tcx, drop_expr.hir_id);
+ if let Some(Node::Arm(Arm { body, .. })) = &parent_node {
+ return body.hir_id == drop_expr.hir_id;
+ }
+ }
+ false
+}
diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
index e1eb3b632..7ff7068f0 100644
--- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
+++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
@@ -39,7 +39,7 @@ declare_clippy_lint! {
/// // a.rs
/// use crate::b;
/// ```
- #[clippy::version = "1.62.0"]
+ #[clippy::version = "1.63.0"]
pub DUPLICATE_MOD,
suspicious,
"file loaded as module multiple times"
diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs
index bbebc0244..0570c2a10 100644
--- a/src/tools/clippy/clippy_lints/src/empty_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs
@@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for EmptyEnum {
}
if let ItemKind::Enum(..) = item.kind {
- let ty = cx.tcx.type_of(item.def_id);
+ let ty = cx.tcx.type_of(item.owner_id);
let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
if adt.variants().is_empty() {
span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index 4e3ae4c96..b44e62435 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -65,28 +65,24 @@ declare_lint_pass!(HashMapPass => [MAP_ENTRY]);
impl<'tcx> LateLintPass<'tcx> for HashMapPass {
#[expect(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 Some(higher::If { cond: cond_expr, then: then_expr, r#else: else_expr }) = higher::If::hir(expr) else {
+ return
};
- let (map_ty, contains_expr) = match try_parse_contains(cx, cond_expr) {
- Some(x) => x,
- None => return,
+ let Some((map_ty, contains_expr)) = try_parse_contains(cx, cond_expr) else {
+ return
};
- let then_search = match find_insert_calls(cx, &contains_expr, then_expr) {
- Some(x) => x,
- None => return,
+ let Some(then_search) = find_insert_calls(cx, &contains_expr, then_expr) else {
+ 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,
+ let Some(else_search) = find_insert_calls(cx, &contains_expr, else_expr) else {
+ return;
};
if then_search.edits.is_empty() && else_search.edits.is_empty() {
@@ -113,13 +109,8 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
),
};
format!(
- "if let {}::{} = {}.entry({}) {} else {}",
+ "if let {}::{entry_kind} = {map_str}.entry({key_str}) {then_str} else {else_str}",
map_ty.entry_path(),
- entry_kind,
- map_str,
- key_str,
- then_str,
- else_str,
)
} else {
// if .. { insert } else { insert }
@@ -137,16 +128,11 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
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,
+ "match {map_str}.entry({key_str}) {{\n{indent_str} {entry}::{then_entry} => {}\n\
+ {indent_str} {entry}::{else_entry} => {}\n{indent_str}}}",
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 {
@@ -163,20 +149,16 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
then_search.snippet_occupied(cx, then_expr.span, &mut app)
};
format!(
- "if let {}::{} = {}.entry({}) {}",
+ "if let {}::{entry_kind} = {map_str}.entry({key_str}) {body_str}",
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)
+ format!("{map_str}.entry({key_str}).or_insert_with(|| {value_str});")
} else {
- format!("{}.entry({}).or_insert({});", map_str, key_str, value_str)
+ format!("{map_str}.entry({key_str}).or_insert({value_str});")
}
} else {
// TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here.
@@ -186,7 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
} 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)
+ format!("{map_str}.entry({key_str}).or_insert_with(|| {block_str});")
} else {
// TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here.
// This would need to be a different lint.
@@ -245,8 +227,8 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio
match expr.kind {
ExprKind::MethodCall(
_,
+ map,
[
- map,
Expr {
kind: ExprKind::AddrOf(_, _, key),
span: key_span,
@@ -280,7 +262,7 @@ struct InsertExpr<'tcx> {
value: &'tcx Expr<'tcx>,
}
fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
- if let ExprKind::MethodCall(_, [map, key, value], _) = expr.kind {
+ 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 })
diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs
index cd36f9fcd..223545fa7 100644
--- a/src/tools/clippy/clippy_lints/src/enum_variants.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs
@@ -202,12 +202,11 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n
cx,
ENUM_VARIANT_NAMES,
span,
- &format!("all variants have the same {}fix: `{}`", what, value),
+ &format!("all variants have the same {what}fix: `{value}`"),
None,
&format!(
- "remove the {}fixes and use full paths to \
- the variants instead of glob imports",
- what
+ "remove the {what}fixes and use full paths to \
+ the variants instead of glob imports"
),
);
}
@@ -266,7 +265,7 @@ impl LateLintPass<'_> for EnumVariantNames {
}
// The `module_name_repetitions` lint should only trigger if the item has the module in its
// name. Having the same name is accepted.
- if cx.tcx.visibility(item.def_id).is_public() && item_camel.len() > mod_camel.len() {
+ if cx.tcx.visibility(item.owner_id).is_public() && 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();
@@ -297,7 +296,7 @@ impl LateLintPass<'_> for EnumVariantNames {
}
}
if let ItemKind::Enum(ref def, _) = item.kind {
- if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.def_id)) {
+ if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id)) {
check_variant(cx, self.threshold, def, item_name, item.span);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index fdfb821ac..b40cb7cdd 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -51,7 +51,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
false
},
PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
- PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.is_some() && array_rec(a),
+ PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x),
PatKind::Path(_) | PatKind::Lit(_) => true,
}
@@ -91,9 +91,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
"this pattern matching can be expressed using equality",
"try",
format!(
- "{} == {}",
+ "{} == {pat_str}",
snippet_with_context(cx, let_expr.init.span, expr.span.ctxt(), "..", &mut applicability).0,
- pat_str,
),
applicability,
);
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 1ac7bfba0..7f1a4c4be 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_hir;
-use clippy_utils::ty::contains_ty;
use rustc_hir::intravisit;
use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind};
+use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::FakeReadCause;
@@ -11,7 +11,6 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::symbol::kw;
use rustc_target::spec::abi::Abi;
-use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
#[derive(Copy, Clone)]
pub struct BoxedLocal {
@@ -30,18 +29,12 @@ declare_clippy_lint! {
///
/// ### Example
/// ```rust
- /// # fn foo(bar: usize) {}
- /// let x = Box::new(1);
- /// foo(*x);
- /// println!("{}", *x);
+ /// fn foo(x: Box<u32>) {}
/// ```
///
/// Use instead:
/// ```rust
- /// # fn foo(bar: usize) {}
- /// let x = 1;
- /// foo(x);
- /// println!("{}", x);
+ /// fn foo(x: u32) {}
/// ```
#[clippy::version = "pre 1.29.0"]
pub BOXED_LOCAL,
@@ -78,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
}
}
- let parent_id = cx.tcx.hir().get_parent_item(hir_id);
+ let parent_id = cx.tcx.hir().get_parent_item(hir_id).def_id;
let parent_node = cx.tcx.hir().find_by_def_id(parent_id);
let mut trait_self_ty = None;
@@ -95,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
// be sure we have `self` parameter in this function
if trait_item.kind == (AssocItemKind::Fn { has_self: true }) {
trait_self_ty = Some(
- TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id())
+ TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id())
.self_ty()
.skip_binder(),
);
@@ -113,9 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
};
let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
- cx.tcx.infer_ctxt().enter(|infcx| {
- ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
- });
+ let infcx = cx.tcx.infer_ctxt().build();
+ ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
for node in v.set {
span_lint_hir(
@@ -172,7 +164,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
// skip if there is a `self` parameter binding to a type
// that contains `Self` (i.e.: `self: Box<Self>`), see #4804
if let Some(trait_self_ty) = self.trait_self_ty {
- if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(cmt.place.ty(), trait_self_ty) {
+ if map.name(cmt.hir_id) == kw::SelfLower && cmt.place.ty().contains(trait_self_ty) {
return;
}
}
@@ -184,7 +176,13 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
}
}
- fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+ fn fake_read(
+ &mut self,
+ _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
+ _: FakeReadCause,
+ _: HirId,
+ ) {
+ }
}
impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 4f9ff97f1..7b9786d7e 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -1,7 +1,7 @@
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::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::usage::local_used_after_expr;
use clippy_utils::{higher, is_adjusted, path_to_local, path_to_local_id};
use if_chain::if_chain;
@@ -11,8 +11,7 @@ use rustc_hir::{Closure, Expr, ExprKind, Param, PatKind, Unsafety};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, ClosureKind, Ty, TypeVisitable};
+use rustc_middle::ty::{self, Ty, TypeVisitable};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::sym;
@@ -83,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
};
if body.value.span.from_expansion() {
if body.params.is_empty() {
- if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, &body.value) {
+ if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, body.value) {
// replace `|| vec![]` with `Vec::new`
span_lint_and_sugg(
cx,
@@ -103,10 +102,10 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
let closure_ty = cx.typeck_results().expr_ty(expr);
if_chain!(
- if !is_adjusted(cx, &body.value);
+ if !is_adjusted(cx, body.value);
if let ExprKind::Call(callee, args) = body.value.kind;
if let ExprKind::Path(_) = callee.kind;
- if check_inputs(cx, body.params, args);
+ if check_inputs(cx, body.params, None, 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));
@@ -123,15 +122,12 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
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 path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr));
-
- then {
+ if let Some(fn_mut_id) = cx.tcx.lang_items().fn_mut_trait()
+ && implements_trait(cx, callee_ty.peel_refs(), fn_mut_id, &[])
+ && path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr))
+ {
// Mutable closure is used after current expr; we cannot consume it.
- snippet = format!("&mut {}", snippet);
- }
+ snippet = format!("&mut {snippet}");
}
diag.span_suggestion(
expr.span,
@@ -145,9 +141,9 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
);
if_chain!(
- if !is_adjusted(cx, &body.value);
- if let ExprKind::MethodCall(path, args, _) = body.value.kind;
- if check_inputs(cx, body.params, args);
+ if !is_adjusted(cx, body.value);
+ if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind;
+ if check_inputs(cx, body.params, Some(receiver), 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.bound_type_of(method_def_id).subst(cx.tcx, substs);
@@ -158,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
diag.span_suggestion(
expr.span,
"replace the closure with the method itself",
- format!("{}::{}", name, path.ident.name),
+ format!("{name}::{}", path.ident.name),
Applicability::MachineApplicable,
);
})
@@ -167,12 +163,17 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
}
}
-fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_>]) -> bool {
- if params.len() != call_args.len() {
+fn check_inputs(
+ cx: &LateContext<'_>,
+ params: &[Param<'_>],
+ receiver: Option<&Expr<'_>>,
+ call_args: &[Expr<'_>],
+) -> bool {
+ if receiver.map_or(params.len() != call_args.len(), |_| params.len() != call_args.len() + 1) {
return false;
}
let binding_modes = cx.typeck_results().pat_binding_modes();
- std::iter::zip(params, call_args).all(|(param, arg)| {
+ let check_inputs = |param: &Param<'_>, arg| {
match param.pat.kind {
PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
_ => return false,
@@ -200,7 +201,8 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_
},
_ => false,
}
- })
+ };
+ std::iter::zip(params, receiver.into_iter().chain(call_args.iter())).all(|(param, arg)| check_inputs(param, arg))
}
fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
@@ -211,9 +213,8 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tc
if !closure_ty.has_late_bound_regions() {
return true;
}
- let substs = match closure_ty.kind() {
- ty::Closure(_, substs) => substs,
- _ => return false,
+ let ty::Closure(_, substs) = closure_ty.kind() else {
+ 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)
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index 173d41b4b..1fece5d1c 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -73,7 +73,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
if_chain! {
if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind;
- if cx.access_levels.is_exported(item.def_id);
+ if cx.effective_visibilities.is_exported(item.owner_id.def_id);
let attrs = cx.tcx.hir().attrs(item.hir_id());
if !attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
then {
@@ -97,7 +97,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
item.span,
msg,
|diag| {
- let sugg = format!("#[non_exhaustive]\n{}", indent);
+ let sugg = format!("#[non_exhaustive]\n{indent}");
diag.span_suggestion(suggestion_span,
"try adding #[non_exhaustive]",
sugg,
diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs
index cbf52d193..407dd1b39 100644
--- a/src/tools/clippy/clippy_lints/src/exit.rs
+++ b/src/tools/clippy/clippy_lints/src/exit.rs
@@ -33,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for Exit {
if let ExprKind::Path(ref path) = path_expr.kind;
if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id();
if match_def_path(cx, def_id, &paths::EXIT);
- let parent = cx.tcx.hir().get_parent_item(e.hir_id);
+ let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id;
if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find_by_def_id(parent);
// If the next item up is a function we check if it is an entry point
// and only then emit a linter warning
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index 5bf4313b4..c0ea6f338 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -45,10 +45,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
// match call to unwrap
- if let ExprKind::MethodCall(unwrap_fun, [write_call], _) = expr.kind;
+ if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind;
if unwrap_fun.ident.name == sym::unwrap;
// match call to write_fmt
- if let ExprKind::MethodCall(write_fun, [write_recv, write_arg], _) = look_in_block(cx, &write_call.kind);
+ if let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind);
if write_fun.ident.name == sym!(write_fmt);
// match calls to std::io::stdout() / std::io::stderr ()
if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() {
@@ -80,12 +80,12 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
// used.
let (used, sugg_mac) = if let Some(macro_name) = calling_macro {
(
- format!("{}!({}(), ...)", macro_name, dest_name),
+ format!("{macro_name}!({dest_name}(), ...)"),
macro_name.replace("write", "print"),
)
} else {
(
- format!("{}().write_fmt(...)", dest_name),
+ format!("{dest_name}().write_fmt(...)"),
"print".into(),
)
};
@@ -100,9 +100,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
cx,
EXPLICIT_WRITE,
expr.span,
- &format!("use of `{}.unwrap()`", used),
+ &format!("use of `{used}.unwrap()`"),
"try this",
- format!("{}{}!({})", prefix, sugg_mac, inputs_snippet),
+ format!("{prefix}{sugg_mac}!({inputs_snippet})"),
applicability,
)
}
@@ -128,7 +128,7 @@ fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>)
if let Some(Node::Pat(res_pat)) = cx.tcx.hir().find(expr_res);
// Find id of the local we found in the block
- if let PatKind::Binding(BindingAnnotation::Unannotated, local_hir_id, _ident, None) = local.pat.kind;
+ if let PatKind::Binding(BindingAnnotation::NONE, local_hir_id, _ident, None) = local.pat.kind;
// If those two are the same hir id
if res_pat.hir_id == local_hir_id;
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index b88e53aec..0a633f242 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom {
// check for `impl From<???> for ..`
if_chain! {
if let hir::ItemKind::Impl(impl_) = &item.kind;
- if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.def_id);
+ if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
if cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.def_id);
then {
lint_impl_body(cx, item.span, impl_.items);
@@ -84,7 +84,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
// 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();
+ let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
{
@@ -107,10 +107,10 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
let body = cx.tcx.hir().body(body_id);
let mut fpu = FindPanicUnwrap {
lcx: cx,
- typeck_results: cx.tcx.typeck(impl_item.id.def_id),
+ typeck_results: cx.tcx.typeck(impl_item.id.owner_id.def_id),
result: Vec::new(),
};
- fpu.visit_expr(&body.value);
+ fpu.visit_expr(body.value);
// if we've found one, lint
if !fpu.result.is_empty() {
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index f2e079809..6fee7fb30 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -173,9 +173,9 @@ impl FloatFormat {
T: fmt::UpperExp + fmt::LowerExp + fmt::Display,
{
match self {
- Self::LowerExp => format!("{:e}", f),
- Self::UpperExp => format!("{:E}", f),
- Self::Normal => format!("{}", f),
+ Self::LowerExp => format!("{f:e}"),
+ Self::UpperExp => format!("{f:E}"),
+ Self::Normal => format!("{f}"),
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index df9b41d2c..0ed301964 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -142,8 +142,7 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su
if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node;
then {
let op = format!(
- "{}{}{}",
- suggestion,
+ "{suggestion}{}{}",
// Check for float literals without numbers following the decimal
// separator such as `2.` and adds a trailing zero
if sym.as_str().ends_with('.') {
@@ -164,15 +163,15 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su
suggestion.maybe_par()
}
-fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
- if let Some(method) = get_specialized_log_method(cx, &args[1]) {
+fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
+ if let Some(method) = get_specialized_log_method(cx, &args[0]) {
span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
expr.span,
"logarithm for bases 2, 10 and e can be computed more accurately",
"consider using",
- format!("{}.{}()", Sugg::hir(cx, &args[0], ".."), method),
+ format!("{}.{method}()", Sugg::hir(cx, receiver, "..").maybe_par()),
Applicability::MachineApplicable,
);
}
@@ -180,14 +179,14 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
// TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and
// suggest usage of `(x + (y - 1)).ln_1p()` instead
-fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
+fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
if let ExprKind::Binary(
Spanned {
node: BinOpKind::Add, ..
},
lhs,
rhs,
- ) = &args[0].kind
+ ) = receiver.kind
{
let recv = match (
constant(cx, cx.typeck_results(), lhs),
@@ -235,41 +234,41 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
}
}
-fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
+fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
// Check receiver
- if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
- let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
- "exp"
+ if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) {
+ if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
+ Some("exp")
} else if F32(2.0) == value || F64(2.0) == value {
- "exp2"
+ Some("exp2")
} else {
- return;
- };
-
- span_lint_and_sugg(
- cx,
- SUBOPTIMAL_FLOPS,
- expr.span,
- "exponent for bases 2 and e can be computed more accurately",
- "consider using",
- format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method),
- Applicability::MachineApplicable,
- );
+ None
+ } {
+ span_lint_and_sugg(
+ cx,
+ SUBOPTIMAL_FLOPS,
+ expr.span,
+ "exponent for bases 2 and e can be computed more accurately",
+ "consider using",
+ format!("{}.{method}()", prepare_receiver_sugg(cx, &args[0])),
+ Applicability::MachineApplicable,
+ );
+ }
}
// Check argument
- if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
+ if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
(
SUBOPTIMAL_FLOPS,
"square-root of a number can be computed more efficiently and accurately",
- format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..")),
+ format!("{}.sqrt()", Sugg::hir(cx, receiver, "..").maybe_par()),
)
} else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value {
(
IMPRECISE_FLOPS,
"cube-root of a number can be computed more accurately",
- format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..")),
+ format!("{}.cbrt()", Sugg::hir(cx, receiver, "..").maybe_par()),
)
} else if let Some(exponent) = get_integer_from_float_constant(&value) {
(
@@ -277,7 +276,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
"exponentiation with integer powers can be computed more efficiently",
format!(
"{}.powi({})",
- Sugg::hir(cx, &args[0], ".."),
+ Sugg::hir(cx, receiver, "..").maybe_par(),
numeric_literal::format(&exponent.to_string(), None, false)
),
)
@@ -297,13 +296,14 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
}
}
-fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
- if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
+fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
+ if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
if value == Int(2) {
if let Some(parent) = get_parent_expr(cx, expr) {
if let Some(grandparent) = get_parent_expr(cx, parent) {
- if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = grandparent.kind {
- if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
+ if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind
+ {
+ if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() {
return;
}
}
@@ -311,7 +311,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
if let ExprKind::Binary(
Spanned {
- node: BinOpKind::Add, ..
+ node: op @ (BinOpKind::Add | BinOpKind::Sub),
+ ..
},
lhs,
rhs,
@@ -319,6 +320,16 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
{
let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs };
+ // Negate expr if original code has subtraction and expr is on the right side
+ let maybe_neg_sugg = |expr, hir_id| {
+ let sugg = Sugg::hir(cx, expr, "..");
+ if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id {
+ format!("-{sugg}")
+ } else {
+ sugg.to_string()
+ }
+ };
+
span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
@@ -327,9 +338,9 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
"consider using",
format!(
"{}.mul_add({}, {})",
- Sugg::hir(cx, &args[0], ".."),
- Sugg::hir(cx, &args[0], ".."),
- Sugg::hir(cx, other_addend, ".."),
+ Sugg::hir(cx, receiver, "..").maybe_par(),
+ maybe_neg_sugg(receiver, expr.hir_id),
+ maybe_neg_sugg(other_addend, other_addend.hir_id),
),
Applicability::MachineApplicable,
);
@@ -339,14 +350,14 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
}
}
-fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
+fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
if let ExprKind::Binary(
Spanned {
node: BinOpKind::Add, ..
},
add_lhs,
add_rhs,
- ) = args[0].kind
+ ) = receiver.kind
{
// check if expression of the form x * x + y * y
if_chain! {
@@ -363,12 +374,12 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
if_chain! {
if let ExprKind::MethodCall(
PathSegment { ident: lmethod_name, .. },
- [largs_0, largs_1, ..],
+ largs_0, [largs_1, ..],
_
) = &add_lhs.kind;
if let ExprKind::MethodCall(
PathSegment { ident: rmethod_name, .. },
- [rargs_0, rargs_1, ..],
+ rargs_0, [rargs_1, ..],
_
) = &add_rhs.kind;
if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
@@ -384,8 +395,8 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
None
}
-fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
- if let Some(message) = detect_hypot(cx, args) {
+fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
+ if let Some(message) = detect_hypot(cx, receiver) {
span_lint_and_sugg(
cx,
IMPRECISE_FLOPS,
@@ -406,7 +417,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
if cx.typeck_results().expr_ty(lhs).is_floating_point();
if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs);
if F32(1.0) == value || F64(1.0) == value;
- if let ExprKind::MethodCall(path, [self_arg, ..], _) = &lhs.kind;
+ if let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind;
if cx.typeck_results().expr_ty(self_arg).is_floating_point();
if path.ident.name.as_str() == "exp";
then {
@@ -418,7 +429,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
"consider using",
format!(
"{}.exp_m1()",
- Sugg::hir(cx, self_arg, "..")
+ Sugg::hir(cx, self_arg, "..").maybe_par()
),
Applicability::MachineApplicable,
);
@@ -443,24 +454,42 @@ fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&'
fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
if let ExprKind::Binary(
Spanned {
- node: BinOpKind::Add, ..
+ node: op @ (BinOpKind::Add | BinOpKind::Sub),
+ ..
},
lhs,
rhs,
) = &expr.kind
{
if let Some(parent) = get_parent_expr(cx, expr) {
- if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = parent.kind {
- if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
+ if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind {
+ if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() {
return;
}
}
}
+ let maybe_neg_sugg = |expr| {
+ let sugg = Sugg::hir(cx, expr, "..");
+ if let BinOpKind::Sub = op {
+ format!("-{sugg}")
+ } else {
+ sugg.to_string()
+ }
+ };
+
let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) {
- (inner_lhs, inner_rhs, rhs)
+ (
+ inner_lhs,
+ Sugg::hir(cx, inner_rhs, "..").to_string(),
+ maybe_neg_sugg(rhs),
+ )
} else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) {
- (inner_lhs, inner_rhs, lhs)
+ (
+ inner_lhs,
+ maybe_neg_sugg(inner_rhs),
+ Sugg::hir(cx, lhs, "..").to_string(),
+ )
} else {
return;
};
@@ -471,12 +500,7 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
expr.span,
"multiply and add expressions can be calculated more efficiently and accurately",
"consider using",
- format!(
- "{}.mul_add({}, {})",
- prepare_receiver_sugg(cx, recv),
- Sugg::hir(cx, arg1, ".."),
- Sugg::hir(cx, arg2, ".."),
- ),
+ format!("{}.mul_add({arg1}, {arg2})", prepare_receiver_sugg(cx, recv)),
Applicability::MachineApplicable,
);
}
@@ -550,11 +574,11 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
then {
let positive_abs_sugg = (
"manual implementation of `abs` method",
- format!("{}.abs()", Sugg::hir(cx, body, "..")),
+ format!("{}.abs()", Sugg::hir(cx, body, "..").maybe_par()),
);
let negative_abs_sugg = (
"manual implementation of negation of `abs` method",
- format!("-{}.abs()", Sugg::hir(cx, body, "..")),
+ format!("-{}.abs()", Sugg::hir(cx, body, "..").maybe_par()),
);
let sugg = if is_testing_positive(cx, cond, body) {
if if_expr_positive {
@@ -586,14 +610,14 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
if_chain! {
- if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, args_a, _) = expr_a.kind;
- if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, args_b, _) = expr_b.kind;
+ if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind;
+ if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind;
then {
return method_name_a.as_str() == method_name_b.as_str() &&
args_a.len() == args_b.len() &&
(
["ln", "log2", "log10"].contains(&method_name_a.as_str()) ||
- method_name_a.as_str() == "log" && args_a.len() == 2 && eq_expr_value(cx, &args_a[1], &args_b[1])
+ method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])
);
}
}
@@ -612,8 +636,8 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
rhs,
) = &expr.kind;
if are_same_base_logs(cx, lhs, rhs);
- if let ExprKind::MethodCall(_, [largs_self, ..], _) = &lhs.kind;
- if let ExprKind::MethodCall(_, [rargs_self, ..], _) = &rhs.kind;
+ if let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind;
+ if let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind;
then {
span_lint_and_sugg(
cx,
@@ -621,7 +645,7 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
expr.span,
"log base can be expressed more clearly",
"consider using",
- format!("{}.log({})", Sugg::hir(cx, largs_self, ".."), Sugg::hir(cx, rargs_self, ".."),),
+ format!("{}.log({})", Sugg::hir(cx, largs_self, "..").maybe_par(), Sugg::hir(cx, rargs_self, ".."),),
Applicability::MachineApplicable,
);
}
@@ -651,7 +675,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) &&
(F32(180_f32) == lvalue || F64(180_f64) == lvalue)
{
- let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
+ let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
if_chain! {
if let ExprKind::Lit(ref literal) = mul_lhs.kind;
if let ast::LitKind::Float(ref value, float_type) = literal.node;
@@ -677,7 +701,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
(F32(180_f32) == rvalue || F64(180_f64) == rvalue) &&
(F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
{
- let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
+ let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
if_chain! {
if let ExprKind::Lit(ref literal) = mul_lhs.kind;
if let ast::LitKind::Float(ref value, float_type) = literal.node;
@@ -711,16 +735,16 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
return;
}
- if let ExprKind::MethodCall(path, args, _) = &expr.kind {
- let recv_ty = cx.typeck_results().expr_ty(&args[0]);
+ if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind {
+ let recv_ty = cx.typeck_results().expr_ty(receiver);
if recv_ty.is_floating_point() {
match path.ident.name.as_str() {
- "ln" => check_ln1p(cx, expr, args),
- "log" => check_log_base(cx, expr, args),
- "powf" => check_powf(cx, expr, args),
- "powi" => check_powi(cx, expr, args),
- "sqrt" => check_hypot(cx, expr, args),
+ "ln" => check_ln1p(cx, expr, receiver),
+ "log" => check_log_base(cx, expr, receiver, args),
+ "powf" => check_powf(cx, expr, receiver, args),
+ "powi" => check_powi(cx, expr, receiver, args),
+ "sqrt" => check_hypot(cx, expr, receiver),
_ => {},
}
}
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index 925a8cb8d..bc0c68f53 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn};
-use clippy_utils::source::{snippet_opt, snippet_with_applicability};
+use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use if_chain::if_chain;
use rustc_errors::Applicability;
@@ -56,29 +56,27 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
};
let mut applicability = Applicability::MachineApplicable;
- if format_args.value_args.is_empty() {
- match *format_args.format_string_parts {
+ if format_args.args.is_empty() {
+ match *format_args.format_string.parts {
[] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability),
[_] => {
- if let Some(s_src) = snippet_opt(cx, format_args.format_string_span) {
- // 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);
- }
+ // Simulate macro expansion, converting {{ and }} to { and }.
+ let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}");
+ let sugg = format!("{s_expand}.to_string()");
+ span_useless_format(cx, call_site, sugg, applicability);
},
[..] => {},
}
- } else if let [value] = *format_args.value_args {
+ } else if let [arg] = &*format_args.args {
+ let value = arg.param.value;
if_chain! {
- if format_args.format_string_parts == [kw::Empty];
+ if format_args.format_string.parts == [kw::Empty];
+ if arg.format.is_default();
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.format_trait == sym::Display && !arg.has_string_formatting());
then {
let is_new_string = match value.kind {
ExprKind::Binary(..) => true,
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 1e6feaac2..f0fe845d3 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -1,15 +1,22 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::is_diag_trait_item;
-use clippy_utils::macros::{is_format_macro, FormatArgsArg, FormatArgsExpn};
+use clippy_utils::macros::FormatParamKind::{Implicit, Named, Numbered, Starred};
+use clippy_utils::macros::{
+ is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, FormatParamUsage,
+};
use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::implements_trait;
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs};
use if_chain::if_chain;
+use itertools::Itertools;
use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_hir::{Expr, ExprKind, HirId, QPath};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_middle::ty::Ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::DefId;
+use rustc_span::edition::Edition::Edition2021;
use rustc_span::{sym, ExpnData, ExpnKind, Span, Symbol};
declare_clippy_lint! {
@@ -63,35 +70,256 @@ declare_clippy_lint! {
"`to_string` applied to a type that implements `Display` in format args"
}
-declare_lint_pass!(FormatArgs => [FORMAT_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS]);
+declare_clippy_lint! {
+ /// ### What it does
+ /// Detect when a variable is not inlined in a format string,
+ /// and suggests to inline it.
+ ///
+ /// ### Why is this bad?
+ /// Non-inlined code is slightly more difficult to read and understand,
+ /// as it requires arguments to be matched against the format string.
+ /// The inlined syntax, where allowed, is simpler.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # let var = 42;
+ /// # let width = 1;
+ /// # let prec = 2;
+ /// format!("{}", var);
+ /// format!("{v:?}", v = var);
+ /// format!("{0} {0}", var);
+ /// format!("{0:1$}", var, width);
+ /// format!("{:.*}", prec, var);
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # let var = 42;
+ /// # let width = 1;
+ /// # let prec = 2;
+ /// format!("{var}");
+ /// format!("{var:?}");
+ /// format!("{var} {var}");
+ /// format!("{var:width$}");
+ /// format!("{var:.prec$}");
+ /// ```
+ ///
+ /// ### Known Problems
+ ///
+ /// There may be a false positive if the format string is expanded from certain proc macros:
+ ///
+ /// ```ignore
+ /// println!(indoc!("{}"), var);
+ /// ```
+ ///
+ /// If a format string contains a numbered argument that cannot be inlined
+ /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
+ #[clippy::version = "1.65.0"]
+ pub UNINLINED_FORMAT_ARGS,
+ pedantic,
+ "using non-inlined variables in `format!` calls"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Detects [formatting parameters] that have no effect on the output of
+ /// `format!()`, `println!()` or similar macros.
+ ///
+ /// ### Why is this bad?
+ /// Shorter format specifiers are easier to read, it may also indicate that
+ /// an expected formatting operation such as adding padding isn't happening.
+ ///
+ /// ### Example
+ /// ```rust
+ /// println!("{:.}", 1.0);
+ ///
+ /// println!("not padded: {:5}", format_args!("..."));
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// println!("{}", 1.0);
+ ///
+ /// println!("not padded: {}", format_args!("..."));
+ /// // OR
+ /// println!("padded: {:5}", format!("..."));
+ /// ```
+ ///
+ /// [formatting parameters]: https://doc.rust-lang.org/std/fmt/index.html#formatting-parameters
+ #[clippy::version = "1.66.0"]
+ pub UNUSED_FORMAT_SPECS,
+ complexity,
+ "use of a format specifier that has no effect"
+}
+
+impl_lint_pass!(FormatArgs => [
+ FORMAT_IN_FORMAT_ARGS,
+ TO_STRING_IN_FORMAT_ARGS,
+ UNINLINED_FORMAT_ARGS,
+ UNUSED_FORMAT_SPECS,
+]);
+
+pub struct FormatArgs {
+ msrv: Option<RustcVersion>,
+}
+
+impl FormatArgs {
+ #[must_use]
+ pub fn new(msrv: Option<RustcVersion>) -> Self {
+ Self { msrv }
+ }
+}
impl<'tcx> LateLintPass<'tcx> for FormatArgs {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if_chain! {
- if let Some(format_args) = FormatArgsExpn::parse(cx, expr);
- let expr_expn_data = expr.span.ctxt().outer_expn_data();
- let outermost_expn_data = outermost_expn_data(expr_expn_data);
- if let Some(macro_def_id) = outermost_expn_data.macro_def_id;
- if is_format_macro(cx, macro_def_id);
- if let ExpnKind::Macro(_, name) = outermost_expn_data.kind;
- if let Some(args) = format_args.args();
- then {
- for (i, arg) in args.iter().enumerate() {
- if arg.format_trait != sym::Display {
- continue;
- }
- if arg.has_string_formatting() {
- continue;
- }
- if is_aliased(&args, i) {
- continue;
- }
- check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.value);
- check_to_string_in_format_args(cx, name, arg.value);
+ if let Some(format_args) = FormatArgsExpn::parse(cx, expr)
+ && let expr_expn_data = expr.span.ctxt().outer_expn_data()
+ && let outermost_expn_data = outermost_expn_data(expr_expn_data)
+ && let Some(macro_def_id) = outermost_expn_data.macro_def_id
+ && is_format_macro(cx, macro_def_id)
+ && let ExpnKind::Macro(_, name) = outermost_expn_data.kind
+ {
+ for arg in &format_args.args {
+ check_unused_format_specifier(cx, arg);
+ if !arg.format.is_default() {
+ continue;
+ }
+ if is_aliased(&format_args, arg.param.value.hir_id) {
+ continue;
}
+ check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value);
+ check_to_string_in_format_args(cx, name, arg.param.value);
+ }
+ if meets_msrv(self.msrv, msrvs::FORMAT_ARGS_CAPTURE) {
+ check_uninlined_args(cx, &format_args, outermost_expn_data.call_site, macro_def_id);
}
}
}
+
+ extract_msrv_attr!(LateContext);
+}
+
+fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) {
+ let param_ty = cx.typeck_results().expr_ty(arg.param.value).peel_refs();
+
+ if let Count::Implied(Some(mut span)) = arg.format.precision
+ && !span.is_empty()
+ {
+ span_lint_and_then(
+ cx,
+ UNUSED_FORMAT_SPECS,
+ span,
+ "empty precision specifier has no effect",
+ |diag| {
+ if param_ty.is_floating_point() {
+ diag.note("a precision specifier is not required to format floats");
+ }
+
+ if arg.format.is_default() {
+ // If there's no other specifiers remove the `:` too
+ span = arg.format_span();
+ }
+
+ diag.span_suggestion_verbose(span, "remove the `.`", "", Applicability::MachineApplicable);
+ },
+ );
+ }
+
+ if is_type_diagnostic_item(cx, param_ty, sym::Arguments) && !arg.format.is_default_for_trait() {
+ span_lint_and_then(
+ cx,
+ UNUSED_FORMAT_SPECS,
+ arg.span,
+ "format specifiers have no effect on `format_args!()`",
+ |diag| {
+ let mut suggest_format = |spec, span| {
+ let message = format!("for the {spec} to apply consider using `format!()`");
+
+ if let Some(mac_call) = root_macro_call(arg.param.value.span)
+ && cx.tcx.is_diagnostic_item(sym::format_args_macro, mac_call.def_id)
+ && arg.span.eq_ctxt(mac_call.span)
+ {
+ diag.span_suggestion(
+ cx.sess().source_map().span_until_char(mac_call.span, '!'),
+ message,
+ "format",
+ Applicability::MaybeIncorrect,
+ );
+ } else if let Some(span) = span {
+ diag.span_help(span, message);
+ }
+ };
+
+ if !arg.format.width.is_implied() {
+ suggest_format("width", arg.format.width.span());
+ }
+
+ if !arg.format.precision.is_implied() {
+ suggest_format("precision", arg.format.precision.span());
+ }
+
+ diag.span_suggestion_verbose(
+ arg.format_span(),
+ "if the current behavior is intentional, remove the format specifiers",
+ "",
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
+ }
+}
+
+fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_site: Span, def_id: DefId) {
+ if args.format_string.span.from_expansion() {
+ return;
+ }
+ if call_site.edition() < Edition2021 && is_panic(cx, def_id) {
+ // panic! before 2021 edition considers a single string argument as non-format
+ return;
+ }
+
+ let mut fixes = Vec::new();
+ // If any of the arguments are referenced by an index number,
+ // and that argument is not a simple variable and cannot be inlined,
+ // we cannot remove any other arguments in the format string,
+ // because the index numbers might be wrong after inlining.
+ // Example of an un-inlinable format: print!("{}{1}", foo, 2)
+ if !args.params().all(|p| check_one_arg(args, &p, &mut fixes)) || fixes.is_empty() {
+ return;
+ }
+
+ // Temporarily ignore multiline spans: https://github.com/rust-lang/rust/pull/102729#discussion_r988704308
+ if fixes.iter().any(|(span, _)| cx.sess().source_map().is_multiline(*span)) {
+ return;
+ }
+
+ span_lint_and_then(
+ cx,
+ UNINLINED_FORMAT_ARGS,
+ call_site,
+ "variables can be used directly in the `format!` string",
+ |diag| {
+ diag.multipart_suggestion("change this to", fixes, Applicability::MachineApplicable);
+ },
+ );
+}
+
+fn check_one_arg(args: &FormatArgsExpn<'_>, param: &FormatParam<'_>, fixes: &mut Vec<(Span, String)>) -> bool {
+ if matches!(param.kind, Implicit | Starred | Named(_) | Numbered)
+ && let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind
+ && let [segment] = path.segments
+ && let Some(arg_span) = args.value_with_prev_comma_span(param.value.hir_id)
+ {
+ let replacement = match param.usage {
+ FormatParamUsage::Argument => segment.ident.name.to_string(),
+ FormatParamUsage::Width => format!("{}$", segment.ident.name),
+ FormatParamUsage::Precision => format!(".{}$", segment.ident.name),
+ };
+ fixes.push((param.span, replacement));
+ fixes.push((arg_span, String::new()));
+ true // successful inlining, continue checking
+ } else {
+ // if we can't inline a numbered argument, we can't continue
+ param.kind != Numbered
+ }
}
fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
@@ -102,7 +330,12 @@ fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
}
}
-fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) {
+fn check_format_in_format_args(
+ cx: &LateContext<'_>,
+ call_site: Span,
+ name: Symbol,
+ arg: &Expr<'_>,
+) {
let expn_data = arg.span.ctxt().outer_expn_data();
if expn_data.call_site.from_expansion() {
return;
@@ -115,11 +348,10 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb
cx,
FORMAT_IN_FORMAT_ARGS,
call_site,
- &format!("`format!` in `{}!` args", name),
+ &format!("`format!` in `{name}!` args"),
|diag| {
diag.help(&format!(
- "combine the `format!(..)` arguments with the outer `{}!(..)` call",
- name
+ "combine the `format!(..)` arguments with the outer `{name}!(..)` call"
));
diag.help("or consider changing `format!` to `format_args!`");
},
@@ -129,50 +361,54 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb
fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) {
if_chain! {
if !value.span.from_expansion();
- if let ExprKind::MethodCall(_, [receiver], _) = value.kind;
+ if let ExprKind::MethodCall(_, receiver, [], to_string_span) = value.kind;
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id);
if is_diag_trait_item(cx, method_def_id, sym::ToString);
let receiver_ty = cx.typeck_results().expr_ty(receiver);
if let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display);
+ let (n_needed_derefs, target) =
+ count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter());
+ if implements_trait(cx, target, display_trait_id, &[]);
+ if let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait();
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
then {
- let (n_needed_derefs, target) = count_needed_derefs(
- receiver_ty,
- cx.typeck_results().expr_adjustments(receiver).iter(),
- );
- if implements_trait(cx, target, display_trait_id, &[]) {
- if n_needed_derefs == 0 {
- span_lint_and_sugg(
- cx,
- TO_STRING_IN_FORMAT_ARGS,
- value.span.with_lo(receiver.span.hi()),
- &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name),
- "remove this",
- String::new(),
- Applicability::MachineApplicable,
- );
- } else {
- span_lint_and_sugg(
- cx,
- TO_STRING_IN_FORMAT_ARGS,
- value.span,
- &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name),
- "use this",
- format!("{:*>width$}{}", "", receiver_snippet, width = n_needed_derefs),
- Applicability::MachineApplicable,
- );
- }
+ let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]);
+ if n_needed_derefs == 0 && !needs_ref {
+ span_lint_and_sugg(
+ cx,
+ TO_STRING_IN_FORMAT_ARGS,
+ to_string_span.with_lo(receiver.span.hi()),
+ &format!(
+ "`to_string` applied to a type that implements `Display` in `{name}!` args"
+ ),
+ "remove this",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ span_lint_and_sugg(
+ cx,
+ TO_STRING_IN_FORMAT_ARGS,
+ value.span,
+ &format!(
+ "`to_string` applied to a type that implements `Display` in `{name}!` args"
+ ),
+ "use this",
+ format!(
+ "{}{:*>n_needed_derefs$}{receiver_snippet}",
+ if needs_ref { "&" } else { "" },
+ ""
+ ),
+ Applicability::MachineApplicable,
+ );
}
}
}
}
-// Returns true if `args[i]` "refers to" or "is referred to by" another argument.
-fn is_aliased(args: &[FormatArgsArg<'_>], i: usize) -> bool {
- let value = args[i].value;
- args.iter()
- .enumerate()
- .any(|(j, arg)| i != j && std::ptr::eq(value, arg.value))
+/// Returns true if `hir_id` is referred to by multiple format params
+fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool {
+ args.params().filter(|param| param.value.hir_id == hir_id).at_most_one().is_err()
}
fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
@@ -182,11 +418,7 @@ where
let mut n_total = 0;
let mut n_needed = 0;
loop {
- if let Some(Adjustment {
- kind: Adjust::Deref(overloaded_deref),
- target,
- }) = iter.next()
- {
+ if let Some(Adjustment { kind: Adjust::Deref(overloaded_deref), target }) = iter.next() {
n_total += 1;
if overloaded_deref.is_some() {
n_needed = n_total;
diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs
index 04b5be6c8..ed1342a54 100644
--- a/src/tools/clippy/clippy_lints/src/format_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/format_impl.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArgsArg, FormatArgsExpn};
+use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArg, FormatArgsExpn};
use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators};
use if_chain::if_chain;
use rustc_errors::Applicability;
@@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl {
fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
// Get the hir_id of the object we are calling the method on
- if let ExprKind::MethodCall(path, [ref self_arg, ..], _) = expr.kind;
+ if let ExprKind::MethodCall(path, self_arg, ..) = expr.kind;
// Is the method to_string() ?
if path.ident.name == sym::to_string;
// Is the method a part of the ToString trait? (i.e. not to_string() implemented
@@ -168,10 +168,9 @@ fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>,
if let macro_def_id = outer_macro.def_id;
if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, outer_macro.expn);
if is_format_macro(cx, macro_def_id);
- if let Some(args) = format_args.args();
then {
- for arg in args {
- if arg.format_trait != impl_trait.name {
+ for arg in format_args.args {
+ if arg.format.r#trait != impl_trait.name {
continue;
}
check_format_arg_self(cx, expr, &arg, impl_trait);
@@ -180,11 +179,11 @@ fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>,
}
}
-fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArgsArg<'_>, impl_trait: FormatTrait) {
+fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArg<'_>, impl_trait: FormatTrait) {
// Handle multiple dereferencing of references e.g. &&self
// Handle dereference of &self -> self that is equivalent (i.e. via *self in fmt() impl)
// Since the argument to fmt is itself a reference: &self
- let reference = peel_ref_operators(cx, arg.value);
+ let reference = peel_ref_operators(cx, arg.param.value);
let map = cx.tcx.hir();
// Is the reference self?
if path_to_local(reference).map(|x| map.name(x)) == Some(kw::SelfLower) {
@@ -215,12 +214,12 @@ fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait:
cx,
PRINT_IN_FORMAT_IMPL,
macro_call.span,
- &format!("use of `{}!` in `{}` impl", name, impl_trait.name),
+ &format!("use of `{name}!` in `{}` impl", impl_trait.name),
"replace with",
if let Some(formatter_name) = impl_trait.formatter_name {
- format!("{}!({}, ..)", replacement, formatter_name)
+ format!("{replacement}!({formatter_name}, ..)")
} else {
- format!("{}!(..)", replacement)
+ format!("{replacement}!(..)")
},
Applicability::HasPlaceholders,
);
diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs
index ebf5ab086..9b9f1872b 100644
--- a/src/tools/clippy/clippy_lints/src/format_push_string.rs
+++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs
@@ -54,7 +54,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
impl<'tcx> LateLintPass<'tcx> for FormatPushString {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let arg = match expr.kind {
- ExprKind::MethodCall(_, [_, arg], _) => {
+ ExprKind::MethodCall(_, _, [arg], _) => {
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) &&
match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
arg
diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs
index db0166da5..a866a6898 100644
--- a/src/tools/clippy/clippy_lints/src/formatting.rs
+++ b/src/tools/clippy/clippy_lints/src/formatting.rs
@@ -1,4 +1,5 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note};
+use clippy_utils::is_span_if;
use clippy_utils::source::snippet_opt;
use if_chain::if_chain;
use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
@@ -153,11 +154,10 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
eqop_span,
&format!(
"this looks like you are trying to use `.. {op}= ..`, but you \
- really are doing `.. = ({op} ..)`",
- op = op
+ really are doing `.. = ({op} ..)`"
),
None,
- &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op),
+ &format!("to remove this lint, use either `{op}=` or `= {op}`"),
);
}
}
@@ -190,16 +190,12 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) {
SUSPICIOUS_UNARY_OP_FORMATTING,
eqop_span,
&format!(
- "by not having a space between `{binop}` and `{unop}` it looks like \
- `{binop}{unop}` is a single operator",
- binop = binop_str,
- unop = unop_str
+ "by not having a space between `{binop_str}` and `{unop_str}` it looks like \
+ `{binop_str}{unop_str}` is a single operator"
),
None,
&format!(
- "put a space between `{binop}` and `{unop}` and remove the space after `{unop}`",
- binop = binop_str,
- unop = unop_str
+ "put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"
),
);
}
@@ -245,12 +241,11 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
cx,
SUSPICIOUS_ELSE_FORMATTING,
else_span,
- &format!("this is an `else {}` but the formatting might hide it", else_desc),
+ &format!("this is an `else {else_desc}` but the formatting might hide it"),
None,
&format!(
"to remove this lint, remove the `else` or remove the new line between \
- `else` and `{}`",
- else_desc,
+ `else` and `{else_desc}`",
),
);
}
@@ -297,12 +292,11 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
if_chain! {
if !first.span.from_expansion() && !second.span.from_expansion();
- if let ExprKind::If(cond_expr, ..) = &first.kind;
+ if matches!(first.kind, ExprKind::If(..));
if is_block(second) || is_if(second);
// Proc-macros can give weird spans. Make sure this is actually an `if`.
- if let Some(if_snip) = snippet_opt(cx, first.span.until(cond_expr.span));
- if if_snip.starts_with("if");
+ if is_span_if(cx, first.span);
// If there is a line break between the two expressions, don't lint.
// If there is a non-whitespace character, this span came from a proc-macro.
@@ -320,11 +314,10 @@ fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
cx,
SUSPICIOUS_ELSE_FORMATTING,
else_span,
- &format!("this looks like {} but the `else` is missing", looks_like),
+ &format!("this looks like {looks_like} but the `else` is missing"),
None,
&format!(
- "to remove this lint, add the missing `else` or add a new line before {}",
- next_thing,
+ "to remove this lint, add the missing `else` or add a new line before {next_thing}",
),
);
}
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index 5d25c1d06..8b24a4962 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -1,11 +1,19 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{meets_msrv, msrvs};
-use if_chain::if_chain;
-use rustc_hir as hir;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::span_is_local;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::{meets_msrv, msrvs, path_def_id};
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::{walk_path, Visitor};
+use rustc_hir::{
+ GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemRef, Item, ItemKind, PatKind, Path, PathSegment, Ty,
+ TyKind,
+};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{kw, sym};
+use rustc_span::{Span, Symbol};
declare_clippy_lint! {
/// ### What it does
@@ -54,28 +62,152 @@ impl FromOverInto {
impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
impl<'tcx> LateLintPass<'tcx> for FromOverInto {
- fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
- if !meets_msrv(self.msrv, msrvs::RE_REBALANCING_COHERENCE) {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+ if !meets_msrv(self.msrv, msrvs::RE_REBALANCING_COHERENCE) || !span_is_local(item.span) {
return;
}
- if_chain! {
- if let hir::ItemKind::Impl{ .. } = &item.kind;
- if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.def_id);
- if cx.tcx.is_diagnostic_item(sym::Into, impl_trait_ref.def_id);
-
- then {
- span_lint_and_help(
- cx,
- FROM_OVER_INTO,
- cx.tcx.sess.source_map().guess_head_span(item.span),
- "an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true",
- None,
- &format!("consider to implement `From<{}>` instead", impl_trait_ref.self_ty()),
- );
- }
+ if let ItemKind::Impl(Impl {
+ of_trait: Some(hir_trait_ref),
+ self_ty,
+ items: [impl_item_ref],
+ ..
+ }) = item.kind
+ && let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
+ // `impl Into<target_ty> for self_ty`
+ && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
+ && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+ && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
+ {
+ span_lint_and_then(
+ cx,
+ FROM_OVER_INTO,
+ cx.tcx.sess.source_map().guess_head_span(item.span),
+ "an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true",
+ |diag| {
+ // If the target type is likely foreign mention the orphan rules as it's a common source of confusion
+ if path_def_id(cx, target_ty.peel_refs()).map_or(true, |id| !id.is_local()) {
+ diag.help(
+ "`impl From<Local> for Foreign` is allowed by the orphan rules, for more information see\n\
+ https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence"
+ );
+ }
+
+ let message = format!("replace the `Into` implentation with `From<{}>`", middle_trait_ref.self_ty());
+ if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) {
+ diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable);
+ } else {
+ diag.help(message);
+ }
+ },
+ );
}
}
extract_msrv_attr!(LateContext);
}
+
+/// Finds the occurences of `Self` and `self`
+struct SelfFinder<'a, 'tcx> {
+ cx: &'a LateContext<'tcx>,
+ /// Occurences of `Self`
+ upper: Vec<Span>,
+ /// Occurences of `self`
+ lower: Vec<Span>,
+ /// If any of the `self`/`Self` usages were from an expansion, or the body contained a binding
+ /// already named `val`
+ invalid: bool,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> {
+ type NestedFilter = OnlyBodies;
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.cx.tcx.hir()
+ }
+
+ fn visit_path(&mut self, path: &'tcx Path<'tcx>, _id: HirId) {
+ for segment in path.segments {
+ match segment.ident.name {
+ kw::SelfLower => self.lower.push(segment.ident.span),
+ kw::SelfUpper => self.upper.push(segment.ident.span),
+ _ => continue,
+ }
+ }
+
+ self.invalid |= path.span.from_expansion();
+ if !self.invalid {
+ walk_path(self, path);
+ }
+ }
+
+ fn visit_name(&mut self, name: Symbol) {
+ if name == sym::val {
+ self.invalid = true;
+ }
+ }
+}
+
+fn convert_to_from(
+ cx: &LateContext<'_>,
+ into_trait_seg: &PathSegment<'_>,
+ target_ty: &Ty<'_>,
+ self_ty: &Ty<'_>,
+ impl_item_ref: &ImplItemRef,
+) -> Option<Vec<(Span, String)>> {
+ let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
+ let ImplItemKind::Fn(ref sig, body_id) = impl_item.kind else { return None };
+ let body = cx.tcx.hir().body(body_id);
+ let [input] = body.params else { return None };
+ let PatKind::Binding(.., self_ident, None) = input.pat.kind else { return None };
+
+ let from = snippet_opt(cx, self_ty.span)?;
+ let into = snippet_opt(cx, target_ty.span)?;
+
+ let mut suggestions = vec![
+ // impl Into<T> for U -> impl From<T> for U
+ // ~~~~ ~~~~
+ (into_trait_seg.ident.span, String::from("From")),
+ // impl Into<T> for U -> impl Into<U> for U
+ // ~ ~
+ (target_ty.span, from.clone()),
+ // impl Into<T> for U -> impl Into<T> for T
+ // ~ ~
+ (self_ty.span, into),
+ // fn into(self) -> T -> fn from(self) -> T
+ // ~~~~ ~~~~
+ (impl_item.ident.span, String::from("from")),
+ // fn into([mut] self) -> T -> fn into([mut] v: T) -> T
+ // ~~~~ ~~~~
+ (self_ident.span, format!("val: {from}")),
+ // fn into(self) -> T -> fn into(self) -> Self
+ // ~ ~~~~
+ (sig.decl.output.span(), String::from("Self")),
+ ];
+
+ let mut finder = SelfFinder {
+ cx,
+ upper: Vec::new(),
+ lower: Vec::new(),
+ invalid: false,
+ };
+ finder.visit_expr(body.value);
+
+ if finder.invalid {
+ return None;
+ }
+
+ // don't try to replace e.g. `Self::default()` with `&[T]::default()`
+ if !finder.upper.is_empty() && !matches!(self_ty.kind, TyKind::Path(_)) {
+ return None;
+ }
+
+ for span in finder.upper {
+ suggestions.push((span, from.clone()));
+ }
+ for span in finder.lower {
+ suggestions.push((span, String::from("val")));
+ }
+
+ Some(suggestions)
+}
diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
index 57b075132..cf8b7acd6 100644
--- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
+++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
@@ -1,4 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_integer_literal;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
@@ -46,7 +47,7 @@ declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]);
impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
if_chain! {
- if let ExprKind::Call(maybe_path, arguments) = &exp.kind;
+ if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind;
if let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind;
// check if the first part of the path is some integer primitive
@@ -60,20 +61,18 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
if pathseg.ident.name.as_str() == "from_str_radix";
// check if the second argument is a primitive `10`
- if arguments.len() == 2;
- if let ExprKind::Lit(lit) = &arguments[1].kind;
- if let rustc_ast::ast::LitKind::Int(10, _) = lit.node;
+ if is_integer_literal(radix, 10);
then {
- let expr = if let ExprKind::AddrOf(_, _, expr) = &arguments[0].kind {
+ let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind {
let ty = cx.typeck_results().expr_ty(expr);
if is_ty_stringish(cx, ty) {
expr
} else {
- &arguments[0]
+ &src
}
} else {
- &arguments[0]
+ &src
};
let sugg = Sugg::hir_with_applicability(
@@ -89,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
exp.span,
"this call to `from_str_radix` can be replaced with a call to `str::parse`",
"try",
- format!("{}.parse::<{}>()", sugg, prim_ty.name_str()),
+ format!("{sugg}.parse::<{}>()", prim_ty.name_str()),
Applicability::MaybeIncorrect
);
}
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index 73261fb8a..90911e0bf 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -1,6 +1,6 @@
mod must_use;
mod not_unsafe_ptr_arg_deref;
-mod result_unit_err;
+mod result;
mod too_many_arguments;
mod too_many_lines;
@@ -217,17 +217,62 @@ declare_clippy_lint! {
"public function returning `Result` with an `Err` type of `()`"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for functions that return `Result` with an unusually large
+ /// `Err`-variant.
+ ///
+ /// ### Why is this bad?
+ /// A `Result` is at least as large as the `Err`-variant. While we
+ /// expect that variant to be seldomly used, the compiler needs to reserve
+ /// and move that much memory every single time.
+ ///
+ /// ### Known problems
+ /// The size determined by Clippy is platform-dependent.
+ ///
+ /// ### Examples
+ /// ```rust
+ /// pub enum ParseError {
+ /// UnparsedBytes([u8; 512]),
+ /// UnexpectedEof,
+ /// }
+ ///
+ /// // The `Result` has at least 512 bytes, even in the `Ok`-case
+ /// pub fn parse() -> Result<(), ParseError> {
+ /// Ok(())
+ /// }
+ /// ```
+ /// should be
+ /// ```
+ /// pub enum ParseError {
+ /// UnparsedBytes(Box<[u8; 512]>),
+ /// UnexpectedEof,
+ /// }
+ ///
+ /// // The `Result` is slightly larger than a pointer
+ /// pub fn parse() -> Result<(), ParseError> {
+ /// Ok(())
+ /// }
+ /// ```
+ #[clippy::version = "1.64.0"]
+ pub RESULT_LARGE_ERR,
+ perf,
+ "function returning `Result` with large `Err` type"
+}
+
#[derive(Copy, Clone)]
pub struct Functions {
too_many_arguments_threshold: u64,
too_many_lines_threshold: u64,
+ large_error_threshold: u64,
}
impl Functions {
- pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64) -> Self {
+ pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64) -> Self {
Self {
too_many_arguments_threshold,
too_many_lines_threshold,
+ large_error_threshold,
}
}
}
@@ -240,6 +285,7 @@ impl_lint_pass!(Functions => [
DOUBLE_MUST_USE,
MUST_USE_CANDIDATE,
RESULT_UNIT_ERR,
+ RESULT_LARGE_ERR,
]);
impl<'tcx> LateLintPass<'tcx> for Functions {
@@ -259,18 +305,18 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
must_use::check_item(cx, item);
- result_unit_err::check_item(cx, item);
+ result::check_item(cx, item, self.large_error_threshold);
}
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
must_use::check_impl_item(cx, item);
- result_unit_err::check_impl_item(cx, item);
+ result::check_impl_item(cx, item, self.large_error_threshold);
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
too_many_arguments::check_trait_item(cx, item, self.too_many_arguments_threshold);
not_unsafe_ptr_arg_deref::check_trait_item(cx, item);
must_use::check_trait_item(cx, item);
- result_unit_err::check_trait_item(cx, item);
+ result::check_trait_item(cx, item, self.large_error_threshold);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index 6672a6cb0..bff69f915 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -1,27 +1,30 @@
use rustc_ast::ast::Attribute;
use rustc_errors::Applicability;
use rustc_hir::def_id::{DefIdSet, LocalDefId};
-use rustc_hir::{self as hir, def::Res, intravisit, QPath};
+use rustc_hir::{self as hir, def::Res, QPath};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::{
lint::in_external_macro,
ty::{self, Ty},
};
-use rustc_span::{sym, Span};
+use rustc_span::{sym, Span, Symbol};
use clippy_utils::attrs::is_proc_macro;
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_must_use_ty;
-use clippy_utils::{match_def_path, return_ty, trait_ref_of_method};
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{return_ty, trait_ref_of_method};
+
+use core::ops::ControlFlow;
use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT};
pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
- let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
+ let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind {
- let is_public = cx.access_levels.is_exported(item.def_id);
+ let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
@@ -31,7 +34,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
sig.decl,
cx.tcx.hir().body(*body_id),
item.span,
- item.def_id,
+ item.owner_id.def_id,
item.span.with_hi(sig.decl.output.span().hi()),
"this function could have a `#[must_use]` attribute",
);
@@ -41,19 +44,20 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind {
- let is_public = cx.access_levels.is_exported(item.def_id);
+ let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
let attrs = cx.tcx.hir().attrs(item.hir_id());
- let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
+ let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
- } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.def_id).is_none() {
+ } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+ {
check_must_use_candidate(
cx,
sig.decl,
cx.tcx.hir().body(*body_id),
item.span,
- item.def_id,
+ item.owner_id.def_id,
item.span.with_hi(sig.decl.output.span().hi()),
"this method could have a `#[must_use]` attribute",
);
@@ -63,11 +67,11 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind {
- let is_public = cx.access_levels.is_exported(item.def_id);
+ let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
let attrs = cx.tcx.hir().attrs(item.hir_id());
- let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
+ let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
} else if let hir::TraitFn::Provided(eid) = *eid {
@@ -78,7 +82,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
sig.decl,
body,
item.span,
- item.def_id,
+ item.owner_id.def_id,
item.span.with_hi(sig.decl.output.span().hi()),
"this method could have a `#[must_use]` attribute",
);
@@ -133,7 +137,7 @@ fn check_must_use_candidate<'tcx>(
|| mutates_static(cx, body)
|| in_external_macro(cx.sess(), item_span)
|| returns_unit(decl)
- || !cx.access_levels.is_exported(item_id)
+ || !cx.effective_visibilities.is_exported(item_id)
|| is_must_use_ty(cx, return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(item_id)))
{
return;
@@ -143,7 +147,7 @@ fn check_must_use_candidate<'tcx>(
diag.span_suggestion(
fn_span,
"add the attribute",
- format!("#[must_use] {}", snippet),
+ format!("#[must_use] {snippet}"),
Applicability::MachineApplicable,
);
}
@@ -171,21 +175,23 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet)
return false; // ignore `_` patterns
}
if cx.tcx.has_typeck_results(pat.hir_id.owner.to_def_id()) {
- is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner).pat_ty(pat), pat.span, tys)
+ is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner.def_id).pat_ty(pat), pat.span, tys)
} else {
false
}
}
-static KNOWN_WRAPPER_TYS: &[&[&str]] = &[&["alloc", "rc", "Rc"], &["std", "sync", "Arc"]];
+static KNOWN_WRAPPER_TYS: &[Symbol] = &[sym::Rc, sym::Arc];
fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &mut DefIdSet) -> bool {
match *ty.kind() {
// primitive types are never mutable
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
ty::Adt(adt, substs) => {
- tys.insert(adt.did()) && !ty.is_freeze(cx.tcx.at(span), cx.param_env)
- || KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did(), path))
+ tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.param_env)
+ || KNOWN_WRAPPER_TYS
+ .iter()
+ .any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did()))
&& substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys))
},
ty::Tuple(substs) => substs.iter().any(|ty| is_mutable_ty(cx, ty, span, tys)),
@@ -199,61 +205,65 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &m
}
}
-struct StaticMutVisitor<'a, 'tcx> {
- cx: &'a LateContext<'tcx>,
- mutates_static: bool,
+fn is_mutated_static(e: &hir::Expr<'_>) -> bool {
+ use hir::ExprKind::{Field, Index, Path};
+
+ match e.kind {
+ Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)),
+ Path(_) => true,
+ Field(inner, _) | Index(inner, _) => is_mutated_static(inner),
+ _ => false,
+ }
}
-impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
- fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
+fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bool {
+ for_each_expr(body.value, |e| {
use hir::ExprKind::{AddrOf, Assign, AssignOp, Call, MethodCall};
- if self.mutates_static {
- return;
- }
- match expr.kind {
- Call(_, args) | MethodCall(_, args, _) => {
+ match e.kind {
+ Call(_, args) => {
let mut tys = DefIdSet::default();
for arg in args {
- if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
+ if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
+ && is_mutable_ty(
+ cx,
+ cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg),
+ arg.span,
+ &mut tys,
+ )
+ && is_mutated_static(arg)
+ {
+ return ControlFlow::Break(());
+ }
+ tys.clear();
+ }
+ ControlFlow::Continue(())
+ },
+ MethodCall(_, receiver, args, _) => {
+ let mut tys = DefIdSet::default();
+ for arg in std::iter::once(receiver).chain(args.iter()) {
+ if cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
&& is_mutable_ty(
- self.cx,
- self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg),
+ cx,
+ cx.tcx.typeck(arg.hir_id.owner.def_id).expr_ty(arg),
arg.span,
&mut tys,
)
&& is_mutated_static(arg)
{
- self.mutates_static = true;
- return;
+ return ControlFlow::Break(());
}
tys.clear();
}
+ ControlFlow::Continue(())
},
- Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => {
- self.mutates_static |= is_mutated_static(target);
+ Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target)
+ if is_mutated_static(target) =>
+ {
+ ControlFlow::Break(())
},
- _ => {},
+ _ => ControlFlow::Continue(()),
}
- }
-}
-
-fn is_mutated_static(e: &hir::Expr<'_>) -> bool {
- use hir::ExprKind::{Field, Index, Path};
-
- match e.kind {
- Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)),
- Path(_) => true,
- Field(inner, _) | Index(inner, _) => is_mutated_static(inner),
- _ => false,
- }
-}
-
-fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bool {
- let mut v = StaticMutVisitor {
- cx,
- mutates_static: false,
- };
- intravisit::walk_expr(&mut v, &body.value);
- v.mutates_static
+ })
+ .is_some()
}
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index 565a1c871..2c0bf551f 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -5,8 +5,11 @@ use rustc_span::def_id::LocalDefId;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::type_is_unsafe_function;
+use clippy_utils::visitors::for_each_expr_with_closures;
use clippy_utils::{iter_input_pats, path_to_local};
+use core::ops::ControlFlow;
+
use super::NOT_UNSAFE_PTR_ARG_DEREF;
pub(super) fn check_fn<'tcx>(
@@ -28,7 +31,7 @@ pub(super) fn check_fn<'tcx>(
pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
let body = cx.tcx.hir().body(eid);
- check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.def_id);
+ check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.owner_id.def_id);
}
}
@@ -39,21 +42,34 @@ fn check_raw_ptr<'tcx>(
body: &'tcx hir::Body<'tcx>,
def_id: LocalDefId,
) {
- let expr = &body.value;
- if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(def_id) {
+ if unsafety == hir::Unsafety::Normal && cx.effective_visibilities.is_exported(def_id) {
let raw_ptrs = iter_input_pats(decl, body)
.filter_map(|arg| raw_ptr_arg(cx, arg))
.collect::<HirIdSet>();
if !raw_ptrs.is_empty() {
- let typeck_results = cx.tcx.typeck_body(body.id());
- let mut v = DerefVisitor {
- cx,
- ptrs: raw_ptrs,
- typeck_results,
- };
-
- intravisit::walk_expr(&mut v, expr);
+ let typeck = cx.tcx.typeck_body(body.id());
+ let _: Option<!> = for_each_expr_with_closures(cx, body.value, |e| {
+ match e.kind {
+ hir::ExprKind::Call(f, args) if type_is_unsafe_function(cx, typeck.expr_ty(f)) => {
+ for arg in args {
+ check_arg(cx, &raw_ptrs, arg);
+ }
+ },
+ hir::ExprKind::MethodCall(_, recv, args, _) => {
+ let def_id = typeck.type_dependent_def_id(e.hir_id).unwrap();
+ if cx.tcx.fn_sig(def_id).skip_binder().unsafety == hir::Unsafety::Unsafe {
+ check_arg(cx, &raw_ptrs, recv);
+ for arg in args {
+ check_arg(cx, &raw_ptrs, arg);
+ }
+ }
+ },
+ hir::ExprKind::Unary(hir::UnOp::Deref, ptr) => check_arg(cx, &raw_ptrs, ptr),
+ _ => (),
+ }
+ ControlFlow::Continue(())
+ });
}
}
}
@@ -70,53 +86,13 @@ fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option<hir::HirId>
}
}
-struct DerefVisitor<'a, 'tcx> {
- cx: &'a LateContext<'tcx>,
- ptrs: HirIdSet,
- typeck_results: &'a ty::TypeckResults<'tcx>,
-}
-
-impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
- fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
- match expr.kind {
- hir::ExprKind::Call(f, args) => {
- let ty = self.typeck_results.expr_ty(f);
-
- if type_is_unsafe_function(self.cx, ty) {
- for arg in args {
- self.check_arg(arg);
- }
- }
- },
- hir::ExprKind::MethodCall(_, args, _) => {
- let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap();
- let base_type = self.cx.tcx.type_of(def_id);
-
- if type_is_unsafe_function(self.cx, base_type) {
- for arg in args {
- self.check_arg(arg);
- }
- }
- },
- hir::ExprKind::Unary(hir::UnOp::Deref, ptr) => self.check_arg(ptr),
- _ => (),
- }
-
- intravisit::walk_expr(self, expr);
- }
-}
-
-impl<'a, 'tcx> DerefVisitor<'a, 'tcx> {
- fn check_arg(&self, ptr: &hir::Expr<'_>) {
- if let Some(id) = path_to_local(ptr) {
- if self.ptrs.contains(&id) {
- span_lint(
- self.cx,
- NOT_UNSAFE_PTR_ARG_DEREF,
- ptr.span,
- "this public function might dereference a raw pointer but is not marked `unsafe`",
- );
- }
- }
+fn check_arg(cx: &LateContext<'_>, raw_ptrs: &HirIdSet, arg: &hir::Expr<'_>) {
+ if path_to_local(arg).map_or(false, |id| raw_ptrs.contains(&id)) {
+ span_lint(
+ cx,
+ NOT_UNSAFE_PTR_ARG_DEREF,
+ arg.span,
+ "this public function might dereference a raw pointer but is not marked `unsafe`",
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
new file mode 100644
index 000000000..5c63fb2ac
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -0,0 +1,100 @@
+use rustc_errors::Diagnostic;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::{self, Ty};
+use rustc_span::{sym, Span};
+
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
+use clippy_utils::trait_ref_of_method;
+use clippy_utils::ty::{approx_ty_size, is_type_diagnostic_item};
+
+use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR};
+
+/// The type of the `Err`-variant in a `std::result::Result` returned by the
+/// given `FnDecl`
+fn result_err_ty<'tcx>(
+ cx: &LateContext<'tcx>,
+ decl: &hir::FnDecl<'tcx>,
+ id: hir::def_id::LocalDefId,
+ item_span: Span,
+) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> {
+ if !in_external_macro(cx.sess(), item_span)
+ && let hir::FnRetTy::Return(hir_ty) = decl.output
+ && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).output())
+ && is_type_diagnostic_item(cx, ty, sym::Result)
+ && let ty::Adt(_, substs) = ty.kind()
+ {
+ let err_ty = substs.type_at(1);
+ Some((hir_ty, err_ty))
+ } else {
+ None
+ }
+}
+
+pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) {
+ if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind
+ && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span)
+ {
+ if cx.effective_visibilities.is_exported(item.owner_id.def_id) {
+ let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
+ check_result_unit_err(cx, err_ty, fn_header_span);
+ }
+ check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold);
+ }
+}
+
+pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64) {
+ // Don't lint if method is a trait's implementation, we can't do anything about those
+ if let hir::ImplItemKind::Fn(ref sig, _) = item.kind
+ && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span)
+ && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+ {
+ if cx.effective_visibilities.is_exported(item.owner_id.def_id) {
+ let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
+ check_result_unit_err(cx, err_ty, fn_header_span);
+ }
+ check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold);
+ }
+}
+
+pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64) {
+ if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
+ let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
+ if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span) {
+ if cx.effective_visibilities.is_exported(item.owner_id.def_id) {
+ check_result_unit_err(cx, err_ty, fn_header_span);
+ }
+ check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold);
+ }
+ }
+}
+
+fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: Span) {
+ if err_ty.is_unit() {
+ span_lint_and_help(
+ cx,
+ RESULT_UNIT_ERR,
+ fn_header_span,
+ "this returns a `Result<_, ()>`",
+ None,
+ "use a custom `Error` type instead",
+ );
+ }
+}
+
+fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) {
+ let ty_size = approx_ty_size(cx, err_ty);
+ if ty_size >= large_err_threshold {
+ span_lint_and_then(
+ cx,
+ RESULT_LARGE_ERR,
+ hir_ty_span,
+ "the `Err`-variant returned from this function is very large",
+ |diag: &mut Diagnostic| {
+ diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes"));
+ diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
+ },
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs b/src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs
deleted file mode 100644
index 2e63a1f92..000000000
--- a/src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty;
-use rustc_span::{sym, Span};
-use rustc_typeck::hir_ty_to_ty;
-
-use if_chain::if_chain;
-
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::trait_ref_of_method;
-use clippy_utils::ty::is_type_diagnostic_item;
-
-use super::RESULT_UNIT_ERR;
-
-pub(super) fn check_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind {
- let is_public = cx.access_levels.is_exported(item.def_id);
- let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
- if is_public {
- check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
- }
- }
-}
-
-pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &hir::ImplItem<'_>) {
- if let hir::ImplItemKind::Fn(ref sig, _) = item.kind {
- let is_public = cx.access_levels.is_exported(item.def_id);
- let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
- if is_public && trait_ref_of_method(cx, item.def_id).is_none() {
- check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
- }
- }
-}
-
-pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>) {
- if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
- let is_public = cx.access_levels.is_exported(item.def_id);
- let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
- if is_public {
- check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
- }
- }
-}
-
-fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span: Span, fn_header_span: Span) {
- if_chain! {
- if !in_external_macro(cx.sess(), item_span);
- if let hir::FnRetTy::Return(ty) = decl.output;
- let ty = hir_ty_to_ty(cx.tcx, ty);
- if is_type_diagnostic_item(cx, ty, sym::Result);
- if let ty::Adt(_, substs) = ty.kind();
- let err_ty = substs.type_at(1);
- if err_ty.is_unit();
- then {
- span_lint_and_help(
- cx,
- RESULT_UNIT_ERR,
- fn_header_span,
- "this returns a `Result<_, ()>`",
- None,
- "use a custom `Error` type instead",
- );
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
index 5c8d8b8e7..1e08922a6 100644
--- a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
@@ -59,10 +59,7 @@ fn check_arg_number(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, fn_span: Span,
cx,
TOO_MANY_ARGUMENTS,
fn_span,
- &format!(
- "this function has too many arguments ({}/{})",
- args, too_many_arguments_threshold
- ),
+ &format!("this function has too many arguments ({args}/{too_many_arguments_threshold})"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
index 54bdea7ea..bd473ac7e 100644
--- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
@@ -22,9 +22,8 @@ pub(super) fn check_fn(
return;
}
- let code_snippet = match snippet_opt(cx, body.value.span) {
- Some(s) => s,
- _ => return,
+ let Some(code_snippet) = snippet_opt(cx, body.value.span) else {
+ return
};
let mut line_count: u64 = 0;
let mut in_comment = false;
@@ -78,10 +77,7 @@ pub(super) fn check_fn(
cx,
TOO_MANY_LINES,
span,
- &format!(
- "this function has too many lines ({}/{})",
- line_count, too_many_lines_threshold
- ),
+ &format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 5c46d6c7d..0519f9ac2 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -4,12 +4,11 @@ use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, FnDecl, HirId};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{EarlyBinder, Opaque, PredicateKind::Trait};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span};
-use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt;
-use rustc_trait_selection::traits::{self, FulfillmentError, TraitEngine};
+use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
+use rustc_trait_selection::traits::{self, FulfillmentError};
declare_clippy_lint! {
/// ### What it does
@@ -78,12 +77,9 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
if is_future {
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
let span = decl.output.span();
- let send_errors = cx.tcx.infer_ctxt().enter(|infcx| {
- let cause = traits::ObligationCause::misc(span, hir_id);
- let mut fulfillment_cx = traits::FulfillmentContext::new();
- fulfillment_cx.register_bound(&infcx, cx.param_env, ret_ty, send_trait, cause);
- fulfillment_cx.select_all_or_error(&infcx)
- });
+ let infcx = cx.tcx.infer_ctxt().build();
+ let cause = traits::ObligationCause::misc(span, hir_id);
+ let send_errors = traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait);
if !send_errors.is_empty() {
span_lint_and_then(
cx,
@@ -91,18 +87,18 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
span,
"future cannot be sent between threads safely",
|db| {
- cx.tcx.infer_ctxt().enter(|infcx| {
- for FulfillmentError { obligation, .. } in send_errors {
- infcx.maybe_note_obligation_cause_for_async_await(db, &obligation);
- if let Trait(trait_pred) = obligation.predicate.kind().skip_binder() {
- db.note(&format!(
- "`{}` doesn't implement `{}`",
- trait_pred.self_ty(),
- trait_pred.trait_ref.print_only_trait_path(),
- ));
- }
+ for FulfillmentError { obligation, .. } in send_errors {
+ infcx
+ .err_ctxt()
+ .maybe_note_obligation_cause_for_async_await(db, &obligation);
+ if let Trait(trait_pred) = obligation.predicate.kind().skip_binder() {
+ db.note(&format!(
+ "`{}` doesn't implement `{}`",
+ trait_pred.self_ty(),
+ trait_pred.trait_ref.print_only_trait_path(),
+ ));
}
- });
+ }
},
);
}
diff --git a/src/tools/clippy/clippy_lints/src/get_first.rs b/src/tools/clippy/clippy_lints/src/get_first.rs
deleted file mode 100644
index 529f7baba..000000000
--- a/src/tools/clippy/clippy_lints/src/get_first.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_slice_of_primitives, match_def_path, paths};
-use if_chain::if_chain;
-use rustc_ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Spanned;
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for using `x.get(0)` instead of
- /// `x.first()`.
- ///
- /// ### Why is this bad?
- /// Using `x.first()` is easier to read and has the same
- /// result.
- ///
- /// ### Example
- /// ```rust
- /// let x = vec![2, 3, 5];
- /// let first_element = x.get(0);
- /// ```
- ///
- /// Use instead:
- /// ```rust
- /// let x = vec![2, 3, 5];
- /// let first_element = x.first();
- /// ```
- #[clippy::version = "1.63.0"]
- pub GET_FIRST,
- style,
- "Using `x.get(0)` when `x.first()` is simpler"
-}
-declare_lint_pass!(GetFirst => [GET_FIRST]);
-
-impl<'tcx> LateLintPass<'tcx> for GetFirst {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if_chain! {
- if let hir::ExprKind::MethodCall(_, [struct_calling_on, method_arg], _) = &expr.kind;
- if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if match_def_path(cx, expr_def_id, &paths::SLICE_GET);
-
- if let Some(_) = is_slice_of_primitives(cx, struct_calling_on);
- if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = method_arg.kind;
-
- then {
- let mut applicability = Applicability::MachineApplicable;
- let slice_name = snippet_with_applicability(
- cx,
- struct_calling_on.span, "..",
- &mut applicability,
- );
- span_lint_and_sugg(
- cx,
- GET_FIRST,
- expr.span,
- &format!("accessing first element with `{0}.get(0)`", slice_name),
- "try",
- format!("{}.first()", slice_name),
- applicability,
- );
- }
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
index e95017007..9ea8c494c 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
@@ -1,8 +1,9 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::SpanlessEq;
use if_chain::if_chain;
+use rustc_errors::Diagnostic;
use rustc_hir::intravisit::{self as visit, Visitor};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -45,16 +46,8 @@ declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]);
impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- let mut arm_visit = ArmVisitor {
- mutex_lock_called: false,
- found_mutex: None,
- cx,
- };
- let mut op_visit = OppVisitor {
- mutex_lock_called: false,
- found_mutex: None,
- cx,
- };
+ let mut arm_visit = ArmVisitor { found_mutex: None, cx };
+ let mut op_visit = OppVisitor { found_mutex: None, cx };
if let Some(higher::IfLet {
let_expr,
if_then,
@@ -63,18 +56,28 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
}) = higher::IfLet::hir(cx, expr)
{
op_visit.visit_expr(let_expr);
- if op_visit.mutex_lock_called {
+ if let Some(op_mutex) = op_visit.found_mutex {
arm_visit.visit_expr(if_then);
arm_visit.visit_expr(if_else);
- if arm_visit.mutex_lock_called && arm_visit.same_mutex(cx, op_visit.found_mutex.unwrap()) {
- span_lint_and_help(
+ if let Some(arm_mutex) = arm_visit.found_mutex_if_same_as(op_mutex) {
+ let diag = |diag: &mut Diagnostic| {
+ diag.span_label(
+ op_mutex.span,
+ "this Mutex will remain locked for the entire `if let`-block...",
+ );
+ diag.span_label(
+ arm_mutex.span,
+ "... and is tried to lock again here, which will always deadlock.",
+ );
+ diag.help("move the lock call outside of the `if let ...` expression");
+ };
+ span_lint_and_then(
cx,
IF_LET_MUTEX,
expr.span,
"calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock",
- None,
- "move the lock call outside of the `if let ...` expression",
+ diag,
);
}
}
@@ -84,7 +87,6 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
/// Checks if `Mutex::lock` is called in the `if let` expr.
pub struct OppVisitor<'a, 'tcx> {
- mutex_lock_called: bool,
found_mutex: Option<&'tcx Expr<'tcx>>,
cx: &'a LateContext<'tcx>,
}
@@ -93,7 +95,6 @@ impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
if let Some(mutex) = is_mutex_lock_call(self.cx, expr) {
self.found_mutex = Some(mutex);
- self.mutex_lock_called = true;
return;
}
visit::walk_expr(self, expr);
@@ -102,7 +103,6 @@ impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> {
/// Checks if `Mutex::lock` is called in any of the branches.
pub struct ArmVisitor<'a, 'tcx> {
- mutex_lock_called: bool,
found_mutex: Option<&'tcx Expr<'tcx>>,
cx: &'a LateContext<'tcx>,
}
@@ -111,7 +111,6 @@ impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
if let Some(mutex) = is_mutex_lock_call(self.cx, expr) {
self.found_mutex = Some(mutex);
- self.mutex_lock_called = true;
return;
}
visit::walk_expr(self, expr);
@@ -119,17 +118,20 @@ impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> {
}
impl<'tcx, 'l> ArmVisitor<'tcx, 'l> {
- fn same_mutex(&self, cx: &LateContext<'_>, op_mutex: &Expr<'_>) -> bool {
- self.found_mutex
- .map_or(false, |arm_mutex| SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex))
+ fn found_mutex_if_same_as(&self, op_mutex: &Expr<'_>) -> Option<&Expr<'_>> {
+ self.found_mutex.and_then(|arm_mutex| {
+ SpanlessEq::new(self.cx)
+ .eq_expr(op_mutex, arm_mutex)
+ .then_some(arm_mutex)
+ })
}
}
fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
if_chain! {
- if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
+ if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
if path.ident.as_str() == "lock";
- let ty = cx.typeck_results().expr_ty(self_arg);
+ let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
if is_type_diagnostic_item(cx, ty, sym::Mutex);
then {
Some(self_arg)
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index b8d227855..0d6718c16 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -1,7 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::eager_or_lazy::switch_to_eager_eval;
use clippy_utils::source::snippet_with_macro_callsite;
-use clippy_utils::{contains_return, higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs, peel_blocks};
-use if_chain::if_chain;
+use clippy_utils::{
+ contains_return, higher, is_else_clause, is_res_lang_ctor, meets_msrv, msrvs, path_res, peel_blocks,
+};
use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_hir::{Expr, ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -11,10 +13,12 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! {
/// ### What it does
- /// Checks for if-else that could be written to `bool::then`.
+ /// Checks for if-else that could be written using either `bool::then` or `bool::then_some`.
///
/// ### Why is this bad?
- /// Looks a little redundant. Using `bool::then` helps it have less lines of code.
+ /// Looks a little redundant. Using `bool::then` is more concise and incurs no loss of clarity.
+ /// For simple calculations and known values, use `bool::then_some`, which is eagerly evaluated
+ /// in comparison to `bool::then`.
///
/// ### Example
/// ```rust
@@ -39,7 +43,7 @@ declare_clippy_lint! {
#[clippy::version = "1.53.0"]
pub IF_THEN_SOME_ELSE_NONE,
restriction,
- "Finds if-else that could be written using `bool::then`"
+ "Finds if-else that could be written using either `bool::then` or `bool::then_some`"
}
pub struct IfThenSomeElseNone {
@@ -56,7 +60,7 @@ impl IfThenSomeElseNone {
impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
- fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if !meets_msrv(self.msrv, msrvs::BOOL_THEN) {
return;
}
@@ -70,43 +74,44 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
return;
}
- if_chain! {
- if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr);
- if let ExprKind::Block(then_block, _) = then.kind;
- if let Some(then_expr) = then_block.expr;
- if let ExprKind::Call(then_call, [then_arg]) = then_expr.kind;
- if let ExprKind::Path(ref then_call_qpath) = then_call.kind;
- if is_lang_ctor(cx, then_call_qpath, OptionSome);
- if let ExprKind::Path(ref qpath) = peel_blocks(els).kind;
- if is_lang_ctor(cx, qpath, OptionNone);
- if !stmts_contains_early_return(then_block.stmts);
- then {
- let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]");
- let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) {
- format!("({})", cond_snip)
- } else {
- cond_snip.into_owned()
- };
- let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, "");
- let closure_body = if then_block.stmts.is_empty() {
- arg_snip.into_owned()
- } else {
- format!("{{ /* snippet */ {} }}", arg_snip)
- };
- let help = format!(
- "consider using `bool::then` like: `{}.then(|| {})`",
- cond_snip,
- closure_body,
- );
- span_lint_and_help(
- cx,
- IF_THEN_SOME_ELSE_NONE,
- expr.span,
- "this could be simplified with `bool::then`",
- None,
- &help,
- );
- }
+ if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr)
+ && let ExprKind::Block(then_block, _) = then.kind
+ && let Some(then_expr) = then_block.expr
+ && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
+ && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome)
+ && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone)
+ && !stmts_contains_early_return(then_block.stmts)
+ {
+ let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]");
+ let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) {
+ format!("({cond_snip})")
+ } else {
+ cond_snip.into_owned()
+ };
+ let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, "");
+ let mut method_body = if then_block.stmts.is_empty() {
+ arg_snip.into_owned()
+ } else {
+ format!("{{ /* snippet */ {arg_snip} }}")
+ };
+ let method_name = if switch_to_eager_eval(cx, expr) && meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) {
+ "then_some"
+ } else {
+ method_body.insert_str(0, "|| ");
+ "then"
+ };
+
+ let help = format!(
+ "consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`",
+ );
+ span_lint_and_help(
+ cx,
+ IF_THEN_SOME_ELSE_NONE,
+ expr.span,
+ &format!("this could be simplified with `bool::{method_name}`"),
+ None,
+ &help,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index 4f9680f60..94e06cf70 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -5,6 +5,7 @@ use rustc_errors::Diagnostic;
use rustc_hir as hir;
use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor};
use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
+use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro;
@@ -12,7 +13,6 @@ use rustc_middle::ty::{Ty, TypeckResults};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::symbol::sym;
-use rustc_typeck::hir_ty_to_ty;
use if_chain::if_chain;
@@ -89,8 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
(
generics_suggestion_span,
format!(
- "<{}{}S: ::std::hash::BuildHasher{}>",
- generics_snip,
+ "<{generics_snip}{}S: ::std::hash::BuildHasher{}>",
if generics_snip.is_empty() { "" } else { ", " },
if vis.suggestions.is_empty() {
""
@@ -112,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
}
}
- if !cx.access_levels.is_exported(item.def_id) {
+ if !cx.effective_visibilities.is_exported(item.owner_id.def_id) {
return;
}
@@ -263,8 +262,8 @@ impl<'tcx> ImplicitHasherType<'tcx> {
fn type_arguments(&self) -> String {
match *self {
- ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{}, {}", k, v),
- ImplicitHasherType::HashSet(.., ref t) => format!("{}", t),
+ ImplicitHasherType::HashMap(.., ref k, ref v) => format!("{k}, {v}"),
+ ImplicitHasherType::HashSet(.., ref t) => format!("{t}"),
}
}
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index a6610ade3..946d04eff 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -2,10 +2,11 @@ use clippy_utils::{
diagnostics::span_lint_hir_and_then,
get_async_fn_body, is_async_fn,
source::{snippet_with_applicability, snippet_with_context, walk_span_to_context},
- visitors::expr_visitor_no_bodies,
+ visitors::for_each_expr,
};
+use core::ops::ControlFlow;
use rustc_errors::Applicability;
-use rustc_hir::intravisit::{FnKind, Visitor};
+use rustc_hir::intravisit::FnKind;
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
@@ -53,7 +54,7 @@ fn lint_return(cx: &LateContext<'_>, emission_place: HirId, span: Span) {
span,
"missing `return` statement",
|diag| {
- diag.span_suggestion(span, "add `return` as shown", format!("return {}", snip), app);
+ diag.span_suggestion(span, "add `return` as shown", format!("return {snip}"), app);
},
);
}
@@ -71,7 +72,7 @@ fn lint_break(cx: &LateContext<'_>, emission_place: HirId, break_span: Span, exp
diag.span_suggestion(
break_span,
"change `break` to `return` as shown",
- format!("return {}", snip),
+ format!("return {snip}"),
app,
);
},
@@ -152,7 +153,7 @@ fn lint_implicit_returns(
ExprKind::Loop(block, ..) => {
let mut add_return = false;
- expr_visitor_no_bodies(|e| {
+ let _: Option<!> = for_each_expr(block, |e| {
if let ExprKind::Break(dest, sub_expr) = e.kind {
if dest.target_id.ok() == Some(expr.hir_id) {
if call_site_span.is_none() && e.span.ctxt() == ctxt {
@@ -167,9 +168,8 @@ fn lint_implicit_returns(
}
}
}
- true
- })
- .visit_block(block);
+ ControlFlow::Continue(())
+ });
if add_return {
#[expect(clippy::option_if_let_else)]
if let Some(span) = call_site_span {
@@ -232,7 +232,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
return;
}
- let res_ty = cx.typeck_results().expr_ty(&body.value);
+ let res_ty = cx.typeck_results().expr_ty(body.value);
if res_ty.is_unit() || res_ty.is_never() {
return;
}
@@ -243,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
None => return,
}
} else {
- &body.value
+ body.value
};
lint_implicit_returns(cx, expr, expr.span.ctxt(), None);
}
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
new file mode 100644
index 000000000..bf1351829
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
@@ -0,0 +1,114 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::get_parent_expr;
+use clippy_utils::source::snippet_with_applicability;
+use if_chain::if_chain;
+use rustc_ast::ast::{LitIntType, LitKind};
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{Int, IntTy, Ty, Uint, UintTy};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for implicit saturating addition.
+ ///
+ /// ### Why is this bad?
+ /// The built-in function is more readable and may be faster.
+ ///
+ /// ### Example
+ /// ```rust
+ ///let mut u:u32 = 7000;
+ ///
+ /// if u != u32::MAX {
+ /// u += 1;
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ ///let mut u:u32 = 7000;
+ ///
+ /// u = u.saturating_add(1);
+ /// ```
+ #[clippy::version = "1.65.0"]
+ pub IMPLICIT_SATURATING_ADD,
+ style,
+ "Perform saturating addition instead of implicitly checking max bound of data type"
+}
+declare_lint_pass!(ImplicitSaturatingAdd => [IMPLICIT_SATURATING_ADD]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+ if_chain! {
+ if let ExprKind::If(cond, then, None) = expr.kind;
+ if let ExprKind::DropTemps(expr1) = cond.kind;
+ if let Some((c, op_node, l)) = get_const(cx, expr1);
+ if let BinOpKind::Ne | BinOpKind::Lt = op_node;
+ if let ExprKind::Block(block, None) = then.kind;
+ if let Block {
+ stmts:
+ [Stmt
+ { kind: StmtKind::Expr(ex) | StmtKind::Semi(ex), .. }],
+ expr: None, ..} |
+ Block { stmts: [], expr: Some(ex), ..} = block;
+ if let ExprKind::AssignOp(op1, target, value) = ex.kind;
+ let ty = cx.typeck_results().expr_ty(target);
+ if Some(c) == get_int_max(ty);
+ if clippy_utils::SpanlessEq::new(cx).eq_expr(l, target);
+ if BinOpKind::Add == op1.node;
+ if let ExprKind::Lit(ref lit) = value.kind;
+ if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
+ if block.expr.is_none();
+ then {
+ let mut app = Applicability::MachineApplicable;
+ let code = snippet_with_applicability(cx, target.span, "_", &mut app);
+ let sugg = if let Some(parent) = get_parent_expr(cx, expr) && let ExprKind::If(_cond, _then, Some(else_)) = parent.kind && else_.hir_id == expr.hir_id {format!("{{{code} = {code}.saturating_add(1); }}")} else {format!("{code} = {code}.saturating_add(1);")};
+ span_lint_and_sugg(cx, IMPLICIT_SATURATING_ADD, expr.span, "manual saturating add detected", "use instead", sugg, app);
+ }
+ }
+ }
+}
+
+fn get_int_max(ty: Ty<'_>) -> Option<u128> {
+ match ty.peel_refs().kind() {
+ Int(IntTy::I8) => i8::max_value().try_into().ok(),
+ Int(IntTy::I16) => i16::max_value().try_into().ok(),
+ Int(IntTy::I32) => i32::max_value().try_into().ok(),
+ Int(IntTy::I64) => i64::max_value().try_into().ok(),
+ Int(IntTy::I128) => i128::max_value().try_into().ok(),
+ Int(IntTy::Isize) => isize::max_value().try_into().ok(),
+ Uint(UintTy::U8) => u8::max_value().try_into().ok(),
+ Uint(UintTy::U16) => u16::max_value().try_into().ok(),
+ Uint(UintTy::U32) => u32::max_value().try_into().ok(),
+ Uint(UintTy::U64) => u64::max_value().try_into().ok(),
+ Uint(UintTy::U128) => Some(u128::max_value()),
+ Uint(UintTy::Usize) => usize::max_value().try_into().ok(),
+ _ => None,
+ }
+}
+
+fn get_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(u128, BinOpKind, &'tcx Expr<'tcx>)> {
+ if let ExprKind::Binary(op, l, r) = expr.kind {
+ let tr = cx.typeck_results();
+ if let Some((Constant::Int(c), _)) = constant(cx, tr, r) {
+ return Some((c, op.node, l));
+ };
+ if let Some((Constant::Int(c), _)) = constant(cx, tr, l) {
+ return Some((c, invert_op(op.node)?, r));
+ }
+ }
+ None
+}
+
+fn invert_op(op: BinOpKind) -> Option<BinOpKind> {
+ use rustc_hir::BinOpKind::{Ge, Gt, Le, Lt, Ne};
+ match op {
+ Lt => Some(Gt),
+ Le => Some(Ge),
+ Ne => Some(Ne),
+ Ge => Some(Le),
+ Gt => Some(Lt),
+ _ => None,
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index 46654bc61..29d59c26d 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{higher, peel_blocks_with_stmt, SpanlessEq};
+use clippy_utils::{higher, is_integer_literal, peel_blocks_with_stmt, SpanlessEq};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
@@ -35,7 +35,7 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "1.44.0"]
pub IMPLICIT_SATURATING_SUB,
- pedantic,
+ style,
"Perform saturating subtraction instead of implicitly checking lower bound of data type"
}
@@ -131,17 +131,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
match peel_blocks_with_stmt(expr).kind {
ExprKind::AssignOp(ref op1, target, value) => {
- if_chain! {
- if BinOpKind::Sub == op1.node;
- // Check if literal being subtracted is one
- if let ExprKind::Lit(ref lit1) = value.kind;
- if let LitKind::Int(1, _) = lit1.node;
- then {
- Some(target)
- } else {
- None
- }
- }
+ // Check if literal being subtracted is one
+ (BinOpKind::Sub == op1.node && is_integer_literal(value, 1)).then_some(target)
},
ExprKind::Assign(target, value, _) => {
if_chain! {
@@ -150,8 +141,7 @@ fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Exp
if SpanlessEq::new(cx).eq_expr(left1, target);
- if let ExprKind::Lit(ref lit1) = right1.kind;
- if let LitKind::Int(1, _) = lit1.node;
+ if is_integer_literal(right1, 1);
then {
Some(target)
} else {
@@ -170,7 +160,7 @@ fn print_lint_and_sugg(cx: &LateContext<'_>, var_name: &str, expr: &Expr<'_>) {
expr.span,
"implicitly performing saturating subtraction",
"try",
- format!("{} = {}.saturating_sub({});", var_name, var_name, '1'),
+ format!("{var_name} = {var_name}.saturating_sub({});", '1'),
Applicability::MachineApplicable,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
index 14b22d2b5..e2f2d3d42 100644
--- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
let mut fields_snippet = String::new();
let (last_ident, idents) = ordered_fields.split_last().unwrap();
for ident in idents {
- let _ = write!(fields_snippet, "{}, ", ident);
+ let _ = write!(fields_snippet, "{ident}, ");
}
fields_snippet.push_str(&last_ident.to_string());
@@ -100,10 +100,8 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
String::new()
};
- let sugg = format!("{} {{ {}{} }}",
+ let sugg = format!("{} {{ {fields_snippet}{base_snippet} }}",
snippet(cx, qpath.span(), ".."),
- fields_snippet,
- base_snippet,
);
span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index d0c6495e3..c7b5badaa 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -95,12 +95,14 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir
let mut removed_pat: FxHashSet<hir::HirId> = FxHashSet::default();
let mut slices: FxIndexMap<hir::HirId, SliceLintInformation> = FxIndexMap::default();
pat.walk_always(|pat| {
- if let hir::PatKind::Binding(binding, value_hir_id, ident, sub_pat) = pat.kind {
- // We'll just ignore mut and ref mut for simplicity sake right now
- if let hir::BindingAnnotation::Mutable | hir::BindingAnnotation::RefMut = binding {
- return;
- }
-
+ // We'll just ignore mut and ref mut for simplicity sake right now
+ if let hir::PatKind::Binding(
+ hir::BindingAnnotation(by_ref, hir::Mutability::Not),
+ value_hir_id,
+ ident,
+ sub_pat,
+ ) = pat.kind
+ {
// This block catches bindings with sub patterns. It would be hard to build a correct suggestion
// for them and it's likely that the user knows what they are doing in such a case.
if removed_pat.contains(&value_hir_id) {
@@ -116,7 +118,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir
if let ty::Slice(inner_ty) | ty::Array(inner_ty, _) = bound_ty.peel_refs().kind() {
// The values need to use the `ref` keyword if they can't be copied.
// This will need to be adjusted if the lint want to support mutable access in the future
- let src_is_ref = bound_ty.is_ref() && binding != hir::BindingAnnotation::Ref;
+ let src_is_ref = bound_ty.is_ref() && by_ref != hir::ByRef::Yes;
let needs_ref = !(src_is_ref || is_copy(cx, *inner_ty));
let slice_info = slices
@@ -137,14 +139,14 @@ fn lint_slice(cx: &LateContext<'_>, slice: &SliceLintInformation) {
.map(|(index, _)| *index)
.collect::<FxHashSet<_>>();
- let value_name = |index| format!("{}_{}", slice.ident.name, index);
+ let value_name = |index| format!("{}_{index}", slice.ident.name);
if let Some(max_index) = used_indices.iter().max() {
let opt_ref = if slice.needs_ref { "ref " } else { "" };
let pat_sugg_idents = (0..=*max_index)
.map(|index| {
if used_indices.contains(&index) {
- format!("{}{}", opt_ref, value_name(index))
+ format!("{opt_ref}{}", value_name(index))
} else {
"_".to_string()
}
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index 4a375752e..af40a5a81 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -19,7 +19,6 @@ declare_clippy_lint! {
///
/// ### Example
/// ```rust,no_run
- /// # #![allow(const_err)]
/// let x = [1, 2, 3, 4];
///
/// x[9];
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index 01c7eef4e..d1d2db27c 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint;
+use clippy_utils::higher;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{higher, match_def_path, path_def_id, paths};
use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -123,54 +123,61 @@ use self::Heuristic::{All, Always, Any, First};
/// is an upper bound, e.g., some methods can return a possibly
/// infinite iterator at worst, e.g., `take_while`.
const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [
- ("zip", 2, All, Infinite),
- ("chain", 2, Any, Infinite),
- ("cycle", 1, Always, Infinite),
- ("map", 2, First, Infinite),
- ("by_ref", 1, First, Infinite),
- ("cloned", 1, First, Infinite),
- ("rev", 1, First, Infinite),
- ("inspect", 1, First, Infinite),
- ("enumerate", 1, First, Infinite),
- ("peekable", 2, First, Infinite),
- ("fuse", 1, First, Infinite),
- ("skip", 2, First, Infinite),
- ("skip_while", 1, First, Infinite),
- ("filter", 2, First, Infinite),
- ("filter_map", 2, First, Infinite),
- ("flat_map", 2, First, Infinite),
- ("unzip", 1, First, Infinite),
- ("take_while", 2, First, MaybeInfinite),
- ("scan", 3, First, MaybeInfinite),
+ ("zip", 1, All, Infinite),
+ ("chain", 1, Any, Infinite),
+ ("cycle", 0, Always, Infinite),
+ ("map", 1, First, Infinite),
+ ("by_ref", 0, First, Infinite),
+ ("cloned", 0, First, Infinite),
+ ("rev", 0, First, Infinite),
+ ("inspect", 0, First, Infinite),
+ ("enumerate", 0, First, Infinite),
+ ("peekable", 1, First, Infinite),
+ ("fuse", 0, First, Infinite),
+ ("skip", 1, First, Infinite),
+ ("skip_while", 0, First, Infinite),
+ ("filter", 1, First, Infinite),
+ ("filter_map", 1, First, Infinite),
+ ("flat_map", 1, First, Infinite),
+ ("unzip", 0, First, Infinite),
+ ("take_while", 1, First, MaybeInfinite),
+ ("scan", 2, First, MaybeInfinite),
];
fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
match expr.kind {
- ExprKind::MethodCall(method, args, _) => {
+ ExprKind::MethodCall(method, receiver, args, _) => {
for &(name, len, heuristic, cap) in &HEURISTICS {
if method.ident.name.as_str() == name && args.len() == len {
return (match heuristic {
Always => Infinite,
- First => is_infinite(cx, &args[0]),
- Any => is_infinite(cx, &args[0]).or(is_infinite(cx, &args[1])),
- All => is_infinite(cx, &args[0]).and(is_infinite(cx, &args[1])),
+ First => is_infinite(cx, receiver),
+ Any => is_infinite(cx, receiver).or(is_infinite(cx, &args[0])),
+ All => is_infinite(cx, receiver).and(is_infinite(cx, &args[0])),
})
.and(cap);
}
}
- if method.ident.name == sym!(flat_map) && args.len() == 2 {
- if let ExprKind::Closure(&Closure { body, .. }) = args[1].kind {
+ if method.ident.name == sym!(flat_map) && args.len() == 1 {
+ if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind {
let body = cx.tcx.hir().body(body);
- return is_infinite(cx, &body.value);
+ return is_infinite(cx, body.value);
}
}
Finite
},
ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)),
ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e),
- ExprKind::Call(path, _) => path_def_id(cx, path)
- .map_or(false, |id| match_def_path(cx, id, &paths::ITER_REPEAT))
- .into(),
+ ExprKind::Call(path, _) => {
+ if let ExprKind::Path(ref qpath) = path.kind {
+ cx.qpath_res(qpath, path.hir_id)
+ .opt_def_id()
+ .map_or(false, |id| cx.tcx.is_diagnostic_item(sym::iter_repeat, id))
+ .into()
+ } else {
+ Finite
+ }
+ },
ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(),
_ => Finite,
}
@@ -179,29 +186,29 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
/// the names and argument lengths of methods that *may* exhaust their
/// iterators
const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [
- ("find", 2),
- ("rfind", 2),
- ("position", 2),
- ("rposition", 2),
- ("any", 2),
- ("all", 2),
+ ("find", 1),
+ ("rfind", 1),
+ ("position", 1),
+ ("rposition", 1),
+ ("any", 1),
+ ("all", 1),
];
/// the names and argument lengths of methods that *always* exhaust
/// their iterators
const COMPLETING_METHODS: [(&str, usize); 12] = [
- ("count", 1),
- ("fold", 3),
- ("for_each", 2),
- ("partition", 2),
- ("max", 1),
- ("max_by", 2),
- ("max_by_key", 2),
- ("min", 1),
- ("min_by", 2),
- ("min_by_key", 2),
- ("sum", 1),
- ("product", 1),
+ ("count", 0),
+ ("fold", 2),
+ ("for_each", 1),
+ ("partition", 1),
+ ("max", 0),
+ ("max_by", 1),
+ ("max_by_key", 1),
+ ("min", 0),
+ ("min_by", 1),
+ ("min_by_key", 1),
+ ("sum", 0),
+ ("product", 0),
];
/// the paths of types that are known to be infinitely allocating
@@ -218,26 +225,26 @@ const INFINITE_COLLECTORS: &[Symbol] = &[
fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
match expr.kind {
- ExprKind::MethodCall(method, args, _) => {
+ ExprKind::MethodCall(method, receiver, args, _) => {
for &(name, len) in &COMPLETING_METHODS {
if method.ident.name.as_str() == name && args.len() == len {
- return is_infinite(cx, &args[0]);
+ return is_infinite(cx, receiver);
}
}
for &(name, len) in &POSSIBLY_COMPLETING_METHODS {
if method.ident.name.as_str() == name && args.len() == len {
- return MaybeInfinite.and(is_infinite(cx, &args[0]));
+ return MaybeInfinite.and(is_infinite(cx, receiver));
}
}
- if method.ident.name == sym!(last) && args.len() == 1 {
+ if method.ident.name == sym!(last) && args.is_empty() {
let not_double_ended = cx
.tcx
.get_diagnostic_item(sym::DoubleEndedIterator)
.map_or(false, |id| {
- !implements_trait(cx, cx.typeck_results().expr_ty(&args[0]), id, &[])
+ !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[])
});
if not_double_ended {
- return is_infinite(cx, &args[0]);
+ return is_infinite(cx, receiver);
}
} else if method.ident.name == sym!(collect) {
let ty = cx.typeck_results().expr_ty(expr);
@@ -245,7 +252,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
.iter()
.any(|diag_item| is_type_diagnostic_item(cx, ty, *diag_item))
{
- return is_infinite(cx, &args[0]);
+ return is_infinite(cx, receiver);
}
}
},
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index 17d867aac..14a37f535 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{get_trait_def_id, paths, return_ty, trait_ref_of_method};
+use clippy_utils::{return_ty, trait_ref_of_method};
use if_chain::if_chain;
use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::String);
// Filters instances of to_string which are required by a trait
- if trait_ref_of_method(cx, impl_item.def_id).is_none();
+ if trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none();
then {
show_lint(cx, impl_item);
@@ -118,10 +118,13 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
}
fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) {
- let display_trait_id = get_trait_def_id(cx, &paths::DISPLAY_TRAIT).expect("Failed to get trait ID of `Display`!");
+ let display_trait_id = cx
+ .tcx
+ .get_diagnostic_item(sym::Display)
+ .expect("Failed to get trait ID of `Display`!");
// Get the real type of 'self'
- let self_type = cx.tcx.fn_sig(item.def_id).input(0);
+ let self_type = cx.tcx.fn_sig(item.owner_id).input(0);
let self_type = self_type.skip_binder().peel_refs();
// Emit either a warning or an error
@@ -131,23 +134,19 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) {
INHERENT_TO_STRING_SHADOW_DISPLAY,
item.span,
&format!(
- "type `{}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`",
- self_type
+ "type `{self_type}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`"
),
None,
- &format!("remove the inherent method from type `{}`", self_type),
+ &format!("remove the inherent method from type `{self_type}`"),
);
} else {
span_lint_and_help(
cx,
INHERENT_TO_STRING,
item.span,
- &format!(
- "implementation of inherent method `to_string(&self) -> String` for type `{}`",
- self_type
- ),
+ &format!("implementation of inherent method `to_string(&self) -> String` for type `{self_type}`"),
None,
- &format!("implement trait `Display` for type `{}` instead", self_type),
+ &format!("implement trait `Display` for type `{self_type}` instead"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
index dd7177e01..d609a5ca4 100644
--- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
+++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
@@ -51,7 +51,7 @@ fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) {
cx,
INLINE_FN_WITHOUT_BODY,
attr.span,
- &format!("use of `#[inline]` on trait method `{}` which has no body", name),
+ &format!("use of `#[inline]` on trait method `{name}` which has no body"),
|diag| {
diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
},
diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
index 9a944def3..33491da3f 100644
--- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs
+++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
@@ -138,8 +138,8 @@ impl IntPlusOne {
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)),
+ Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")),
+ Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")),
};
return rec;
}
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
index 36e03e50a..0ef77e03d 100644
--- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -145,9 +145,7 @@ 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 {
+ let Some((rel, normalized_lhs, normalized_rhs)) = normalized else {
return;
};
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index b56d87c53..e76de77f1 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
let name = item.ident.name.as_str();
if matches!(name, "iter" | "iter_mut") {
if let TraitItemKind::Fn(fn_sig, _) = &item.kind {
- check_sig(cx, name, fn_sig, item.def_id);
+ check_sig(cx, name, fn_sig, item.owner_id.def_id);
}
}
}
@@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
)
{
if let ImplItemKind::Fn(fn_sig, _) = &item.kind {
- check_sig(cx, name, fn_sig, item.def_id);
+ check_sig(cx, name, fn_sig, item.owner_id.def_id);
}
}
}
@@ -80,10 +80,7 @@ fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefI
cx,
ITER_NOT_RETURNING_ITERATOR,
sig.span,
- &format!(
- "this method is named `{}` but its return type does not implement `Iterator`",
- name
- ),
+ &format!("this method is named `{name}` but its return type does not implement `Iterator`"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index 984c5cd4e..76c83ab47 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -2,12 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_then;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind};
+use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, ConstKind};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{BytePos, Pos, Span};
-use rustc_typeck::hir_ty_to_ty;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index c58df126d..06e957285 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -1,13 +1,12 @@
//! lint when there is a large size difference between variants on an enum
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{diagnostics::span_lint_and_then, ty::is_copy};
+use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size, ty::is_copy};
use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{Adt, Ty};
+use rustc_middle::ty::{Adt, AdtDef, GenericArg, List, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
@@ -17,7 +16,7 @@ declare_clippy_lint! {
/// `enum`s.
///
/// ### Why is this bad?
- /// Enum size is bounded by the largest variant. Having a
+ /// Enum size is bounded by the largest variant. Having one
/// large variant can penalize the memory layout of that enum.
///
/// ### Known problems
@@ -33,8 +32,9 @@ declare_clippy_lint! {
/// use case it may be possible to store the large data in an auxiliary
/// structure (e.g. Arena or ECS).
///
- /// The lint will ignore generic types if the layout depends on the
- /// generics, even if the size difference will be large anyway.
+ /// The lint will ignore the impact of generic types to the type layout by
+ /// assuming every type parameter is zero-sized. Depending on your use case,
+ /// this may lead to a false positive.
///
/// ### Example
/// ```rust
@@ -83,6 +83,38 @@ struct VariantInfo {
fields_size: Vec<FieldInfo>,
}
+fn variants_size<'tcx>(
+ cx: &LateContext<'tcx>,
+ adt: AdtDef<'tcx>,
+ subst: &'tcx List<GenericArg<'tcx>>,
+) -> Vec<VariantInfo> {
+ let mut variants_size = adt
+ .variants()
+ .iter()
+ .enumerate()
+ .map(|(i, variant)| {
+ let mut fields_size = variant
+ .fields
+ .iter()
+ .enumerate()
+ .map(|(i, f)| FieldInfo {
+ ind: i,
+ size: approx_ty_size(cx, f.ty(cx.tcx, subst)),
+ })
+ .collect::<Vec<_>>();
+ fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
+
+ VariantInfo {
+ ind: i,
+ size: fields_size.iter().map(|info| info.size).sum(),
+ fields_size,
+ }
+ })
+ .collect::<Vec<_>>();
+ variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
+ variants_size
+}
+
impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
@@ -91,37 +123,14 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
return;
}
if let ItemKind::Enum(ref def, _) = item.kind {
- let ty = cx.tcx.type_of(item.def_id);
- let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
+ let ty = cx.tcx.type_of(item.owner_id);
+ let Adt(adt, subst) = ty.kind() else {
+ panic!("already checked whether this is an enum")
+ };
if adt.variants().len() <= 1 {
return;
}
- let mut variants_size: Vec<VariantInfo> = Vec::new();
- for (i, variant) in adt.variants().iter().enumerate() {
- let mut fields_size = Vec::new();
- for (i, f) in variant.fields.iter().enumerate() {
- let ty = cx.tcx.type_of(f.did);
- // don't lint variants which have a field of generic type.
- match cx.layout_of(ty) {
- Ok(l) => {
- let fsize = l.size.bytes();
- fields_size.push(FieldInfo { ind: i, size: fsize });
- },
- Err(_) => {
- return;
- },
- }
- }
- let size: u64 = fields_size.iter().map(|info| info.size).sum();
-
- variants_size.push(VariantInfo {
- ind: i,
- size,
- fields_size,
- });
- }
-
- variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
+ let variants_size = variants_size(cx, *adt, subst);
let mut difference = variants_size[0].size - variants_size[1].size;
if difference > self.maximum_size_difference_allowed {
@@ -129,20 +138,30 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
span_lint_and_then(
cx,
LARGE_ENUM_VARIANT,
- def.variants[variants_size[0].ind].span,
+ item.span,
"large size difference between variants",
|diag| {
diag.span_label(
+ item.span,
+ format!("the entire enum is at least {} bytes", approx_ty_size(cx, ty)),
+ );
+ diag.span_label(
def.variants[variants_size[0].ind].span,
- &format!("this variant is {} bytes", variants_size[0].size),
+ format!("the largest variant contains at least {} bytes", variants_size[0].size),
);
- diag.span_note(
+ diag.span_label(
def.variants[variants_size[1].ind].span,
- &format!("and the second-largest variant is {} bytes:", variants_size[1].size),
+ &if variants_size[1].fields_size.is_empty() {
+ "the second-largest variant carries no data at all".to_owned()
+ } else {
+ format!(
+ "the second-largest variant contains at least {} bytes",
+ variants_size[1].size
+ )
+ },
);
let fields = def.variants[variants_size[0].ind].data.fields();
- variants_size[0].fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
let mut applicability = Applicability::MaybeIncorrect;
if is_copy(cx, ty) || maybe_copy(cx, ty) {
diag.span_note(
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
index 0acbd81ae..5857d81ab 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet;
-use if_chain::if_chain;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, ConstKind};
@@ -39,29 +38,28 @@ impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]);
impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- if_chain! {
- if let ExprKind::Repeat(_, _) = expr.kind;
- if let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind();
- if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind();
- if let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx);
- if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes());
- if self.maximum_allowed_size < element_count * element_size;
- then {
- span_lint_and_help(
- cx,
- LARGE_STACK_ARRAYS,
- expr.span,
- &format!(
- "allocating a local array larger than {} bytes",
- self.maximum_allowed_size
- ),
- None,
- &format!(
- "consider allocating on the heap with `vec!{}.into_boxed_slice()`",
- snippet(cx, expr.span, "[...]")
- ),
- );
- }
- }
+ if let ExprKind::Repeat(_, _) = expr.kind
+ && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind()
+ && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind()
+ && let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx)
+ && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
+ && !cx.tcx.hir().parent_iter(expr.hir_id)
+ .any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. })))
+ && self.maximum_allowed_size < element_count * element_size {
+ span_lint_and_help(
+ cx,
+ LARGE_STACK_ARRAYS,
+ expr.span,
+ &format!(
+ "allocating a local array larger than {} bytes",
+ self.maximum_allowed_size
+ ),
+ None,
+ &format!(
+ "consider allocating on the heap with `vec!{}.into_boxed_slice()`",
+ snippet(cx, expr.span, "[...]")
+ ),
+ );
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 246f5aad8..b0cba40c2 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -134,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
if item.ident.name == sym::len;
if let ImplItemKind::Fn(sig, _) = &item.kind;
if sig.decl.implicit_self.has_implicit_self();
- if cx.access_levels.is_exported(item.def_id);
+ if cx.effective_visibilities.is_exported(item.owner_id.def_id);
if matches!(sig.decl.output, FnRetTy::Return(_));
if let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id());
if imp.of_trait.is_none();
@@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
if let Some(local_id) = ty_id.as_local();
let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
if !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id);
- if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.def_id).skip_binder());
+ if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).skip_binder());
then {
let (name, kind) = match cx.tcx.hir().find(ty_hir_id) {
Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"),
@@ -195,7 +195,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool {
item.ident.name == name
&& if let AssocItemKind::Fn { has_self } = item.kind {
- has_self && { cx.tcx.fn_sig(item.id.def_id).inputs().skip_binder().len() == 1 }
+ has_self && { cx.tcx.fn_sig(item.id.owner_id).inputs().skip_binder().len() == 1 }
} else {
false
}
@@ -210,10 +210,11 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
}
}
- if cx.access_levels.is_exported(visited_trait.def_id) && trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
+ if cx.effective_visibilities.is_exported(visited_trait.owner_id.def_id)
+ && trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
{
let mut current_and_super_traits = DefIdSet::default();
- fill_trait_set(visited_trait.def_id.to_def_id(), &mut current_and_super_traits, cx);
+ fill_trait_set(visited_trait.owner_id.to_def_id(), &mut current_and_super_traits, cx);
let is_empty = sym!(is_empty);
let is_empty_method_found = current_and_super_traits
@@ -278,15 +279,13 @@ impl<'tcx> LenOutput<'tcx> {
_ => "",
};
match self {
- Self::Integral => format!("expected signature: `({}self) -> bool`", self_ref),
- Self::Option(_) => format!(
- "expected signature: `({}self) -> bool` or `({}self) -> Option<bool>",
- self_ref, self_ref
- ),
- Self::Result(..) => format!(
- "expected signature: `({}self) -> bool` or `({}self) -> Result<bool>",
- self_ref, self_ref
- ),
+ Self::Integral => format!("expected signature: `({self_ref}self) -> bool`"),
+ Self::Option(_) => {
+ format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Option<bool>")
+ },
+ Self::Result(..) => {
+ format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Result<bool>")
+ },
}
}
}
@@ -326,17 +325,15 @@ fn check_for_is_empty<'tcx>(
let (msg, is_empty_span, self_kind) = match is_empty {
None => (
format!(
- "{} `{}` has a public `len` method, but no `is_empty` method",
- item_kind,
+ "{item_kind} `{}` has a public `len` method, but no `is_empty` method",
item_name.as_str(),
),
None,
None,
),
- Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => (
+ Some(is_empty) if !cx.effective_visibilities.is_exported(is_empty.def_id.expect_local()) => (
format!(
- "{} `{}` has a public `len` method, but a private `is_empty` method",
- item_kind,
+ "{item_kind} `{}` has a public `len` method, but a private `is_empty` method",
item_name.as_str(),
),
Some(cx.tcx.def_span(is_empty.def_id)),
@@ -348,8 +345,7 @@ fn check_for_is_empty<'tcx>(
{
(
format!(
- "{} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature",
- item_kind,
+ "{item_kind} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature",
item_name.as_str(),
),
Some(cx.tcx.def_span(is_empty.def_id)),
@@ -370,7 +366,8 @@ fn check_for_is_empty<'tcx>(
}
fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
- if let (&ExprKind::MethodCall(method_path, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
+ if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind)
+ {
// check if we are in an is_empty() method
if let Some(name) = get_item_name(cx, method) {
if name.as_str() == "is_empty" {
@@ -378,16 +375,28 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
}
}
- check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to);
+ check_len(
+ cx,
+ span,
+ method_path.ident.name,
+ receiver,
+ args,
+ &lit.node,
+ op,
+ compare_to,
+ );
} else {
check_empty_expr(cx, span, method, lit, op);
}
}
+// FIXME(flip1995): Figure out how to reduce the number of arguments
+#[allow(clippy::too_many_arguments)]
fn check_len(
cx: &LateContext<'_>,
span: Span,
method_name: Symbol,
+ receiver: &Expr<'_>,
args: &[Expr<'_>],
lit: &LitKind,
op: &str,
@@ -399,18 +408,17 @@ fn check_len(
return;
}
- if method_name == sym::len && args.len() == 1 && has_is_empty(cx, &args[0]) {
+ if method_name == sym::len && args.is_empty() && has_is_empty(cx, receiver) {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
LEN_ZERO,
span,
&format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
- &format!("using `{}is_empty` is clearer and more explicit", op),
+ &format!("using `{op}is_empty` is clearer and more explicit"),
format!(
- "{}{}.is_empty()",
- op,
- snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
+ "{op}{}.is_empty()",
+ snippet_with_applicability(cx, receiver.span, "_", &mut applicability)
),
applicability,
);
@@ -426,10 +434,9 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex
COMPARISON_TO_EMPTY,
span,
"comparison to empty slice",
- &format!("using `{}is_empty` is clearer and more explicit", op),
+ &format!("using `{op}is_empty` is clearer and more explicit"),
format!(
- "{}{}.is_empty()",
- op,
+ "{op}{}.is_empty()",
snippet_with_applicability(cx, lit1.span, "_", &mut applicability)
),
applicability,
diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
index 56bbbbbc8..db41bc67d 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -4,7 +4,7 @@ use clippy_utils::{path_to_local_id, visitors::is_local_used};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
-use rustc_hir::BindingAnnotation;
+use rustc_hir::{BindingAnnotation, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
let span = stmt.span.to(if_.span);
let has_interior_mutability = !cx.typeck_results().node_type(canonical_id).is_freeze(
- cx.tcx.at(span),
+ cx.tcx,
cx.param_env,
);
if has_interior_mutability { return; }
@@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
};
let mutability = match mode {
- BindingAnnotation::RefMut | BindingAnnotation::Mutable => "<mut> ",
+ BindingAnnotation(_, Mutability::Mut) => "<mut> ",
_ => "",
};
@@ -106,8 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
// use mutably after the `if`
let sug = format!(
- "let {mut}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};",
- mut=mutability,
+ "let {mutability}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};",
name=ident.name,
cond=snippet(cx, cond.span, "_"),
then=if then.stmts.len() > 1 { " ..;" } else { "" },
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 176787497..b7798b1c1 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::{is_must_use_ty, match_type};
+use clippy_utils::ty::{is_must_use_ty, is_type_diagnostic_item, match_type};
use clippy_utils::{is_must_use_func_call, paths};
use if_chain::if_chain;
use rustc_hir::{Local, PatKind};
@@ -7,6 +7,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, Symbol};
declare_clippy_lint! {
/// ### What it does
@@ -99,10 +100,9 @@ declare_clippy_lint! {
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]);
-const SYNC_GUARD_PATHS: [&[&str]; 6] = [
- &paths::MUTEX_GUARD,
- &paths::RWLOCK_READ_GUARD,
- &paths::RWLOCK_WRITE_GUARD,
+const SYNC_GUARD_SYMS: [Symbol; 3] = [sym::MutexGuard, sym::RwLockReadGuard, sym::RwLockWriteGuard];
+
+const SYNC_GUARD_PATHS: [&[&str]; 3] = [
&paths::PARKING_LOT_MUTEX_GUARD,
&paths::PARKING_LOT_RWLOCK_READ_GUARD,
&paths::PARKING_LOT_RWLOCK_WRITE_GUARD,
@@ -121,7 +121,10 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
let init_ty = cx.typeck_results().expr_ty(init);
let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
GenericArgKind::Type(inner_ty) => {
- SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path))
+ SYNC_GUARD_SYMS
+ .iter()
+ .any(|&sym| is_type_diagnostic_item(cx, inner_ty, sym))
+ || SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path))
},
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
@@ -134,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
"non-binding let on a synchronization lock",
None,
"consider using an underscore-prefixed named \
- binding or dropping explicitly with `std::mem::drop`"
+ binding or dropping explicitly with `std::mem::drop`",
);
} else if init_ty.needs_drop(cx.tcx, cx.param_env) {
span_lint_and_help(
@@ -144,7 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
"non-binding `let` on a type that implements `Drop`",
None,
"consider using an underscore-prefixed named \
- binding or dropping explicitly with `std::mem::drop`"
+ binding or dropping explicitly with `std::mem::drop`",
);
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
span_lint_and_help(
@@ -153,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
local.span,
"non-binding let on an expression with `#[must_use]` type",
None,
- "consider explicitly using expression value"
+ "consider explicitly using expression value",
);
} else if is_must_use_func_call(cx, init) {
span_lint_and_help(
@@ -162,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
local.span,
"non-binding let on a result of a `#[must_use]` function",
None,
- "consider explicitly using function result"
+ "consider explicitly using function result",
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
index 763dd2a40..c455e1561 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
@@ -15,18 +15,20 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE),
LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
- 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(bool_to_int_with_if::BOOL_TO_INT_WITH_IF),
LintId::of(booleans::NONMINIMAL_BOOL),
+ LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
- LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN),
+ LintId::of(box_default::BOX_DEFAULT),
LintId::of(casts::CAST_ABS_TO_UNSIGNED),
LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
LintId::of(casts::CAST_ENUM_TRUNCATION),
+ LintId::of(casts::CAST_NAN_TO_INT),
LintId::of(casts::CAST_REF_TO_MUT),
LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
+ LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
LintId::of(casts::CHAR_LIT_AS_U8),
LintId::of(casts::FN_TO_NUMERIC_CAST),
LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
@@ -39,12 +41,14 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
+ LintId::of(dereference::EXPLICIT_AUTO_DEREF),
LintId::of(dereference::NEEDLESS_BORROW),
LintId::of(derivable_impls::DERIVABLE_IMPLS),
LintId::of(derive::DERIVE_HASH_XOR_EQ),
LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
- LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
+ LintId::of(disallowed_macros::DISALLOWED_MACROS),
LintId::of(disallowed_methods::DISALLOWED_METHODS),
+ LintId::of(disallowed_names::DISALLOWED_NAMES),
LintId::of(disallowed_types::DISALLOWED_TYPES),
LintId::of(doc::MISSING_SAFETY_DOC),
LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
@@ -68,6 +72,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(format::USELESS_FORMAT),
LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
+ LintId::of(format_args::UNUSED_FORMAT_SPECS),
LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
LintId::of(format_impl::RECURSIVE_FORMAT_IMPL),
LintId::of(formatting::POSSIBLE_MISSING_COMMA),
@@ -79,10 +84,12 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(functions::DOUBLE_MUST_USE),
LintId::of(functions::MUST_USE_UNIT),
LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
+ LintId::of(functions::RESULT_LARGE_ERR),
LintId::of(functions::RESULT_UNIT_ERR),
LintId::of(functions::TOO_MANY_ARGUMENTS),
- LintId::of(get_first::GET_FIRST),
LintId::of(if_let_mutex::IF_LET_MUTEX),
+ LintId::of(implicit_saturating_add::IMPLICIT_SATURATING_ADD),
+ LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
LintId::of(infinite_iter::INFINITE_ITER),
LintId::of(inherent_to_string::INHERENT_TO_STRING),
@@ -105,7 +112,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
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_FIND),
LintId::of(loops::MANUAL_FLATTEN),
@@ -123,16 +129,17 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(main_recursion::MAIN_RECURSION),
LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
LintId::of(manual_bits::MANUAL_BITS),
+ LintId::of(manual_clamp::MANUAL_CLAMP),
LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID),
LintId::of(manual_retain::MANUAL_RETAIN),
LintId::of(manual_strip::MANUAL_STRIP),
- LintId::of(map_clone::MAP_CLONE),
LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
LintId::of(match_result_ok::MATCH_RESULT_OK),
LintId::of(matches::COLLAPSIBLE_MATCH),
LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
+ LintId::of(matches::MANUAL_FILTER),
LintId::of(matches::MANUAL_MAP),
LintId::of(matches::MANUAL_UNWRAP_OR),
LintId::of(matches::MATCH_AS_REF),
@@ -149,17 +156,20 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
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_COUNT_TO_LEN),
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::COLLAPSIBLE_STR_REPLACE),
LintId::of(methods::ERR_EXPECT),
LintId::of(methods::EXPECT_FUN_CALL),
LintId::of(methods::EXTEND_WITH_DRAIN),
LintId::of(methods::FILTER_MAP_IDENTITY),
LintId::of(methods::FILTER_NEXT),
LintId::of(methods::FLAT_MAP_IDENTITY),
+ LintId::of(methods::GET_FIRST),
LintId::of(methods::GET_LAST_WITH_LEN),
LintId::of(methods::INSPECT_FOR_EACH),
LintId::of(methods::INTO_ITER_ON_REF),
@@ -167,6 +177,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(methods::ITERATOR_STEP_BY_ZERO),
LintId::of(methods::ITER_CLONED_COLLECT),
LintId::of(methods::ITER_COUNT),
+ LintId::of(methods::ITER_KV_MAP),
LintId::of(methods::ITER_NEXT_SLICE),
LintId::of(methods::ITER_NTH),
LintId::of(methods::ITER_NTH_ZERO),
@@ -177,13 +188,16 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
LintId::of(methods::MANUAL_SPLIT_ONCE),
LintId::of(methods::MANUAL_STR_REPEAT),
+ LintId::of(methods::MAP_CLONE),
LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
LintId::of(methods::MAP_FLATTEN),
LintId::of(methods::MAP_IDENTITY),
+ LintId::of(methods::MUT_MUTEX_LOCK),
LintId::of(methods::NEEDLESS_OPTION_AS_DEREF),
LintId::of(methods::NEEDLESS_OPTION_TAKE),
LintId::of(methods::NEEDLESS_SPLITN),
LintId::of(methods::NEW_RET_NO_SELF),
+ LintId::of(methods::NONSENSICAL_OPEN_OPTIONS),
LintId::of(methods::NO_EFFECT_REPLACE),
LintId::of(methods::OBFUSCATED_IF_ELSE),
LintId::of(methods::OK_EXPECT),
@@ -192,6 +206,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(methods::OPTION_MAP_OR_NONE),
LintId::of(methods::OR_FUN_CALL),
LintId::of(methods::OR_THEN_UNWRAP),
+ LintId::of(methods::RANGE_ZIP_WITH_LEN),
+ LintId::of(methods::REPEAT_ONCE),
LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
LintId::of(methods::SEARCH_IS_SOME),
LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
@@ -201,14 +217,18 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(methods::STRING_EXTEND_CHARS),
LintId::of(methods::SUSPICIOUS_MAP),
LintId::of(methods::SUSPICIOUS_SPLITN),
+ LintId::of(methods::SUSPICIOUS_TO_OWNED),
LintId::of(methods::UNINIT_ASSUMED_INIT),
+ LintId::of(methods::UNIT_HASH),
LintId::of(methods::UNNECESSARY_FILTER_MAP),
LintId::of(methods::UNNECESSARY_FIND_MAP),
LintId::of(methods::UNNECESSARY_FOLD),
LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
+ LintId::of(methods::UNNECESSARY_SORT_BY),
LintId::of(methods::UNNECESSARY_TO_OWNED),
LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
LintId::of(methods::USELESS_ASREF),
+ LintId::of(methods::VEC_RESIZE_TO_ZERO),
LintId::of(methods::WRONG_SELF_CONVENTION),
LintId::of(methods::ZST_OFFSET),
LintId::of(minmax::MIN_MAX),
@@ -223,8 +243,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
+ LintId::of(multi_assignments::MULTI_ASSIGNMENTS),
LintId::of(mut_key::MUTABLE_KEY_TYPE),
- LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
LintId::of(needless_bool::BOOL_COMPARISON),
@@ -244,7 +264,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
LintId::of(octal_escapes::OCTAL_ESCAPES),
- LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
+ LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
LintId::of(operators::ABSURD_EXTREME_COMPARISONS),
LintId::of(operators::ASSIGN_OP_PATTERN),
LintId::of(operators::BAD_BIT_MASK),
@@ -265,6 +285,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
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(partialeq_to_none::PARTIALEQ_TO_NONE),
LintId::of(precedence::PRECEDENCE),
LintId::of(ptr::CMP_NULL),
LintId::of(ptr::INVALID_NULL_PTR_USAGE),
@@ -273,7 +294,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
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(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
LintId::of(read_zero_byte_vec::READ_ZERO_BYTE_VEC),
@@ -284,7 +304,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
LintId::of(reference::DEREF_ADDROF),
LintId::of(regex::INVALID_REGEX),
- LintId::of(repeat_once::REPEAT_ONCE),
LintId::of(returns::LET_AND_RETURN),
LintId::of(returns::NEEDLESS_RETURN),
LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
@@ -312,10 +331,10 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
+ LintId::of(transmute::TRANSMUTING_NULL),
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
LintId::of(transmute::USELESS_TRANSMUTE),
LintId::of(transmute::WRONG_TRANSMUTE),
- LintId::of(transmuting_null::TRANSMUTING_NULL),
LintId::of(types::BORROWED_BOX),
LintId::of(types::BOX_COLLECTION),
LintId::of(types::REDUNDANT_ALLOCATION),
@@ -323,7 +342,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(types::VEC_BOX),
LintId::of(unicode::INVISIBLE_CHARACTERS),
LintId::of(uninit_vec::UNINIT_VEC),
- LintId::of(unit_hash::UNIT_HASH),
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(unit_types::LET_UNIT_VALUE),
LintId::of(unit_types::UNIT_ARG),
@@ -331,7 +349,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
LintId::of(unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS),
- 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),
@@ -341,7 +358,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
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),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
index ed5446f58..8be9dc4ba 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
@@ -6,13 +6,14 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
LintId::of(attrs::DEPRECATED_CFG_ATTR),
LintId::of(booleans::NONMINIMAL_BOOL),
LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
- LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN),
LintId::of(casts::CHAR_LIT_AS_U8),
LintId::of(casts::UNNECESSARY_CAST),
+ LintId::of(dereference::EXPLICIT_AUTO_DEREF),
LintId::of(derivable_impls::DERIVABLE_IMPLS),
LintId::of(double_parens::DOUBLE_PARENS),
LintId::of(explicit_write::EXPLICIT_WRITE),
LintId::of(format::USELESS_FORMAT),
+ LintId::of(format_args::UNUSED_FORMAT_SPECS),
LintId::of(functions::TOO_MANY_ARGUMENTS),
LintId::of(int_plus_one::INT_PLUS_ONE),
LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
@@ -22,16 +23,19 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
LintId::of(loops::MANUAL_FLATTEN),
LintId::of(loops::SINGLE_ELEMENT_LOOP),
LintId::of(loops::WHILE_LET_LOOP),
+ LintId::of(manual_clamp::MANUAL_CLAMP),
LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID),
LintId::of(manual_strip::MANUAL_STRIP),
LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
+ LintId::of(matches::MANUAL_FILTER),
LintId::of(matches::MANUAL_UNWRAP_OR),
LintId::of(matches::MATCH_AS_REF),
LintId::of(matches::MATCH_SINGLE_BINDING),
LintId::of(matches::NEEDLESS_MATCH),
LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
LintId::of(methods::BIND_INSTEAD_OF_MAP),
+ LintId::of(methods::BYTES_COUNT_TO_LEN),
LintId::of(methods::CLONE_ON_COPY),
LintId::of(methods::FILTER_MAP_IDENTITY),
LintId::of(methods::FILTER_NEXT),
@@ -39,6 +43,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
LintId::of(methods::GET_LAST_WITH_LEN),
LintId::of(methods::INSPECT_FOR_EACH),
LintId::of(methods::ITER_COUNT),
+ LintId::of(methods::ITER_KV_MAP),
LintId::of(methods::MANUAL_FILTER_MAP),
LintId::of(methods::MANUAL_FIND_MAP),
LintId::of(methods::MANUAL_SPLIT_ONCE),
@@ -50,10 +55,13 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
LintId::of(methods::OPTION_AS_REF_DEREF),
LintId::of(methods::OPTION_FILTER_MAP),
LintId::of(methods::OR_THEN_UNWRAP),
+ LintId::of(methods::RANGE_ZIP_WITH_LEN),
+ LintId::of(methods::REPEAT_ONCE),
LintId::of(methods::SEARCH_IS_SOME),
LintId::of(methods::SKIP_WHILE_NEXT),
LintId::of(methods::UNNECESSARY_FILTER_MAP),
LintId::of(methods::UNNECESSARY_FIND_MAP),
+ LintId::of(methods::UNNECESSARY_SORT_BY),
LintId::of(methods::USELESS_ASREF),
LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
@@ -68,6 +76,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
LintId::of(no_effect::NO_EFFECT),
LintId::of(no_effect::UNNECESSARY_OPERATION),
+ LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
LintId::of(operators::DOUBLE_COMPARISONS),
LintId::of(operators::DURATION_SUBSEC),
LintId::of(operators::IDENTITY_OP),
@@ -75,11 +84,9 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
LintId::of(precedence::PRECEDENCE),
LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
- LintId::of(ranges::RANGE_ZIP_WITH_LEN),
LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
LintId::of(redundant_slicing::REDUNDANT_SLICING),
LintId::of(reference::DEREF_ADDROF),
- LintId::of(repeat_once::REPEAT_ONCE),
LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
LintId::of(swap::MANUAL_SWAP),
@@ -98,7 +105,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
LintId::of(types::TYPE_COMPLEXITY),
LintId::of(types::VEC_BOX),
LintId::of(unit_types::UNIT_ARG),
- LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY),
LintId::of(unwrap::UNNECESSARY_UNWRAP),
LintId::of(useless_conversion::USELESS_CONVERSION),
LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
index 9975859c5..bb94037ec 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
@@ -8,7 +8,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
LintId::of(attrs::DEPRECATED_SEMVER),
LintId::of(attrs::MISMATCHED_TARGET_OS),
LintId::of(attrs::USELESS_ATTRIBUTE),
- LintId::of(booleans::LOGIC_BUG),
+ LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
LintId::of(casts::CAST_REF_TO_MUT),
LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
LintId::of(copies::IFS_SAME_COND),
@@ -39,12 +39,14 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
LintId::of(methods::CLONE_DOUBLE_REF),
LintId::of(methods::ITERATOR_STEP_BY_ZERO),
+ LintId::of(methods::NONSENSICAL_OPEN_OPTIONS),
LintId::of(methods::SUSPICIOUS_SPLITN),
LintId::of(methods::UNINIT_ASSUMED_INIT),
+ LintId::of(methods::UNIT_HASH),
+ LintId::of(methods::VEC_RESIZE_TO_ZERO),
LintId::of(methods::ZST_OFFSET),
LintId::of(minmax::MIN_MAX),
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
- LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
LintId::of(operators::ABSURD_EXTREME_COMPARISONS),
LintId::of(operators::BAD_BIT_MASK),
LintId::of(operators::CMP_NAN),
@@ -62,17 +64,15 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
LintId::of(serde_api::SERDE_API_MISUSE),
LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
LintId::of(swap::ALMOST_SWAPPED),
+ LintId::of(transmute::TRANSMUTING_NULL),
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
LintId::of(transmute::WRONG_TRANSMUTE),
- LintId::of(transmuting_null::TRANSMUTING_NULL),
LintId::of(unicode::INVISIBLE_CHARACTERS),
LintId::of(uninit_vec::UNINIT_VEC),
- LintId::of(unit_hash::UNIT_HASH),
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(unit_types::UNIT_CMP),
LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
LintId::of(unwrap::PANICKING_UNWRAP),
- LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_internal.rs b/src/tools/clippy/clippy_lints/src/lib.register_internal.rs
index be63646a1..40c94c6e8 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_internal.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_internal.rs
@@ -3,20 +3,20 @@
// Manual edits will be overwritten.
store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
- LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL),
- LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
- LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS),
- LintId::of(utils::internal_lints::DEFAULT_DEPRECATION_REASON),
- LintId::of(utils::internal_lints::DEFAULT_LINT),
- LintId::of(utils::internal_lints::IF_CHAIN_STYLE),
- LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL),
- LintId::of(utils::internal_lints::INVALID_CLIPPY_VERSION_ATTRIBUTE),
- LintId::of(utils::internal_lints::INVALID_PATHS),
- LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS),
- LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
- LintId::of(utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE),
- LintId::of(utils::internal_lints::MISSING_MSRV_ATTR_IMPL),
- LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA),
- LintId::of(utils::internal_lints::PRODUCE_ICE),
- LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR),
+ LintId::of(utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL),
+ LintId::of(utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS),
+ LintId::of(utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS),
+ LintId::of(utils::internal_lints::if_chain_style::IF_CHAIN_STYLE),
+ LintId::of(utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL),
+ LintId::of(utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR),
+ LintId::of(utils::internal_lints::invalid_paths::INVALID_PATHS),
+ LintId::of(utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON),
+ LintId::of(utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT),
+ LintId::of(utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE),
+ LintId::of(utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS),
+ LintId::of(utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE),
+ LintId::of(utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL),
+ LintId::of(utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA),
+ LintId::of(utils::internal_lints::produce_ice::PRODUCE_ICE),
+ LintId::of(utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH),
])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
index 99bde35cf..800e3a876 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
@@ -4,41 +4,40 @@
store.register_lints(&[
#[cfg(feature = "internal")]
- utils::internal_lints::CLIPPY_LINTS_INTERNAL,
+ utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL,
#[cfg(feature = "internal")]
- utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
+ utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS,
#[cfg(feature = "internal")]
- utils::internal_lints::COMPILER_LINT_FUNCTIONS,
+ utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS,
#[cfg(feature = "internal")]
- utils::internal_lints::DEFAULT_DEPRECATION_REASON,
+ utils::internal_lints::if_chain_style::IF_CHAIN_STYLE,
#[cfg(feature = "internal")]
- utils::internal_lints::DEFAULT_LINT,
+ utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL,
#[cfg(feature = "internal")]
- utils::internal_lints::IF_CHAIN_STYLE,
+ utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR,
#[cfg(feature = "internal")]
- utils::internal_lints::INTERNING_DEFINED_SYMBOL,
+ utils::internal_lints::invalid_paths::INVALID_PATHS,
#[cfg(feature = "internal")]
- utils::internal_lints::INVALID_CLIPPY_VERSION_ATTRIBUTE,
+ utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON,
#[cfg(feature = "internal")]
- utils::internal_lints::INVALID_PATHS,
+ utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT,
#[cfg(feature = "internal")]
- utils::internal_lints::LINT_WITHOUT_LINT_PASS,
+ utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE,
#[cfg(feature = "internal")]
- utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
+ utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS,
#[cfg(feature = "internal")]
- utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE,
+ utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE,
#[cfg(feature = "internal")]
- utils::internal_lints::MISSING_MSRV_ATTR_IMPL,
+ utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL,
#[cfg(feature = "internal")]
- utils::internal_lints::OUTER_EXPN_EXPN_DATA,
+ utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA,
#[cfg(feature = "internal")]
- utils::internal_lints::PRODUCE_ICE,
+ utils::internal_lints::produce_ice::PRODUCE_ICE,
#[cfg(feature = "internal")]
- utils::internal_lints::UNNECESSARY_SYMBOL_STR,
+ utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH,
almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE,
approx_const::APPROX_CONSTANT,
as_conversions::AS_CONVERSIONS,
- as_underscore::AS_UNDERSCORE,
asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
@@ -55,25 +54,26 @@ store.register_lints(&[
await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE,
await_holding_invalid::AWAIT_HOLDING_LOCK,
await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
- blacklisted_name::BLACKLISTED_NAME,
blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
bool_assert_comparison::BOOL_ASSERT_COMPARISON,
- booleans::LOGIC_BUG,
+ bool_to_int_with_if::BOOL_TO_INT_WITH_IF,
booleans::NONMINIMAL_BOOL,
- borrow_as_ptr::BORROW_AS_PTR,
+ booleans::OVERLY_COMPLEX_BOOL_EXPR,
borrow_deref_ref::BORROW_DEREF_REF,
- bytecount::NAIVE_BYTECOUNT,
- bytes_count_to_len::BYTES_COUNT_TO_LEN,
+ box_default::BOX_DEFAULT,
cargo::CARGO_COMMON_METADATA,
cargo::MULTIPLE_CRATE_VERSIONS,
cargo::NEGATIVE_FEATURE_NAMES,
cargo::REDUNDANT_FEATURE_NAMES,
cargo::WILDCARD_DEPENDENCIES,
- case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+ casts::AS_PTR_CAST_MUT,
+ casts::AS_UNDERSCORE,
+ casts::BORROW_AS_PTR,
casts::CAST_ABS_TO_UNSIGNED,
casts::CAST_ENUM_CONSTRUCTOR,
casts::CAST_ENUM_TRUNCATION,
casts::CAST_LOSSLESS,
+ casts::CAST_NAN_TO_INT,
casts::CAST_POSSIBLE_TRUNCATION,
casts::CAST_POSSIBLE_WRAP,
casts::CAST_PRECISION_LOSS,
@@ -81,6 +81,7 @@ store.register_lints(&[
casts::CAST_REF_TO_MUT,
casts::CAST_SIGN_LOSS,
casts::CAST_SLICE_DIFFERENT_SIZES,
+ casts::CAST_SLICE_FROM_RAW_PARTS,
casts::CHAR_LIT_AS_U8,
casts::FN_TO_NUMERIC_CAST,
casts::FN_TO_NUMERIC_CAST_ANY,
@@ -115,15 +116,17 @@ store.register_lints(&[
derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ,
derive::EXPL_IMPL_CLONE_ON_COPY,
derive::UNSAFE_DERIVE_DESERIALIZE,
+ disallowed_macros::DISALLOWED_MACROS,
disallowed_methods::DISALLOWED_METHODS,
+ disallowed_names::DISALLOWED_NAMES,
disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,
disallowed_types::DISALLOWED_TYPES,
+ doc::DOC_LINK_WITH_QUOTES,
doc::DOC_MARKDOWN,
doc::MISSING_ERRORS_DOC,
doc::MISSING_PANICS_DOC,
doc::MISSING_SAFETY_DOC,
doc::NEEDLESS_DOCTEST_MAIN,
- doc_link_with_quotes::DOC_LINK_WITH_QUOTES,
double_parens::DOUBLE_PARENS,
drop_forget_ref::DROP_COPY,
drop_forget_ref::DROP_NON_DROP,
@@ -160,6 +163,8 @@ store.register_lints(&[
format::USELESS_FORMAT,
format_args::FORMAT_IN_FORMAT_ARGS,
format_args::TO_STRING_IN_FORMAT_ARGS,
+ format_args::UNINLINED_FORMAT_ARGS,
+ format_args::UNUSED_FORMAT_SPECS,
format_impl::PRINT_IN_FORMAT_IMPL,
format_impl::RECURSIVE_FORMAT_IMPL,
format_push_string::FORMAT_PUSH_STRING,
@@ -173,16 +178,17 @@ store.register_lints(&[
functions::MUST_USE_CANDIDATE,
functions::MUST_USE_UNIT,
functions::NOT_UNSAFE_PTR_ARG_DEREF,
+ functions::RESULT_LARGE_ERR,
functions::RESULT_UNIT_ERR,
functions::TOO_MANY_ARGUMENTS,
functions::TOO_MANY_LINES,
future_not_send::FUTURE_NOT_SEND,
- get_first::GET_FIRST,
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_add::IMPLICIT_SATURATING_ADD,
implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR,
index_refutable_slice::INDEX_REFUTABLE_SLICE,
@@ -224,7 +230,6 @@ store.register_lints(&[
loops::EXPLICIT_INTO_ITER_LOOP,
loops::EXPLICIT_ITER_LOOP,
loops::FOR_KV_MAP,
- loops::FOR_LOOPS_OVER_FALLIBLES,
loops::ITER_NEXT_LOOP,
loops::MANUAL_FIND,
loops::MANUAL_FLATTEN,
@@ -244,18 +249,19 @@ store.register_lints(&[
manual_assert::MANUAL_ASSERT,
manual_async_fn::MANUAL_ASYNC_FN,
manual_bits::MANUAL_BITS,
+ manual_clamp::MANUAL_CLAMP,
+ manual_instant_elapsed::MANUAL_INSTANT_ELAPSED,
manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
- manual_ok_or::MANUAL_OK_OR,
manual_rem_euclid::MANUAL_REM_EUCLID,
manual_retain::MANUAL_RETAIN,
+ manual_string_new::MANUAL_STRING_NEW,
manual_strip::MANUAL_STRIP,
- 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_result_ok::MATCH_RESULT_OK,
matches::COLLAPSIBLE_MATCH,
matches::INFALLIBLE_DESTRUCTURING_MATCH,
+ matches::MANUAL_FILTER,
matches::MANUAL_MAP,
matches::MANUAL_UNWRAP_OR,
matches::MATCH_AS_REF,
@@ -283,13 +289,16 @@ store.register_lints(&[
mem_replace::MEM_REPLACE_WITH_DEFAULT,
mem_replace::MEM_REPLACE_WITH_UNINIT,
methods::BIND_INSTEAD_OF_MAP,
+ methods::BYTES_COUNT_TO_LEN,
methods::BYTES_NTH,
+ methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
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::COLLAPSIBLE_STR_REPLACE,
methods::ERR_EXPECT,
methods::EXPECT_FUN_CALL,
methods::EXPECT_USED,
@@ -301,6 +310,7 @@ store.register_lints(&[
methods::FLAT_MAP_IDENTITY,
methods::FLAT_MAP_OPTION,
methods::FROM_ITER_INSTEAD_OF_COLLECT,
+ methods::GET_FIRST,
methods::GET_LAST_WITH_LEN,
methods::GET_UNWRAP,
methods::IMPLICIT_CLONE,
@@ -311,25 +321,34 @@ store.register_lints(&[
methods::ITERATOR_STEP_BY_ZERO,
methods::ITER_CLONED_COLLECT,
methods::ITER_COUNT,
+ methods::ITER_KV_MAP,
methods::ITER_NEXT_SLICE,
methods::ITER_NTH,
methods::ITER_NTH_ZERO,
+ methods::ITER_ON_EMPTY_COLLECTIONS,
+ methods::ITER_ON_SINGLE_ITEMS,
methods::ITER_OVEREAGER_CLONED,
methods::ITER_SKIP_NEXT,
methods::ITER_WITH_DRAIN,
methods::MANUAL_FILTER_MAP,
methods::MANUAL_FIND_MAP,
+ methods::MANUAL_OK_OR,
methods::MANUAL_SATURATING_ARITHMETIC,
methods::MANUAL_SPLIT_ONCE,
methods::MANUAL_STR_REPEAT,
+ methods::MAP_CLONE,
methods::MAP_COLLECT_RESULT_UNIT,
+ methods::MAP_ERR_IGNORE,
methods::MAP_FLATTEN,
methods::MAP_IDENTITY,
methods::MAP_UNWRAP_OR,
+ methods::MUT_MUTEX_LOCK,
+ methods::NAIVE_BYTECOUNT,
methods::NEEDLESS_OPTION_AS_DEREF,
methods::NEEDLESS_OPTION_TAKE,
methods::NEEDLESS_SPLITN,
methods::NEW_RET_NO_SELF,
+ methods::NONSENSICAL_OPEN_OPTIONS,
methods::NO_EFFECT_REPLACE,
methods::OBFUSCATED_IF_ELSE,
methods::OK_EXPECT,
@@ -338,25 +357,34 @@ store.register_lints(&[
methods::OPTION_MAP_OR_NONE,
methods::OR_FUN_CALL,
methods::OR_THEN_UNWRAP,
+ methods::PATH_BUF_PUSH_OVERWRITE,
+ methods::RANGE_ZIP_WITH_LEN,
+ methods::REPEAT_ONCE,
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::STABLE_SORT_PRIMITIVE,
methods::STRING_EXTEND_CHARS,
methods::SUSPICIOUS_MAP,
methods::SUSPICIOUS_SPLITN,
+ methods::SUSPICIOUS_TO_OWNED,
methods::UNINIT_ASSUMED_INIT,
+ methods::UNIT_HASH,
methods::UNNECESSARY_FILTER_MAP,
methods::UNNECESSARY_FIND_MAP,
methods::UNNECESSARY_FOLD,
methods::UNNECESSARY_JOIN,
methods::UNNECESSARY_LAZY_EVALUATIONS,
+ methods::UNNECESSARY_SORT_BY,
methods::UNNECESSARY_TO_OWNED,
methods::UNWRAP_OR_ELSE_DEFAULT,
methods::UNWRAP_USED,
methods::USELESS_ASREF,
+ methods::VEC_RESIZE_TO_ZERO,
+ methods::VERBOSE_FILE_READS,
methods::WRONG_SELF_CONVENTION,
methods::ZST_OFFSET,
minmax::MIN_MAX,
@@ -379,13 +407,14 @@ store.register_lints(&[
missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES,
missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
+ missing_trait_methods::MISSING_TRAIT_METHODS,
mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION,
mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION,
module_style::MOD_MODULE_FILES,
module_style::SELF_NAMED_MODULE_FILES,
+ multi_assignments::MULTI_ASSIGNMENTS,
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,
@@ -417,9 +446,8 @@ store.register_lints(&[
nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES,
octal_escapes::OCTAL_ESCAPES,
only_used_in_recursion::ONLY_USED_IN_RECURSION,
- open_options::NONSENSICAL_OPEN_OPTIONS,
operators::ABSURD_EXTREME_COMPARISONS,
- operators::ARITHMETIC,
+ operators::ARITHMETIC_SIDE_EFFECTS,
operators::ASSIGN_OP_PATTERN,
operators::BAD_BIT_MASK,
operators::CMP_NAN,
@@ -452,10 +480,11 @@ store.register_lints(&[
panic_unimplemented::TODO,
panic_unimplemented::UNIMPLEMENTED,
panic_unimplemented::UNREACHABLE,
+ partial_pub_fields::PARTIAL_PUB_FIELDS,
partialeq_ne_impl::PARTIALEQ_NE_IMPL,
+ partialeq_to_none::PARTIALEQ_TO_NONE,
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,
@@ -468,7 +497,6 @@ store.register_lints(&[
ranges::MANUAL_RANGE_CONTAINS,
ranges::RANGE_MINUS_ONE,
ranges::RANGE_PLUS_ONE,
- ranges::RANGE_ZIP_WITH_LEN,
ranges::REVERSED_EMPTY_RANGES,
rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT,
read_zero_byte_vec::READ_ZERO_BYTE_VEC,
@@ -484,7 +512,6 @@ store.register_lints(&[
reference::DEREF_ADDROF,
regex::INVALID_REGEX,
regex::TRIVIAL_REGEX,
- repeat_once::REPEAT_ONCE,
return_self_not_must_use::RETURN_SELF_NOT_MUST_USE,
returns::LET_AND_RETURN,
returns::NEEDLESS_RETURN,
@@ -499,7 +526,6 @@ store.register_lints(&[
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,
std_instead_of_core::ALLOC_INSTEAD_OF_CORE,
std_instead_of_core::STD_INSTEAD_OF_ALLOC,
std_instead_of_core::STD_INSTEAD_OF_CORE,
@@ -535,10 +561,10 @@ store.register_lints(&[
transmute::TRANSMUTE_PTR_TO_PTR,
transmute::TRANSMUTE_PTR_TO_REF,
transmute::TRANSMUTE_UNDEFINED_REPR,
+ transmute::TRANSMUTING_NULL,
transmute::UNSOUND_COLLECTION_TRANSMUTE,
transmute::USELESS_TRANSMUTE,
transmute::WRONG_TRANSMUTE,
- transmuting_null::TRANSMUTING_NULL,
types::BORROWED_BOX,
types::BOX_COLLECTION,
types::LINKEDLIST,
@@ -553,7 +579,6 @@ store.register_lints(&[
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,
@@ -562,12 +587,12 @@ store.register_lints(&[
unnamed_address::VTABLE_ADDRESS_COMPARISONS,
unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS,
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_peekable::UNUSED_PEEKABLE,
unused_rounding::UNUSED_ROUNDING,
unused_self::UNUSED_SELF,
unused_unit::UNUSED_UNIT,
@@ -579,8 +604,6 @@ store.register_lints(&[
useless_conversion::USELESS_CONVERSION,
vec::USELESS_VEC,
vec_init_then_push::VEC_INIT_THEN_PUSH,
- vec_resize_to_zero::VEC_RESIZE_TO_ZERO,
- verbose_file_reads::VERBOSE_FILE_READS,
wildcard_imports::ENUM_GLOB_USE,
wildcard_imports::WILDCARD_IMPORTS,
write::PRINTLN_EMPTY_STRING,
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
index 973191eb1..65616d28d 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
@@ -4,9 +4,10 @@
store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
+ LintId::of(casts::AS_PTR_CAST_MUT),
LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
LintId::of(copies::BRANCHES_SHARING_CODE),
- LintId::of(dereference::EXPLICIT_AUTO_DEREF),
+ LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
LintId::of(equatable_if_let::EQUATABLE_IF_LET),
LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
@@ -15,22 +16,24 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE),
LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
+ LintId::of(methods::ITER_ON_EMPTY_COLLECTIONS),
+ LintId::of(methods::ITER_ON_SINGLE_ITEMS),
LintId::of(methods::ITER_WITH_DRAIN),
+ LintId::of(methods::PATH_BUF_PUSH_OVERWRITE),
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_ATOMIC),
LintId::of(mutex_atomic::MUTEX_INTEGER),
LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
- LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
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::TRANSMUTE_UNDEFINED_REPR),
+ LintId::of(unused_peekable::UNUSED_PEEKABLE),
LintId::of(unused_rounding::UNUSED_ROUNDING),
LintId::of(use_self::USE_SELF),
])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
index a1b546658..44e969585 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
@@ -4,9 +4,7 @@
store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(attrs::INLINE_ALWAYS),
- LintId::of(borrow_as_ptr::BORROW_AS_PTR),
- LintId::of(bytecount::NAIVE_BYTECOUNT),
- LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
+ LintId::of(casts::BORROW_AS_PTR),
LintId::of(casts::CAST_LOSSLESS),
LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
LintId::of(casts::CAST_POSSIBLE_WRAP),
@@ -22,20 +20,20 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(dereference::REF_BINDING_TO_REFERENCE),
LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY),
LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE),
+ LintId::of(doc::DOC_LINK_WITH_QUOTES),
LintId::of(doc::DOC_MARKDOWN),
LintId::of(doc::MISSING_ERRORS_DOC),
LintId::of(doc::MISSING_PANICS_DOC),
- LintId::of(doc_link_with_quotes::DOC_LINK_WITH_QUOTES),
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(format_args::UNINLINED_FORMAT_ARGS),
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),
@@ -49,20 +47,25 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
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(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED),
+ LintId::of(manual_string_new::MANUAL_STRING_NEW),
LintId::of(matches::MATCH_BOOL),
LintId::of(matches::MATCH_ON_VEC_ITEMS),
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::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
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::MANUAL_OK_OR),
LintId::of(methods::MAP_UNWRAP_OR),
+ LintId::of(methods::NAIVE_BYTECOUNT),
+ LintId::of(methods::STABLE_SORT_PRIMITIVE),
LintId::of(methods::UNNECESSARY_JOIN),
LintId::of(misc::USED_UNDERSCORE_BINDING),
LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER),
@@ -84,7 +87,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
LintId::of(ref_option_ref::REF_OPTION_REF),
LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
- LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
LintId::of(strings::STRING_ADD_ASSIGN),
LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_perf.rs b/src/tools/clippy/clippy_lints/src/lib.register_perf.rs
index e1b90acb9..8e927470e 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_perf.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_perf.rs
@@ -3,16 +3,19 @@
// Manual edits will be overwritten.
store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
+ LintId::of(box_default::BOX_DEFAULT),
LintId::of(entry::MAP_ENTRY),
LintId::of(escape::BOXED_LOCAL),
LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
+ LintId::of(functions::RESULT_LARGE_ERR),
LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
LintId::of(loops::MANUAL_MEMCPY),
LintId::of(loops::MISSING_SPIN_LOOP),
LintId::of(loops::NEEDLESS_COLLECT),
LintId::of(manual_retain::MANUAL_RETAIN),
+ LintId::of(methods::COLLAPSIBLE_STR_REPLACE),
LintId::of(methods::EXPECT_FUN_CALL),
LintId::of(methods::EXTEND_WITH_DRAIN),
LintId::of(methods::ITER_NTH),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
index a7339ef27..f62d57af5 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
@@ -4,11 +4,11 @@
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(as_conversions::AS_CONVERSIONS),
- LintId::of(as_underscore::AS_UNDERSCORE),
LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON),
+ LintId::of(casts::AS_UNDERSCORE),
LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
LintId::of(create_dir::CREATE_DIR),
LintId::of(dbg_macro::DBG_MACRO),
@@ -30,7 +30,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
LintId::of(large_include_file::LARGE_INCLUDE_FILE),
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::TRY_ERR),
LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
@@ -39,17 +38,20 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
LintId::of(methods::EXPECT_USED),
LintId::of(methods::FILETYPE_IS_FILE),
LintId::of(methods::GET_UNWRAP),
+ LintId::of(methods::MAP_ERR_IGNORE),
LintId::of(methods::UNWRAP_USED),
+ LintId::of(methods::VERBOSE_FILE_READS),
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(missing_trait_methods::MISSING_TRAIT_METHODS),
LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION),
LintId::of(module_style::MOD_MODULE_FILES),
LintId::of(module_style::SELF_NAMED_MODULE_FILES),
- LintId::of(operators::ARITHMETIC),
+ LintId::of(operators::ARITHMETIC_SIDE_EFFECTS),
LintId::of(operators::FLOAT_ARITHMETIC),
LintId::of(operators::FLOAT_CMP_CONST),
LintId::of(operators::INTEGER_ARITHMETIC),
@@ -60,6 +62,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
LintId::of(panic_unimplemented::TODO),
LintId::of(panic_unimplemented::UNIMPLEMENTED),
LintId::of(panic_unimplemented::UNREACHABLE),
+ LintId::of(partial_pub_fields::PARTIAL_PUB_FIELDS),
LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
LintId::of(pub_use::PUB_USE),
LintId::of(redundant_slicing::DEREF_BY_SLICING),
@@ -81,7 +84,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
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),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_style.rs b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
index e95bab1d0..3312f5648 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_style.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
@@ -4,9 +4,9 @@
store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
- 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(bool_to_int_with_if::BOOL_TO_INT_WITH_IF),
LintId::of(casts::FN_TO_NUMERIC_CAST),
LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
@@ -15,8 +15,9 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
LintId::of(dereference::NEEDLESS_BORROW),
- LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
+ LintId::of(disallowed_macros::DISALLOWED_MACROS),
LintId::of(disallowed_methods::DISALLOWED_METHODS),
+ LintId::of(disallowed_names::DISALLOWED_NAMES),
LintId::of(disallowed_types::DISALLOWED_TYPES),
LintId::of(doc::MISSING_SAFETY_DOC),
LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
@@ -29,7 +30,8 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(functions::DOUBLE_MUST_USE),
LintId::of(functions::MUST_USE_UNIT),
LintId::of(functions::RESULT_UNIT_ERR),
- LintId::of(get_first::GET_FIRST),
+ LintId::of(implicit_saturating_add::IMPLICIT_SATURATING_ADD),
+ LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
LintId::of(inherent_to_string::INHERENT_TO_STRING),
LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
LintId::of(len_zero::COMPARISON_TO_EMPTY),
@@ -45,7 +47,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
LintId::of(manual_bits::MANUAL_BITS),
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::COLLAPSIBLE_MATCH),
LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
@@ -61,6 +62,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(methods::CHARS_LAST_CMP),
LintId::of(methods::CHARS_NEXT_CMP),
LintId::of(methods::ERR_EXPECT),
+ LintId::of(methods::GET_FIRST),
LintId::of(methods::INTO_ITER_ON_REF),
LintId::of(methods::IS_DIGIT_ASCII_RADIX),
LintId::of(methods::ITER_CLONED_COLLECT),
@@ -68,7 +70,9 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(methods::ITER_NTH_ZERO),
LintId::of(methods::ITER_SKIP_NEXT),
LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
+ LintId::of(methods::MAP_CLONE),
LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
+ LintId::of(methods::MUT_MUTEX_LOCK),
LintId::of(methods::NEW_RET_NO_SELF),
LintId::of(methods::OBFUSCATED_IF_ELSE),
LintId::of(methods::OK_EXPECT),
@@ -88,7 +92,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
LintId::of(misc_early::REDUNDANT_PATTERN),
- LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS),
@@ -100,6 +103,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(operators::ASSIGN_OP_PATTERN),
LintId::of(operators::OP_REF),
LintId::of(operators::PTR_EQ),
+ LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE),
LintId::of(ptr::CMP_NULL),
LintId::of(ptr::PTR_ARG),
LintId::of(question_mark::QUESTION_MARK),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
index 964992bd9..b70c4bb73 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
@@ -11,6 +11,8 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
LintId::of(casts::CAST_ABS_TO_UNSIGNED),
LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
LintId::of(casts::CAST_ENUM_TRUNCATION),
+ LintId::of(casts::CAST_NAN_TO_INT),
+ LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
LintId::of(drop_forget_ref::DROP_NON_DROP),
LintId::of(drop_forget_ref::FORGET_NON_DROP),
@@ -20,10 +22,11 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
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::NO_EFFECT_REPLACE),
LintId::of(methods::SUSPICIOUS_MAP),
+ LintId::of(methods::SUSPICIOUS_TO_OWNED),
+ LintId::of(multi_assignments::MULTI_ASSIGNMENTS),
LintId::of(mut_key::MUTABLE_KEY_TYPE),
LintId::of(octal_escapes::OCTAL_ESCAPES),
LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS),
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 5a3111632..1307096b2 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -5,7 +5,6 @@
#![feature(drain_filter)]
#![feature(iter_intersperse)]
#![feature(let_chains)]
-#![feature(let_else)]
#![feature(lint_reasons)]
#![feature(never_type)]
#![feature(once_cell)]
@@ -32,20 +31,19 @@ extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_hir;
+extern crate rustc_hir_analysis;
+extern crate rustc_hir_typeck;
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;
@@ -171,23 +169,19 @@ mod renamed_lints;
mod almost_complete_letter_range;
mod approx_const;
mod as_conversions;
-mod as_underscore;
mod asm_syntax;
mod assertions_on_constants;
mod assertions_on_result_states;
mod async_yields_async;
mod attrs;
mod await_holding_invalid;
-mod blacklisted_name;
mod blocks_in_if_conditions;
mod bool_assert_comparison;
+mod bool_to_int_with_if;
mod booleans;
-mod borrow_as_ptr;
mod borrow_deref_ref;
-mod bytecount;
-mod bytes_count_to_len;
+mod box_default;
mod cargo;
-mod case_sensitive_file_extension_comparisons;
mod casts;
mod checked_conversions;
mod cognitive_complexity;
@@ -205,11 +199,12 @@ mod default_union_representation;
mod dereference;
mod derivable_impls;
mod derive;
+mod disallowed_macros;
mod disallowed_methods;
+mod disallowed_names;
mod disallowed_script_idents;
mod disallowed_types;
mod doc;
-mod doc_link_with_quotes;
mod double_parens;
mod drop_forget_ref;
mod duplicate_mod;
@@ -239,12 +234,12 @@ mod from_over_into;
mod from_str_radix_10;
mod functions;
mod future_not_send;
-mod get_first;
mod if_let_mutex;
mod if_not_else;
mod if_then_some_else_none;
mod implicit_hasher;
mod implicit_return;
+mod implicit_saturating_add;
mod implicit_saturating_sub;
mod inconsistent_struct_constructor;
mod index_refutable_slice;
@@ -274,13 +269,13 @@ mod main_recursion;
mod manual_assert;
mod manual_async_fn;
mod manual_bits;
+mod manual_clamp;
+mod manual_instant_elapsed;
mod manual_non_exhaustive;
-mod manual_ok_or;
mod manual_rem_euclid;
mod manual_retain;
+mod manual_string_new;
mod manual_strip;
-mod map_clone;
-mod map_err_ignore;
mod map_unit_fn;
mod match_result_ok;
mod matches;
@@ -295,11 +290,12 @@ mod missing_const_for_fn;
mod missing_doc;
mod missing_enforced_import_rename;
mod missing_inline;
+mod missing_trait_methods;
mod mixed_read_write_in_expression;
mod module_style;
+mod multi_assignments;
mod mut_key;
mod mut_mut;
-mod mut_mutex_lock;
mod mut_reference;
mod mutable_debug_assertion;
mod mutex_atomic;
@@ -324,16 +320,16 @@ mod non_send_fields_in_send_ty;
mod nonstandard_macro_braces;
mod octal_escapes;
mod only_used_in_recursion;
-mod open_options;
mod operators;
mod option_env_unwrap;
mod option_if_let_else;
mod overflow_check_conditional;
mod panic_in_result_fn;
mod panic_unimplemented;
+mod partial_pub_fields;
mod partialeq_ne_impl;
+mod partialeq_to_none;
mod pass_by_ref_or_value;
-mod path_buf_push_overwrite;
mod pattern_type_mismatch;
mod precedence;
mod ptr;
@@ -353,7 +349,6 @@ mod redundant_static_lifetimes;
mod ref_option_ref;
mod reference;
mod regex;
-mod repeat_once;
mod return_self_not_must_use;
mod returns;
mod same_name_method;
@@ -365,7 +360,6 @@ mod single_char_lifetime_names;
mod single_component_path_imports;
mod size_of_in_element_count;
mod slow_vector_initialization;
-mod stable_sort_primitive;
mod std_instead_of_core;
mod strings;
mod strlen_on_c_strings;
@@ -379,23 +373,21 @@ mod to_digit_is_some;
mod trailing_empty_array;
mod trait_bounds;
mod transmute;
-mod transmuting_null;
mod types;
mod undocumented_unsafe_blocks;
mod unicode;
mod uninit_vec;
-mod unit_hash;
mod unit_return_expecting_ord;
mod unit_types;
mod unnamed_address;
mod unnecessary_owned_empty_strings;
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_peekable;
mod unused_rounding;
mod unused_self;
mod unused_unit;
@@ -406,8 +398,6 @@ mod use_self;
mod useless_conversion;
mod vec;
mod vec_init_then_push;
-mod vec_resize_to_zero;
-mod verbose_file_reads;
mod wildcard_imports;
mod write;
mod zero_div_zero;
@@ -430,15 +420,13 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se
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
+ sess.err(format!(
+ "error reading Clippy's configuration file. `{s}` is not a valid Rust version"
));
None
})
});
- store.register_pre_expansion_pass(|| Box::new(write::Write::default()));
store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv }));
}
@@ -448,9 +436,8 @@ fn read_msrv(conf: &Conf, sess: &Session) -> Option<RustcVersion> {
.and_then(|v| parse_msrv(&v, None, None));
let clippy_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
+ sess.err(format!(
+ "error reading Clippy's configuration file. `{s}` is not a valid Rust version"
));
None
})
@@ -460,9 +447,8 @@ fn read_msrv(conf: &Conf, sess: &Session) -> Option<RustcVersion> {
if let Some(clippy_msrv) = clippy_msrv {
// if both files have an msrv, let's compare them and emit a warning if they differ
if clippy_msrv != cargo_msrv {
- sess.warn(&format!(
- "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{}` from `clippy.toml`",
- clippy_msrv
+ sess.warn(format!(
+ "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
));
}
@@ -481,22 +467,31 @@ pub fn read_conf(sess: &Session) -> Conf {
Ok(Some(path)) => path,
Ok(None) => return Conf::default(),
Err(error) => {
- sess.struct_err(&format!("error finding Clippy's configuration file: {}", 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);
+ let TryConf { conf, errors, warnings } = 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.err(&format!(
+ sess.err(format!(
"error reading Clippy's configuration file `{}`: {}",
file_name.display(),
format_error(error)
));
}
+ for warning in warnings {
+ sess.struct_warn(format!(
+ "error reading Clippy's configuration file `{}`: {}",
+ file_name.display(),
+ format_error(warning)
+ ))
+ .emit();
+ }
+
conf
}
@@ -528,7 +523,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
#[cfg(feature = "internal")]
{
if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
- store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
+ store.register_late_pass(|_| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
return;
}
}
@@ -536,72 +531,81 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
// all the internal lints
#[cfg(feature = "internal")]
{
- store.register_early_pass(|| Box::new(utils::internal_lints::ClippyLintsInternal));
- store.register_early_pass(|| Box::new(utils::internal_lints::ProduceIce));
- store.register_late_pass(|| Box::new(utils::internal_lints::CollapsibleCalls));
- store.register_late_pass(|| Box::new(utils::internal_lints::CompilerLintFunctions::new()));
- store.register_late_pass(|| Box::new(utils::internal_lints::IfChainStyle));
- store.register_late_pass(|| Box::new(utils::internal_lints::InvalidPaths));
- store.register_late_pass(|| Box::new(utils::internal_lints::InterningDefinedSymbol::default()));
- store.register_late_pass(|| Box::new(utils::internal_lints::LintWithoutLintPass::default()));
- store.register_late_pass(|| Box::new(utils::internal_lints::MatchTypeOnDiagItem));
- store.register_late_pass(|| Box::new(utils::internal_lints::OuterExpnDataPass));
- store.register_late_pass(|| Box::new(utils::internal_lints::MsrvAttrImpl));
+ store.register_early_pass(|| Box::new(utils::internal_lints::clippy_lints_internal::ClippyLintsInternal));
+ store.register_early_pass(|| Box::new(utils::internal_lints::produce_ice::ProduceIce));
+ store.register_late_pass(|_| Box::new(utils::internal_lints::collapsible_calls::CollapsibleCalls));
+ store.register_late_pass(|_| {
+ Box::new(utils::internal_lints::compiler_lint_functions::CompilerLintFunctions::new())
+ });
+ store.register_late_pass(|_| Box::new(utils::internal_lints::if_chain_style::IfChainStyle));
+ store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths));
+ store.register_late_pass(|_| {
+ Box::<utils::internal_lints::interning_defined_symbol::InterningDefinedSymbol>::default()
+ });
+ store.register_late_pass(|_| {
+ Box::<utils::internal_lints::lint_without_lint_pass::LintWithoutLintPass>::default()
+ });
+ store.register_late_pass(|_| Box::<utils::internal_lints::unnecessary_def_path::UnnecessaryDefPath>::default());
+ store.register_late_pass(|_| Box::new(utils::internal_lints::outer_expn_data_pass::OuterExpnDataPass));
+ store.register_late_pass(|_| Box::new(utils::internal_lints::msrv_attr_impl::MsrvAttrImpl));
}
- let arithmetic_allowed = conf.arithmetic_allowed.clone();
- store.register_late_pass(move || Box::new(operators::arithmetic::Arithmetic::new(arithmetic_allowed.clone())));
- store.register_late_pass(|| Box::new(utils::dump_hir::DumpHir));
- store.register_late_pass(|| Box::new(utils::author::Author));
+ let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone();
+ store.register_late_pass(move |_| {
+ Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(
+ arithmetic_side_effects_allowed.clone(),
+ ))
+ });
+ store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
+ store.register_late_pass(|_| Box::new(utils::author::Author));
let await_holding_invalid_types = conf.await_holding_invalid_types.clone();
- store.register_late_pass(move || {
+ store.register_late_pass(move |_| {
Box::new(await_holding_invalid::AwaitHolding::new(
await_holding_invalid_types.clone(),
))
});
- store.register_late_pass(|| Box::new(serde_api::SerdeApi));
+ 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 || {
+ 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(enum_clike::UnportableVariant));
- store.register_late_pass(|| Box::new(float_literal::FloatLiteral));
- store.register_late_pass(|| Box::new(ptr::Ptr));
- store.register_late_pass(|| Box::new(needless_bool::NeedlessBool));
- 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(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(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_late_pass(|_| Box::new(booleans::NonminimalBool));
+ store.register_late_pass(|_| Box::new(enum_clike::UnportableVariant));
+ store.register_late_pass(|_| Box::new(float_literal::FloatLiteral));
+ store.register_late_pass(|_| Box::new(ptr::Ptr));
+ store.register_late_pass(|_| Box::new(needless_bool::NeedlessBool));
+ 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(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(unicode::Unicode));
+ store.register_late_pass(|_| Box::new(uninit_vec::UninitVec));
+ 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 = read_msrv(conf, sess);
let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
let allow_expect_in_tests = conf.allow_expect_in_tests;
let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
- store.register_late_pass(move || Box::new(approx_const::ApproxConstant::new(msrv)));
- store.register_late_pass(move || {
+ 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,
@@ -609,154 +613,148 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
allow_unwrap_in_tests,
))
});
- store.register_late_pass(move || Box::new(matches::Matches::new(msrv)));
+ store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv)));
store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv)));
- store.register_late_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv)));
- store.register_late_pass(move || Box::new(manual_strip::ManualStrip::new(msrv)));
+ store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::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_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv)));
+ store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv)));
+ store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv)));
+ store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv)));
+ store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv)));
+ store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv)));
+ store.register_late_pass(move |_| Box::new(needless_question_mark::NeedlessQuestionMark));
+ store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv)));
store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv)));
- store.register_late_pass(move || Box::new(map_clone::MapClone::new(msrv)));
-
- store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount));
- store.register_late_pass(|| Box::new(same_name_method::SameNameMethod));
+ store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount));
+ store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod));
let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length;
- store.register_late_pass(move || {
+ store.register_late_pass(move |_| {
Box::new(index_refutable_slice::IndexRefutableSlice::new(
max_suggested_slice_pattern_length,
msrv,
))
});
- store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore));
- store.register_late_pass(|| Box::new(shadow::Shadow::default()));
- store.register_late_pass(|| Box::new(unit_types::UnitTypes));
- store.register_late_pass(|| Box::new(loops::Loops));
- store.register_late_pass(|| Box::new(main_recursion::MainRecursion::default()));
- store.register_late_pass(|| Box::new(lifetimes::Lifetimes));
- store.register_late_pass(|| Box::new(entry::HashMapPass));
- store.register_late_pass(|| Box::new(minmax::MinMaxPass));
- store.register_late_pass(|| Box::new(open_options::OpenOptions));
- store.register_late_pass(|| Box::new(zero_div_zero::ZeroDiv));
- store.register_late_pass(|| Box::new(mutex_atomic::Mutex));
- store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate));
- store.register_late_pass(|| Box::new(needless_borrowed_ref::NeedlessBorrowedRef));
- store.register_late_pass(|| Box::new(borrow_deref_ref::BorrowDerefRef));
- store.register_late_pass(|| Box::new(no_effect::NoEffect));
- store.register_late_pass(|| Box::new(temporary_assignment::TemporaryAssignment));
- store.register_late_pass(move || Box::new(transmute::Transmute::new(msrv)));
+ store.register_late_pass(|_| Box::<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::<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(zero_div_zero::ZeroDiv));
+ store.register_late_pass(|_| Box::new(mutex_atomic::Mutex));
+ store.register_late_pass(|_| Box::new(needless_update::NeedlessUpdate));
+ store.register_late_pass(|_| Box::new(needless_borrowed_ref::NeedlessBorrowedRef));
+ store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef));
+ store.register_late_pass(|_| Box::new(no_effect::NoEffect));
+ store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment));
+ store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv)));
let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
- store.register_late_pass(move || {
+ 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(drop_forget_ref::DropForgetRef));
- store.register_late_pass(|| Box::new(empty_enum::EmptyEnum));
- 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())));
+ 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(drop_forget_ref::DropForgetRef));
+ store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
+ 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_without_default::NewWithoutDefault>::default());
+ let disallowed_names = conf.disallowed_names.iter().cloned().collect::<FxHashSet<_>>();
+ store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_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 || {
+ let large_error_threshold = conf.large_error_threshold;
+ store.register_late_pass(move |_| {
Box::new(functions::Functions::new(
too_many_arguments_threshold,
too_many_lines_threshold,
+ large_error_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(let_if_seq::LetIfSeq));
- store.register_late_pass(|| Box::new(mixed_read_write_in_expression::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));
+ 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(let_if_seq::LetIfSeq));
+ store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::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));
+ 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(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(question_mark::QuestionMark));
+ 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(infinite_iter::InfiniteIter));
+ store.register_late_pass(|_| Box::new(inline_fn_without_body::InlineFnWithoutBody));
+ store.register_late_pass(|_| Box::<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(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(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(assertions_on_result_states::AssertionsOnResultStates));
- 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(inherent_to_string::InherentToString));
+ 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(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(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(assertions_on_result_states::AssertionsOnResultStates));
+ 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(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_early_pass(|| Box::new(reference::DerefAddrOf));
store.register_early_pass(|| Box::new(double_parens::DoubleParens));
- store.register_late_pass(|| Box::new(format_impl::FormatImpl::new()));
+ store.register_late_pass(|_| Box::new(format_impl::FormatImpl::new()));
store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
store.register_early_pass(|| Box::new(formatting::Formatting));
store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints));
store.register_early_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
- store.register_late_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
+ store.register_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_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_late_pass(|| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals));
+ store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals));
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_late_pass(|_| Box::new(create_dir::CreateDir));
store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType));
let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
store.register_early_pass(move || {
@@ -771,7 +769,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
))
});
let enum_variant_name_threshold = conf.enum_variant_name_threshold;
- store.register_late_pass(move || {
+ store.register_late_pass(move |_| {
Box::new(enum_variants::EnumVariantNames::new(
enum_variant_name_threshold,
avoid_breaking_exported_api,
@@ -779,23 +777,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
});
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 || {
+ 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(move || Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api)));
- 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));
+ store.register_late_pass(|_| Box::<default::Default>::default());
+ store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api)));
+ 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_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_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;
@@ -807,20 +805,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
});
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(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));
+ store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
+ store.register_late_pass(|_| Box::<redundant_pub_crate::RedundantPubCrate>::default());
+ store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress));
+ store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv)));
+ 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(manual_async_fn::ManualAsyncFn));
+ 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 {
@@ -829,98 +824,101 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
});
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(manual_ok_or::ManualOkOr));
- store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
- store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync));
+ store.register_late_pass(|_| Box::<macro_use::MacroUseImports>::default());
+ store.register_late_pass(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch));
+ store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult));
+ store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
+ store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync));
+ let disallowed_macros = conf.disallowed_macros.clone();
+ store.register_late_pass(move |_| Box::new(disallowed_macros::DisallowedMacros::new(disallowed_macros.clone())));
let disallowed_methods = conf.disallowed_methods.clone();
- store.register_late_pass(move || Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
+ store.register_late_pass(move |_| Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
- store.register_late_pass(|| Box::new(empty_drop::EmptyDrop));
- 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(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv)));
- store.register_late_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison));
+ store.register_late_pass(|_| Box::new(empty_drop::EmptyDrop));
+ 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::<vec_init_then_push::VecInitThenPush>::default());
+ store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing));
+ store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10));
+ 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));
+ store.register_late_pass(|_| Box::new(unused_async::UnusedAsync));
let disallowed_types = conf.disallowed_types.clone();
- store.register_late_pass(move || Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
+ store.register_late_pass(move |_| Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
let import_renames = conf.enforced_import_renames.clone();
- store.register_late_pass(move || {
+ store.register_late_pass(move |_| {
Box::new(missing_enforced_import_rename::ImportRename::new(
import_renames.clone(),
))
});
let scripts = conf.allowed_scripts.clone();
store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(&scripts)));
- store.register_late_pass(|| Box::new(strlen_on_c_strings::StrlenOnCStrings));
- store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors));
- store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
- store.register_late_pass(move || Box::new(manual_assert::ManualAssert));
+ store.register_late_pass(|_| Box::new(strlen_on_c_strings::StrlenOnCStrings));
+ store.register_late_pass(move |_| Box::new(self_named_constructors::SelfNamedConstructors));
+ store.register_late_pass(move |_| Box::new(iter_not_returning_iterator::IterNotReturningIterator));
+ store.register_late_pass(move |_| Box::new(manual_assert::ManualAssert));
let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
- store.register_late_pass(move || {
+ store.register_late_pass(move |_| {
Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(
enable_raw_pointer_heuristic_for_send,
))
});
- store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
- store.register_late_pass(move || Box::new(format_args::FormatArgs));
- store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
+ store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
+ store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv)));
+ store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
- store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit));
- store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
- store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields));
+ store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit));
+ store.register_late_pass(|_| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
+ store.register_late_pass(|_| Box::new(init_numbered_fields::NumberedFields));
store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
- store.register_late_pass(move || Box::new(borrow_as_ptr::BorrowAsPtr::new(msrv)));
- store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv)));
- store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation));
- store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes));
- store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion));
+ store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv)));
+ store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation));
+ store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default());
let allow_dbg_in_tests = conf.allow_dbg_in_tests;
- store.register_late_pass(move || Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
+ store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
let cargo_ignore_publish = conf.cargo_ignore_publish;
- store.register_late_pass(move || {
+ store.register_late_pass(move |_| {
Box::new(cargo::Cargo {
ignore_publish: cargo_ignore_publish,
})
});
+ store.register_late_pass(|_| Box::<write::Write>::default());
store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets));
- store.register_late_pass(|| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
+ store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
store.register_early_pass(|| Box::new(pub_use::PubUse));
- store.register_late_pass(|| Box::new(format_push_string::FormatPushString));
- store.register_late_pass(|| Box::new(bytes_count_to_len::BytesCountToLen));
+ store.register_late_pass(|_| Box::new(format_push_string::FormatPushString));
let max_include_file_size = conf.max_include_file_size;
- store.register_late_pass(move || Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
- store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace));
- store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
- store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default()));
- store.register_late_pass(|| Box::new(get_first::GetFirst));
+ store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
+ store.register_late_pass(|_| Box::new(strings::TrimSplitWhitespace));
+ store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
+ store.register_early_pass(|| Box::<duplicate_mod::DuplicateMod>::default());
store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv)));
- store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef));
- store.register_late_pass(|| Box::new(mismatching_type_param_order::TypeParamMismatch));
- store.register_late_pass(|| Box::new(as_underscore::AsUnderscore));
- store.register_late_pass(|| Box::new(read_zero_byte_vec::ReadZeroByteVec));
- store.register_late_pass(|| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
- store.register_late_pass(move || Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv)));
- store.register_late_pass(move || Box::new(manual_retain::ManualRetain::new(msrv)));
+ store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef));
+ store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch));
+ store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec));
+ store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
+ store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv)));
+ store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv)));
let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
- store.register_late_pass(move || Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
- store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
- store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default()));
+ store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
+ store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
+ store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default());
+ store.register_late_pass(|_| Box::new(manual_instant_elapsed::ManualInstantElapsed));
+ store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
+ store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(msrv)));
+ store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew));
+ store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable));
+ store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments));
+ store.register_late_pass(|_| Box::new(bool_to_int_with_if::BoolToIntWithIf));
+ store.register_late_pass(|_| Box::new(box_default::BoxDefault));
+ store.register_late_pass(|_| Box::new(implicit_saturating_add::ImplicitSaturatingAdd));
+ store.register_early_pass(|| Box::new(partial_pub_fields::PartialPubFields));
+ store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
// add lints here, do not remove this comment, it's used in `new_lint`
}
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 573a7c016..3bf2d7e4e 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -9,8 +9,8 @@ use rustc_hir::intravisit::{
use rustc_hir::FnRetTy::Return;
use rustc_hir::{
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
- ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin,
- TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
+ ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin, TraitFn,
+ TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter as middle_nested_filter;
@@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
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.def_id).is_none();
+ let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id.def_id).is_none();
check_fn_inner(
cx,
sig.decl,
@@ -276,7 +276,7 @@ fn could_use_elision<'tcx>(
let mut checker = BodyLifetimeChecker {
lifetimes_used_in_body: false,
};
- checker.visit_expr(&body.value);
+ checker.visit_expr(body.value);
if checker.lifetimes_used_in_body {
return false;
}
@@ -422,7 +422,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
self.record(&Some(*lifetime));
}
- fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>, tbm: TraitBoundModifier) {
+ fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>) {
let trait_ref = &poly_tref.trait_ref;
if CLOSURE_TRAIT_BOUNDS.iter().any(|&item| {
self.cx
@@ -435,13 +435,13 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
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);
+ walk_poly_trait_ref(self, poly_tref);
}
}
fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
match ty.kind {
- TyKind::OpaqueDef(item, bounds) => {
+ TyKind::OpaqueDef(item, bounds, _) => {
let map = self.cx.tcx.hir();
let item = map.item(item);
let len = self.lts.len();
@@ -466,7 +466,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
self.unelided_trait_object_lifetime = true;
}
for bound in bounds {
- self.visit_poly_trait_ref(bound, TraitBoundModifier::None);
+ self.visit_poly_trait_ref(bound);
}
},
_ => walk_ty(self, ty),
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index fb2104861..25f19b9c6 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -478,7 +478,7 @@ impl DecimalLiteralRepresentation {
if num_lit.radix == Radix::Decimal;
if val >= u128::from(self.threshold);
then {
- let hex = format!("{:#X}", val);
+ let hex = format!("{val:#X}");
let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| {
warning_type.display(num_lit.format(), cx, lit.span);
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
index 8e3ab26a9..14f223481 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
@@ -44,11 +44,10 @@ pub(super) fn check<'tcx>(
cx,
EXPLICIT_COUNTER_LOOP,
span,
- &format!("the variable `{}` is used as a loop counter", name),
+ &format!("the variable `{name}` is used as a loop counter"),
"consider using",
format!(
- "for ({}, {}) in {}.enumerate()",
- name,
+ "for ({name}, {}) in {}.enumerate()",
snippet_with_applicability(cx, pat.span, "item", &mut applicability),
make_iterator_snippet(cx, arg, &mut applicability),
),
@@ -65,24 +64,21 @@ pub(super) fn check<'tcx>(
cx,
EXPLICIT_COUNTER_LOOP,
span,
- &format!("the variable `{}` is used as a loop counter", name),
+ &format!("the variable `{name}` is used as a loop counter"),
|diag| {
diag.span_suggestion(
span,
"consider using",
format!(
- "for ({}, {}) in (0_{}..).zip({})",
- name,
+ "for ({name}, {}) in (0_{int_name}..).zip({})",
snippet_with_applicability(cx, pat.span, "item", &mut applicability),
- int_name,
make_iterator_snippet(cx, arg, &mut applicability),
),
applicability,
);
diag.note(&format!(
- "`{}` is of type `{}`, making it ineligible for `Iterator::enumerate`",
- name, int_name
+ "`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`"
));
},
);
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index 5f5beccd0..b1f294162 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, m
"it is more concise to loop over references to containers instead of using explicit \
iteration methods",
"to write this more concisely, try",
- format!("&{}{}", muta, object),
+ format!("&{muta}{object}"),
applicability,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
index bee0e1d76..ed620460d 100644
--- a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
@@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx
cx,
FOR_KV_MAP,
arg_span,
- &format!("you seem to want to iterate on a map's {}s", kind),
+ &format!("you seem to want to iterate on a map's {kind}s"),
|diag| {
let map = sugg::Sugg::hir(cx, arg, "map");
multispan_sugg(
@@ -46,7 +46,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx
"use the corresponding method",
vec![
(pat_span, snippet(cx, new_pat_span, kind).into_owned()),
- (arg_span, format!("{}.{}s{}()", map.maybe_par(), kind, mutbl)),
+ (arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_par())),
],
);
},
diff --git a/src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs b/src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs
deleted file mode 100644
index 77de90fd7..000000000
--- a/src/tools/clippy/clippy_lints/src/loops/for_loops_over_fallibles.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-use super::FOR_LOOPS_OVER_FALLIBLES;
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
-use rustc_hir::{Expr, Pat};
-use rustc_lint::LateContext;
-use rustc_span::symbol::sym;
-
-/// Checks for `for` loops over `Option`s and `Result`s.
-pub(super) fn check(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, method_name: Option<&str>) {
- let ty = cx.typeck_results().expr_ty(arg);
- if is_type_diagnostic_item(cx, ty, sym::Option) {
- let help_string = if let Some(method_name) = method_name {
- format!(
- "consider replacing `for {0} in {1}.{method_name}()` with `if let Some({0}) = {1}`",
- snippet(cx, pat.span, "_"),
- snippet(cx, arg.span, "_")
- )
- } else {
- format!(
- "consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`",
- snippet(cx, pat.span, "_"),
- snippet(cx, arg.span, "_")
- )
- };
- span_lint_and_help(
- cx,
- FOR_LOOPS_OVER_FALLIBLES,
- arg.span,
- &format!(
- "for loop over `{0}`, which is an `Option`. This is more readably written as an \
- `if let` statement",
- snippet(cx, arg.span, "_")
- ),
- None,
- &help_string,
- );
- } else if is_type_diagnostic_item(cx, ty, sym::Result) {
- let help_string = if let Some(method_name) = method_name {
- format!(
- "consider replacing `for {0} in {1}.{method_name}()` with `if let Ok({0}) = {1}`",
- snippet(cx, pat.span, "_"),
- snippet(cx, arg.span, "_")
- )
- } else {
- format!(
- "consider replacing `for {0} in {1}` with `if let Ok({0}) = {1}`",
- snippet(cx, pat.span, "_"),
- snippet(cx, arg.span, "_")
- )
- };
- span_lint_and_help(
- cx,
- FOR_LOOPS_OVER_FALLIBLES,
- arg.span,
- &format!(
- "for loop over `{0}`, which is a `Result`. This is more readably written as an \
- `if let` statement",
- snippet(cx, arg.span, "_")
- ),
- None,
- &help_string,
- );
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs b/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs
index e640c62eb..b8a263817 100644
--- a/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs
@@ -5,7 +5,7 @@ use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_span::sym;
-pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
+pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) {
if is_trait_method(cx, arg, sym::Iterator) {
span_lint(
cx,
@@ -14,8 +14,5 @@ pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
"you are iterating over `Iterator::next()` which is an Option; this will compile but is \
probably not what you want",
);
- true
- } else {
- false
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
index 215c83a7e..4bb9936e9 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
@@ -1,7 +1,7 @@
use super::utils::make_iterator_snippet;
use super::MANUAL_FIND;
use clippy_utils::{
- diagnostics::span_lint_and_then, higher, is_lang_ctor, path_res, peel_blocks_with_stmt,
+ diagnostics::span_lint_and_then, higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt,
source::snippet_with_applicability, ty::implements_trait,
};
use if_chain::if_chain;
@@ -30,8 +30,8 @@ pub(super) fn check<'tcx>(
if let [stmt] = block.stmts;
if let StmtKind::Semi(semi) = stmt.kind;
if let ExprKind::Ret(Some(ret_value)) = semi.kind;
- if let ExprKind::Call(Expr { kind: ExprKind::Path(ctor), .. }, [inner_ret]) = ret_value.kind;
- if is_lang_ctor(cx, ctor, LangItem::OptionSome);
+ if let ExprKind::Call(ctor, [inner_ret]) = ret_value.kind;
+ if is_res_lang_ctor(cx, path_res(cx, ctor), LangItem::OptionSome);
if path_res(cx, inner_ret) == Res::Local(binding_id);
if let Some((last_stmt, last_ret)) = last_stmt_and_ret(cx, expr);
then {
@@ -106,7 +106,7 @@ fn get_binding(pat: &Pat<'_>) -> Option<HirId> {
hir_id = None;
return;
}
- if let BindingAnnotation::Unannotated = annotation {
+ if let BindingAnnotation::NONE = annotation {
hir_id = Some(id);
}
});
@@ -143,8 +143,7 @@ fn last_stmt_and_ret<'tcx>(
if let Some((_, Node::Block(block))) = parent_iter.next();
if let Some((last_stmt, last_ret)) = extract(block);
if last_stmt.hir_id == node_hir;
- if let ExprKind::Path(path) = &last_ret.kind;
- if is_lang_ctor(cx, path, LangItem::OptionNone);
+ if is_res_lang_ctor(cx, path_res(cx, last_ret), LangItem::OptionNone);
if let Some((_, Node::Expr(_block))) = parent_iter.next();
// This includes the function header
if let Some((_, func)) = parent_iter.next();
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
index 1d6ddf4b9..8c27c0940 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -3,13 +3,13 @@ use super::MANUAL_FLATTEN;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher;
use clippy_utils::visitors::is_local_used;
-use clippy_utils::{is_lang_ctor, path_to_local_id, peel_blocks_with_stmt};
+use clippy_utils::{path_to_local_id, peel_blocks_with_stmt};
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::LangItem::{OptionSome, ResultOk};
+use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, Pat, PatKind};
use rustc_lint::LateContext;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, DefIdTree};
use rustc_span::source_map::Span;
/// Check for unnecessary `if let` usage in a for loop where only the `Some` or `Ok` variant of the
@@ -30,15 +30,17 @@ pub(super) fn check<'tcx>(
if path_to_local_id(let_expr, pat_hir_id);
// Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
if let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind;
- let some_ctor = is_lang_ctor(cx, qpath, OptionSome);
- let ok_ctor = is_lang_ctor(cx, qpath, ResultOk);
+ if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id);
+ if let Some(variant_id) = cx.tcx.opt_parent(ctor_id);
+ let some_ctor = cx.tcx.lang_items().option_some_variant() == Some(variant_id);
+ let ok_ctor = cx.tcx.lang_items().result_ok_variant() == Some(variant_id);
if some_ctor || ok_ctor;
// Ensure expr in `if let` is not used afterwards
if !is_local_used(cx, if_then, pat_hir_id);
then {
let if_let_type = if some_ctor { "Some" } else { "Ok" };
// Prepare the error message
- let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type);
+ let msg = format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used");
// Prepare the help message
let mut applicability = Applicability::MaybeIncorrect;
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index b31015d19..c87fc4f90 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -119,11 +119,9 @@ fn build_manual_memcpy_suggestion<'tcx>(
let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
if_chain! {
- if let ExprKind::MethodCall(method, len_args, _) = end.kind;
+ if let ExprKind::MethodCall(method, recv, [], _) = end.kind;
if method.ident.name == sym::len;
- if len_args.len() == 1;
- if let Some(arg) = len_args.get(0);
- if path_to_local(arg) == path_to_local(base);
+ if path_to_local(recv) == path_to_local(base);
then {
if sugg.to_string() == end_str {
sugg::EMPTY.into()
@@ -179,13 +177,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
let dst = if dst_offset == sugg::EMPTY && dst_limit == sugg::EMPTY {
dst_base_str
} else {
- format!(
- "{}[{}..{}]",
- dst_base_str,
- dst_offset.maybe_par(),
- dst_limit.maybe_par()
- )
- .into()
+ format!("{dst_base_str}[{}..{}]", dst_offset.maybe_par(), dst_limit.maybe_par()).into()
};
let method_str = if is_copy(cx, elem_ty) {
@@ -195,10 +187,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
};
format!(
- "{}.{}(&{}[{}..{}]);",
- dst,
- method_str,
- src_base_str,
+ "{dst}.{method_str}(&{src_base_str}[{}..{}]);",
src_offset.maybe_par(),
src_limit.maybe_par()
)
@@ -343,10 +332,8 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti
fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
if_chain! {
- if let ExprKind::MethodCall(method, args, _) = expr.kind;
+ if let ExprKind::MethodCall(method, arg, [], _) = expr.kind;
if method.ident.name == sym::clone;
- if args.len() == 1;
- if let Some(arg) = args.get(0);
then { arg } else { expr }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
index 0696afa39..8412875b1 100644
--- a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
@@ -33,7 +33,7 @@ fn unpack_cond<'tcx>(cond: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
if_chain! {
if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind;
- if let ExprKind::MethodCall(method, [callee, ..], _) = unpack_cond(cond).kind;
+ if let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind;
if [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name);
if let ty::Adt(def, _substs) = cx.typeck_results().expr_ty(callee).kind();
if cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did());
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index ed270bd49..bcf278d9c 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -3,7 +3,6 @@ mod explicit_counter_loop;
mod explicit_into_iter_loop;
mod explicit_iter_loop;
mod for_kv_map;
-mod for_loops_over_fallibles;
mod iter_next_loop;
mod manual_find;
mod manual_flatten;
@@ -175,49 +174,6 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
- /// Checks for `for` loops over `Option` or `Result` values.
- ///
- /// ### Why is this bad?
- /// Readability. This is more clearly expressed as an `if
- /// let`.
- ///
- /// ### Example
- /// ```rust
- /// # let opt = Some(1);
- /// # let res: Result<i32, std::io::Error> = Ok(1);
- /// for x in opt {
- /// // ..
- /// }
- ///
- /// for x in &res {
- /// // ..
- /// }
- ///
- /// for x in res.iter() {
- /// // ..
- /// }
- /// ```
- ///
- /// Use instead:
- /// ```rust
- /// # let opt = Some(1);
- /// # let res: Result<i32, std::io::Error> = Ok(1);
- /// if let Some(x) = opt {
- /// // ..
- /// }
- ///
- /// if let Ok(x) = res {
- /// // ..
- /// }
- /// ```
- #[clippy::version = "1.45.0"]
- pub FOR_LOOPS_OVER_FALLIBLES,
- suspicious,
- "for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`"
-}
-
-declare_clippy_lint! {
- /// ### What it does
/// Detects `loop + match` combinations that are easier
/// written as a `while let` loop.
///
@@ -635,7 +591,7 @@ declare_clippy_lint! {
/// arr.into_iter().find(|&el| el == 1)
/// }
/// ```
- #[clippy::version = "1.61.0"]
+ #[clippy::version = "1.64.0"]
pub MANUAL_FIND,
complexity,
"manual implementation of `Iterator::find`"
@@ -648,7 +604,6 @@ declare_lint_pass!(Loops => [
EXPLICIT_ITER_LOOP,
EXPLICIT_INTO_ITER_LOOP,
ITER_NEXT_LOOP,
- FOR_LOOPS_OVER_FALLIBLES,
WHILE_LET_LOOP,
NEEDLESS_COLLECT,
EXPLICIT_COUNTER_LOOP,
@@ -739,30 +694,22 @@ fn check_for_loop<'tcx>(
manual_find::check(cx, pat, arg, body, span, expr);
}
-fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
- let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
-
- if let ExprKind::MethodCall(method, [self_arg], _) = arg.kind {
+fn check_for_loop_arg(cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) {
+ if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
let method_name = method.ident.as_str();
// check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
match method_name {
"iter" | "iter_mut" => {
explicit_iter_loop::check(cx, self_arg, arg, method_name);
- for_loops_over_fallibles::check(cx, pat, self_arg, Some(method_name));
},
"into_iter" => {
explicit_iter_loop::check(cx, self_arg, arg, method_name);
explicit_into_iter_loop::check(cx, self_arg, arg);
- for_loops_over_fallibles::check(cx, pat, self_arg, Some(method_name));
},
"next" => {
- next_loop_linted = iter_next_loop::check(cx, arg);
+ iter_next_loop::check(cx, arg);
},
_ => {},
}
}
-
- if !next_loop_linted {
- for_loops_over_fallibles::check(cx, pat, arg, None);
- }
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index aedf3810b..91b321c44 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -4,11 +4,11 @@ use clippy_utils::{get_enclosing_block, higher, path_to_local};
use if_chain::if_chain;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind};
+use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
use rustc_middle::{mir::FakeReadCause, ty};
use rustc_span::source_map::Span;
-use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
if_chain! {
@@ -44,7 +44,7 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId>
if_chain! {
if let Some(hir_id) = path_to_local(bound);
if let Node::Pat(pat) = cx.tcx.hir().get(hir_id);
- if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind;
+ if let PatKind::Binding(BindingAnnotation::MUT, ..) = pat.kind;
then {
return Some(hir_id);
}
@@ -65,16 +65,15 @@ fn check_for_mutation<'tcx>(
span_low: None,
span_high: None,
};
- cx.tcx.infer_ctxt().enter(|infcx| {
- ExprUseVisitor::new(
- &mut delegate,
- &infcx,
- body.hir_id.owner,
- cx.param_env,
- cx.typeck_results(),
- )
- .walk_expr(body);
- });
+ let infcx = cx.tcx.infer_ctxt().build();
+ ExprUseVisitor::new(
+ &mut delegate,
+ &infcx,
+ body.hir_id.owner.def_id,
+ cx.param_env,
+ cx.typeck_results(),
+ )
+ .walk_expr(body);
delegate.mutation_span()
}
@@ -114,7 +113,13 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
}
}
- fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+ fn fake_read(
+ &mut self,
+ _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
+ _: FakeReadCause,
+ _: HirId,
+ ) {
+ }
}
impl MutatePairDelegate<'_, '_> {
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
index ddaffc751..66f9e2859 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
@@ -1,5 +1,6 @@
use super::NEEDLESS_COLLECT;
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
+use clippy_utils::higher;
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
@@ -24,11 +25,11 @@ pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
}
fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
if_chain! {
- if let ExprKind::MethodCall(method, args, _) = expr.kind;
- if let ExprKind::MethodCall(chain_method, _, _) = args[0].kind;
- if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
+ if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind;
+ if let ExprKind::MethodCall(chain_method, ..) = receiver.kind;
+ if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator);
then {
- let ty = cx.typeck_results().expr_ty(&args[0]);
+ let ty = cx.typeck_results().expr_ty(receiver);
let mut applicability = Applicability::MaybeIncorrect;
let is_empty_sugg = "next().is_none()".to_string();
let method_name = method.ident.name.as_str();
@@ -40,11 +41,11 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
"len" => "count()".to_string(),
"is_empty" => is_empty_sugg,
"contains" => {
- let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability);
+ let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability);
let (arg, pred) = contains_arg
.strip_prefix('&')
.map_or(("&x", &*contains_arg), |s| ("x", s));
- format!("any(|{}| x == {})", arg, pred)
+ format!("any(|{arg}| x == {pred})")
}
_ => return,
}
@@ -79,7 +80,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
if let StmtKind::Local(local) = stmt.kind;
if let PatKind::Binding(_, id, ..) = local.pat.kind;
if let Some(init_expr) = local.init;
- if let ExprKind::MethodCall(method_name, &[ref iter_source], ..) = init_expr.kind;
+ if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind;
if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
let ty = cx.typeck_results().expr_ty(init_expr);
if is_type_diagnostic_item(cx, ty, sym::Vec) ||
@@ -140,9 +141,9 @@ impl IterFunction {
IterFunctionKind::Contains(span) => {
let s = snippet(cx, *span, "..");
if let Some(stripped) = s.strip_prefix('&') {
- format!(".any(|x| x == {})", stripped)
+ format!(".any(|x| x == {stripped})")
} else {
- format!(".any(|x| x == *{})", s)
+ format!(".any(|x| x == *{s})")
}
},
}
@@ -184,16 +185,25 @@ struct IterFunctionVisitor<'a, 'tcx> {
impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
fn visit_block(&mut self, block: &'tcx Block<'tcx>) {
for (expr, hir_id) in block.stmts.iter().filter_map(get_expr_and_hir_id_from_stmt) {
+ if check_loop_kind(expr).is_some() {
+ continue;
+ }
self.visit_block_expr(expr, hir_id);
}
if let Some(expr) = block.expr {
- self.visit_block_expr(expr, None);
+ if let Some(loop_kind) = check_loop_kind(expr) {
+ if let LoopKind::Conditional(block_expr) = loop_kind {
+ self.visit_block_expr(block_expr, None);
+ }
+ } else {
+ self.visit_block_expr(expr, None);
+ }
}
}
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
// Check function calls on our collection
- if let ExprKind::MethodCall(method_name, [recv, args @ ..], _) = &expr.kind {
+ if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind {
if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) {
self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
self.visit_expr(recv);
@@ -264,6 +274,28 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
}
}
+enum LoopKind<'tcx> {
+ Conditional(&'tcx Expr<'tcx>),
+ Loop,
+}
+
+fn check_loop_kind<'tcx>(expr: &Expr<'tcx>) -> Option<LoopKind<'tcx>> {
+ if let Some(higher::WhileLet { let_expr, .. }) = higher::WhileLet::hir(expr) {
+ return Some(LoopKind::Conditional(let_expr));
+ }
+ if let Some(higher::While { condition, .. }) = higher::While::hir(expr) {
+ return Some(LoopKind::Conditional(condition));
+ }
+ if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr) {
+ return Some(LoopKind::Conditional(arg));
+ }
+ if let ExprKind::Loop { .. } = expr.kind {
+ return Some(LoopKind::Loop);
+ }
+
+ None
+}
+
impl<'tcx> IterFunctionVisitor<'_, 'tcx> {
fn visit_block_expr(&mut self, expr: &'tcx Expr<'tcx>, hir_id: Option<HirId>) {
self.current_statement_hir_id = hir_id;
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index a7ef562b2..27ba27202 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::ty::has_iter_method;
use clippy_utils::visitors::is_local_used;
-use clippy_utils::{contains_name, higher, is_integer_const, match_trait_method, paths, sugg, SpanlessEq};
+use clippy_utils::{contains_name, higher, is_integer_const, sugg, SpanlessEq};
use if_chain::if_chain;
use rustc_ast::ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -145,7 +145,7 @@ pub(super) fn check<'tcx>(
cx,
NEEDLESS_RANGE_LOOP,
arg.span,
- &format!("the loop variable `{}` is used to index `{}`", ident.name, indexed),
+ &format!("the loop variable `{}` is used to index `{indexed}`", ident.name),
|diag| {
multispan_sugg(
diag,
@@ -154,7 +154,7 @@ pub(super) fn check<'tcx>(
(pat.span, format!("({}, <item>)", ident.name)),
(
arg.span,
- format!("{}.{}().enumerate(){}{}", indexed, method, method_1, method_2),
+ format!("{indexed}.{method}().enumerate(){method_1}{method_2}"),
),
],
);
@@ -162,16 +162,16 @@ pub(super) fn check<'tcx>(
);
} else {
let repl = if starts_at_zero && take_is_empty {
- format!("&{}{}", ref_mut, indexed)
+ format!("&{ref_mut}{indexed}")
} else {
- format!("{}.{}(){}{}", indexed, method, method_1, method_2)
+ format!("{indexed}.{method}(){method_1}{method_2}")
};
span_lint_and_then(
cx,
NEEDLESS_RANGE_LOOP,
arg.span,
- &format!("the loop variable `{}` is only used to index `{}`", ident.name, indexed),
+ &format!("the loop variable `{}` is only used to index `{indexed}`", ident.name),
|diag| {
multispan_sugg(
diag,
@@ -188,10 +188,9 @@ pub(super) fn check<'tcx>(
fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool {
if_chain! {
- if let ExprKind::MethodCall(method, len_args, _) = expr.kind;
- if len_args.len() == 1;
+ if let ExprKind::MethodCall(method, recv, [], _) = expr.kind;
if method.ident.name == sym::len;
- if let ExprKind::Path(QPath::Resolved(_, path)) = len_args[0].kind;
+ if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind;
if path.segments.len() == 1;
if path.segments[0].ident.name == var;
then {
@@ -264,7 +263,8 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
match res {
Res::Local(hir_id) => {
let parent_def_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
- let extent = self.cx
+ let extent = self
+ .cx
.tcx
.region_scope_tree(parent_def_id)
.var_scope(hir_id.local_id)
@@ -275,11 +275,12 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
(Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)),
);
} else {
- self.indexed_indirectly.insert(seqvar.segments[0].ident.name, Some(extent));
+ self.indexed_indirectly
+ .insert(seqvar.segments[0].ident.name, Some(extent));
}
- return false; // no need to walk further *on the variable*
- }
- Res::Def(DefKind::Static (_)| DefKind::Const, ..) => {
+ return false; // no need to walk further *on the variable*
+ },
+ Res::Def(DefKind::Static(_) | DefKind::Const, ..) => {
if index_used_directly {
self.indexed_directly.insert(
seqvar.segments[0].ident.name,
@@ -288,8 +289,8 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
} else {
self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None);
}
- return false; // no need to walk further *on the variable*
- }
+ return false; // no need to walk further *on the variable*
+ },
_ => (),
}
}
@@ -302,18 +303,27 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
if_chain! {
// a range index op
- if let ExprKind::MethodCall(meth, [args_0, args_1, ..], _) = &expr.kind;
- if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX))
- || (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT));
+ if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind;
+ if let Some(trait_id) = self
+ .cx
+ .typeck_results()
+ .type_dependent_def_id(expr.hir_id)
+ .and_then(|def_id| self.cx.tcx.trait_of_item(def_id));
+ if (meth.ident.name == sym::index && self.cx.tcx.lang_items().index_trait() == Some(trait_id))
+ || (meth.ident.name == sym::index_mut && self.cx.tcx.lang_items().index_mut_trait() == Some(trait_id));
if !self.check(args_1, args_0, expr);
- then { return }
+ then {
+ return;
+ }
}
if_chain! {
// an index op
if let ExprKind::Index(seqexpr, idx) = expr.kind;
if !self.check(idx, seqexpr, expr);
- then { return }
+ then {
+ return;
+ }
}
if_chain! {
@@ -357,9 +367,12 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
self.visit_expr(expr);
}
},
- ExprKind::MethodCall(_, args, _) => {
+ ExprKind::MethodCall(_, receiver, args, _) => {
let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
- for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args) {
+ for (ty, expr) in iter::zip(
+ self.cx.tcx.fn_sig(def_id).inputs().skip_binder(),
+ std::iter::once(receiver).chain(args.iter()),
+ ) {
self.prefer_mutable = false;
if let ty::Ref(_, _, mutbl) = *ty.kind() {
if mutbl == Mutability::Mut {
@@ -371,7 +384,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
},
ExprKind::Closure(&Closure { body, .. }) => {
let body = self.cx.tcx.hir().body(body);
- self.visit_expr(&body.value);
+ self.visit_expr(body.value);
},
_ => walk_expr(self, expr),
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 32de20f65..16b00ad66 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -42,6 +42,7 @@ pub(super) fn check(
}
}
+#[derive(Copy, Clone)]
enum NeverLoopResult {
// A break/return always get triggered but not necessarily for the main loop.
AlwaysBreak,
@@ -51,8 +52,8 @@ enum NeverLoopResult {
}
#[must_use]
-fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult {
- match *arg {
+fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
+ match arg {
NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
}
@@ -92,19 +93,29 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
}
fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult {
- let mut iter = block.stmts.iter().filter_map(stmt_to_expr).chain(block.expr);
+ let mut iter = block
+ .stmts
+ .iter()
+ .filter_map(stmt_to_expr)
+ .chain(block.expr.map(|expr| (expr, None)));
never_loop_expr_seq(&mut iter, main_loop_id)
}
-fn never_loop_expr_seq<'a, T: Iterator<Item = &'a Expr<'a>>>(es: &mut T, main_loop_id: HirId) -> NeverLoopResult {
- es.map(|e| never_loop_expr(e, main_loop_id))
- .fold(NeverLoopResult::Otherwise, combine_seq)
+fn never_loop_expr_seq<'a, T: Iterator<Item = (&'a Expr<'a>, Option<&'a Block<'a>>)>>(
+ es: &mut T,
+ main_loop_id: HirId,
+) -> NeverLoopResult {
+ es.map(|(e, els)| {
+ let e = never_loop_expr(e, main_loop_id);
+ els.map_or(e, |els| combine_branches(e, never_loop_block(els, main_loop_id)))
+ })
+ .fold(NeverLoopResult::Otherwise, combine_seq)
}
-fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'tcx Block<'tcx>>)> {
match stmt.kind {
- StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some(e),
- StmtKind::Local(local) => local.init,
+ StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some((e, None)),
+ StmtKind::Local(local) => local.init.map(|init| (init, local.els)),
StmtKind::Item(..) => None,
}
}
@@ -120,8 +131,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
| ExprKind::Repeat(e, _)
| ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id),
- ExprKind::Array(es) | ExprKind::MethodCall(_, es, _) | ExprKind::Tup(es) => {
- never_loop_expr_all(&mut es.iter(), main_loop_id)
+ ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), main_loop_id),
+ ExprKind::MethodCall(_, receiver, es, _) => {
+ never_loop_expr_all(&mut std::iter::once(receiver).chain(es.iter()), main_loop_id)
},
ExprKind::Struct(_, fields, base) => {
let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), main_loop_id);
@@ -138,7 +150,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
| ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().copied(), main_loop_id),
ExprKind::Loop(b, _, _, _) => {
// Break can come from the inner loop so remove them.
- absorb_break(&never_loop_block(b, main_loop_id))
+ absorb_break(never_loop_block(b, main_loop_id))
},
ExprKind::If(e, e2, e3) => {
let e1 = never_loop_expr(e, main_loop_id);
@@ -178,9 +190,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
never_loop_expr(expr, main_loop_id)
},
- InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter(), main_loop_id),
+ InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter().copied(), main_loop_id),
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
- never_loop_expr_all(&mut once(in_expr).chain(out_expr.iter()), main_loop_id)
+ never_loop_expr_all(&mut once(*in_expr).chain(out_expr.iter().copied()), main_loop_id)
},
InlineAsmOperand::Const { .. }
| InlineAsmOperand::SymFn { .. }
@@ -210,9 +222,5 @@ fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>)
let pat_snippet = snippet(cx, pat.span, "_");
let iter_snippet = make_iterator_snippet(cx, iterator, &mut Applicability::Unspecified);
- format!(
- "if let Some({pat}) = {iter}.next()",
- pat = pat_snippet,
- iter = iter_snippet
- )
+ format!("if let Some({pat_snippet}) = {iter_snippet}.next()")
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index 1439f1f4c..07edee46f 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -7,7 +7,7 @@ use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind};
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind};
use rustc_lint::LateContext;
use rustc_span::symbol::sym;
use std::iter::Iterator;
@@ -30,10 +30,7 @@ pub(super) fn check<'tcx>(
vec.span,
"it looks like the same item is being pushed into this Vec",
None,
- &format!(
- "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
- item_str, vec_str, item_str
- ),
+ &format!("try using vec![{item_str};SIZE] or {vec_str}.resize(NEW_SIZE, {item_str})"),
);
}
@@ -65,7 +62,7 @@ pub(super) fn check<'tcx>(
if_chain! {
if let Node::Pat(pat) = node;
if let PatKind::Binding(bind_ann, ..) = pat.kind;
- if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
+ if !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut));
let parent_node = cx.tcx.hir().get_parent_node(hir_id);
if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node);
if let Some(init) = parent_let_expr.init;
@@ -180,10 +177,9 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&
if_chain! {
// Extract method being called
if let StmtKind::Semi(semi_stmt) = &stmt.kind;
- if let ExprKind::MethodCall(path, args, _) = &semi_stmt.kind;
+ if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind;
// Figure out the parameters for the method call
- if let Some(self_expr) = args.get(0);
- if let Some(pushed_item) = args.get(1);
+ if let Some(pushed_item) = args.get(0);
// Check that the method being called is push() on a Vec
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
if path.ident.name.as_str() == "push";
diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
index a0bd7ad0a..f4b47808d 100644
--- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
@@ -35,32 +35,29 @@ pub(super) fn check<'tcx>(
) => (arg, "&mut "),
ExprKind::MethodCall(
method,
- [
- Expr {
- kind: ExprKind::Array([arg]),
- ..
- },
- ],
+ Expr {
+ kind: ExprKind::Array([arg]),
+ ..
+ },
+ [],
_,
) if method.ident.name == rustc_span::sym::iter => (arg, "&"),
ExprKind::MethodCall(
method,
- [
- Expr {
- kind: ExprKind::Array([arg]),
- ..
- },
- ],
+ Expr {
+ kind: ExprKind::Array([arg]),
+ ..
+ },
+ [],
_,
) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "),
ExprKind::MethodCall(
method,
- [
- Expr {
- kind: ExprKind::Array([arg]),
- ..
- },
- ],
+ Expr {
+ kind: ExprKind::Array([arg]),
+ ..
+ },
+ [],
_,
) if method.ident.name == rustc_span::sym::into_iter => (arg, ""),
// Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise.
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 4801a84eb..b6f4cf7bb 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -5,12 +5,12 @@ use rustc_ast::ast::{LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, walk_local, walk_pat, walk_stmt, Visitor};
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, Local, Mutability, Pat, PatKind, Stmt};
+use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Ty};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Symbol};
-use rustc_typeck::hir_ty_to_ty;
use std::iter::Iterator;
#[derive(Debug, PartialEq, Eq)]
@@ -344,9 +344,8 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
_ => arg,
};
format!(
- "{}.{}()",
+ "{}.{method_name}()",
sugg::Sugg::hir_with_applicability(cx, caller, "_", applic_ref).maybe_par(),
- method_name,
)
},
_ => format!(
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
index ca617859d..735d704a4 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
@@ -11,7 +11,14 @@ use rustc_lint::LateContext;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) {
([stmt, stmts @ ..], expr) => {
- if let StmtKind::Local(&Local { init: Some(e), els: None, .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind {
+ if let StmtKind::Local(&Local {
+ init: Some(e),
+ els: None,
+ ..
+ })
+ | StmtKind::Semi(e)
+ | StmtKind::Expr(e) = stmt.kind
+ {
(e, !stmts.is_empty() || expr.is_some())
} else {
return;
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index e9e215e66..55989f8a4 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -3,13 +3,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{
- get_enclosing_loop_or_multi_call_closure, is_refutable, is_trait_method, match_def_path, paths,
- visitors::is_res_used,
+ get_enclosing_loop_or_multi_call_closure, is_refutable, is_res_lang_ctor, is_trait_method, visitors::is_res_used,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{def::Res, Closure, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp};
+use rustc_hir::{def::Res, Closure, Expr, ExprKind, HirId, LangItem, Local, Mutability, PatKind, UnOp};
use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::ty::adjustment::Adjust;
@@ -19,11 +18,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let (scrutinee_expr, iter_expr_struct, iter_expr, some_pat, loop_expr) = if_chain! {
if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr);
// check for `Some(..)` pattern
- if let PatKind::TupleStruct(QPath::Resolved(None, pat_path), some_pat, _) = let_pat.kind;
- if let Res::Def(_, pat_did) = pat_path.res;
- if match_def_path(cx, pat_did, &paths::OPTION_SOME);
+ if let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind;
+ if is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome);
// check for call to `Iterator::next`
- if let ExprKind::MethodCall(method_name, [iter_expr], _) = let_expr.kind;
+ if let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind;
if method_name.ident.name == sym::next;
if is_trait_method(cx, let_expr, sym::Iterator);
if let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr);
@@ -67,7 +65,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
expr.span.with_hi(scrutinee_expr.span.hi()),
"this loop could be written as a `for` loop",
"try",
- format!("for {} in {}{}", loop_var, iterator, by_ref),
+ format!("for {loop_var} in {iterator}{by_ref}"),
applicability,
);
}
@@ -333,9 +331,8 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
}
if let Some(e) = get_enclosing_loop_or_multi_call_closure(cx, loop_expr) {
- let local_id = match iter_expr.path {
- Res::Local(id) => id,
- _ => return true,
+ let Res::Local(local_id) = iter_expr.path else {
+ return true
};
let mut v = NestedLoopVisitor {
cx,
@@ -356,7 +353,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
after_loop: false,
used_iter: false,
};
- v.visit_expr(&cx.tcx.hir().body(cx.enclosing_body.unwrap()).value);
+ v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value);
v.used_iter
}
}
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index d573a1b4f..594f6af76 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -189,9 +189,9 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
let mut suggestions = vec![];
for ((root, span, hir_id), path) in used {
if path.len() == 1 {
- suggestions.push((span, format!("{}::{}", root, path[0]), hir_id));
+ suggestions.push((span, format!("{root}::{}", path[0]), hir_id));
} else {
- suggestions.push((span, format!("{}::{{{}}}", root, path.join(", ")), hir_id));
+ suggestions.push((span, format!("{root}::{{{}}}", path.join(", ")), hir_id));
}
}
@@ -199,7 +199,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
// such as `std::prelude::v1::foo` or some other macro that expands to an import.
if self.mac_refs.is_empty() {
for (span, import, hir_id) in suggestions {
- let help = format!("use {};", import);
+ let help = format!("use {import};");
span_lint_hir_and_then(
cx,
MACRO_USE_IMPORTS,
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index 26b53ab5d..b8ed9b9ec 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -1,7 +1,8 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use crate::rustc_lint::LintContext;
+use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::{root_macro_call, FormatArgsExpn};
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{peel_blocks_with_stmt, sugg};
+use clippy_utils::{peel_blocks_with_stmt, span_extract_comment, sugg};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
@@ -50,20 +51,38 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert {
let mut applicability = Applicability::MachineApplicable;
let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability);
let cond = cond.peel_drop_temps();
+ let mut comments = span_extract_comment(cx.sess().source_map(), expr.span);
+ if !comments.is_empty() {
+ comments += "\n";
+ }
let (cond, not) = match cond.kind {
ExprKind::Unary(UnOp::Not, e) => (e, ""),
_ => (cond, "!"),
};
let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
- span_lint_and_sugg(
+ // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block
+ span_lint_and_then(
cx,
MANUAL_ASSERT,
expr.span,
"only a `panic!` in `if`-then statement",
- "try",
- sugg,
- Applicability::MachineApplicable,
+ |diag| {
+ // comments can be noisy, do not show them to the user
+ if !comments.is_empty() {
+ diag.tool_only_span_suggestion(
+ expr.span.shrink_to_lo(),
+ "add comments back",
+ comments,
+ applicability);
+ }
+ diag.span_suggestion(
+ expr.span,
+ "try instead",
+ sugg,
+ applicability);
+ }
+
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index a0ca7e6ff..090f9f8ff 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::match_function_call;
-use clippy_utils::paths::FUTURE_FROM_GENERATOR;
+use clippy_utils::match_function_call_with_def_id;
use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt};
use if_chain::if_chain;
use rustc_errors::Applicability;
@@ -74,11 +73,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
if let Some(ret_pos) = position_before_rarrow(&header_snip);
if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output);
then {
- let help = format!("make the function `async` and {}", ret_sugg);
+ let help = format!("make the function `async` and {ret_sugg}");
diag.span_suggestion(
header_span,
&help,
- format!("async {}{}", &header_snip[..ret_pos], ret_snip),
+ format!("async {}{ret_snip}", &header_snip[..ret_pos]),
Applicability::MachineApplicable
);
@@ -103,7 +102,7 @@ fn future_trait_ref<'tcx>(
ty: &'tcx Ty<'tcx>,
) -> Option<(&'tcx TraitRef<'tcx>, Vec<LifetimeName>)> {
if_chain! {
- if let TyKind::OpaqueDef(item_id, bounds) = ty.kind;
+ if let TyKind::OpaqueDef(item_id, bounds, false) = ty.kind;
let item = cx.tcx.hir().item(item_id);
if let ItemKind::OpaqueTy(opaque) = &item.kind;
if let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| {
@@ -140,9 +139,9 @@ fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'t
if args.bindings.len() == 1;
let binding = &args.bindings[0];
if binding.ident.name == sym::Output;
- if let TypeBindingKind::Equality{term: Term::Ty(output)} = binding.kind;
+ if let TypeBindingKind::Equality { term: Term::Ty(output) } = binding.kind;
then {
- return Some(output)
+ return Some(output);
}
}
@@ -175,9 +174,16 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName])
fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
if_chain! {
if let Some(block_expr) = block.expr;
- if let Some(args) = match_function_call(cx, block_expr, &FUTURE_FROM_GENERATOR);
+ if let Some(args) = cx
+ .tcx
+ .lang_items()
+ .from_generator_fn()
+ .and_then(|def_id| match_function_call_with_def_id(cx, block_expr, def_id));
if args.len() == 1;
- if let Expr{kind: ExprKind::Closure(&Closure { body, .. }), ..} = args[0];
+ if let Expr {
+ kind: ExprKind::Closure(&Closure { body, .. }),
+ ..
+ } = args[0];
let closure_body = cx.tcx.hir().body(body);
if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block));
then {
@@ -192,11 +198,11 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str,
match output.kind {
TyKind::Tup(tys) if tys.is_empty() => {
let sugg = "remove the return type";
- Some((sugg, "".into()))
+ Some((sugg, String::new()))
},
_ => {
let sugg = "return the output of the future directly";
- snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {}", snip)))
+ snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {snip}")))
},
}
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index 60bbcde4f..6655c92b1 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -105,7 +105,7 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id);
then {
- cx.typeck_results().node_substs(count_func.hir_id).types().next().map(|resolved_ty| (real_ty, resolved_ty))
+ cx.typeck_results().node_substs(count_func.hir_id).types().next().map(|resolved_ty| (*real_ty, resolved_ty))
} else {
None
}
@@ -134,7 +134,7 @@ fn create_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, base_sugg: String) -> Stri
fn is_ty_conversion(expr: &Expr<'_>) -> bool {
if let ExprKind::Cast(..) = expr.kind {
true
- } else if let ExprKind::MethodCall(path, [_], _) = expr.kind
+ } else if let ExprKind::MethodCall(path, _, [], _) = expr.kind
&& path.ident.name == rustc_span::sym::try_into
{
// This is only called for `usize` which implements `TryInto`. Therefore,
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
new file mode 100644
index 000000000..02dc8755d
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -0,0 +1,717 @@
+use itertools::Itertools;
+use rustc_errors::Diagnostic;
+use rustc_hir::{
+ def::Res, Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind,
+};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Ty;
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{symbol::sym, Span};
+use std::ops::Deref;
+
+use clippy_utils::{
+ diagnostics::{span_lint_and_then, span_lint_hir_and_then},
+ eq_expr_value,
+ higher::If,
+ is_diag_trait_item, is_trait_method, meets_msrv, msrvs, path_res, path_to_local_id, peel_blocks,
+ peel_blocks_with_stmt,
+ sugg::Sugg,
+ ty::implements_trait,
+ visitors::is_const_evaluatable,
+ MaybePath,
+};
+use rustc_errors::Applicability;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Identifies good opportunities for a clamp function from std or core, and suggests using it.
+ ///
+ /// ### Why is this bad?
+ /// clamp is much shorter, easier to read, and doesn't use any control flow.
+ ///
+ /// ### Known issue(s)
+ /// If the clamped variable is NaN this suggestion will cause the code to propagate NaN
+ /// rather than returning either `max` or `min`.
+ ///
+ /// `clamp` functions will panic if `max < min`, `max.is_nan()`, or `min.is_nan()`.
+ /// Some may consider panicking in these situations to be desirable, but it also may
+ /// introduce panicking where there wasn't any before.
+ ///
+ /// ### Examples
+ /// ```rust
+ /// # let (input, min, max) = (0, -2, 1);
+ /// if input > max {
+ /// max
+ /// } else if input < min {
+ /// min
+ /// } else {
+ /// input
+ /// }
+ /// # ;
+ /// ```
+ ///
+ /// ```rust
+ /// # let (input, min, max) = (0, -2, 1);
+ /// input.max(min).min(max)
+ /// # ;
+ /// ```
+ ///
+ /// ```rust
+ /// # let (input, min, max) = (0, -2, 1);
+ /// match input {
+ /// x if x > max => max,
+ /// x if x < min => min,
+ /// x => x,
+ /// }
+ /// # ;
+ /// ```
+ ///
+ /// ```rust
+ /// # let (input, min, max) = (0, -2, 1);
+ /// let mut x = input;
+ /// if x < min { x = min; }
+ /// if x > max { x = max; }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # let (input, min, max) = (0, -2, 1);
+ /// input.clamp(min, max)
+ /// # ;
+ /// ```
+ #[clippy::version = "1.66.0"]
+ pub MANUAL_CLAMP,
+ complexity,
+ "using a clamp pattern instead of the clamp function"
+}
+impl_lint_pass!(ManualClamp => [MANUAL_CLAMP]);
+
+pub struct ManualClamp {
+ msrv: Option<RustcVersion>,
+}
+
+impl ManualClamp {
+ pub fn new(msrv: Option<RustcVersion>) -> Self {
+ Self { msrv }
+ }
+}
+
+#[derive(Debug)]
+struct ClampSuggestion<'tcx> {
+ params: InputMinMax<'tcx>,
+ span: Span,
+ make_assignment: Option<&'tcx Expr<'tcx>>,
+ hir_with_ignore_attr: Option<HirId>,
+}
+
+#[derive(Debug)]
+struct InputMinMax<'tcx> {
+ input: &'tcx Expr<'tcx>,
+ min: &'tcx Expr<'tcx>,
+ max: &'tcx Expr<'tcx>,
+ is_float: bool,
+}
+
+impl<'tcx> LateLintPass<'tcx> for ManualClamp {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+ if !meets_msrv(self.msrv, msrvs::CLAMP) {
+ return;
+ }
+ if !expr.span.from_expansion() {
+ let suggestion = is_if_elseif_else_pattern(cx, expr)
+ .or_else(|| is_max_min_pattern(cx, expr))
+ .or_else(|| is_call_max_min_pattern(cx, expr))
+ .or_else(|| is_match_pattern(cx, expr))
+ .or_else(|| is_if_elseif_pattern(cx, expr));
+ if let Some(suggestion) = suggestion {
+ emit_suggestion(cx, &suggestion);
+ }
+ }
+ }
+
+ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
+ if !meets_msrv(self.msrv, msrvs::CLAMP) {
+ return;
+ }
+ for suggestion in is_two_if_pattern(cx, block) {
+ emit_suggestion(cx, &suggestion);
+ }
+ }
+ extract_msrv_attr!(LateContext);
+}
+
+fn emit_suggestion<'tcx>(cx: &LateContext<'tcx>, suggestion: &ClampSuggestion<'tcx>) {
+ let ClampSuggestion {
+ params: InputMinMax {
+ input,
+ min,
+ max,
+ is_float,
+ },
+ span,
+ make_assignment,
+ hir_with_ignore_attr,
+ } = suggestion;
+ let input = Sugg::hir(cx, input, "..").maybe_par();
+ let min = Sugg::hir(cx, min, "..");
+ let max = Sugg::hir(cx, max, "..");
+ let semicolon = if make_assignment.is_some() { ";" } else { "" };
+ let assignment = if let Some(assignment) = make_assignment {
+ let assignment = Sugg::hir(cx, assignment, "..");
+ format!("{assignment} = ")
+ } else {
+ String::new()
+ };
+ let suggestion = format!("{assignment}{input}.clamp({min}, {max}){semicolon}");
+ let msg = "clamp-like pattern without using clamp function";
+ let lint_builder = |d: &mut Diagnostic| {
+ d.span_suggestion(*span, "replace with clamp", suggestion, Applicability::MaybeIncorrect);
+ if *is_float {
+ d.note("clamp will panic if max < min, min.is_nan(), or max.is_nan()")
+ .note("clamp returns NaN if the input is NaN");
+ } else {
+ d.note("clamp will panic if max < min");
+ }
+ };
+ if let Some(hir_id) = hir_with_ignore_attr {
+ span_lint_hir_and_then(cx, MANUAL_CLAMP, *hir_id, *span, msg, lint_builder);
+ } else {
+ span_lint_and_then(cx, MANUAL_CLAMP, *span, msg, lint_builder);
+ }
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+enum TypeClampability {
+ Float,
+ Ord,
+}
+
+impl TypeClampability {
+ fn is_clampable<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<TypeClampability> {
+ if ty.is_floating_point() {
+ Some(TypeClampability::Float)
+ } else if cx
+ .tcx
+ .get_diagnostic_item(sym::Ord)
+ .map_or(false, |id| implements_trait(cx, ty, id, &[]))
+ {
+ Some(TypeClampability::Ord)
+ } else {
+ None
+ }
+ }
+
+ fn is_float(self) -> bool {
+ matches!(self, TypeClampability::Float)
+ }
+}
+
+/// Targets patterns like
+///
+/// ```
+/// # let (input, min, max) = (0, -3, 12);
+///
+/// if input < min {
+/// min
+/// } else if input > max {
+/// max
+/// } else {
+/// input
+/// }
+/// # ;
+/// ```
+fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<ClampSuggestion<'tcx>> {
+ if let Some(If {
+ cond,
+ then,
+ r#else: Some(else_if),
+ }) = If::hir(expr)
+ && let Some(If {
+ cond: else_if_cond,
+ then: else_if_then,
+ r#else: Some(else_body),
+ }) = If::hir(peel_blocks(else_if))
+ {
+ let params = is_clamp_meta_pattern(
+ cx,
+ &BinaryOp::new(peel_blocks(cond))?,
+ &BinaryOp::new(peel_blocks(else_if_cond))?,
+ peel_blocks(then),
+ peel_blocks(else_if_then),
+ None,
+ )?;
+ // Contents of the else should be the resolved input.
+ if !eq_expr_value(cx, params.input, peel_blocks(else_body)) {
+ return None;
+ }
+ Some(ClampSuggestion {
+ params,
+ span: expr.span,
+ make_assignment: None,
+ hir_with_ignore_attr: None,
+ })
+ } else {
+ None
+ }
+}
+
+/// Targets patterns like
+///
+/// ```
+/// # let (input, min_value, max_value) = (0, -3, 12);
+///
+/// input.max(min_value).min(max_value)
+/// # ;
+/// ```
+fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<ClampSuggestion<'tcx>> {
+ if let ExprKind::MethodCall(seg_second, receiver, [arg_second], _) = &expr.kind
+ && (cx.typeck_results().expr_ty_adjusted(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord))
+ && let ExprKind::MethodCall(seg_first, input, [arg_first], _) = &receiver.kind
+ && (cx.typeck_results().expr_ty_adjusted(input).is_floating_point() || is_trait_method(cx, receiver, sym::Ord))
+ {
+ let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point();
+ let (min, max) = match (seg_first.ident.as_str(), seg_second.ident.as_str()) {
+ ("min", "max") => (arg_second, arg_first),
+ ("max", "min") => (arg_first, arg_second),
+ _ => return None,
+ };
+ Some(ClampSuggestion {
+ params: InputMinMax { input, min, max, is_float },
+ span: expr.span,
+ make_assignment: None,
+ hir_with_ignore_attr: None,
+ })
+ } else {
+ None
+ }
+}
+
+/// Targets patterns like
+///
+/// ```
+/// # let (input, min_value, max_value) = (0, -3, 12);
+/// # use std::cmp::{max, min};
+/// min(max(input, min_value), max_value)
+/// # ;
+/// ```
+fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<ClampSuggestion<'tcx>> {
+ fn segment<'tcx>(cx: &LateContext<'_>, func: &Expr<'tcx>) -> Option<FunctionType<'tcx>> {
+ match func.kind {
+ ExprKind::Path(QPath::Resolved(None, path)) => {
+ let id = path.res.opt_def_id()?;
+ match cx.tcx.get_diagnostic_name(id) {
+ Some(sym::cmp_min) => Some(FunctionType::CmpMin),
+ Some(sym::cmp_max) => Some(FunctionType::CmpMax),
+ _ if is_diag_trait_item(cx, id, sym::Ord) => {
+ Some(FunctionType::OrdOrFloat(path.segments.last().expect("infallible")))
+ },
+ _ => None,
+ }
+ },
+ ExprKind::Path(QPath::TypeRelative(ty, seg)) => {
+ matches!(path_res(cx, ty), Res::PrimTy(PrimTy::Float(_))).then(|| FunctionType::OrdOrFloat(seg))
+ },
+ _ => None,
+ }
+ }
+
+ enum FunctionType<'tcx> {
+ CmpMin,
+ CmpMax,
+ OrdOrFloat(&'tcx PathSegment<'tcx>),
+ }
+
+ fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ outer_fn: &'tcx Expr<'tcx>,
+ inner_call: &'tcx Expr<'tcx>,
+ outer_arg: &'tcx Expr<'tcx>,
+ span: Span,
+ ) -> Option<ClampSuggestion<'tcx>> {
+ if let ExprKind::Call(inner_fn, [first, second]) = &inner_call.kind
+ && let Some(inner_seg) = segment(cx, inner_fn)
+ && let Some(outer_seg) = segment(cx, outer_fn)
+ {
+ let (input, inner_arg) = match (is_const_evaluatable(cx, first), is_const_evaluatable(cx, second)) {
+ (true, false) => (second, first),
+ (false, true) => (first, second),
+ _ => return None,
+ };
+ let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point();
+ let (min, max) = match (inner_seg, outer_seg) {
+ (FunctionType::CmpMin, FunctionType::CmpMax) => (outer_arg, inner_arg),
+ (FunctionType::CmpMax, FunctionType::CmpMin) => (inner_arg, outer_arg),
+ (FunctionType::OrdOrFloat(first_segment), FunctionType::OrdOrFloat(second_segment)) => {
+ match (first_segment.ident.as_str(), second_segment.ident.as_str()) {
+ ("min", "max") => (outer_arg, inner_arg),
+ ("max", "min") => (inner_arg, outer_arg),
+ _ => return None,
+ }
+ }
+ _ => return None,
+ };
+ Some(ClampSuggestion {
+ params: InputMinMax { input, min, max, is_float },
+ span,
+ make_assignment: None,
+ hir_with_ignore_attr: None,
+ })
+ } else {
+ None
+ }
+ }
+
+ if let ExprKind::Call(outer_fn, [first, second]) = &expr.kind {
+ check(cx, outer_fn, first, second, expr.span).or_else(|| check(cx, outer_fn, second, first, expr.span))
+ } else {
+ None
+ }
+}
+
+/// Targets patterns like
+///
+/// ```
+/// # let (input, min, max) = (0, -3, 12);
+///
+/// match input {
+/// input if input > max => max,
+/// input if input < min => min,
+/// input => input,
+/// }
+/// # ;
+/// ```
+fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<ClampSuggestion<'tcx>> {
+ if let ExprKind::Match(value, [first_arm, second_arm, last_arm], rustc_hir::MatchSource::Normal) = &expr.kind {
+ // Find possible min/max branches
+ let minmax_values = |a: &'tcx Arm<'tcx>| {
+ if let PatKind::Binding(_, var_hir_id, _, None) = &a.pat.kind
+ && let Some(Guard::If(e)) = a.guard {
+ Some((e, var_hir_id, a.body))
+ } else {
+ None
+ }
+ };
+ let (first, first_hir_id, first_expr) = minmax_values(first_arm)?;
+ let (second, second_hir_id, second_expr) = minmax_values(second_arm)?;
+ let first = BinaryOp::new(first)?;
+ let second = BinaryOp::new(second)?;
+ if let PatKind::Binding(_, binding, _, None) = &last_arm.pat.kind
+ && path_to_local_id(peel_blocks_with_stmt(last_arm.body), *binding)
+ && last_arm.guard.is_none()
+ {
+ // Proceed as normal
+ } else {
+ return None;
+ }
+ if let Some(params) = is_clamp_meta_pattern(
+ cx,
+ &first,
+ &second,
+ first_expr,
+ second_expr,
+ Some((*first_hir_id, *second_hir_id)),
+ ) {
+ return Some(ClampSuggestion {
+ params: InputMinMax {
+ input: value,
+ min: params.min,
+ max: params.max,
+ is_float: params.is_float,
+ },
+ span: expr.span,
+ make_assignment: None,
+ hir_with_ignore_attr: None,
+ });
+ }
+ }
+ None
+}
+
+/// Targets patterns like
+///
+/// ```
+/// # let (input, min, max) = (0, -3, 12);
+///
+/// let mut x = input;
+/// if x < min { x = min; }
+/// if x > max { x = max; }
+/// ```
+fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Vec<ClampSuggestion<'tcx>> {
+ block_stmt_with_last(block)
+ .tuple_windows()
+ .filter_map(|(maybe_set_first, maybe_set_second)| {
+ if let StmtKind::Expr(first_expr) = *maybe_set_first
+ && let StmtKind::Expr(second_expr) = *maybe_set_second
+ && let Some(If { cond: first_cond, then: first_then, r#else: None }) = If::hir(first_expr)
+ && let Some(If { cond: second_cond, then: second_then, r#else: None }) = If::hir(second_expr)
+ && let ExprKind::Assign(
+ maybe_input_first_path,
+ maybe_min_max_first,
+ _
+ ) = peel_blocks_with_stmt(first_then).kind
+ && let ExprKind::Assign(
+ maybe_input_second_path,
+ maybe_min_max_second,
+ _
+ ) = peel_blocks_with_stmt(second_then).kind
+ && eq_expr_value(cx, maybe_input_first_path, maybe_input_second_path)
+ && let Some(first_bin) = BinaryOp::new(first_cond)
+ && let Some(second_bin) = BinaryOp::new(second_cond)
+ && let Some(input_min_max) = is_clamp_meta_pattern(
+ cx,
+ &first_bin,
+ &second_bin,
+ maybe_min_max_first,
+ maybe_min_max_second,
+ None
+ )
+ {
+ Some(ClampSuggestion {
+ params: InputMinMax {
+ input: maybe_input_first_path,
+ min: input_min_max.min,
+ max: input_min_max.max,
+ is_float: input_min_max.is_float,
+ },
+ span: first_expr.span.to(second_expr.span),
+ make_assignment: Some(maybe_input_first_path),
+ hir_with_ignore_attr: Some(first_expr.hir_id()),
+ })
+ } else {
+ None
+ }
+ })
+ .collect()
+}
+
+/// Targets patterns like
+///
+/// ```
+/// # let (mut input, min, max) = (0, -3, 12);
+///
+/// if input < min {
+/// input = min;
+/// } else if input > max {
+/// input = max;
+/// }
+/// ```
+fn is_if_elseif_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<ClampSuggestion<'tcx>> {
+ if let Some(If {
+ cond,
+ then,
+ r#else: Some(else_if),
+ }) = If::hir(expr)
+ && let Some(If {
+ cond: else_if_cond,
+ then: else_if_then,
+ r#else: None,
+ }) = If::hir(peel_blocks(else_if))
+ && let ExprKind::Assign(
+ maybe_input_first_path,
+ maybe_min_max_first,
+ _
+ ) = peel_blocks_with_stmt(then).kind
+ && let ExprKind::Assign(
+ maybe_input_second_path,
+ maybe_min_max_second,
+ _
+ ) = peel_blocks_with_stmt(else_if_then).kind
+ {
+ let params = is_clamp_meta_pattern(
+ cx,
+ &BinaryOp::new(peel_blocks(cond))?,
+ &BinaryOp::new(peel_blocks(else_if_cond))?,
+ peel_blocks(maybe_min_max_first),
+ peel_blocks(maybe_min_max_second),
+ None,
+ )?;
+ if !eq_expr_value(cx, maybe_input_first_path, maybe_input_second_path) {
+ return None;
+ }
+ Some(ClampSuggestion {
+ params,
+ span: expr.span,
+ make_assignment: Some(maybe_input_first_path),
+ hir_with_ignore_attr: None,
+ })
+ } else {
+ None
+ }
+}
+
+/// `ExprKind::Binary` but more narrowly typed
+#[derive(Debug, Clone, Copy)]
+struct BinaryOp<'tcx> {
+ op: BinOpKind,
+ left: &'tcx Expr<'tcx>,
+ right: &'tcx Expr<'tcx>,
+}
+
+impl<'tcx> BinaryOp<'tcx> {
+ fn new(e: &'tcx Expr<'tcx>) -> Option<BinaryOp<'tcx>> {
+ match &e.kind {
+ ExprKind::Binary(op, left, right) => Some(BinaryOp {
+ op: op.node,
+ left,
+ right,
+ }),
+ _ => None,
+ }
+ }
+
+ fn flip(&self) -> Self {
+ Self {
+ op: match self.op {
+ BinOpKind::Le => BinOpKind::Ge,
+ BinOpKind::Lt => BinOpKind::Gt,
+ BinOpKind::Ge => BinOpKind::Le,
+ BinOpKind::Gt => BinOpKind::Lt,
+ other => other,
+ },
+ left: self.right,
+ right: self.left,
+ }
+ }
+}
+
+/// The clamp meta pattern is a pattern shared between many (but not all) patterns.
+/// In summary, this pattern consists of two if statements that meet many criteria,
+/// - binary operators that are one of [`>`, `<`, `>=`, `<=`].
+/// - Both binary statements must have a shared argument
+/// - Which can appear on the left or right side of either statement
+/// - The binary operators must define a finite range for the shared argument. To put this in
+/// the terms of Rust `std` library, the following ranges are acceptable
+/// - `Range`
+/// - `RangeInclusive`
+/// And all other range types are not accepted. For the purposes of `clamp` it's irrelevant
+/// whether the range is inclusive or not, the output is the same.
+/// - The result of each if statement must be equal to the argument unique to that if statement. The
+/// result can not be the shared argument in either case.
+fn is_clamp_meta_pattern<'tcx>(
+ cx: &LateContext<'tcx>,
+ first_bin: &BinaryOp<'tcx>,
+ second_bin: &BinaryOp<'tcx>,
+ first_expr: &'tcx Expr<'tcx>,
+ second_expr: &'tcx Expr<'tcx>,
+ // This parameters is exclusively for the match pattern.
+ // It exists because the variable bindings used in that pattern
+ // refer to the variable bound in the match arm, not the variable
+ // bound outside of it. Fortunately due to context we know this has to
+ // be the input variable, not the min or max.
+ input_hir_ids: Option<(HirId, HirId)>,
+) -> Option<InputMinMax<'tcx>> {
+ fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ first_bin: &BinaryOp<'tcx>,
+ second_bin: &BinaryOp<'tcx>,
+ first_expr: &'tcx Expr<'tcx>,
+ second_expr: &'tcx Expr<'tcx>,
+ input_hir_ids: Option<(HirId, HirId)>,
+ is_float: bool,
+ ) -> Option<InputMinMax<'tcx>> {
+ match (&first_bin.op, &second_bin.op) {
+ (BinOpKind::Ge | BinOpKind::Gt, BinOpKind::Le | BinOpKind::Lt) => {
+ let (min, max) = (second_expr, first_expr);
+ let refers_to_input = match input_hir_ids {
+ Some((first_hir_id, second_hir_id)) => {
+ path_to_local_id(peel_blocks(first_bin.left), first_hir_id)
+ && path_to_local_id(peel_blocks(second_bin.left), second_hir_id)
+ },
+ None => eq_expr_value(cx, first_bin.left, second_bin.left),
+ };
+ (refers_to_input
+ && eq_expr_value(cx, first_bin.right, first_expr)
+ && eq_expr_value(cx, second_bin.right, second_expr))
+ .then_some(InputMinMax {
+ input: first_bin.left,
+ min,
+ max,
+ is_float,
+ })
+ },
+ _ => None,
+ }
+ }
+ // First filter out any expressions with side effects
+ let exprs = [
+ first_bin.left,
+ first_bin.right,
+ second_bin.left,
+ second_bin.right,
+ first_expr,
+ second_expr,
+ ];
+ let clampability = TypeClampability::is_clampable(cx, cx.typeck_results().expr_ty(first_expr))?;
+ let is_float = clampability.is_float();
+ if exprs.iter().any(|e| peel_blocks(e).can_have_side_effects()) {
+ return None;
+ }
+ if !(is_ord_op(first_bin.op) && is_ord_op(second_bin.op)) {
+ return None;
+ }
+ let cases = [
+ (*first_bin, *second_bin),
+ (first_bin.flip(), second_bin.flip()),
+ (first_bin.flip(), *second_bin),
+ (*first_bin, second_bin.flip()),
+ ];
+
+ cases.into_iter().find_map(|(first, second)| {
+ check(cx, &first, &second, first_expr, second_expr, input_hir_ids, is_float).or_else(|| {
+ check(
+ cx,
+ &second,
+ &first,
+ second_expr,
+ first_expr,
+ input_hir_ids.map(|(l, r)| (r, l)),
+ is_float,
+ )
+ })
+ })
+}
+
+fn block_stmt_with_last<'tcx>(block: &'tcx Block<'tcx>) -> impl Iterator<Item = MaybeBorrowedStmtKind<'tcx>> {
+ block
+ .stmts
+ .iter()
+ .map(|s| MaybeBorrowedStmtKind::Borrowed(&s.kind))
+ .chain(
+ block
+ .expr
+ .as_ref()
+ .map(|e| MaybeBorrowedStmtKind::Owned(StmtKind::Expr(e))),
+ )
+}
+
+fn is_ord_op(op: BinOpKind) -> bool {
+ matches!(op, BinOpKind::Ge | BinOpKind::Gt | BinOpKind::Le | BinOpKind::Lt)
+}
+
+/// Really similar to Cow, but doesn't have a `Clone` requirement.
+#[derive(Debug)]
+enum MaybeBorrowedStmtKind<'a> {
+ Borrowed(&'a StmtKind<'a>),
+ Owned(StmtKind<'a>),
+}
+
+impl<'a> Clone for MaybeBorrowedStmtKind<'a> {
+ fn clone(&self) -> Self {
+ match self {
+ Self::Borrowed(t) => Self::Borrowed(t),
+ Self::Owned(StmtKind::Expr(e)) => Self::Owned(StmtKind::Expr(e)),
+ Self::Owned(_) => unreachable!("Owned should only ever contain a StmtKind::Expr."),
+ }
+ }
+}
+
+impl<'a> Deref for MaybeBorrowedStmtKind<'a> {
+ type Target = StmtKind<'a>;
+
+ fn deref(&self) -> &Self::Target {
+ match self {
+ Self::Borrowed(t) => t,
+ Self::Owned(t) => t,
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs b/src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs
new file mode 100644
index 000000000..331cda1db
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs
@@ -0,0 +1,69 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Spanned;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Lints subtraction between `Instant::now()` and another `Instant`.
+ ///
+ /// ### Why is this bad?
+ /// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns
+ /// as `Instant` subtraction saturates.
+ ///
+ /// `prev_instant.elapsed()` also more clearly signals intention.
+ ///
+ /// ### Example
+ /// ```rust
+ /// use std::time::Instant;
+ /// let prev_instant = Instant::now();
+ /// let duration = Instant::now() - prev_instant;
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// use std::time::Instant;
+ /// let prev_instant = Instant::now();
+ /// let duration = prev_instant.elapsed();
+ /// ```
+ #[clippy::version = "1.64.0"]
+ pub MANUAL_INSTANT_ELAPSED,
+ pedantic,
+ "subtraction between `Instant::now()` and previous `Instant`"
+}
+
+declare_lint_pass!(ManualInstantElapsed => [MANUAL_INSTANT_ELAPSED]);
+
+impl LateLintPass<'_> for ManualInstantElapsed {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
+ if let ExprKind::Binary(Spanned {node: BinOpKind::Sub, ..}, lhs, rhs) = expr.kind
+ && check_instant_now_call(cx, lhs)
+ && let ty_resolved = cx.typeck_results().expr_ty(rhs)
+ && let rustc_middle::ty::Adt(def, _) = ty_resolved.kind()
+ && clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT)
+ && let Some(sugg) = clippy_utils::sugg::Sugg::hir_opt(cx, rhs)
+ {
+ span_lint_and_sugg(
+ cx,
+ MANUAL_INSTANT_ELAPSED,
+ expr.span,
+ "manual implementation of `Instant::elapsed`",
+ "try",
+ format!("{}.elapsed()", sugg.maybe_par()),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+}
+
+fn check_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
+ if let ExprKind::Call(fn_expr, []) = expr_block.kind
+ && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr)
+ && clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW)
+ {
+ true
+ } else {
+ false
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 2b04475c7..6806c1466 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -133,7 +133,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
diag.span_suggestion(
header_span,
"add the attribute",
- format!("#[non_exhaustive] {}", snippet),
+ format!("#[non_exhaustive] {snippet}"),
Applicability::Unspecified,
);
}
@@ -166,7 +166,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
if let Some((id, span)) = iter.next()
&& iter.next().is_none()
{
- self.potential_enums.push((item.def_id, id, item.span, span));
+ self.potential_enums.push((item.owner_id.def_id, id, item.span, span));
}
}
}
@@ -207,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
diag.span_suggestion(
header_span,
"add the attribute",
- format!("#[non_exhaustive] {}", snippet),
+ format!("#[non_exhaustive] {snippet}"),
Applicability::Unspecified,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
deleted file mode 100644
index 9abf2507b..000000000
--- a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
+++ /dev/null
@@ -1,98 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_lang_ctor, path_to_local_id};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::LangItem::{ResultErr, ResultOk};
-use rustc_hir::{Closure, Expr, ExprKind, PatKind};
-use rustc_lint::LintContext;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::sym;
-
-declare_clippy_lint! {
- /// ### What it does
- ///
- /// Finds patterns that reimplement `Option::ok_or`.
- ///
- /// ### Why is this bad?
- ///
- /// Concise code helps focusing on behavior instead of boilerplate.
- ///
- /// ### Examples
- /// ```rust
- /// let foo: Option<i32> = None;
- /// foo.map_or(Err("error"), |v| Ok(v));
- /// ```
- ///
- /// Use instead:
- /// ```rust
- /// let foo: Option<i32> = None;
- /// foo.ok_or("error");
- /// ```
- #[clippy::version = "1.49.0"]
- pub MANUAL_OK_OR,
- pedantic,
- "finds patterns that can be encoded more concisely with `Option::ok_or`"
-}
-
-declare_lint_pass!(ManualOkOr => [MANUAL_OK_OR]);
-
-impl<'tcx> LateLintPass<'tcx> for ManualOkOr {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'tcx>) {
- if in_external_macro(cx.sess(), scrutinee.span) {
- return;
- }
-
- if_chain! {
- if let ExprKind::MethodCall(method_segment, args, _) = scrutinee.kind;
- if method_segment.ident.name == sym!(map_or);
- if args.len() == 3;
- let method_receiver = &args[0];
- let ty = cx.typeck_results().expr_ty(method_receiver);
- if is_type_diagnostic_item(cx, ty, sym::Option);
- let or_expr = &args[1];
- if is_ok_wrapping(cx, &args[2]);
- if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind;
- if is_lang_ctor(cx, err_path, ResultErr);
- if let Some(method_receiver_snippet) = snippet_opt(cx, method_receiver.span);
- if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span);
- if let Some(indent) = indent_of(cx, scrutinee.span);
- then {
- let reindented_err_arg_snippet =
- reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4));
- span_lint_and_sugg(
- cx,
- MANUAL_OK_OR,
- scrutinee.span,
- "this pattern reimplements `Option::ok_or`",
- "replace with",
- format!(
- "{}.ok_or({})",
- method_receiver_snippet,
- reindented_err_arg_snippet
- ),
- Applicability::MachineApplicable,
- );
- }
- }
- }
-}
-
-fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool {
- if let ExprKind::Path(ref qpath) = map_expr.kind {
- if is_lang_ctor(cx, qpath, ResultOk) {
- return true;
- }
- }
- if_chain! {
- if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind;
- let body = cx.tcx.hir().body(body);
- if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind;
- if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind;
- if is_lang_ctor(cx, ok_path, ResultOk);
- then { path_to_local_id(ok_arg, param_id) } else { false }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index 95cc6bdbd..6f25a2ed8 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -27,7 +27,7 @@ declare_clippy_lint! {
/// let x: i32 = 24;
/// let rem = x.rem_euclid(4);
/// ```
- #[clippy::version = "1.63.0"]
+ #[clippy::version = "1.64.0"]
pub MANUAL_REM_EUCLID,
complexity,
"manually reimplementing `rem_euclid`"
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 42d2577cc..3181bc86d 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -43,7 +43,7 @@ declare_clippy_lint! {
/// let mut vec = vec![0, 1, 2];
/// vec.retain(|x| x % 2 == 0);
/// ```
- #[clippy::version = "1.63.0"]
+ #[clippy::version = "1.64.0"]
pub MANUAL_RETAIN,
perf,
"`retain()` is simpler and the same functionalitys"
@@ -66,9 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if let Some(parent_expr) = get_parent_expr(cx, expr)
&& let Assign(left_expr, collect_expr, _) = &parent_expr.kind
- && let hir::ExprKind::MethodCall(seg, _, _) = &collect_expr.kind
+ && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind
&& seg.args.is_none()
- && let hir::ExprKind::MethodCall(_, [target_expr], _) = &collect_expr.kind
+ && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
&& let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
&& match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
check_into_iter(cx, parent_expr, left_expr, target_expr, self.msrv);
@@ -87,12 +87,12 @@ fn check_into_iter(
target_expr: &hir::Expr<'_>,
msrv: Option<RustcVersion>,
) {
- if let hir::ExprKind::MethodCall(_, [into_iter_expr, _], _) = &target_expr.kind
+ if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
- && let hir::ExprKind::MethodCall(_, [struct_expr], _) = &into_iter_expr.kind
+ && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind
&& let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id)
- && match_def_path(cx, into_iter_def_id, &paths::CORE_ITER_INTO_ITER)
+ && cx.tcx.lang_items().require(hir::LangItem::IntoIterIntoIter).ok() == Some(into_iter_def_id)
&& match_acceptable_type(cx, left_expr, msrv)
&& SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) {
suggest(cx, parent_expr, left_expr, target_expr);
@@ -106,14 +106,14 @@ fn check_iter(
target_expr: &hir::Expr<'_>,
msrv: Option<RustcVersion>,
) {
- if let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind
+ if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
&& let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
&& (match_def_path(cx, copied_def_id, &paths::CORE_ITER_COPIED)
|| match_def_path(cx, copied_def_id, &paths::CORE_ITER_CLONED))
- && let hir::ExprKind::MethodCall(_, [iter_expr, _], _) = &filter_expr.kind
+ && let hir::ExprKind::MethodCall(_, iter_expr, [_], _) = &filter_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
- && let hir::ExprKind::MethodCall(_, [struct_expr], _) = &iter_expr.kind
+ && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &iter_expr.kind
&& let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id)
&& match_acceptable_def_path(cx, iter_expr_def_id)
&& match_acceptable_type(cx, left_expr, msrv)
@@ -130,13 +130,13 @@ fn check_to_owned(
msrv: Option<RustcVersion>,
) {
if meets_msrv(msrv, msrvs::STRING_RETAIN)
- && let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind
+ && let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
&& let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
&& match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD)
- && let hir::ExprKind::MethodCall(_, [chars_expr, _], _) = &filter_expr.kind
+ && let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
- && let hir::ExprKind::MethodCall(_, [str_expr], _) = &chars_expr.kind
+ && let hir::ExprKind::MethodCall(_, str_expr, [], _) = &chars_expr.kind
&& let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id)
&& match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS)
&& let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
@@ -147,13 +147,13 @@ fn check_to_owned(
}
fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) {
- if let hir::ExprKind::MethodCall(_, [_, closure], _) = filter_expr.kind
+ if let hir::ExprKind::MethodCall(_, _, [closure], _) = filter_expr.kind
&& let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind
&& let filter_body = cx.tcx.hir().body(body)
&& let [filter_params] = filter_body.params
&& let Some(sugg) = match filter_params.pat.kind {
hir::PatKind::Binding(_, _, filter_param_ident, None) => {
- Some(format!("{}.retain(|{}| {})", snippet(cx, left_expr.span, ".."), filter_param_ident, snippet(cx, filter_body.value.span, "..")))
+ Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, "..")))
},
hir::PatKind::Tuple([key_pat, value_pat], _) => {
make_sugg(cx, key_pat, value_pat, left_expr, filter_body)
@@ -161,7 +161,7 @@ fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::E
hir::PatKind::Ref(pat, _) => {
match pat.kind {
hir::PatKind::Binding(_, _, filter_param_ident, None) => {
- Some(format!("{}.retain(|{}| {})", snippet(cx, left_expr.span, ".."), filter_param_ident, snippet(cx, filter_body.value.span, "..")))
+ Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, "..")))
},
_ => None
}
@@ -190,23 +190,19 @@ fn make_sugg(
match (&key_pat.kind, &value_pat.kind) {
(hir::PatKind::Binding(_, _, key_param_ident, None), hir::PatKind::Binding(_, _, value_param_ident, None)) => {
Some(format!(
- "{}.retain(|{}, &mut {}| {})",
+ "{}.retain(|{key_param_ident}, &mut {value_param_ident}| {})",
snippet(cx, left_expr.span, ".."),
- key_param_ident,
- value_param_ident,
snippet(cx, filter_body.value.span, "..")
))
},
(hir::PatKind::Binding(_, _, key_param_ident, None), hir::PatKind::Wild) => Some(format!(
- "{}.retain(|{}, _| {})",
+ "{}.retain(|{key_param_ident}, _| {})",
snippet(cx, left_expr.span, ".."),
- key_param_ident,
snippet(cx, filter_body.value.span, "..")
)),
(hir::PatKind::Wild, hir::PatKind::Binding(_, _, value_param_ident, None)) => Some(format!(
- "{}.retain(|_, &mut {}| {})",
+ "{}.retain(|_, &mut {value_param_ident}| {})",
snippet(cx, left_expr.span, ".."),
- value_param_ident,
snippet(cx, filter_body.value.span, "..")
)),
_ => None,
diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
new file mode 100644
index 000000000..6acfb2ae3
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
@@ -0,0 +1,135 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability::MachineApplicable;
+use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, symbol, Span};
+
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// Checks for usage of `""` to create a `String`, such as `"".to_string()`, `"".to_owned()`,
+ /// `String::from("")` and others.
+ ///
+ /// ### Why is this bad?
+ ///
+ /// Different ways of creating an empty string makes your code less standardized, which can
+ /// be confusing.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let a = "".to_string();
+ /// let b: String = "".into();
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let a = String::new();
+ /// let b = String::new();
+ /// ```
+ #[clippy::version = "1.65.0"]
+ pub MANUAL_STRING_NEW,
+ pedantic,
+ "empty String is being created manually"
+}
+declare_lint_pass!(ManualStringNew => [MANUAL_STRING_NEW]);
+
+impl LateLintPass<'_> for ManualStringNew {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if expr.span.from_expansion() {
+ return;
+ }
+
+ let ty = cx.typeck_results().expr_ty(expr);
+ match ty.kind() {
+ ty::Adt(adt_def, _) if adt_def.is_struct() => {
+ if !cx.tcx.is_diagnostic_item(sym::String, adt_def.did()) {
+ return;
+ }
+ },
+ _ => return,
+ }
+
+ match expr.kind {
+ ExprKind::Call(func, args) => {
+ parse_call(cx, expr.span, func, args);
+ },
+ ExprKind::MethodCall(path_segment, receiver, ..) => {
+ parse_method_call(cx, expr.span, path_segment, receiver);
+ },
+ _ => (),
+ }
+ }
+}
+
+/// Checks if an expression's kind corresponds to an empty &str.
+fn is_expr_kind_empty_str(expr_kind: &ExprKind<'_>) -> bool {
+ if let ExprKind::Lit(lit) = expr_kind &&
+ let LitKind::Str(value, _) = lit.node &&
+ value == symbol::kw::Empty
+ {
+ return true;
+ }
+
+ false
+}
+
+fn warn_then_suggest(cx: &LateContext<'_>, span: Span) {
+ span_lint_and_sugg(
+ cx,
+ MANUAL_STRING_NEW,
+ span,
+ "empty String is being created manually",
+ "consider using",
+ "String::new()".into(),
+ MachineApplicable,
+ );
+}
+
+/// Tries to parse an expression as a method call, emitting the warning if necessary.
+fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, receiver: &Expr<'_>) {
+ let ident = path_segment.ident.as_str();
+ let method_arg_kind = &receiver.kind;
+ if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) {
+ warn_then_suggest(cx, span);
+ } else if let ExprKind::Call(func, args) = method_arg_kind {
+ // If our first argument is a function call itself, it could be an `unwrap`-like function.
+ // E.g. String::try_from("hello").unwrap(), TryFrom::try_from("").expect("hello"), etc.
+ parse_call(cx, span, func, args);
+ }
+}
+
+/// Tries to parse an expression as a function call, emitting the warning if necessary.
+fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, args: &[Expr<'_>]) {
+ if args.len() != 1 {
+ return;
+ }
+
+ let arg_kind = &args[0].kind;
+ if let ExprKind::Path(qpath) = &func.kind {
+ if let QPath::TypeRelative(_, _) = qpath {
+ // String::from(...) or String::try_from(...)
+ if let QPath::TypeRelative(ty, path_seg) = qpath &&
+ [sym::from, sym::try_from].contains(&path_seg.ident.name) &&
+ let TyKind::Path(qpath) = &ty.kind &&
+ let QPath::Resolved(_, path) = qpath &&
+ let [path_seg] = path.segments &&
+ path_seg.ident.name == sym::String &&
+ is_expr_kind_empty_str(arg_kind)
+ {
+ warn_then_suggest(cx, span);
+ }
+ } else if let QPath::Resolved(_, path) = qpath {
+ // From::from(...) or TryFrom::try_from(...)
+ if let [path_seg1, path_seg2] = path.segments &&
+ is_expr_kind_empty_str(arg_kind) && (
+ (path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from) ||
+ (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from)
+ )
+ {
+ warn_then_suggest(cx, span);
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index dfb3efc4e..0976940af 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
if_chain! {
if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
- if let ExprKind::MethodCall(_, [target_arg, pattern], _) = cond.kind;
+ if let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind;
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id);
if let ExprKind::Path(target_path) = &target_arg.kind;
then {
@@ -108,15 +108,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
};
let test_span = expr.span.until(then.span);
- span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {} manually", kind_word), |diag| {
- diag.span_note(test_span, &format!("the {} was tested here", kind_word));
+ span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| {
+ diag.span_note(test_span, &format!("the {kind_word} was tested here"));
multispan_sugg(
diag,
- &format!("try using the `strip_{}` method", kind_word),
+ &format!("try using the `strip_{kind_word}` method"),
vec![(test_span,
- format!("if let Some(<stripped>) = {}.strip_{}({}) ",
+ format!("if let Some(<stripped>) = {}.strip_{kind_word}({}) ",
snippet(cx, target_arg.span, ".."),
- kind_word,
snippet(cx, pattern.span, "..")))]
.into_iter().chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))),
);
@@ -132,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
// Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise.
fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
if_chain! {
- if let ExprKind::MethodCall(_, [arg], _) = expr.kind;
+ if let ExprKind::MethodCall(_, arg, [], _) = expr.kind;
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if match_def_path(cx, method_def_id, &paths::STR_LEN);
then {
diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs
deleted file mode 100644
index 95c312f1f..000000000
--- a/src/tools/clippy/clippy_lints/src/map_clone.rs
+++ /dev/null
@@ -1,167 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
-use clippy_utils::{is_trait_method, meets_msrv, msrvs, peel_blocks};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::mir::Mutability;
-use rustc_middle::ty;
-use rustc_middle::ty::adjustment::Adjust;
-use rustc_semver::RustcVersion;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::symbol::Ident;
-use rustc_span::{sym, Span};
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for usage of `map(|x| x.clone())` or
- /// dereferencing closures for `Copy` types, on `Iterator` or `Option`,
- /// and suggests `cloned()` or `copied()` instead
- ///
- /// ### Why is this bad?
- /// Readability, this can be written more concisely
- ///
- /// ### Example
- /// ```rust
- /// let x = vec![42, 43];
- /// let y = x.iter();
- /// let z = y.map(|i| *i);
- /// ```
- ///
- /// The correct use would be:
- ///
- /// ```rust
- /// let x = vec![42, 43];
- /// let y = x.iter();
- /// let z = y.cloned();
- /// ```
- #[clippy::version = "pre 1.29.0"]
- pub MAP_CLONE,
- style,
- "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
-}
-
-pub struct MapClone {
- msrv: Option<RustcVersion>,
-}
-
-impl_lint_pass!(MapClone => [MAP_CLONE]);
-
-impl MapClone {
- pub fn new(msrv: Option<RustcVersion>) -> Self {
- Self { msrv }
- }
-}
-
-impl<'tcx> LateLintPass<'tcx> for MapClone {
- fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
- if e.span.from_expansion() {
- return;
- }
-
- if_chain! {
- if let hir::ExprKind::MethodCall(method, args, _) = e.kind;
- if args.len() == 2;
- if method.ident.name == sym::map;
- let ty = cx.typeck_results().expr_ty(&args[0]);
- if is_type_diagnostic_item(cx, ty, sym::Option) || is_trait_method(cx, e, sym::Iterator);
- if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = args[1].kind;
- then {
- let closure_body = cx.tcx.hir().body(body);
- let closure_expr = peel_blocks(&closure_body.value);
- match closure_body.params[0].pat.kind {
- hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
- hir::BindingAnnotation::Unannotated, .., name, None
- ) = inner.kind {
- if ident_eq(name, closure_expr) {
- self.lint_explicit_closure(cx, e.span, args[0].span, true);
- }
- },
- hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => {
- match closure_expr.kind {
- hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
- if ident_eq(name, inner) {
- if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
- self.lint_explicit_closure(cx, e.span, args[0].span, true);
- }
- }
- },
- hir::ExprKind::MethodCall(method, [obj], _) => if_chain! {
- if ident_eq(name, obj) && method.ident.name == sym::clone;
- if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id);
- if let Some(trait_id) = cx.tcx.trait_of_item(fn_id);
- if cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id);
- // no autoderefs
- if !cx.typeck_results().expr_adjustments(obj).iter()
- .any(|a| matches!(a.kind, Adjust::Deref(Some(..))));
- then {
- let obj_ty = cx.typeck_results().expr_ty(obj);
- if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
- if matches!(mutability, Mutability::Not) {
- let copy = is_copy(cx, *ty);
- self.lint_explicit_closure(cx, e.span, args[0].span, copy);
- }
- } else {
- lint_needless_cloning(cx, e.span, args[0].span);
- }
- }
- },
- _ => {},
- }
- },
- _ => {},
- }
- }
- }
- }
-
- extract_msrv_attr!(LateContext);
-}
-
-fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool {
- if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind {
- path.segments.len() == 1 && path.segments[0].ident == name
- } else {
- false
- }
-}
-
-fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
- span_lint_and_sugg(
- cx,
- MAP_CLONE,
- root.trim_start(receiver).unwrap(),
- "you are needlessly cloning iterator elements",
- "remove the `map` call",
- String::new(),
- Applicability::MachineApplicable,
- );
-}
-
-impl MapClone {
- fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) {
- let mut applicability = Applicability::MachineApplicable;
-
- let (message, sugg_method) = if is_copy && meets_msrv(self.msrv, msrvs::ITERATOR_COPIED) {
- ("you are using an explicit closure for copying elements", "copied")
- } else {
- ("you are using an explicit closure for cloning elements", "cloned")
- };
-
- span_lint_and_sugg(
- cx,
- MAP_CLONE,
- replace,
- message,
- &format!("consider calling the dedicated `{}` method", sugg_method),
- format!(
- "{}.{}()",
- snippet_with_applicability(cx, root, "..", &mut applicability),
- sugg_method,
- ),
- applicability,
- );
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
deleted file mode 100644
index 21d0e19eb..000000000
--- a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
+++ /dev/null
@@ -1,154 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for instances of `map_err(|_| Some::Enum)`
- ///
- /// ### Why is this bad?
- /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error
- ///
- /// ### Example
- /// Before:
- /// ```rust
- /// use std::fmt;
- ///
- /// #[derive(Debug)]
- /// enum Error {
- /// Indivisible,
- /// Remainder(u8),
- /// }
- ///
- /// impl fmt::Display for Error {
- /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- /// match self {
- /// Error::Indivisible => write!(f, "could not divide input by three"),
- /// Error::Remainder(remainder) => write!(
- /// f,
- /// "input is not divisible by three, remainder = {}",
- /// remainder
- /// ),
- /// }
- /// }
- /// }
- ///
- /// impl std::error::Error for Error {}
- ///
- /// fn divisible_by_3(input: &str) -> Result<(), Error> {
- /// input
- /// .parse::<i32>()
- /// .map_err(|_| Error::Indivisible)
- /// .map(|v| v % 3)
- /// .and_then(|remainder| {
- /// if remainder == 0 {
- /// Ok(())
- /// } else {
- /// Err(Error::Remainder(remainder as u8))
- /// }
- /// })
- /// }
- /// ```
- ///
- /// After:
- /// ```rust
- /// use std::{fmt, num::ParseIntError};
- ///
- /// #[derive(Debug)]
- /// enum Error {
- /// Indivisible(ParseIntError),
- /// Remainder(u8),
- /// }
- ///
- /// impl fmt::Display for Error {
- /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- /// match self {
- /// Error::Indivisible(_) => write!(f, "could not divide input by three"),
- /// Error::Remainder(remainder) => write!(
- /// f,
- /// "input is not divisible by three, remainder = {}",
- /// remainder
- /// ),
- /// }
- /// }
- /// }
- ///
- /// impl std::error::Error for Error {
- /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- /// match self {
- /// Error::Indivisible(source) => Some(source),
- /// _ => None,
- /// }
- /// }
- /// }
- ///
- /// fn divisible_by_3(input: &str) -> Result<(), Error> {
- /// input
- /// .parse::<i32>()
- /// .map_err(Error::Indivisible)
- /// .map(|v| v % 3)
- /// .and_then(|remainder| {
- /// if remainder == 0 {
- /// Ok(())
- /// } else {
- /// Err(Error::Remainder(remainder as u8))
- /// }
- /// })
- /// }
- /// ```
- #[clippy::version = "1.48.0"]
- pub MAP_ERR_IGNORE,
- restriction,
- "`map_err` should not ignore the original error"
-}
-
-declare_lint_pass!(MapErrIgnore => [MAP_ERR_IGNORE]);
-
-impl<'tcx> LateLintPass<'tcx> for MapErrIgnore {
- // do not try to lint if this is from a macro or desugaring
- fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
- if e.span.from_expansion() {
- return;
- }
-
- // check if this is a method call (e.g. x.foo())
- if let ExprKind::MethodCall(method, args, _) = e.kind {
- // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1]
- // Enum::Variant[2]))
- if method.ident.as_str() == "map_err" && args.len() == 2 {
- // make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span
- // fields
- if let ExprKind::Closure(&Closure {
- capture_clause,
- body,
- fn_decl_span,
- ..
- }) = args[1].kind
- {
- // check if this is by Reference (meaning there's no move statement)
- if capture_clause == CaptureBy::Ref {
- // Get the closure body to check the parameters and values
- let closure_body = cx.tcx.hir().body(body);
- // make sure there's only one parameter (`|_|`)
- if closure_body.params.len() == 1 {
- // make sure that parameter is the wild token (`_`)
- if let PatKind::Wild = closure_body.params[0].pat.kind {
- // span the area of the closure capture and warn that the
- // original error will be thrown away
- span_lint_and_help(
- cx,
- MAP_ERR_IGNORE,
- fn_decl_span,
- "`map_err(|_|...` wildcard pattern discards the original error",
- None,
- "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)",
- );
- }
- }
- }
- }
- }
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index af9d948af..32da37a86 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -97,11 +97,7 @@ declare_clippy_lint! {
declare_lint_pass!(MapUnit => [OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN]);
fn is_unit_type(ty: Ty<'_>) -> bool {
- match ty.kind() {
- ty::Tuple(slice) => slice.is_empty(),
- ty::Never => true,
- _ => false,
- }
+ ty.is_unit() || ty.is_never()
}
fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
@@ -135,12 +131,12 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) ->
},
hir::ExprKind::Block(block, _) => {
match (block.stmts, block.expr.as_ref()) {
- (&[], Some(inner_expr)) => {
+ ([], Some(inner_expr)) => {
// If block only contains an expression,
// reduce `{ X }` to `X`
reduce_unit_expression(cx, inner_expr)
},
- (&[ref inner_stmt], None) => {
+ ([inner_stmt], None) => {
// If block only contains statements,
// reduce `{ X; }` to `X` or `X;`
match inner_stmt.kind {
@@ -198,14 +194,16 @@ fn let_binding_name(cx: &LateContext<'_>, var_arg: &hir::Expr<'_>) -> String {
#[must_use]
fn suggestion_msg(function_type: &str, map_type: &str) -> String {
- format!(
- "called `map(f)` on an `{0}` value where `f` is a {1} that returns the unit type `()`",
- map_type, function_type
- )
+ format!("called `map(f)` on an `{map_type}` value where `f` is a {function_type} that returns the unit type `()`")
}
-fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) {
- let var_arg = &map_args[0];
+fn lint_map_unit_fn(
+ cx: &LateContext<'_>,
+ stmt: &hir::Stmt<'_>,
+ expr: &hir::Expr<'_>,
+ map_args: (&hir::Expr<'_>, &[hir::Expr<'_>]),
+) {
+ let var_arg = &map_args.0;
let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) {
("Option", "Some", OPTION_MAP_UNIT_FN)
@@ -214,7 +212,7 @@ fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr
} else {
return;
};
- let fn_arg = &map_args[1];
+ let fn_arg = &map_args.1[0];
if is_unit_function(cx, fn_arg) {
let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/match_result_ok.rs b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
index 3349b85f1..a020282d2 100644
--- a/src/tools/clippy/clippy_lints/src/match_result_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
@@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
};
if_chain! {
- if let ExprKind::MethodCall(ok_path, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
+ if let ExprKind::MethodCall(ok_path, result_types_0, ..) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = let_pat.kind; //get operation
if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() method use std::marker::Sized;
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result);
@@ -70,9 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability);
let trimmed_ok = snippet_with_applicability(cx, let_expr.span.until(ok_path.ident.span), "", &mut applicability);
let sugg = format!(
- "{} let Ok({}) = {}",
- ifwhile,
- some_expr_string,
+ "{ifwhile} let Ok({some_expr_string}) = {}",
trimmed_ok.trim().trim_end_matches('.'),
);
span_lint_and_sugg(
@@ -80,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
MATCH_RESULT_OK,
expr.span.with_hi(let_expr.span.hi()),
"matching on `Some` with `ok()` is redundant",
- &format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),
+ &format!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"),
sugg,
applicability,
);
diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
index 07021f1bc..33a052c41 100644
--- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
@@ -1,7 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLetOrMatch;
+use clippy_utils::source::snippet;
use clippy_utils::visitors::is_local_used;
-use clippy_utils::{is_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq};
+use clippy_utils::{
+ is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq,
+};
use if_chain::if_chain;
use rustc_errors::MultiSpan;
use rustc_hir::LangItem::OptionNone;
@@ -61,7 +64,8 @@ fn check_arm<'tcx>(
if !pat_contains_or(inner_then_pat);
// the binding must come from the pattern of the containing match arm
// ..<local>.. => match <local> { .. }
- if let Some(binding_span) = find_pat_binding(outer_pat, binding_id);
+ if let (Some(binding_span), is_innermost_parent_pat_struct)
+ = find_pat_binding_and_is_innermost_parent_pat_struct(outer_pat, binding_id);
// the "else" branches must be equal
if match (outer_else_body, inner_else_body) {
(None, None) => true,
@@ -86,6 +90,13 @@ fn check_arm<'tcx>(
if matches!(inner, IfLetOrMatch::Match(..)) { "match" } else { "if let" },
if outer_is_match { "match" } else { "if let" },
);
+ // collapsing patterns need an explicit field name in struct pattern matching
+ // ex: Struct {x: Some(1)}
+ let replace_msg = if is_innermost_parent_pat_struct {
+ format!(", prefixed by {}:", snippet(cx, binding_span, "their field name"))
+ } else {
+ String::new()
+ };
span_lint_and_then(
cx,
COLLAPSIBLE_MATCH,
@@ -94,7 +105,7 @@ fn check_arm<'tcx>(
|diag| {
let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]);
help_span.push_span_label(binding_span, "replace this binding");
- help_span.push_span_label(inner_then_pat.span, "with this pattern");
+ help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}"));
diag.span_help(help_span, "the outer pattern can be modified to include the inner pattern");
},
);
@@ -110,13 +121,14 @@ fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
}
match arm.pat.kind {
PatKind::Binding(..) | PatKind::Wild => true,
- PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
+ PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
_ => false,
}
}
-fn find_pat_binding(pat: &Pat<'_>, hir_id: HirId) -> Option<Span> {
+fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: HirId) -> (Option<Span>, bool) {
let mut span = None;
+ let mut is_innermost_parent_pat_struct = false;
pat.walk_short(|p| match &p.kind {
// ignore OR patterns
PatKind::Or(_) => false,
@@ -127,9 +139,12 @@ fn find_pat_binding(pat: &Pat<'_>, hir_id: HirId) -> Option<Span> {
}
!found
},
- _ => true,
+ _ => {
+ is_innermost_parent_pat_struct = matches!(p.kind, PatKind::Struct(..));
+ true
+ },
});
- span
+ (span, is_innermost_parent_pat_struct)
}
fn pat_contains_or(pat: &Pat<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
new file mode 100644
index 000000000..66ba1f6f9
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
@@ -0,0 +1,153 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::contains_unsafe_block;
+use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id};
+
+use rustc_hir::LangItem::OptionSome;
+use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::{sym, SyntaxContext};
+
+use super::manual_utils::{check_with, SomeExpr};
+use super::MANUAL_FILTER;
+
+// Function called on the <expr> of `[&+]Some((ref | ref mut) x) => <expr>`
+// Need to check if it's of the form `<expr>=if <cond> {<then_expr>} else {<else_expr>}`
+// AND that only one `then/else_expr` resolves to `Some(x)` while the other resolves to `None`
+// return the `cond` expression if so.
+fn get_cond_expr<'tcx>(
+ cx: &LateContext<'tcx>,
+ pat: &Pat<'_>,
+ expr: &'tcx Expr<'_>,
+ ctxt: SyntaxContext,
+) -> Option<SomeExpr<'tcx>> {
+ if_chain! {
+ if let Some(block_expr) = peels_blocks_incl_unsafe_opt(expr);
+ if let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind;
+ if let PatKind::Binding(_,target, ..) = pat.kind;
+ if let (then_visitor, else_visitor)
+ = (is_some_expr(cx, target, ctxt, then_expr),
+ is_some_expr(cx, target, ctxt, else_expr));
+ if then_visitor != else_visitor; // check that one expr resolves to `Some(x)`, the other to `None`
+ then {
+ return Some(SomeExpr {
+ expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()),
+ needs_unsafe_block: contains_unsafe_block(cx, expr),
+ needs_negated: !then_visitor // if the `then_expr` resolves to `None`, need to negate the cond
+ })
+ }
+ };
+ None
+}
+
+fn peels_blocks_incl_unsafe_opt<'a>(expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
+ // we don't want to use `peel_blocks` here because we don't care if the block is unsafe, it's
+ // checked by `contains_unsafe_block`
+ if let ExprKind::Block(block, None) = expr.kind {
+ if block.stmts.is_empty() {
+ return block.expr;
+ }
+ };
+ None
+}
+
+fn peels_blocks_incl_unsafe<'a>(expr: &'a Expr<'a>) -> &'a Expr<'a> {
+ peels_blocks_incl_unsafe_opt(expr).unwrap_or(expr)
+}
+
+// function called for each <expr> expression:
+// Some(x) => if <cond> {
+// <expr>
+// } else {
+// <expr>
+// }
+// Returns true if <expr> resolves to `Some(x)`, `false` otherwise
+fn is_some_expr<'tcx>(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: &'tcx Expr<'_>) -> bool {
+ if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
+ // there can be not statements in the block as they would be removed when switching to `.filter`
+ if let ExprKind::Call(callee, [arg]) = inner_expr.kind {
+ return ctxt == expr.span.ctxt()
+ && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome)
+ && path_to_local_id(arg, target);
+ }
+ };
+ false
+}
+
+// given the closure: `|<pattern>| <expr>`
+// returns `|&<pattern>| <expr>`
+fn add_ampersand_if_copy(body_str: String, has_copy_trait: bool) -> String {
+ if has_copy_trait {
+ let mut with_ampersand = body_str;
+ with_ampersand.insert(1, '&');
+ with_ampersand
+ } else {
+ body_str
+ }
+}
+
+pub(super) fn check_match<'tcx>(
+ cx: &LateContext<'tcx>,
+ scrutinee: &'tcx Expr<'_>,
+ arms: &'tcx [Arm<'_>],
+ expr: &'tcx Expr<'_>,
+) {
+ let ty = cx.typeck_results().expr_ty(expr);
+ if is_type_diagnostic_item(cx, ty, sym::Option)
+ && let [first_arm, second_arm] = arms
+ && first_arm.guard.is_none()
+ && second_arm.guard.is_none()
+ {
+ check(cx, expr, scrutinee, first_arm.pat, first_arm.body, Some(second_arm.pat), second_arm.body);
+ }
+}
+
+pub(super) fn check_if_let<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ let_pat: &'tcx Pat<'_>,
+ let_expr: &'tcx Expr<'_>,
+ then_expr: &'tcx Expr<'_>,
+ else_expr: &'tcx Expr<'_>,
+) {
+ check(cx, expr, let_expr, let_pat, then_expr, None, else_expr);
+}
+
+fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ scrutinee: &'tcx Expr<'_>,
+ then_pat: &'tcx Pat<'_>,
+ then_body: &'tcx Expr<'_>,
+ else_pat: Option<&'tcx Pat<'_>>,
+ else_body: &'tcx Expr<'_>,
+) {
+ if let Some(sugg_info) = check_with(
+ cx,
+ expr,
+ scrutinee,
+ then_pat,
+ then_body,
+ else_pat,
+ else_body,
+ get_cond_expr,
+ ) {
+ let body_str = add_ampersand_if_copy(sugg_info.body_str, sugg_info.scrutinee_impl_copy);
+ span_lint_and_sugg(
+ cx,
+ MANUAL_FILTER,
+ expr.span,
+ "manual implementation of `Option::filter`",
+ "try this",
+ if sugg_info.needs_brackets {
+ format!(
+ "{{ {}{}.filter({body_str}) }}",
+ sugg_info.scrutinee_str, sugg_info.as_ref_str
+ )
+ } else {
+ format!("{}{}.filter({body_str})", sugg_info.scrutinee_str, sugg_info.as_ref_str)
+ },
+ sugg_info.app,
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_map.rs b/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
index 8f98b43b9..aaba23967 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
@@ -1,22 +1,13 @@
-use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF};
+use super::manual_utils::{check_with, SomeExpr};
+use super::MANUAL_MAP;
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
-use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
-use clippy_utils::{
- can_move_expr_to_closure, is_else_clause, is_lang_ctor, is_lint_allowed, path_to_local_id, peel_blocks,
- peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
-};
-use rustc_ast::util::parser::PREC_POSTFIX;
-use rustc_errors::Applicability;
-use rustc_hir::LangItem::{OptionNone, OptionSome};
-use rustc_hir::{
- def::Res, Arm, BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path,
- QPath, UnsafeSource,
-};
-use rustc_lint::LateContext;
-use rustc_span::{sym, SyntaxContext};
-use super::MANUAL_MAP;
+use clippy_utils::{is_res_lang_ctor, path_res};
+
+use rustc_hir::LangItem::OptionSome;
+use rustc_hir::{Arm, Block, BlockCheckMode, Expr, ExprKind, Pat, UnsafeSource};
+use rustc_lint::LateContext;
+use rustc_span::SyntaxContext;
pub(super) fn check_match<'tcx>(
cx: &LateContext<'tcx>,
@@ -43,7 +34,6 @@ pub(super) fn check_if_let<'tcx>(
check(cx, expr, let_expr, let_pat, then_expr, None, else_expr);
}
-#[expect(clippy::too_many_lines)]
fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>,
@@ -53,254 +43,74 @@ fn check<'tcx>(
else_pat: Option<&'tcx Pat<'_>>,
else_body: &'tcx Expr<'_>,
) {
- let (scrutinee_ty, ty_ref_count, ty_mutability) =
- peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrutinee));
- if !(is_type_diagnostic_item(cx, scrutinee_ty, sym::Option)
- && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Option))
- {
- return;
- }
-
- let expr_ctxt = expr.span.ctxt();
- let (some_expr, some_pat, pat_ref_count, is_wild_none) = match (
- try_parse_pattern(cx, then_pat, expr_ctxt),
- else_pat.map_or(Some(OptionPat::Wild), |p| try_parse_pattern(cx, p, expr_ctxt)),
+ if let Some(sugg_info) = check_with(
+ cx,
+ expr,
+ scrutinee,
+ then_pat,
+ then_body,
+ else_pat,
+ else_body,
+ get_some_expr,
) {
- (Some(OptionPat::Wild), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_body) => {
- (else_body, pattern, ref_count, true)
- },
- (Some(OptionPat::None), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_body) => {
- (else_body, pattern, ref_count, false)
- },
- (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::Wild)) if is_none_expr(cx, else_body) => {
- (then_body, pattern, ref_count, true)
- },
- (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::None)) if is_none_expr(cx, else_body) => {
- (then_body, pattern, ref_count, false)
- },
- _ => return,
- };
-
- // Top level or patterns aren't allowed in closures.
- if matches!(some_pat.kind, PatKind::Or(_)) {
- return;
- }
-
- let some_expr = match get_some_expr(cx, some_expr, false, expr_ctxt) {
- Some(expr) => expr,
- None => return,
- };
-
- // These two lints will go back and forth with each other.
- if cx.typeck_results().expr_ty(some_expr.expr) == cx.tcx.types.unit
- && !is_lint_allowed(cx, OPTION_MAP_UNIT_FN, expr.hir_id)
- {
- return;
- }
-
- // `map` won't perform any adjustments.
- if !cx.typeck_results().expr_adjustments(some_expr.expr).is_empty() {
- return;
- }
-
- // Determine which binding mode to use.
- let explicit_ref = some_pat.contains_explicit_ref_binding();
- let binding_ref = explicit_ref.or_else(|| (ty_ref_count != pat_ref_count).then_some(ty_mutability));
-
- let as_ref_str = match binding_ref {
- Some(Mutability::Mut) => ".as_mut()",
- Some(Mutability::Not) => ".as_ref()",
- None => "",
- };
-
- match can_move_expr_to_closure(cx, some_expr.expr) {
- Some(captures) => {
- // 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 let Some(binding_ref_mutability) = binding_ref {
- let e = peel_hir_expr_while(scrutinee, |e| match e.kind {
- ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e),
- _ => None,
- });
- if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind {
- match captures.get(l) {
- Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return,
- Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => {
- return;
- },
- Some(CaptureKind::Ref(Mutability::Not)) | None => (),
- }
- }
- }
- },
- None => return,
- };
-
- let mut app = Applicability::MachineApplicable;
-
- // Remove address-of expressions from the scrutinee. Either `as_ref` will be called, or
- // it's being passed by value.
- let scrutinee = peel_hir_expr_refs(scrutinee).0;
- let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
- let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX {
- format!("({})", scrutinee_str)
- } else {
- scrutinee_str.into()
- };
-
- let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind {
- if_chain! {
- if !some_expr.needs_unsafe_block;
- if let Some(func) = can_pass_as_func(cx, id, some_expr.expr);
- if func.span.ctxt() == some_expr.expr.span.ctxt();
- then {
- snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
+ span_lint_and_sugg(
+ cx,
+ MANUAL_MAP,
+ expr.span,
+ "manual implementation of `Option::map`",
+ "try this",
+ if sugg_info.needs_brackets {
+ format!(
+ "{{ {}{}.map({}) }}",
+ sugg_info.scrutinee_str, sugg_info.as_ref_str, sugg_info.body_str
+ )
} else {
- if path_to_local_id(some_expr.expr, id)
- && !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id)
- && binding_ref.is_some()
- {
- return;
- }
-
- // `ref` and `ref mut` annotations were handled earlier.
- let annotation = if matches!(annotation, BindingAnnotation::Mutable) {
- "mut "
- } else {
- ""
- };
- let expr_snip = snippet_with_context(cx, some_expr.expr.span, expr_ctxt, "..", &mut app).0;
- if some_expr.needs_unsafe_block {
- format!("|{}{}| unsafe {{ {} }}", annotation, some_binding, expr_snip)
- } else {
- format!("|{}{}| {}", annotation, some_binding, expr_snip)
- }
- }
- }
- } else if !is_wild_none && explicit_ref.is_none() {
- // TODO: handle explicit reference annotations.
- let pat_snip = snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0;
- let expr_snip = snippet_with_context(cx, some_expr.expr.span, expr_ctxt, "..", &mut app).0;
- if some_expr.needs_unsafe_block {
- format!("|{}| unsafe {{ {} }}", pat_snip, expr_snip)
- } else {
- format!("|{}| {}", pat_snip, expr_snip)
- }
- } else {
- // Refutable bindings and mixed reference annotations can't be handled by `map`.
- return;
- };
-
- span_lint_and_sugg(
- cx,
- MANUAL_MAP,
- expr.span,
- "manual implementation of `Option::map`",
- "try this",
- if else_pat.is_none() && is_else_clause(cx.tcx, expr) {
- format!("{{ {}{}.map({}) }}", scrutinee_str, as_ref_str, body_str)
- } else {
- format!("{}{}.map({})", scrutinee_str, as_ref_str, body_str)
- },
- app,
- );
-}
-
-// Checks whether the expression could be passed as a function, or whether a closure is needed.
-// Returns the function to be passed to `map` if it exists.
-fn can_pass_as_func<'tcx>(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
- match expr.kind {
- ExprKind::Call(func, [arg])
- if path_to_local_id(arg, binding)
- && cx.typeck_results().expr_adjustments(arg).is_empty()
- && !type_is_unsafe_function(cx, cx.typeck_results().expr_ty(func).peel_refs()) =>
- {
- Some(func)
- },
- _ => None,
- }
-}
-
-enum OptionPat<'a> {
- Wild,
- None,
- Some {
- // The pattern contained in the `Some` tuple.
- pattern: &'a Pat<'a>,
- // The number of references before the `Some` tuple.
- // e.g. `&&Some(_)` has a ref count of 2.
- ref_count: usize,
- },
-}
-
-struct SomeExpr<'tcx> {
- expr: &'tcx Expr<'tcx>,
- needs_unsafe_block: bool,
-}
-
-// Try to parse into a recognized `Option` pattern.
-// i.e. `_`, `None`, `Some(..)`, or a reference to any of those.
-fn try_parse_pattern<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
- fn f<'tcx>(
- cx: &LateContext<'tcx>,
- pat: &'tcx Pat<'_>,
- ref_count: usize,
- ctxt: SyntaxContext,
- ) -> Option<OptionPat<'tcx>> {
- match pat.kind {
- PatKind::Wild => Some(OptionPat::Wild),
- PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
- PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone) => Some(OptionPat::None),
- PatKind::TupleStruct(ref qpath, [pattern], _)
- if is_lang_ctor(cx, qpath, OptionSome) && pat.span.ctxt() == ctxt =>
- {
- Some(OptionPat::Some { pattern, ref_count })
+ format!(
+ "{}{}.map({})",
+ sugg_info.scrutinee_str, sugg_info.as_ref_str, sugg_info.body_str
+ )
},
- _ => None,
- }
+ sugg_info.app,
+ );
}
- f(cx, pat, 0, ctxt)
}
// Checks for an expression wrapped by the `Some` constructor. Returns the contained expression.
fn get_some_expr<'tcx>(
cx: &LateContext<'tcx>,
+ _: &'tcx Pat<'_>,
expr: &'tcx Expr<'_>,
- needs_unsafe_block: bool,
ctxt: SyntaxContext,
) -> Option<SomeExpr<'tcx>> {
- // TODO: Allow more complex expressions.
- match expr.kind {
- ExprKind::Call(
- Expr {
- kind: ExprKind::Path(ref qpath),
- ..
- },
- [arg],
- ) if ctxt == expr.span.ctxt() && is_lang_ctor(cx, qpath, OptionSome) => Some(SomeExpr {
- expr: arg,
- needs_unsafe_block,
- }),
- ExprKind::Block(
- Block {
- stmts: [],
- expr: Some(expr),
- rules,
- ..
+ fn get_some_expr_internal<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ needs_unsafe_block: bool,
+ ctxt: SyntaxContext,
+ ) -> Option<SomeExpr<'tcx>> {
+ // TODO: Allow more complex expressions.
+ match expr.kind {
+ ExprKind::Call(callee, [arg])
+ if ctxt == expr.span.ctxt() && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome) =>
+ {
+ Some(SomeExpr::new_no_negated(arg, needs_unsafe_block))
},
- _,
- ) => get_some_expr(
- cx,
- expr,
- needs_unsafe_block || *rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
- ctxt,
- ),
- _ => None,
+ ExprKind::Block(
+ Block {
+ stmts: [],
+ expr: Some(expr),
+ rules,
+ ..
+ },
+ _,
+ ) => get_some_expr_internal(
+ cx,
+ expr,
+ needs_unsafe_block || *rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
+ ctxt,
+ ),
+ _ => None,
+ }
}
-}
-
-// Checks for the `None` value.
-fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- matches!(peel_blocks(expr).kind, ExprKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
+ get_some_expr_internal(cx, expr, false, ctxt)
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
index e1111c80f..587c926dc 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -3,12 +3,14 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::usage::contains_return_break_continue_macro;
-use clippy_utils::{is_lang_ctor, path_to_local_id, sugg};
+use clippy_utils::{is_res_lang_ctor, path_to_local_id, sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::LangItem::{OptionNone, ResultErr};
use rustc_hir::{Arm, Expr, PatKind};
use rustc_lint::LateContext;
+use rustc_middle::ty::DefIdTree;
use rustc_span::sym;
use super::MANUAL_UNWRAP_OR;
@@ -42,12 +44,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee:
span_lint_and_sugg(
cx,
MANUAL_UNWRAP_OR, expr.span,
- &format!("this pattern reimplements `{}::unwrap_or`", ty_name),
+ &format!("this pattern reimplements `{ty_name}::unwrap_or`"),
"replace with",
format!(
- "{}.unwrap_or({})",
- suggestion,
- reindented_or_body,
+ "{suggestion}.unwrap_or({reindented_or_body})",
),
Applicability::MachineApplicable,
);
@@ -61,15 +61,19 @@ fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'
if arms.iter().all(|arm| arm.guard.is_none());
if let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| {
match arm.pat.kind {
- PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
+ PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
PatKind::TupleStruct(ref qpath, [pat], _) =>
- matches!(pat.kind, PatKind::Wild) && is_lang_ctor(cx, qpath, ResultErr),
+ matches!(pat.kind, PatKind::Wild)
+ && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr),
_ => false,
}
});
let unwrap_arm = &arms[1 - idx];
if let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = unwrap_arm.pat.kind;
- if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk);
+ if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, unwrap_arm.pat.hir_id);
+ if let Some(variant_id) = cx.tcx.opt_parent(ctor_id);
+ if cx.tcx.lang_items().option_some_variant() == Some(variant_id)
+ || cx.tcx.lang_items().result_ok_variant() == Some(variant_id);
if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind;
if path_to_local_id(unwrap_arm.body, binding_hir_id);
if cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty();
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
new file mode 100644
index 000000000..5b7644a53
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -0,0 +1,277 @@
+use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF};
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
+use clippy_utils::ty::{is_copy, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
+use clippy_utils::{
+ can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, path_to_local_id,
+ peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, sugg::Sugg, CaptureKind,
+};
+use rustc_ast::util::parser::PREC_POSTFIX;
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::{OptionNone, OptionSome};
+use rustc_hir::{def::Res, BindingAnnotation, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath};
+use rustc_lint::LateContext;
+use rustc_span::{sym, SyntaxContext};
+
+#[expect(clippy::too_many_arguments)]
+#[expect(clippy::too_many_lines)]
+pub(super) fn check_with<'tcx, F>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ scrutinee: &'tcx Expr<'_>,
+ then_pat: &'tcx Pat<'_>,
+ then_body: &'tcx Expr<'_>,
+ else_pat: Option<&'tcx Pat<'_>>,
+ else_body: &'tcx Expr<'_>,
+ get_some_expr_fn: F,
+) -> Option<SuggInfo<'tcx>>
+where
+ F: Fn(&LateContext<'tcx>, &'tcx Pat<'_>, &'tcx Expr<'_>, SyntaxContext) -> Option<SomeExpr<'tcx>>,
+{
+ let (scrutinee_ty, ty_ref_count, ty_mutability) =
+ peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrutinee));
+ if !(is_type_diagnostic_item(cx, scrutinee_ty, sym::Option)
+ && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Option))
+ {
+ return None;
+ }
+
+ let expr_ctxt = expr.span.ctxt();
+ let (some_expr, some_pat, pat_ref_count, is_wild_none) = match (
+ try_parse_pattern(cx, then_pat, expr_ctxt),
+ else_pat.map_or(Some(OptionPat::Wild), |p| try_parse_pattern(cx, p, expr_ctxt)),
+ ) {
+ (Some(OptionPat::Wild), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_body) => {
+ (else_body, pattern, ref_count, true)
+ },
+ (Some(OptionPat::None), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_body) => {
+ (else_body, pattern, ref_count, false)
+ },
+ (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::Wild)) if is_none_expr(cx, else_body) => {
+ (then_body, pattern, ref_count, true)
+ },
+ (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::None)) if is_none_expr(cx, else_body) => {
+ (then_body, pattern, ref_count, false)
+ },
+ _ => return None,
+ };
+
+ // Top level or patterns aren't allowed in closures.
+ if matches!(some_pat.kind, PatKind::Or(_)) {
+ return None;
+ }
+
+ let Some(some_expr) = get_some_expr_fn(cx, some_pat, some_expr, expr_ctxt) else {
+ return None;
+ };
+
+ // These two lints will go back and forth with each other.
+ if cx.typeck_results().expr_ty(some_expr.expr) == cx.tcx.types.unit
+ && !is_lint_allowed(cx, OPTION_MAP_UNIT_FN, expr.hir_id)
+ {
+ return None;
+ }
+
+ // `map` won't perform any adjustments.
+ if !cx.typeck_results().expr_adjustments(some_expr.expr).is_empty() {
+ return None;
+ }
+
+ // Determine which binding mode to use.
+ let explicit_ref = some_pat.contains_explicit_ref_binding();
+ let binding_ref = explicit_ref.or_else(|| (ty_ref_count != pat_ref_count).then_some(ty_mutability));
+
+ let as_ref_str = match binding_ref {
+ Some(Mutability::Mut) => ".as_mut()",
+ Some(Mutability::Not) => ".as_ref()",
+ None => "",
+ };
+
+ match can_move_expr_to_closure(cx, some_expr.expr) {
+ Some(captures) => {
+ // 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 let Some(binding_ref_mutability) = binding_ref {
+ let e = peel_hir_expr_while(scrutinee, |e| match e.kind {
+ ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e),
+ _ => None,
+ });
+ if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind {
+ match captures.get(l) {
+ Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None,
+ Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => {
+ return None;
+ },
+ Some(CaptureKind::Ref(Mutability::Not)) | None => (),
+ }
+ }
+ }
+ },
+ None => return None,
+ };
+
+ let mut app = Applicability::MachineApplicable;
+
+ // Remove address-of expressions from the scrutinee. Either `as_ref` will be called, or
+ // it's being passed by value.
+ let scrutinee = peel_hir_expr_refs(scrutinee).0;
+ let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
+ let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX {
+ format!("({scrutinee_str})")
+ } else {
+ scrutinee_str.into()
+ };
+
+ let closure_expr_snip = some_expr.to_snippet_with_context(cx, expr_ctxt, &mut app);
+ let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind {
+ if_chain! {
+ if !some_expr.needs_unsafe_block;
+ if let Some(func) = can_pass_as_func(cx, id, some_expr.expr);
+ if func.span.ctxt() == some_expr.expr.span.ctxt();
+ then {
+ snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
+ } else {
+ if path_to_local_id(some_expr.expr, id)
+ && !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id)
+ && binding_ref.is_some()
+ {
+ return None;
+ }
+
+ // `ref` and `ref mut` annotations were handled earlier.
+ let annotation = if matches!(annotation, BindingAnnotation::MUT) {
+ "mut "
+ } else {
+ ""
+ };
+
+ if some_expr.needs_unsafe_block {
+ format!("|{annotation}{some_binding}| unsafe {{ {closure_expr_snip} }}")
+ } else {
+ format!("|{annotation}{some_binding}| {closure_expr_snip}")
+ }
+ }
+ }
+ } else if !is_wild_none && explicit_ref.is_none() {
+ // TODO: handle explicit reference annotations.
+ let pat_snip = snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0;
+ if some_expr.needs_unsafe_block {
+ format!("|{pat_snip}| unsafe {{ {closure_expr_snip} }}")
+ } else {
+ format!("|{pat_snip}| {closure_expr_snip}")
+ }
+ } else {
+ // Refutable bindings and mixed reference annotations can't be handled by `map`.
+ return None;
+ };
+
+ // relies on the fact that Option<T>: Copy where T: copy
+ let scrutinee_impl_copy = is_copy(cx, scrutinee_ty);
+
+ Some(SuggInfo {
+ needs_brackets: else_pat.is_none() && is_else_clause(cx.tcx, expr),
+ scrutinee_impl_copy,
+ scrutinee_str,
+ as_ref_str,
+ body_str,
+ app,
+ })
+}
+
+pub struct SuggInfo<'a> {
+ pub needs_brackets: bool,
+ pub scrutinee_impl_copy: bool,
+ pub scrutinee_str: String,
+ pub as_ref_str: &'a str,
+ pub body_str: String,
+ pub app: Applicability,
+}
+
+// Checks whether the expression could be passed as a function, or whether a closure is needed.
+// Returns the function to be passed to `map` if it exists.
+fn can_pass_as_func<'tcx>(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+ match expr.kind {
+ ExprKind::Call(func, [arg])
+ if path_to_local_id(arg, binding)
+ && cx.typeck_results().expr_adjustments(arg).is_empty()
+ && !type_is_unsafe_function(cx, cx.typeck_results().expr_ty(func).peel_refs()) =>
+ {
+ Some(func)
+ },
+ _ => None,
+ }
+}
+
+#[derive(Debug)]
+pub(super) enum OptionPat<'a> {
+ Wild,
+ None,
+ Some {
+ // The pattern contained in the `Some` tuple.
+ pattern: &'a Pat<'a>,
+ // The number of references before the `Some` tuple.
+ // e.g. `&&Some(_)` has a ref count of 2.
+ ref_count: usize,
+ },
+}
+
+pub(super) struct SomeExpr<'tcx> {
+ pub expr: &'tcx Expr<'tcx>,
+ pub needs_unsafe_block: bool,
+ pub needs_negated: bool, // for `manual_filter` lint
+}
+
+impl<'tcx> SomeExpr<'tcx> {
+ pub fn new_no_negated(expr: &'tcx Expr<'tcx>, needs_unsafe_block: bool) -> Self {
+ Self {
+ expr,
+ needs_unsafe_block,
+ needs_negated: false,
+ }
+ }
+
+ pub fn to_snippet_with_context(
+ &self,
+ cx: &LateContext<'tcx>,
+ ctxt: SyntaxContext,
+ app: &mut Applicability,
+ ) -> Sugg<'tcx> {
+ let sugg = Sugg::hir_with_context(cx, self.expr, ctxt, "..", app);
+ if self.needs_negated { !sugg } else { sugg }
+ }
+}
+
+// Try to parse into a recognized `Option` pattern.
+// i.e. `_`, `None`, `Some(..)`, or a reference to any of those.
+pub(super) fn try_parse_pattern<'tcx>(
+ cx: &LateContext<'tcx>,
+ pat: &'tcx Pat<'_>,
+ ctxt: SyntaxContext,
+) -> Option<OptionPat<'tcx>> {
+ fn f<'tcx>(
+ cx: &LateContext<'tcx>,
+ pat: &'tcx Pat<'_>,
+ ref_count: usize,
+ ctxt: SyntaxContext,
+ ) -> Option<OptionPat<'tcx>> {
+ match pat.kind {
+ PatKind::Wild => Some(OptionPat::Wild),
+ PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
+ PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionNone) => {
+ Some(OptionPat::None)
+ },
+ PatKind::TupleStruct(ref qpath, [pattern], _)
+ if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionSome) && pat.span.ctxt() == ctxt =>
+ {
+ Some(OptionPat::Some { pattern, ref_count })
+ },
+ _ => None,
+ }
+ }
+ f(cx, pat, 0, ctxt)
+}
+
+// Checks for the `None` value.
+fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ is_res_lang_ctor(cx, path_res(cx, peel_blocks(expr)), OptionNone)
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
index d914eba01..2818f030b 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
@@ -1,8 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_lang_ctor, peel_blocks};
+use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks};
use rustc_errors::Applicability;
-use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, LangItem, PatKind, QPath};
+use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty;
@@ -10,18 +10,17 @@ use super::MATCH_AS_REF;
pub(crate) fn check(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]) {
+ let arm_ref_mut = 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"
+ if let Some(rb) = arm_ref_mut {
+ let suggestion = match rb {
+ Mutability::Not => "as_ref",
+ Mutability::Mut => "as_mut",
};
let output_ty = cx.typeck_results().expr_ty(expr);
@@ -46,13 +45,11 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
cx,
MATCH_AS_REF,
expr.span,
- &format!("use `{}()` instead", suggestion),
+ &format!("use `{suggestion}()` instead"),
"try this",
format!(
- "{}.{}(){}",
+ "{}.{suggestion}(){cast}",
snippet_with_applicability(cx, ex.span, "_", &mut applicability),
- suggestion,
- cast,
),
applicability,
);
@@ -62,23 +59,24 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
// 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, LangItem::OptionNone))
+ matches!(
+ arm.pat.kind,
+ PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::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> {
+fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
if_chain! {
if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind;
- if is_lang_ctor(cx, qpath, LangItem::OptionSome);
- if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
- if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
- if let ExprKind::Call(e, args) = peel_blocks(arm.body).kind;
- if let ExprKind::Path(ref some_path) = e.kind;
- if is_lang_ctor(cx, some_path, LangItem::OptionSome) && args.len() == 1;
- if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind;
+ if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome);
+ if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind;
+ if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind;
+ if is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome);
+ if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind;
if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
then {
- return Some(rb)
+ return Some(mutabl)
}
}
None
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
index 0da4833f1..107fad323 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
@@ -1,10 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_wild;
use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::span_contains_comment;
use rustc_ast::{Attribute, LitKind};
use rustc_errors::Applicability;
use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat};
-use rustc_lint::LateContext;
+use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty;
use rustc_span::source_map::Spanned;
@@ -76,6 +77,7 @@ where
>,
{
if_chain! {
+ if !span_contains_comment(cx.sess().source_map(), expr.span);
if iter.len() >= 2;
if cx.typeck_results().expr_ty(expr).is_bool();
if let Some((_, last_pat_opt, last_expr, _)) = iter.next_back();
@@ -110,7 +112,7 @@ where
.join(" | ")
};
let pat_and_guard = if let Some(Guard::If(g)) = first_guard {
- format!("{} if {}", pat, snippet_with_applicability(cx, g.span, "..", &mut applicability))
+ format!("{pat} if {}", snippet_with_applicability(cx, g.span, "..", &mut applicability))
} else {
pat
};
@@ -129,10 +131,9 @@ where
&format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }),
"try this",
format!(
- "{}matches!({}, {})",
+ "{}matches!({}, {pat_and_guard})",
if b0 { "" } else { "!" },
snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
- pat_and_guard,
),
applicability,
);
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 582782f24..168c1e4d2 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -8,11 +8,10 @@ use rustc_arena::DroplessArena;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
-use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdSet, Pat, PatKind, RangeEnd};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::Symbol;
-use std::collections::hash_map::Entry;
use super::MATCH_SAME_ARMS;
@@ -71,9 +70,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
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,
+ HirIdMapEntry::Vacant(entry) => entry,
// check if using the same bindings as before
- Entry::Occupied(entry) => return *entry.get() == b_id,
+ HirIdMapEntry::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);
@@ -135,7 +134,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
diag.span_suggestion(
keep_arm.pat.span,
"try merging the arm patterns",
- format!("{} | {}", keep_pat_snip, move_pat_snip),
+ format!("{keep_pat_snip} | {move_pat_snip}"),
Applicability::MaybeIncorrect,
)
.help("or try changing either arm body")
@@ -222,7 +221,6 @@ fn iter_matching_struct_fields<'a>(
#[expect(clippy::similar_names)]
impl<'a> NormalizedPat<'a> {
- #[expect(clippy::too_many_lines)]
fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self {
match pat.kind {
PatKind::Wild | PatKind::Binding(.., None) => Self::Wild,
@@ -236,9 +234,8 @@ impl<'a> NormalizedPat<'a> {
Self::Struct(cx.qpath_res(path, pat.hir_id).opt_def_id(), fields)
},
PatKind::TupleStruct(ref path, pats, wild_idx) => {
- let adt = match cx.typeck_results().pat_ty(pat).ty_adt_def() {
- Some(x) => x,
- None => return Self::Wild,
+ let Some(adt) = cx.typeck_results().pat_ty(pat).ty_adt_def() else {
+ return Self::Wild
};
let (var_id, variant) = if adt.is_enum() {
match cx.qpath_res(path, pat.hir_id).opt_def_id() {
@@ -248,7 +245,7 @@ impl<'a> NormalizedPat<'a> {
} else {
(None, adt.non_enum_variant())
};
- let (front, back) = match wild_idx {
+ let (front, back) = match wild_idx.as_opt_usize() {
Some(i) => pats.split_at(i),
None => (pats, [].as_slice()),
};
@@ -268,7 +265,7 @@ impl<'a> NormalizedPat<'a> {
ty::Tuple(subs) => subs.len(),
_ => return Self::Wild,
};
- let (front, back) = match wild_idx {
+ let (front, back) = match wild_idx.as_opt_usize() {
Some(i) => pats.split_at(i),
None => (pats, [].as_slice()),
};
@@ -290,7 +287,7 @@ impl<'a> NormalizedPat<'a> {
LitKind::Char(val) => Self::LitInt(val.into()),
LitKind::Int(val, _) => Self::LitInt(val),
LitKind::Bool(val) => Self::LitBool(val),
- LitKind::Float(..) | LitKind::Err(_) => Self::Wild,
+ LitKind::Float(..) | LitKind::Err => Self::Wild,
},
_ => Self::Wild,
},
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
index 5ae4a65ac..1bf8d4e96 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
@@ -58,6 +58,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
&snippet_body,
&mut applicability,
Some(span),
+ true,
);
span_lint_and_sugg(
@@ -75,12 +76,11 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
Some(AssignmentExpr::Local { span, pat_span }) => (
span,
format!(
- "let {} = {};\n{}let {} = {};",
+ "let {} = {};\n{}let {} = {snippet_body};",
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, pat_span, "..", &mut applicability),
- snippet_body
+ snippet_with_applicability(cx, pat_span, "..", &mut applicability)
),
),
None => {
@@ -91,6 +91,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
&snippet_body,
&mut applicability,
None,
+ true,
);
(expr.span, sugg)
},
@@ -108,12 +109,14 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
},
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
+ let sugg = sugg_with_curlies(
+ cx,
+ (ex, expr),
+ (bind_names, matched_vars),
+ &snippet_body,
+ &mut applicability,
+ None,
+ false,
);
span_lint_and_sugg(
@@ -172,16 +175,17 @@ fn sugg_with_curlies<'a>(
snippet_body: &str,
applicability: &mut Applicability,
assignment: Option<Span>,
+ needs_var_binding: bool,
) -> String {
let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
let (mut cbrace_start, mut cbrace_end) = (String::new(), String::new());
if let Some(parent_expr) = get_parent_expr(cx, match_expr) {
if let ExprKind::Closure { .. } = parent_expr.kind {
- cbrace_end = format!("\n{}}}", indent);
+ 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);
+ cbrace_start = format!("{{\n{indent}");
}
}
@@ -190,10 +194,10 @@ fn sugg_with_curlies<'a>(
let parent_node_id = cx.tcx.hir().get_parent_node(match_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);
+ 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);
+ cbrace_start = format!("{{\n{indent}");
}
}
@@ -203,14 +207,15 @@ fn sugg_with_curlies<'a>(
s
});
- format!(
- "{}let {} = {};\n{}{}{}{}",
- cbrace_start,
- snippet_with_applicability(cx, bind_names, "..", applicability),
- snippet_with_applicability(cx, matched_vars, "..", applicability),
- indent,
- assignment_str,
- snippet_body,
- cbrace_end
- )
+ let scrutinee = if needs_var_binding {
+ format!(
+ "let {} = {}",
+ snippet_with_applicability(cx, bind_names, "..", applicability),
+ snippet_with_applicability(cx, matched_vars, "..", applicability)
+ )
+ } else {
+ snippet_with_applicability(cx, matched_vars, "..", applicability).to_string()
+ };
+
+ format!("{cbrace_start}{scrutinee};\n{indent}{assignment_str}{snippet_body}{cbrace_end}")
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
index fa3b8d1fc..6647322ca 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -48,7 +48,7 @@ struct MatchExprVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
match ex.kind {
- ExprKind::MethodCall(segment, [receiver], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
+ ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
_ => walk_expr(self, ex),
}
}
@@ -118,8 +118,8 @@ fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad
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),
+ &format!("consider changing the case of this arm to respect `{method_str}`"),
+ format!("\"{suggestion}\""),
Applicability::MachineApplicable,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
index bc16f17b6..42f1e2629 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
@@ -38,9 +38,9 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'
span_lint_and_note(cx,
MATCH_WILD_ERR_ARM,
arm.pat.span,
- &format!("`Err({})` matches all errors", ident_bind_name),
+ &format!("`Err({ident_bind_name})` matches all errors"),
None,
- "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable",
+ "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable",
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index eba230e5a..7d8171ead 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -1,7 +1,9 @@
mod collapsible_match;
mod infallible_destructuring_match;
+mod manual_filter;
mod manual_map;
mod manual_unwrap_or;
+mod manual_utils;
mod match_as_ref;
mod match_bool;
mod match_like_matches;
@@ -21,8 +23,8 @@ mod single_match;
mod try_err;
mod wild_in_or_pats;
-use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context};
-use clippy_utils::{higher, in_constant, meets_msrv, msrvs};
+use clippy_utils::source::{snippet_opt, walk_span_to_context};
+use clippy_utils::{higher, in_constant, is_span_match, meets_msrv, msrvs};
use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -898,6 +900,34 @@ declare_clippy_lint! {
"reimplementation of `map`"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usages of `match` which could be implemented using `filter`
+ ///
+ /// ### Why is this bad?
+ /// Using the `filter` method is clearer and more concise.
+ ///
+ /// ### Example
+ /// ```rust
+ /// match Some(0) {
+ /// Some(x) => if x % 2 == 0 {
+ /// Some(x)
+ /// } else {
+ /// None
+ /// },
+ /// None => None,
+ /// };
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// Some(0).filter(|&x| x % 2 == 0);
+ /// ```
+ #[clippy::version = "1.66.0"]
+ pub MANUAL_FILTER,
+ complexity,
+ "reimplentation of `filter`"
+}
+
#[derive(Default)]
pub struct Matches {
msrv: Option<RustcVersion>,
@@ -939,6 +969,7 @@ impl_lint_pass!(Matches => [
SIGNIFICANT_DROP_IN_SCRUTINEE,
TRY_ERR,
MANUAL_MAP,
+ MANUAL_FILTER,
]);
impl<'tcx> LateLintPass<'tcx> for Matches {
@@ -949,7 +980,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
let from_expansion = expr.span.from_expansion();
if let ExprKind::Match(ex, arms, source) = expr.kind {
- if source == MatchSource::Normal && !span_starts_with(cx, expr.span, "match") {
+ if source == MatchSource::Normal && !is_span_match(cx, expr.span) {
return;
}
if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) {
@@ -988,6 +1019,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
if !in_constant(cx, expr.hir_id) {
manual_unwrap_or::check(cx, expr, ex, arms);
manual_map::check_match(cx, expr, ex, arms);
+ manual_filter::check_match(cx, ex, arms, expr);
}
if self.infallible_destructuring_match_linted {
@@ -1014,6 +1046,14 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
}
if !in_constant(cx, expr.hir_id) {
manual_map::check_if_let(cx, expr, if_let.let_pat, if_let.let_expr, if_let.if_then, else_expr);
+ manual_filter::check_if_let(
+ cx,
+ expr,
+ if_let.let_pat,
+ if_let.let_expr,
+ if_let.if_then,
+ else_expr,
+ );
}
}
redundant_pattern_match::check_if_let(
diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
index fa19cddd3..c4f6852ae 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -3,15 +3,15 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts};
use clippy_utils::{
- eq_expr_value, get_parent_expr_for_hir, get_parent_node, higher, is_else_clause, is_lang_ctor, over,
+ eq_expr_value, get_parent_expr_for_hir, get_parent_node, higher, is_else_clause, is_res_lang_ctor, over, path_res,
peel_blocks_with_stmt,
};
use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Node, Pat, PatKind, Path, QPath};
+use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath};
+use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::LateContext;
use rustc_span::sym;
-use rustc_typeck::hir_ty_to_ty;
pub(crate) fn check_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
if arms.len() > 1 && expr_ty_matches_p_ty(cx, ex, expr) && check_all_arms(cx, ex, arms) {
@@ -65,8 +65,26 @@ pub(crate) fn check_if_let<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'_>, if_let:
fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>]) -> bool {
for arm in arms {
let arm_expr = peel_blocks_with_stmt(arm.body);
+
+ if let Some(guard_expr) = &arm.guard {
+ match guard_expr {
+ // gives up if `pat if expr` can have side effects
+ Guard::If(if_cond) => {
+ if if_cond.can_have_side_effects() {
+ return false;
+ }
+ },
+ // gives up `pat if let ...` arm
+ Guard::IfLet(_) => {
+ return false;
+ },
+ };
+ }
+
if let PatKind::Wild = arm.pat.kind {
- return eq_expr_value(cx, match_expr, strip_return(arm_expr));
+ if !eq_expr_value(cx, match_expr, strip_return(arm_expr)) {
+ return false;
+ }
} else if !pat_same_as_expr(arm.pat, arm_expr) {
return false;
}
@@ -94,10 +112,7 @@ fn check_if_let_inner(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool
let ret = strip_return(else_expr);
let let_expr_ty = cx.typeck_results().expr_ty(if_let.let_expr);
if is_type_diagnostic_item(cx, let_expr_ty, sym::Option) {
- if let ExprKind::Path(ref qpath) = ret.kind {
- return is_lang_ctor(cx, qpath, OptionNone) || eq_expr_value(cx, if_let.let_expr, ret);
- }
- return false;
+ return is_res_lang_ctor(cx, path_res(cx, ret), OptionNone) || eq_expr_value(cx, if_let.let_expr, ret);
}
return eq_expr_value(cx, if_let.let_expr, ret);
}
@@ -171,8 +186,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
},
)),
) => {
- return !matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut)
- && pat_ident.name == first_seg.ident.name;
+ return !matches!(annot, BindingAnnotation(ByRef::Yes, _)) && pat_ident.name == first_seg.ident.name;
},
// Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
(PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => {
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index 8499e050a..81bebff34 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -2,17 +2,18 @@ use super::REDUNDANT_PATTERN_MATCHING;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::needs_ordered_drop;
+use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
use clippy_utils::visitors::any_temporaries_need_ordered_drop;
-use clippy_utils::{higher, is_lang_ctor, is_trait_method, match_def_path, paths};
+use clippy_utils::{higher, is_trait_method};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
-use rustc_hir::LangItem::{OptionNone, PollPending};
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty};
-use rustc_span::sym;
+use rustc_span::{sym, Symbol};
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
@@ -75,9 +76,9 @@ fn find_sugg_for_if_let<'tcx>(
("is_some()", op_ty)
} else if Some(id) == lang_items.poll_ready_variant() {
("is_ready()", op_ty)
- } else if match_def_path(cx, id, &paths::IPADDR_V4) {
+ } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V4))) {
("is_ipv4()", op_ty)
- } else if match_def_path(cx, id, &paths::IPADDR_V6) {
+ } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V6))) {
("is_ipv6()", op_ty)
} else {
return;
@@ -87,15 +88,21 @@ fn find_sugg_for_if_let<'tcx>(
}
},
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()"
+ if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(path, check_pat.hir_id)
+ && let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
+ {
+ let method = if cx.tcx.lang_items().option_none_variant() == Some(variant_id) {
+ "is_none()"
+ } else if cx.tcx.lang_items().poll_pending_variant() == Some(variant_id) {
+ "is_pending()"
+ } else {
+ return;
+ };
+ // `None` and `Pending` don't have an inner type.
+ (method, cx.tcx.types.unit)
} else {
return;
- };
- // `None` and `Pending` don't have an inner type.
- (method, cx.tcx.types.unit)
+ }
},
_ => return,
};
@@ -120,7 +127,7 @@ fn find_sugg_for_if_let<'tcx>(
// 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 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 {
@@ -138,7 +145,7 @@ fn find_sugg_for_if_let<'tcx>(
cx,
REDUNDANT_PATTERN_MATCHING,
let_pat.span,
- &format!("redundant pattern matching, consider using `{}`", good_method),
+ &format!("redundant pattern matching, consider using `{good_method}`"),
|diag| {
// if/while let ... = ... { ... }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -162,7 +169,7 @@ fn find_sugg_for_if_let<'tcx>(
.maybe_par()
.to_string();
- diag.span_suggestion(span, "try this", format!("{} {}.{}", keyword, sugg, good_method), 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");
@@ -187,8 +194,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
arms,
path_left,
path_right,
- &paths::RESULT_OK,
- &paths::RESULT_ERR,
+ Item::Lang(ResultOk),
+ Item::Lang(ResultErr),
"is_ok()",
"is_err()",
)
@@ -198,8 +205,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
arms,
path_left,
path_right,
- &paths::IPADDR_V4,
- &paths::IPADDR_V6,
+ Item::Diag(sym::IpAddr, sym!(V4)),
+ Item::Diag(sym::IpAddr, sym!(V6)),
"is_ipv4()",
"is_ipv6()",
)
@@ -218,8 +225,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
arms,
path_left,
path_right,
- &paths::OPTION_SOME,
- &paths::OPTION_NONE,
+ Item::Lang(OptionSome),
+ Item::Lang(OptionNone),
"is_some()",
"is_none()",
)
@@ -229,8 +236,8 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
arms,
path_left,
path_right,
- &paths::POLL_READY,
- &paths::POLL_PENDING,
+ Item::Lang(PollReady),
+ Item::Lang(PollPending),
"is_ready()",
"is_pending()",
)
@@ -252,12 +259,12 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
cx,
REDUNDANT_PATTERN_MATCHING,
expr.span,
- &format!("redundant pattern matching, consider using `{}`", good_method),
+ &format!("redundant pattern matching, consider using `{good_method}`"),
|diag| {
diag.span_suggestion(
span,
"try this",
- format!("{}.{}", snippet(cx, result_expr.span, "_"), good_method),
+ format!("{}.{good_method}", snippet(cx, result_expr.span, "_")),
Applicability::MaybeIncorrect, // snippet
);
},
@@ -266,28 +273,58 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
}
}
+#[derive(Clone, Copy)]
+enum Item {
+ Lang(LangItem),
+ Diag(Symbol, Symbol),
+}
+
+fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expected_item: Item) -> bool {
+ let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else { return false };
+
+ match expected_item {
+ Item::Lang(expected_lang_item) => {
+ let expected_id = cx.tcx.lang_items().require(expected_lang_item).unwrap();
+ cx.tcx.parent(id) == expected_id
+ },
+ Item::Diag(expected_ty, expected_variant) => {
+ let ty = cx.typeck_results().pat_ty(pat);
+
+ if is_type_diagnostic_item(cx, ty, expected_ty) {
+ let variant = ty
+ .ty_adt_def()
+ .expect("struct pattern type is not an ADT")
+ .variant_of_res(cx.qpath_res(path, pat.hir_id));
+
+ return variant.name == expected_variant;
+ }
+
+ false
+ },
+ }
+}
+
#[expect(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],
+ expected_item_left: Item,
+ expected_item_right: Item,
should_be_left: &'a str,
should_be_right: &'a str,
) -> Option<&'a str> {
- let left_id = cx
- .typeck_results()
- .qpath_res(path_left, arms[0].pat.hir_id)
- .opt_def_id()?;
- let right_id = cx
- .typeck_results()
- .qpath_res(path_right, arms[1].pat.hir_id)
- .opt_def_id()?;
- let body_node_pair = if match_def_path(cx, left_id, expected_left) && match_def_path(cx, right_id, expected_right) {
+ let first_pat = arms[0].pat;
+ let second_pat = arms[1].pat;
+
+ let body_node_pair = if (is_pat_variant(cx, first_pat, path_left, expected_item_left))
+ && (is_pat_variant(cx, second_pat, path_right, expected_item_right))
+ {
(&arms[0].body.kind, &arms[1].body.kind)
- } else if match_def_path(cx, right_id, expected_left) && match_def_path(cx, right_id, expected_right) {
+ } else if (is_pat_variant(cx, first_pat, path_left, expected_item_right))
+ && (is_pat_variant(cx, second_pat, path_right, expected_item_left))
+ {
(&arms[1].body.kind, &arms[0].body.kind)
} else {
return None;
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index b0b15b3f5..85269e533 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -50,13 +50,13 @@ fn set_diagnostic<'tcx>(diag: &mut Diagnostic, cx: &LateContext<'tcx>, expr: &'t
let trailing_indent = " ".repeat(indent_of(cx, found.found_span).unwrap_or(0));
let replacement = if found.lint_suggestion == LintSuggestion::MoveAndDerefToCopy {
- format!("let value = *{};\n{}", original, trailing_indent)
+ format!("let value = *{original};\n{trailing_indent}")
} else if found.is_unit_return_val {
// If the return value of the expression to be moved is unit, then we don't need to
// capture the result in a temporary -- we can just replace it completely with `()`.
- format!("{};\n{}", original, trailing_indent)
+ format!("{original};\n{trailing_indent}")
} else {
- format!("let value = {};\n{}", original, trailing_indent)
+ format!("let value = {original};\n{trailing_indent}")
};
let suggestion_message = if found.lint_suggestion == LintSuggestion::MoveOnly {
@@ -291,7 +291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
self.is_chain_end = false;
match ex.kind {
- ExprKind::MethodCall(_, [ref expr, ..], _) => {
+ ExprKind::MethodCall(_, expr, ..) => {
self.visit_expr(expr);
}
ExprKind::Binary(_, left, right) => {
@@ -331,8 +331,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
ExprKind::Index(..) |
ExprKind::Ret(..) |
ExprKind::Repeat(..) |
- ExprKind::Yield(..) |
- ExprKind::MethodCall(..) => walk_expr(self, ex),
+ ExprKind::Yield(..) => walk_expr(self, ex),
ExprKind::AddrOf(_, _, _) |
ExprKind::Block(_, _) |
ExprKind::Break(_, _) |
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 92091a0c3..e5a15b2e1 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -1,14 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{expr_block, snippet};
-use clippy_utils::ty::{implements_trait, match_type, peel_mid_ty_refs};
-use clippy_utils::{
- is_lint_allowed, is_unit_expr, is_wild, paths, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs,
-};
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs};
+use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs};
use core::cmp::max;
use rustc_errors::Applicability;
use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, Pat, PatKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
+use rustc_span::sym;
use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE};
@@ -99,23 +98,21 @@ fn report_single_pattern(
let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`";
let sugg = format!(
- "if {} == {}{} {}{}",
+ "if {} == {}{} {}{els_str}",
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 {} = {} {}{}",
+ "if let {} = {} {}{els_str}",
snippet(cx, arms[0].pat.span, ".."),
snippet(cx, ex.span, ".."),
expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
- els_str,
);
(msg, sugg)
}
@@ -158,10 +155,10 @@ fn pat_in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'a>, pat: &Pat<'_>) ->
/// Returns `true` if the given type is an enum we know won't be expanded in the future
fn in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'_>) -> bool {
// list of candidate `Enum`s we know will never get any more members
- let candidates = [&paths::COW, &paths::OPTION, &paths::RESULT];
+ let candidates = [sym::Cow, sym::Option, sym::Result];
for candidate_ty in candidates {
- if match_type(cx, ty, candidate_ty) {
+ if is_type_diagnostic_item(cx, ty, candidate_ty) {
return true;
}
}
@@ -175,7 +172,7 @@ fn collect_pat_paths<'a>(acc: &mut Vec<Ty<'a>>, cx: &LateContext<'a>, pat: &Pat<
let p_ty = cx.typeck_results().pat_ty(p);
collect_pat_paths(acc, cx, p, p_ty);
}),
- PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::Unannotated, .., None) | PatKind::Path(_) => {
+ PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::NONE, .., None) | PatKind::Path(_) => {
acc.push(ty);
},
_ => {},
@@ -200,13 +197,11 @@ fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>,
// We don't actually know the position and the presence of the `..` (dotdot) operator
// in the arms, so we need to evaluate the correct offsets here in order to iterate in
// both arms at the same time.
+ let left_pos = left_pos.as_opt_usize();
+ let right_pos = right_pos.as_opt_usize();
let len = max(
- left_in.len() + {
- if left_pos.is_some() { 1 } else { 0 }
- },
- right_in.len() + {
- if right_pos.is_some() { 1 } else { 0 }
- },
+ left_in.len() + usize::from(left_pos.is_some()),
+ right_in.len() + usize::from(right_pos.is_some()),
);
let mut left_pos = left_pos.unwrap_or(usize::MAX);
let mut right_pos = right_pos.unwrap_or(usize::MAX);
diff --git a/src/tools/clippy/clippy_lints/src/matches/try_err.rs b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
index 0491a0679..c6cba81d8 100644
--- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{get_parent_expr, is_lang_ctor, match_def_path, paths};
+use clippy_utils::{get_parent_expr, is_res_lang_ctor, match_def_path, path_res, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::ResultErr;
@@ -23,14 +23,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
// val,
// };
if_chain! {
- if let ExprKind::Call(match_fun, try_args) = scrutinee.kind;
+ if let ExprKind::Call(match_fun, [try_arg, ..]) = scrutinee.kind;
if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..));
- if let Some(try_arg) = try_args.get(0);
- if let ExprKind::Call(err_fun, err_args) = try_arg.kind;
- if let Some(err_arg) = err_args.get(0);
- if let ExprKind::Path(ref err_fun_path) = err_fun.kind;
- if is_lang_ctor(cx, err_fun_path, ResultErr);
+ if let ExprKind::Call(err_fun, [err_arg, ..]) = try_arg.kind;
+ if is_res_lang_ctor(cx, path_res(cx, err_fun), ResultErr);
if let Some(return_ty) = find_return_type(cx, &expr.kind);
then {
let prefix;
@@ -63,9 +60,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
"return "
};
let suggestion = if err_ty == expr_err_ty {
- format!("{}{}{}{}", ret_prefix, prefix, origin_snippet, suffix)
+ format!("{ret_prefix}{prefix}{origin_snippet}{suffix}")
} else {
- format!("{}{}{}.into(){}", ret_prefix, prefix, origin_snippet, suffix)
+ format!("{ret_prefix}{prefix}{origin_snippet}.into(){suffix}")
};
span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index 41073d40f..0c4d9f100 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::ty::is_non_aggregate_primitive_type;
-use clippy_utils::{is_default_equivalent, is_lang_ctor, meets_msrv, msrvs};
+use clippy_utils::{is_default_equivalent, is_res_lang_ctor, meets_msrv, msrvs, path_res};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone;
@@ -102,40 +102,38 @@ impl_lint_pass!(MemReplace =>
[MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]);
fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) {
- if let ExprKind::Path(ref replacement_qpath) = src.kind {
- // Check that second argument is `Option::None`
- if is_lang_ctor(cx, replacement_qpath, OptionNone) {
- // Since this is a late pass (already type-checked),
- // and we already know that the second argument is an
- // `Option`, we do not need to check the first
- // argument's type. All that's left is to get
- // replacee's path.
- let replaced_path = match dest.kind {
- ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, replaced) => {
- if let ExprKind::Path(QPath::Resolved(None, replaced_path)) = replaced.kind {
- replaced_path
- } else {
- return;
- }
- },
- ExprKind::Path(QPath::Resolved(None, replaced_path)) => replaced_path,
- _ => return,
- };
+ // Check that second argument is `Option::None`
+ if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) {
+ // Since this is a late pass (already type-checked),
+ // and we already know that the second argument is an
+ // `Option`, we do not need to check the first
+ // argument's type. All that's left is to get
+ // replacee's path.
+ let replaced_path = match dest.kind {
+ ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, replaced) => {
+ if let ExprKind::Path(QPath::Resolved(None, replaced_path)) = replaced.kind {
+ replaced_path
+ } else {
+ return;
+ }
+ },
+ ExprKind::Path(QPath::Resolved(None, replaced_path)) => replaced_path,
+ _ => return,
+ };
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- MEM_REPLACE_OPTION_WITH_NONE,
- expr_span,
- "replacing an `Option` with `None`",
- "consider `Option::take()` instead",
- format!(
- "{}.take()",
- snippet_with_applicability(cx, replaced_path.span, "", &mut applicability)
- ),
- applicability,
- );
- }
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ MEM_REPLACE_OPTION_WITH_NONE,
+ expr_span,
+ "replacing an `Option` with `None`",
+ "consider `Option::take()` instead",
+ format!(
+ "{}.take()",
+ snippet_with_applicability(cx, replaced_path.span, "", &mut applicability)
+ ),
+ applicability,
+ );
}
}
@@ -163,8 +161,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'
}
if_chain! {
- if let ExprKind::Call(repl_func, repl_args) = src.kind;
- if repl_args.is_empty();
+ if let ExprKind::Call(repl_func, []) = src.kind;
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();
then {
@@ -204,10 +201,8 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<
return;
}
// disable lint for Option since it is covered in another lint
- if let ExprKind::Path(q) = &src.kind {
- if is_lang_ctor(cx, q, OptionNone) {
- return;
- }
+ if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) {
+ return;
}
if is_default_equivalent(cx, src) && !in_external_macro(cx.tcx.sess, expr_span) {
span_lint_and_then(
@@ -246,11 +241,10 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
// Check that `expr` is a call to `mem::replace()`
- if let ExprKind::Call(func, func_args) = expr.kind;
+ if let ExprKind::Call(func, [dest, src]) = expr.kind;
if let ExprKind::Path(ref func_qpath) = func.kind;
if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
if cx.tcx.is_diagnostic_item(sym::mem_replace, def_id);
- if let [dest, src] = func_args;
then {
check_replace_option_with_none(cx, src, dest, expr.span);
check_replace_with_uninit(cx, src, dest, expr.span);
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index 2f117e4dc..cc26b0f7f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -85,7 +85,7 @@ pub(crate) trait BindInsteadOfMap {
let closure_args_snip = snippet(cx, closure_args_span, "..");
let option_snip = snippet(cx, recv.span, "..");
- let note = format!("{}.{}({} {})", option_snip, Self::GOOD_METHOD_NAME, closure_args_snip, some_inner_snip);
+ let note = format!("{option_snip}.{}({closure_args_snip} {some_inner_snip})", Self::GOOD_METHOD_NAME);
span_lint_and_sugg(
cx,
BIND_INSTEAD_OF_MAP,
@@ -152,7 +152,7 @@ pub(crate) trait BindInsteadOfMap {
match arg.kind {
hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) => {
let closure_body = cx.tcx.hir().body(body);
- let closure_expr = peel_blocks(&closure_body.value);
+ let closure_expr = peel_blocks(closure_body.value);
if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, fn_decl_span) {
true
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
new file mode 100644
index 000000000..fef90f6eb
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
@@ -0,0 +1,70 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::match_type;
+use clippy_utils::visitors::is_local_used;
+use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, UintTy};
+use rustc_span::sym;
+
+use super::NAIVE_BYTECOUNT;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ filter_recv: &'tcx Expr<'_>,
+ filter_arg: &'tcx Expr<'_>,
+) {
+ if_chain! {
+ if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind;
+ let body = cx.tcx.hir().body(body);
+ if let [param] = body.params;
+ if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind;
+ if let ExprKind::Binary(ref op, l, r) = body.value.kind;
+ if op.node == BinOpKind::Eq;
+ if match_type(cx,
+ cx.typeck_results().expr_ty(filter_recv).peel_refs(),
+ &paths::SLICE_ITER);
+ let operand_is_arg = |expr| {
+ let expr = peel_ref_operators(cx, peel_blocks(expr));
+ path_to_local_id(expr, arg_id)
+ };
+ let needle = if operand_is_arg(l) {
+ r
+ } else if operand_is_arg(r) {
+ l
+ } else {
+ return;
+ };
+ if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
+ if !is_local_used(cx, needle, arg_id);
+ then {
+ let haystack = if let ExprKind::MethodCall(path, receiver, [], _) =
+ filter_recv.kind {
+ let p = path.ident.name;
+ if p == sym::iter || p == sym!(iter_mut) {
+ receiver
+ } else {
+ filter_recv
+ }
+ } else {
+ filter_recv
+ };
+ let mut applicability = Applicability::MaybeIncorrect;
+ span_lint_and_sugg(
+ cx,
+ NAIVE_BYTECOUNT,
+ expr.span,
+ "you appear to be counting bytes the naive way",
+ "consider using the bytecount crate",
+ format!("bytecount::count({}, {})",
+ snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
+ snippet_with_applicability(cx, needle.span, "..", &mut applicability)),
+ applicability,
+ );
+ }
+ };
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
new file mode 100644
index 000000000..fcfc25b52
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
@@ -0,0 +1,37 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::is_type_diagnostic_item;
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::BYTES_COUNT_TO_LEN;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx hir::Expr<'_>,
+ count_recv: &'tcx hir::Expr<'_>,
+ bytes_recv: &'tcx hir::Expr<'_>,
+) {
+ if_chain! {
+ if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id);
+ if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id);
+ if cx.tcx.type_of(impl_id).is_str();
+ let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs();
+ if ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String);
+ then {
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ BYTES_COUNT_TO_LEN,
+ expr.span,
+ "using long and hard to read `.bytes().count()`",
+ "consider calling `.len()` instead",
+ format!("{}.len()", snippet_with_applicability(cx, bytes_recv.span, "..", &mut applicability)),
+ applicability
+ );
+ }
+ };
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
index 44857d61f..2e96346be 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
@@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
cx,
BYTES_NTH,
expr.span,
- &format!("called `.bytes().nth()` on a `{}`", caller_type),
+ &format!("called `.bytes().nth()` on a `{caller_type}`"),
"try",
format!(
"{}.as_bytes().get({})",
diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
new file mode 100644
index 000000000..b3c2c7c9a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
@@ -0,0 +1,41 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::is_type_diagnostic_item;
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::{source_map::Spanned, symbol::sym, Span};
+
+use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ call_span: Span,
+ recv: &'tcx Expr<'_>,
+ arg: &'tcx Expr<'_>,
+) {
+ if_chain! {
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+ if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
+ if cx.tcx.type_of(impl_id).is_str();
+ if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind;
+ if (2..=6).contains(&ext_literal.as_str().len());
+ let ext_str = ext_literal.as_str();
+ if ext_str.starts_with('.');
+ if ext_str.chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit())
+ || ext_str.chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit());
+ let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs();
+ if recv_ty.is_str() || is_type_diagnostic_item(cx, recv_ty, sym::String);
+ then {
+ span_lint_and_help(
+ cx,
+ CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+ call_span,
+ "case-sensitive file extension comparison",
+ None,
+ "consider using a case-insensitive comparison instead",
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
index f7b79f083..56b7fbb9d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
@@ -23,7 +23,7 @@ pub(super) fn check(
if Some(id) == cx.tcx.lang_items().option_some_variant();
then {
let mut applicability = Applicability::MachineApplicable;
- let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
+ let self_ty = cx.typeck_results().expr_ty_adjusted(args[0].0).peel_refs();
if *self_ty.kind() != ty::Str {
return false;
@@ -33,12 +33,11 @@ pub(super) fn check(
cx,
lint,
info.expr.span,
- &format!("you should use the `{}` method", suggest),
+ &format!("you should use the `{suggest}` method"),
"like this",
- format!("{}{}.{}({})",
+ format!("{}{}.{suggest}({})",
if info.eq { "" } else { "!" },
- snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
- suggest,
+ snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)),
applicability,
);
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
index a7c0e4392..7e8087606 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
@@ -26,12 +26,11 @@ pub(super) fn check<'tcx>(
cx,
lint,
info.expr.span,
- &format!("you should use the `{}` method", suggest),
+ &format!("you should use the `{suggest}` method"),
"like this",
- format!("{}{}.{}('{}')",
+ format!("{}{}.{suggest}('{}')",
if info.eq { "" } else { "!" },
- snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
- suggest,
+ snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
c.escape_default()),
applicability,
);
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
index 0b38a0720..7c7938dd2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
@@ -4,7 +4,7 @@ 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_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, adjustment::Adjust};
use rustc_span::symbol::{sym, Symbol};
@@ -14,10 +14,17 @@ 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,
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ method_name: Symbol,
+ receiver: &Expr<'_>,
+ args: &[Expr<'_>],
+) {
+ let arg = if method_name == sym::clone && args.is_empty() {
+ receiver
+ } else {
+ return;
};
if cx
.typeck_results()
@@ -42,8 +49,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
expr.span,
&format!(
"using `clone` on a double-reference; \
- this will copy the reference of type `{}` instead of cloning the inner type",
- ty
+ this will copy the reference of type `{ty}` instead of cloning the inner type"
),
|diag| {
if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
@@ -55,11 +61,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
}
let refs = "&".repeat(n + 1);
let derefs = "*".repeat(n);
- let explicit = format!("<{}{}>::clone({})", refs, ty, snip);
+ let explicit = format!("<{refs}{ty}>::clone({snip})");
diag.span_suggestion(
expr.span,
"try dereferencing it",
- format!("{}({}{}).clone()", refs, derefs, snip.deref()),
+ format!("{refs}({derefs}{}).clone()", snip.deref()),
Applicability::MaybeIncorrect,
);
diag.span_suggestion(
@@ -81,24 +87,24 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
// &*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, ..], _)
+ 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,
+ // ? is a Call, makes sure not to rec *x?, but rather (*x)?
+ ExprKind::Call(hir_callee, _) => matches!(
+ hir_callee.kind,
+ ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _))
+ ),
+ 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, ..)
- ) =>
- {
+ Some(Node::Local(l)) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => {
return;
},
_ => false,
@@ -114,16 +120,16 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
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))
+ ("try dereferencing it", format!("({}{snip})", "*".repeat(deref_count)))
} else {
- ("try dereferencing it", format!("{}{}", "*".repeat(deref_count), snip))
+ ("try dereferencing it", format!("{}{snip}", "*".repeat(deref_count)))
};
span_lint_and_sugg(
cx,
CLONE_ON_COPY,
expr.span,
- &format!("using `clone` on type `{}` which implements the `Copy` trait", ty),
+ &format!("using `clone` on type `{ty}` which implements the `Copy` trait"),
help,
sugg,
app,
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
index 6417bc813..355f53532 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
@@ -10,12 +10,17 @@ use rustc_span::symbol::{sym, Symbol};
use super::CLONE_ON_REF_PTR;
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
- if !(args.len() == 1 && method_name == sym::clone) {
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ expr: &hir::Expr<'_>,
+ method_name: Symbol,
+ receiver: &hir::Expr<'_>,
+ args: &[hir::Expr<'_>],
+) {
+ if !(args.is_empty() && method_name == sym::clone) {
return;
}
- let arg = &args[0];
- let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs();
+ let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
if let ty::Adt(_, subst) = obj_ty.kind() {
let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
@@ -28,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Sym
return;
};
- let snippet = snippet_with_macro_callsite(cx, arg.span, "..");
+ let snippet = snippet_with_macro_callsite(cx, receiver.span, "..");
span_lint_and_sugg(
cx,
@@ -36,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Sym
expr.span,
"using `.clone()` on a ref-counted pointer",
"try this",
- format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet),
+ format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)),
Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak
);
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
new file mode 100644
index 000000000..501646863
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
@@ -0,0 +1,96 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{eq_expr_value, get_parent_expr};
+use core::ops::ControlFlow;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use std::collections::VecDeque;
+
+use super::method_call;
+use super::COLLAPSIBLE_STR_REPLACE;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx hir::Expr<'tcx>,
+ from: &'tcx hir::Expr<'tcx>,
+ to: &'tcx hir::Expr<'tcx>,
+) {
+ let replace_methods = collect_replace_calls(cx, expr, to);
+ if replace_methods.methods.len() > 1 {
+ let from_kind = cx.typeck_results().expr_ty(from).peel_refs().kind();
+ // If the parent node's `to` argument is the same as the `to` argument
+ // of the last replace call in the current chain, don't lint as it was already linted
+ if let Some(parent) = get_parent_expr(cx, expr)
+ && let Some(("replace", _, [current_from, current_to], _)) = method_call(parent)
+ && eq_expr_value(cx, to, current_to)
+ && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
+ {
+ return;
+ }
+
+ check_consecutive_replace_calls(cx, expr, &replace_methods, to);
+ }
+}
+
+struct ReplaceMethods<'tcx> {
+ methods: VecDeque<&'tcx hir::Expr<'tcx>>,
+ from_args: VecDeque<&'tcx hir::Expr<'tcx>>,
+}
+
+fn collect_replace_calls<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx hir::Expr<'tcx>,
+ to_arg: &'tcx hir::Expr<'tcx>,
+) -> ReplaceMethods<'tcx> {
+ let mut methods = VecDeque::new();
+ let mut from_args = VecDeque::new();
+
+ let _: Option<()> = for_each_expr(expr, |e| {
+ if let Some(("replace", _, [from, to], _)) = method_call(e) {
+ if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
+ methods.push_front(e);
+ from_args.push_front(from);
+ ControlFlow::Continue(())
+ } else {
+ ControlFlow::BREAK
+ }
+ } else {
+ ControlFlow::Continue(())
+ }
+ });
+
+ ReplaceMethods { methods, from_args }
+}
+
+/// Check a chain of `str::replace` calls for `collapsible_str_replace` lint.
+fn check_consecutive_replace_calls<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx hir::Expr<'tcx>,
+ replace_methods: &ReplaceMethods<'tcx>,
+ to_arg: &'tcx hir::Expr<'tcx>,
+) {
+ let from_args = &replace_methods.from_args;
+ let from_arg_reprs: Vec<String> = from_args
+ .iter()
+ .map(|from_arg| snippet(cx, from_arg.span, "..").to_string())
+ .collect();
+ let app = Applicability::MachineApplicable;
+ let earliest_replace_call = replace_methods.methods.front().unwrap();
+ if let Some((_, _, [..], span_lo)) = method_call(earliest_replace_call) {
+ span_lint_and_sugg(
+ cx,
+ COLLAPSIBLE_STR_REPLACE,
+ expr.span.with_lo(span_lo.lo()),
+ "used consecutive `str::replace` call",
+ "replace with",
+ format!(
+ "replace([{}], {})",
+ from_arg_reprs.join(", "),
+ snippet(cx, to_arg.span, ".."),
+ ),
+ app,
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
index 570a1b873..720d9a68c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
@@ -1,6 +1,6 @@
use super::ERR_EXPECT;
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::implements_trait;
+use clippy_utils::ty::has_debug_impl;
use clippy_utils::{meets_msrv, msrvs, ty::is_type_diagnostic_item};
use rustc_errors::Applicability;
use rustc_lint::LateContext;
@@ -28,7 +28,7 @@ pub(super) fn check(
// Tests if the T type in a `Result<T, E>` is not None
if let Some(data_type) = get_data_type(cx, result_type);
// Tests if the T type in a `Result<T, E>` implements debug
- if has_debug_impl(data_type, cx);
+ if has_debug_impl(cx, data_type);
then {
span_lint_and_sugg(
@@ -51,10 +51,3 @@ fn get_data_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
_ => None,
}
}
-
-/// Given a type, very if the Debug trait has been impl'd
-fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
- cx.tcx
- .get_diagnostic_item(sym::Debug)
- .map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
-}
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index 6f2307d8f..d0cf411df 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -19,6 +19,7 @@ pub(super) fn check<'tcx>(
expr: &hir::Expr<'_>,
method_span: Span,
name: &str,
+ receiver: &'tcx hir::Expr<'tcx>,
args: &'tcx [hir::Expr<'tcx>],
) {
// Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
@@ -28,16 +29,13 @@ pub(super) fn check<'tcx>(
loop {
arg_root = match &arg_root.kind {
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
- hir::ExprKind::MethodCall(method_name, call_args, _) => {
- if call_args.len() == 1
- && (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref)
- && {
- let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
- let base_type = arg_type.peel_refs();
- *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String)
- }
- {
- &call_args[0]
+ hir::ExprKind::MethodCall(method_name, receiver, [], ..) => {
+ if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && {
+ let arg_type = cx.typeck_results().expr_ty(receiver);
+ let base_type = arg_type.peel_refs();
+ *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String)
+ } {
+ receiver
} else {
break;
}
@@ -114,11 +112,11 @@ pub(super) fn check<'tcx>(
}
}
- if args.len() != 2 || name != "expect" || !is_call(&args[1].kind) {
+ if args.len() != 1 || name != "expect" || !is_call(&args[0].kind) {
return;
}
- let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]);
+ let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver);
let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) {
"||"
} else if is_type_diagnostic_item(cx, receiver_type, sym::Result) {
@@ -127,7 +125,7 @@ pub(super) fn check<'tcx>(
return;
};
- let arg_root = get_arg_root(cx, &args[1]);
+ let arg_root = get_arg_root(cx, &args[0]);
let span_replace_word = method_span.with_hi(expr.span.hi());
@@ -145,9 +143,9 @@ pub(super) fn check<'tcx>(
cx,
EXPECT_FUN_CALL,
span_replace_word,
- &format!("use of `{}` followed by a function call", name),
+ &format!("use of `{name}` followed by a function call"),
"try this",
- format!("unwrap_or_else({} panic!({}))", closure_args, sugg),
+ format!("unwrap_or_else({closure_args} panic!({sugg}))"),
applicability,
);
return;
@@ -162,12 +160,9 @@ pub(super) fn check<'tcx>(
cx,
EXPECT_FUN_CALL,
span_replace_word,
- &format!("use of `{}` followed by a function call", name),
+ &format!("use of `{name}` followed by a function call"),
"try this",
- format!(
- "unwrap_or_else({} {{ panic!(\"{{}}\", {}) }})",
- closure_args, arg_root_snippet
- ),
+ format!("unwrap_or_else({closure_args} {{ panic!(\"{{}}\", {arg_root_snippet}) }})"),
applicability,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
index fbc3348f1..d59fefa1d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
@@ -7,30 +7,38 @@ use rustc_span::sym;
use super::EXPECT_USED;
-/// lint use of `expect()` for `Option`s and `Result`s
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_expect_in_tests: bool) {
+/// lint use of `expect()` or `expect_err` for `Result` and `expect()` for `Option`.
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ expr: &hir::Expr<'_>,
+ recv: &hir::Expr<'_>,
+ is_err: bool,
+ allow_expect_in_tests: bool,
+) {
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
- let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
- Some((EXPECT_USED, "an Option", "None"))
+ let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
+ Some((EXPECT_USED, "an Option", "None", ""))
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
- Some((EXPECT_USED, "a Result", "Err"))
+ Some((EXPECT_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an "))
} else {
None
};
+ let method = if is_err { "expect_err" } else { "expect" };
+
if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
return;
}
- if let Some((lint, kind, none_value)) = mess {
+ if let Some((lint, kind, none_value, none_prefix)) = mess {
span_lint_and_help(
cx,
lint,
expr.span,
- &format!("used `expect()` on `{}` value", kind,),
+ &format!("used `{method}()` on `{kind}` value"),
None,
- &format!("if this value is an `{}`, it will panic", none_value,),
+ &format!("if this value is {none_prefix}`{none_value}`, it will panic"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
index a15fe6094..37b284635 100644
--- a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
@@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
if_chain! {
if is_type_diagnostic_item(cx, ty, sym::Vec);
//check source object
- if let ExprKind::MethodCall(src_method, [drain_vec, drain_arg], _) = &arg.kind;
+ if let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind;
if src_method.ident.as_str() == "drain";
let src_ty = cx.typeck_results().expr_ty(drain_vec);
//check if actual src type is mutable for code suggestion
diff --git a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
index 7b2967feb..3fef53739 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
@@ -1,17 +1,18 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::match_type;
-use clippy_utils::{get_parent_expr, paths};
+use clippy_utils::get_parent_expr;
+use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::source_map::Span;
+use rustc_span::sym;
use super::FILETYPE_IS_FILE;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
let ty = cx.typeck_results().expr_ty(recv);
- if !match_type(cx, ty, &paths::FILE_TYPE) {
+ if !is_type_diagnostic_item(cx, ty, sym::FileType) {
return;
}
@@ -35,7 +36,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
span = expr.span;
}
}
- let lint_msg = format!("`{}FileType::is_file()` only {} regular files", lint_unary, verb);
- let help_msg = format!("use `{}FileType::is_dir()` instead", help_unary);
+ let lint_msg = format!("`{lint_unary}FileType::is_file()` only {verb} regular files");
+ let help_msg = format!("use `{help_unary}FileType::is_dir()` instead");
span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg);
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 692e22a7c..9719b2f1c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -25,14 +25,14 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
},
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
let body = cx.tcx.hir().body(body);
- let closure_expr = peel_blocks(&body.value);
+ let closure_expr = peel_blocks(body.value);
let arg_id = body.params[0].pat.hir_id;
match closure_expr.kind {
- hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, args, _) => {
+ hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
if_chain! {
if ident.name == method_name;
- if let hir::ExprKind::Path(path) = &args[0].kind;
- if let Res::Local(ref local) = cx.qpath_res(path, args[0].hir_id);
+ if let hir::ExprKind::Path(path) = &receiver.kind;
+ if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id);
then {
return arg_id == *local
}
@@ -106,7 +106,7 @@ pub(super) fn check<'tcx>(
};
// closure ends with is_some() or is_ok()
if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
- if let ExprKind::MethodCall(path, [filter_arg], _) = filter_body.value.kind;
+ if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
Some(false)
@@ -123,13 +123,13 @@ pub(super) fn check<'tcx>(
if let [map_param] = map_body.params;
if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
// closure ends with expect() or unwrap()
- if let ExprKind::MethodCall(seg, [map_arg, ..], _) = map_body.value.kind;
+ if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
// .filter(..).map(|y| f(y).copied().unwrap())
// ~~~~
let map_arg_peeled = match map_arg.kind {
- ExprKind::MethodCall(method, [original_arg], _) if acceptable_methods(method) => {
+ ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
original_arg
},
_ => map_arg,
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
index 38ec4d8e3..ddf8a1f09 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
@@ -32,7 +32,7 @@ pub(super) fn check<'tcx>(
expr.span,
msg,
"try this",
- format!("{}.find_map({})", iter_snippet, filter_snippet),
+ format!("{iter_snippet}.find_map({filter_snippet})"),
Applicability::MachineApplicable,
);
} else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
index bcf8d93b6..edcec0fc1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
@@ -32,7 +32,7 @@ pub(super) fn check<'tcx>(
expr.span,
msg,
"try this",
- format!("{}.find({})", iter_snippet, filter_snippet),
+ format!("{iter_snippet}.find({filter_snippet})"),
Applicability::MachineApplicable,
);
} else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
index 6436e28a6..66dfce368 100644
--- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
@@ -23,7 +23,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp
// `expr` implements `FromIterator` trait
let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par();
let turbofish = extract_turbofish(cx, expr, ty);
- let sugg = format!("{}.collect::<{}>()", iter_expr, turbofish);
+ let sugg = format!("{iter_expr}.collect::<{turbofish}>()");
span_lint_and_sugg(
cx,
FROM_ITER_INSTEAD_OF_COLLECT,
@@ -63,7 +63,7 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) ->
if e == type_specifier { None } else { Some((*e).to_string()) }
}).collect::<Vec<_>>();
// join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
- format!("{}{}", without_ts.join("::"), type_specifier)
+ format!("{}{type_specifier}", without_ts.join("::"))
} else {
// type is not explicitly specified so wildcards are needed
// i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
@@ -72,7 +72,7 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) ->
let end = ty_str.find('>').unwrap_or(ty_str.len());
let nb_wildcard = ty_str[start..end].split(',').count();
let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
- format!("{}<{}>", elements.join("::"), wildcards)
+ format!("{}<{wildcards}>", elements.join("::"))
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
new file mode 100644
index 000000000..cb17af608
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
@@ -0,0 +1,39 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_slice_of_primitives;
+use clippy_utils::source::snippet_with_applicability;
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_span::source_map::Spanned;
+
+use super::GET_FIRST;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx hir::Expr<'_>,
+ recv: &'tcx hir::Expr<'_>,
+ arg: &'tcx hir::Expr<'_>,
+) {
+ if_chain! {
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+ if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
+ if cx.tcx.type_of(impl_id).is_slice();
+ if let Some(_) = is_slice_of_primitives(cx, recv);
+ if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind;
+ then {
+ let mut app = Applicability::MachineApplicable;
+ let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app);
+ span_lint_and_sugg(
+ cx,
+ GET_FIRST,
+ expr.span,
+ &format!("accessing first element with `{slice_name}.get(0)`"),
+ "try",
+ format!("{slice_name}.first()"),
+ app,
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs
index 23368238e..3bdc154df 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::SpanlessEq;
-use rustc_ast::LitKind;
+use clippy_utils::{is_integer_literal, SpanlessEq};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
@@ -22,12 +21,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
) = arg.kind
// LHS of subtraction is "x.len()"
- && let ExprKind::MethodCall(lhs_path, [lhs_recv], _) = &lhs.kind
+ && let ExprKind::MethodCall(lhs_path, lhs_recv, [], _) = &lhs.kind
&& lhs_path.ident.name == sym::len
// RHS of subtraction is 1
- && let ExprKind::Lit(rhs_lit) = &rhs.kind
- && let LitKind::Int(1, ..) = rhs_lit.node
+ && is_integer_literal(rhs, 1)
// check that recv == lhs_recv `recv.get(lhs_recv.len() - 1)`
&& SpanlessEq::new(cx).eq_expr(recv, lhs_recv)
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
index 18e08d6ee..ffc3a4d78 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
@@ -71,16 +71,11 @@ pub(super) fn check<'tcx>(
cx,
GET_UNWRAP,
span,
- &format!(
- "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise",
- mut_str, caller_type
- ),
+ &format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"),
"try this",
format!(
- "{}{}[{}]",
- borrow_str,
- snippet_with_applicability(cx, recv.span, "..", &mut applicability),
- get_args_str
+ "{borrow_str}{}[{get_args_str}]",
+ snippet_with_applicability(cx, recv.span, "..", &mut applicability)
),
applicability,
);
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index 9651a52be..429cdc191 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -26,12 +26,12 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
cx,
IMPLICIT_CLONE,
expr.span,
- &format!("implicitly cloning a `{}` by calling `{}` on its dereferenced type", ty_name, method_name),
+ &format!("implicitly cloning a `{ty_name}` by calling `{method_name}` on its dereferenced type"),
"consider using",
if ref_count > 1 {
- format!("({}{}).clone()", "*".repeat(ref_count - 1), recv_snip)
+ format!("({}{recv_snip}).clone()", "*".repeat(ref_count - 1))
} else {
- format!("{}.clone()", recv_snip)
+ format!("{recv_snip}.clone()")
},
app,
);
diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
index f52170df6..ede3b8bb7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
@@ -12,13 +12,19 @@ use rustc_span::symbol::{sym, Symbol};
use super::INEFFICIENT_TO_STRING;
/// Checks for the `INEFFICIENT_TO_STRING` lint
-pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
+pub fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &hir::Expr<'_>,
+ method_name: Symbol,
+ receiver: &hir::Expr<'_>,
+ args: &[hir::Expr<'_>],
+) {
if_chain! {
- if args.len() == 1 && method_name == sym::to_string;
+ if args.is_empty() && method_name == sym::to_string;
if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id);
- let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
+ let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver);
let self_ty = substs.type_at(0);
let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty);
if deref_count >= 1;
@@ -28,18 +34,17 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
cx,
INEFFICIENT_TO_STRING,
expr.span,
- &format!("calling `to_string` on `{}`", arg_ty),
+ &format!("calling `to_string` on `{arg_ty}`"),
|diag| {
diag.help(&format!(
- "`{}` implements `ToString` through a slower blanket impl, but `{}` has a fast specialization of `ToString`",
- self_ty, deref_self_ty
+ "`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`"
));
let mut applicability = Applicability::MachineApplicable;
- let arg_snippet = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
+ let arg_snippet = snippet_with_applicability(cx, receiver.span, "..", &mut applicability);
diag.span_suggestion(
expr.span,
"try dereferencing the receiver",
- format!("({}{}).to_string()", "*".repeat(deref_count), arg_snippet),
+ format!("({}{arg_snippet}).to_string()", "*".repeat(deref_count)),
applicability,
);
},
@@ -60,7 +65,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
}
if let ty::Adt(adt, substs) = ty.kind() {
- match_def_path(cx, adt.did(), &paths::COW) && substs.type_at(1).is_str()
+ cx.tcx.is_diagnostic_item(sym::Cow, adt.did()) && substs.type_at(1).is_str()
} else {
false
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
index da13b4ba3..8adf9e370 100644
--- a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
@@ -16,9 +16,9 @@ pub(super) fn check(
expr: &hir::Expr<'_>,
method_span: Span,
method_name: Symbol,
- args: &[hir::Expr<'_>],
+ receiver: &hir::Expr<'_>,
) {
- let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
+ let self_ty = cx.typeck_results().expr_ty_adjusted(receiver);
if_chain! {
if let ty::Ref(..) = self_ty.kind();
if method_name == sym::into_iter;
@@ -30,8 +30,7 @@ pub(super) fn check(
INTO_ITER_ON_REF,
method_span,
&format!(
- "this `.into_iter()` call is equivalent to `.{}()` and will not consume the `{}`",
- method_name, kind,
+ "this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`",
),
"call directly",
method_name.to_string(),
@@ -43,9 +42,8 @@ pub(super) fn check(
fn ty_has_iter_method(cx: &LateContext<'_>, self_ref_ty: Ty<'_>) -> Option<(Symbol, &'static str)> {
has_iter_method(cx, self_ref_ty).map(|ty_name| {
- let mutbl = match self_ref_ty.kind() {
- ty::Ref(_, _, mutbl) => mutbl,
- _ => unreachable!(),
+ let ty::Ref(_, _, mutbl) = self_ref_ty.kind() else {
+ unreachable!()
};
let method_name = match mutbl {
hir::Mutability::Not => "iter",
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
index aa176dcc8..304024e80 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
@@ -37,12 +37,11 @@ pub(super) fn check<'tcx>(
cx,
IS_DIGIT_ASCII_RADIX,
expr.span,
- &format!("use of `char::is_digit` with literal radix of {}", num),
+ &format!("use of `char::is_digit` with literal radix of {num}"),
"try",
format!(
- "{}.{}()",
- snippet_with_applicability(cx, self_arg.span, "..", &mut applicability),
- replacement
+ "{}.{replacement}()",
+ snippet_with_applicability(cx, self_arg.span, "..", &mut applicability)
),
applicability,
);
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
index 30d56113c..bde6f92b0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
@@ -20,8 +20,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir:
cx,
ITER_CLONED_COLLECT,
to_replace,
- &format!("called `iter().{}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
- more readable", method_name),
+ &format!("called `iter().{method_name}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
+ more readable"),
"try",
".to_vec()".to_string(),
Applicability::MachineApplicable,
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
index 052be3d8e..bcddc7c78 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
@@ -37,7 +37,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
cx,
ITER_COUNT,
expr.span,
- &format!("called `.{}().count()` on a `{}`", iter_method, caller_type),
+ &format!("called `.{iter_method}().count()` on a `{caller_type}`"),
"try",
format!(
"{}.len()",
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
new file mode 100644
index 000000000..2244ebfb1
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -0,0 +1,87 @@
+#![allow(unused_imports)]
+
+use super::ITER_KV_MAP;
+use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::source::{snippet, snippet_with_applicability};
+use clippy_utils::sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::is_local_used;
+use rustc_hir::{BindingAnnotation, Body, BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::ty;
+use rustc_span::sym;
+use rustc_span::Span;
+
+/// lint use of:
+/// - `hashmap.iter().map(|(_, v)| v)`
+/// - `hashmap.into_iter().map(|(_, v)| v)`
+/// on `HashMaps` and `BTreeMaps` in std
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ map_type: &'tcx str, // iter / into_iter
+ expr: &'tcx Expr<'tcx>, // .iter().map(|(_, v_| v))
+ recv: &'tcx Expr<'tcx>, // hashmap
+ m_arg: &'tcx Expr<'tcx>, // |(_, v)| v
+) {
+ if_chain! {
+ if !expr.span.from_expansion();
+ if let ExprKind::Closure(c) = m_arg.kind;
+ if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body);
+ if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind;
+
+ let (replacement_kind, binded_ident) = match (&key_pat.kind, &val_pat.kind) {
+ (key, PatKind::Binding(_, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", value),
+ (PatKind::Binding(_, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", key),
+ _ => return,
+ };
+
+ let ty = cx.typeck_results().expr_ty(recv);
+ if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap);
+
+ then {
+ let mut applicability = rustc_errors::Applicability::MachineApplicable;
+ let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability);
+ let into_prefix = if map_type == "into_iter" {"into_"} else {""};
+
+ if_chain! {
+ if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind;
+ if let [local_ident] = path.segments;
+ if local_ident.ident.as_str() == binded_ident.as_str();
+
+ then {
+ span_lint_and_sugg(
+ cx,
+ ITER_KV_MAP,
+ expr.span,
+ &format!("iterating on a map's {replacement_kind}s"),
+ "try",
+ format!("{recv_snippet}.{into_prefix}{replacement_kind}s()"),
+ applicability,
+ );
+ } else {
+ span_lint_and_sugg(
+ cx,
+ ITER_KV_MAP,
+ expr.span,
+ &format!("iterating on a map's {replacement_kind}s"),
+ "try",
+ format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{binded_ident}| {})",
+ snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)),
+ applicability,
+ );
+ }
+ }
+ }
+ }
+}
+
+/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_`
+/// that is not locally used.
+fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool {
+ match *pat {
+ PatKind::Wild => true,
+ PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id),
+ _ => false,
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
index b8d1dabe0..83c1bf203 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
@@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
let suggest = if start_idx == 0 {
format!("{}.first()", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability))
} else {
- format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx)
+ format!("{}.get({start_idx})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability))
};
span_lint_and_sugg(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
index 80ca4c942..ceee12784 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
@@ -32,8 +32,8 @@ pub(super) fn check<'tcx>(
cx,
ITER_NTH,
expr.span,
- &format!("called `.iter{0}().nth()` on a {1}", mut_str, caller_type),
+ &format!("called `.iter{mut_str}().nth()` on a {caller_type}"),
None,
- &format!("calling `.get{}()` is both faster and more readable", mut_str),
+ &format!("calling `.get{mut_str}()` is both faster and more readable"),
);
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
new file mode 100644
index 000000000..4f73b3ec4
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
@@ -0,0 +1,92 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::{get_expr_use_or_unification_node, is_no_std_crate, is_res_lang_ctor, path_res};
+
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::{OptionNone, OptionSome};
+use rustc_hir::{Expr, ExprKind, Node};
+use rustc_lint::LateContext;
+
+use super::{ITER_ON_EMPTY_COLLECTIONS, ITER_ON_SINGLE_ITEMS};
+
+enum IterType {
+ Iter,
+ IterMut,
+ IntoIter,
+}
+
+impl IterType {
+ fn ref_prefix(&self) -> &'static str {
+ match self {
+ Self::Iter => "&",
+ Self::IterMut => "&mut ",
+ Self::IntoIter => "",
+ }
+ }
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) {
+ let item = match recv.kind {
+ ExprKind::Array([]) => None,
+ ExprKind::Array([e]) => Some(e),
+ ExprKind::Path(ref p) if is_res_lang_ctor(cx, cx.qpath_res(p, recv.hir_id), OptionNone) => None,
+ ExprKind::Call(f, [arg]) if is_res_lang_ctor(cx, path_res(cx, f), OptionSome) => Some(arg),
+ _ => return,
+ };
+ let iter_type = match method_name {
+ "iter" => IterType::Iter,
+ "iter_mut" => IterType::IterMut,
+ "into_iter" => IterType::IntoIter,
+ _ => return,
+ };
+
+ let is_unified = match get_expr_use_or_unification_node(cx.tcx, expr) {
+ Some((Node::Expr(parent), child_id)) => match parent.kind {
+ ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id == child_id => false,
+ ExprKind::If(_, _, _)
+ | ExprKind::Match(_, _, _)
+ | ExprKind::Closure(_)
+ | ExprKind::Ret(_)
+ | ExprKind::Break(_, _) => true,
+ _ => false,
+ },
+ Some((Node::Stmt(_) | Node::Local(_), _)) => false,
+ _ => true,
+ };
+
+ if is_unified {
+ return;
+ }
+
+ if let Some(i) = item {
+ let sugg = format!(
+ "{}::iter::once({}{})",
+ if is_no_std_crate(cx) { "core" } else { "std" },
+ iter_type.ref_prefix(),
+ snippet(cx, i.span, "...")
+ );
+ span_lint_and_sugg(
+ cx,
+ ITER_ON_SINGLE_ITEMS,
+ expr.span,
+ &format!("`{method_name}` call on a collection with only one item"),
+ "try",
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ span_lint_and_sugg(
+ cx,
+ ITER_ON_EMPTY_COLLECTIONS,
+ expr.span,
+ &format!("`{method_name}` call on an empty collection"),
+ "try",
+ if is_no_std_crate(cx) {
+ "core::iter::empty()".to_string()
+ } else {
+ "std::iter::empty()".to_string()
+ },
+ Applicability::MaybeIncorrect,
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
index 43e9451f7..beb772100 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
@@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
if let Some(id) = path_to_local(recv);
if let Node::Pat(pat) = cx.tcx.hir().get(id);
if let PatKind::Binding(ann, _, _, _) = pat.kind;
- if ann != BindingAnnotation::Mutable;
+ if ann != BindingAnnotation::MUT;
then {
application = Applicability::Unspecified;
diag.span_help(
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs
index 152072e09..3da230e12 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs
@@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span
cx,
ITER_WITH_DRAIN,
span.with_hi(expr.span.hi()),
- &format!("`drain(..)` used on a `{}`", ty_name),
+ &format!("`drain(..)` used on a `{ty_name}`"),
"try this",
"into_iter()".to_string(),
Applicability::MaybeIncorrect,
@@ -35,7 +35,7 @@ fn is_full_range(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -
&& range.end.map_or(true, |e| {
if range.limits == RangeLimits::HalfOpen
&& let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind
- && let ExprKind::MethodCall(name, [self_arg], _) = e.kind
+ && let ExprKind::MethodCall(name, self_arg, [], _) = e.kind
&& name.ident.name == sym::len
&& let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind
{
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
new file mode 100644
index 000000000..5b758f1e6
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
@@ -0,0 +1,64 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::{ResultErr, ResultOk};
+use rustc_hir::{Expr, ExprKind, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
+
+use super::MANUAL_OK_OR;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'tcx>,
+ recv: &'tcx Expr<'_>,
+ or_expr: &'tcx Expr<'_>,
+ map_expr: &'tcx Expr<'_>,
+) {
+ if_chain! {
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+ if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
+ if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Option);
+ if let ExprKind::Call(err_path, [err_arg]) = or_expr.kind;
+ if is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr);
+ if is_ok_wrapping(cx, map_expr);
+ if let Some(recv_snippet) = snippet_opt(cx, recv.span);
+ if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span);
+ if let Some(indent) = indent_of(cx, expr.span);
+ then {
+ let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4));
+ span_lint_and_sugg(
+ cx,
+ MANUAL_OK_OR,
+ expr.span,
+ "this pattern reimplements `Option::ok_or`",
+ "replace with",
+ format!(
+ "{recv_snippet}.ok_or({reindented_err_arg_snippet})"
+ ),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+}
+
+fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool {
+ match map_expr.kind {
+ ExprKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, map_expr.hir_id), ResultOk) => true,
+ ExprKind::Closure(closure) => {
+ let body = cx.tcx.hir().body(closure.body);
+ if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind
+ && let ExprKind::Call(callee, [ok_arg]) = body.value.kind
+ && is_res_lang_ctor(cx, path_res(cx, callee), ResultOk)
+ {
+ path_to_local_id(ok_arg, param_id)
+ } else {
+ false
+ }
+ },
+ _ => false,
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
index 0fe510bea..b80541b86 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
@@ -21,11 +21,7 @@ pub fn check(
return;
}
- let mm = if let Some(mm) = is_min_or_max(cx, unwrap_arg) {
- mm
- } else {
- return;
- };
+ let Some(mm) = is_min_or_max(cx, unwrap_arg) else { return };
if ty.is_signed() {
use self::{
@@ -33,9 +29,7 @@ pub fn check(
Sign::{Neg, Pos},
};
- let sign = if let Some(sign) = lit_sign(arith_rhs) {
- sign
- } else {
+ let Some(sign) = lit_sign(arith_rhs) else {
return;
};
@@ -57,11 +51,10 @@ pub fn check(
super::MANUAL_SATURATING_ARITHMETIC,
expr.span,
"manual saturating arithmetic",
- &format!("try using `saturating_{}`", arith),
+ &format!("try using `saturating_{arith}`"),
format!(
- "{}.saturating_{}({})",
+ "{}.saturating_{arith}({})",
snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability),
- arith,
snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability),
),
applicability,
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
index 46d2fc493..8b6b8f1bf 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
@@ -1,8 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_path_diagnostic_item;
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type};
-use clippy_utils::{is_expr_path_def_path, paths};
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
use if_chain::if_chain;
use rustc_ast::LitKind;
use rustc_errors::Applicability;
@@ -38,7 +38,7 @@ fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> {
let ty = cx.typeck_results().expr_ty(e);
if is_type_diagnostic_item(cx, ty, sym::String)
|| (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, Ty::is_str))
- || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, Ty::is_str))
+ || (is_type_diagnostic_item(cx, ty, sym::Cow) && get_ty_param(ty).map_or(false, Ty::is_str))
{
Some(RepeatKind::String)
} else {
@@ -57,7 +57,7 @@ pub(super) fn check(
) {
if_chain! {
if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind;
- if is_expr_path_def_path(cx, repeat_fn, &paths::ITER_REPEAT);
+ if is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat);
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::String);
if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id);
if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id);
@@ -91,7 +91,7 @@ pub(super) fn check(
collect_expr.span,
"manual implementation of `str::repeat` using iterators",
"try this",
- format!("{}.repeat({})", val_str, count_snip),
+ format!("{val_str}.repeat({count_snip})"),
app
)
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
new file mode 100644
index 000000000..7ce14ec08
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -0,0 +1,121 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
+use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs, peel_blocks};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_middle::mir::Mutability;
+use rustc_middle::ty;
+use rustc_middle::ty::adjustment::Adjust;
+use rustc_semver::RustcVersion;
+use rustc_span::symbol::Ident;
+use rustc_span::{sym, Span};
+
+use super::MAP_CLONE;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'_>,
+ e: &hir::Expr<'_>,
+ recv: &hir::Expr<'_>,
+ arg: &'tcx hir::Expr<'_>,
+ msrv: Option<RustcVersion>,
+) {
+ if_chain! {
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id);
+ if cx.tcx.impl_of_method(method_id)
+ .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id), sym::Option))
+ || is_diag_trait_item(cx, method_id, sym::Iterator);
+ if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind;
+ then {
+ let closure_body = cx.tcx.hir().body(body);
+ let closure_expr = peel_blocks(closure_body.value);
+ match closure_body.params[0].pat.kind {
+ hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
+ hir::BindingAnnotation::NONE, .., name, None
+ ) = inner.kind {
+ if ident_eq(name, closure_expr) {
+ lint_explicit_closure(cx, e.span, recv.span, true, msrv);
+ }
+ },
+ hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => {
+ match closure_expr.kind {
+ hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
+ if ident_eq(name, inner) {
+ if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
+ lint_explicit_closure(cx, e.span, recv.span, true, msrv);
+ }
+ }
+ },
+ hir::ExprKind::MethodCall(method, obj, [], _) => if_chain! {
+ if ident_eq(name, obj) && method.ident.name == sym::clone;
+ if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id);
+ if let Some(trait_id) = cx.tcx.trait_of_item(fn_id);
+ if cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id);
+ // no autoderefs
+ if !cx.typeck_results().expr_adjustments(obj).iter()
+ .any(|a| matches!(a.kind, Adjust::Deref(Some(..))));
+ then {
+ let obj_ty = cx.typeck_results().expr_ty(obj);
+ if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
+ if matches!(mutability, Mutability::Not) {
+ let copy = is_copy(cx, *ty);
+ lint_explicit_closure(cx, e.span, recv.span, copy, msrv);
+ }
+ } else {
+ lint_needless_cloning(cx, e.span, recv.span);
+ }
+ }
+ },
+ _ => {},
+ }
+ },
+ _ => {},
+ }
+ }
+ }
+}
+
+fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool {
+ if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind {
+ path.segments.len() == 1 && path.segments[0].ident == name
+ } else {
+ false
+ }
+}
+
+fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
+ span_lint_and_sugg(
+ cx,
+ MAP_CLONE,
+ root.trim_start(receiver).unwrap(),
+ "you are needlessly cloning iterator elements",
+ "remove the `map` call",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+}
+
+fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: Option<RustcVersion>) {
+ let mut applicability = Applicability::MachineApplicable;
+
+ let (message, sugg_method) = if is_copy && meets_msrv(msrv, msrvs::ITERATOR_COPIED) {
+ ("you are using an explicit closure for copying elements", "copied")
+ } else {
+ ("you are using an explicit closure for cloning elements", "cloned")
+ };
+
+ span_lint_and_sugg(
+ cx,
+ MAP_CLONE,
+ replace,
+ message,
+ &format!("consider calling the dedicated `{sugg_method}` method"),
+ format!(
+ "{}.{sugg_method}()",
+ snippet_with_applicability(cx, root, "..", &mut applicability),
+ ),
+ applicability,
+ );
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
new file mode 100644
index 000000000..1fb661714
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
@@ -0,0 +1,34 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::MAP_ERR_IGNORE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'_>, e: &Expr<'_>, arg: &'tcx Expr<'_>) {
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Result)
+ && let ExprKind::Closure(&Closure {
+ capture_clause: CaptureBy::Ref,
+ body,
+ fn_decl_span,
+ ..
+ }) = arg.kind
+ && let closure_body = cx.tcx.hir().body(body)
+ && let [param] = closure_body.params
+ && let PatKind::Wild = param.pat.kind
+ {
+ // span the area of the closure capture and warn that the
+ // original error will be thrown away
+ span_lint_and_help(
+ cx,
+ MAP_ERR_IGNORE,
+ fn_decl_span,
+ "`map_err(|_|...` wildcard pattern discards the original error",
+ None,
+ "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)",
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
index 13853dec9..361ffcb5e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
@@ -20,12 +20,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_
cx,
MAP_FLATTEN,
expr.span.with_lo(map_span.lo()),
- &format!("called `map(..).flatten()` on `{}`", caller_ty_name),
- &format!(
- "try replacing `map` with `{}` and remove the `.flatten()`",
- method_to_use
- ),
- format!("{}({})", method_to_use, closure_snippet),
+ &format!("called `map(..).flatten()` on `{caller_ty_name}`"),
+ &format!("try replacing `map` with `{method_to_use}` and remove the `.flatten()`"),
+ format!("{method_to_use}({closure_snippet})"),
applicability,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
index 862a9578e..0f25ef82e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
@@ -30,7 +30,7 @@ pub(super) fn check(
MAP_IDENTITY,
sugg_span,
"unnecessary map of the identity function",
- &format!("remove the call to `{}`", name),
+ &format!("remove the call to `{name}`"),
String::new(),
Applicability::MachineApplicable,
)
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
index 4a8e7ce4d..74fdead21 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
@@ -65,7 +65,7 @@ pub(super) fn check<'tcx>(
expr.span,
msg,
"try this",
- format!("{}.map_or_else({}, {})", var_snippet, unwrap_snippet, map_snippet),
+ format!("{var_snippet}.map_or_else({unwrap_snippet}, {map_snippet})"),
Applicability::MachineApplicable,
);
return true;
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 202fbc1f7..8a76ba0b0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -1,5 +1,8 @@
mod bind_instead_of_map;
+mod bytecount;
+mod bytes_count_to_len;
mod bytes_nth;
+mod case_sensitive_file_extension_comparisons;
mod chars_cmp;
mod chars_cmp_with_unwrap;
mod chars_last_cmp;
@@ -9,6 +12,7 @@ mod chars_next_cmp_with_unwrap;
mod clone_on_copy;
mod clone_on_ref_ptr;
mod cloned_instead_of_copied;
+mod collapsible_str_replace;
mod err_expect;
mod expect_fun_call;
mod expect_used;
@@ -21,6 +25,7 @@ mod filter_next;
mod flat_map_identity;
mod flat_map_option;
mod from_iter_instead_of_collect;
+mod get_first;
mod get_last_with_len;
mod get_unwrap;
mod implicit_clone;
@@ -30,69 +35,85 @@ mod into_iter_on_ref;
mod is_digit_ascii_radix;
mod iter_cloned_collect;
mod iter_count;
+mod iter_kv_map;
mod iter_next_slice;
mod iter_nth;
mod iter_nth_zero;
+mod iter_on_single_or_empty_collections;
mod iter_overeager_cloned;
mod iter_skip_next;
mod iter_with_drain;
mod iterator_step_by_zero;
+mod manual_ok_or;
mod manual_saturating_arithmetic;
mod manual_str_repeat;
+mod map_clone;
mod map_collect_result_unit;
+mod map_err_ignore;
mod map_flatten;
mod map_identity;
mod map_unwrap_or;
+mod mut_mutex_lock;
mod needless_option_as_deref;
mod needless_option_take;
mod no_effect_replace;
mod obfuscated_if_else;
mod ok_expect;
+mod open_options;
mod option_as_ref_deref;
mod option_map_or_none;
mod option_map_unwrap_or;
mod or_fun_call;
mod or_then_unwrap;
+mod path_buf_push_overwrite;
+mod range_zip_with_len;
+mod repeat_once;
mod search_is_some;
mod single_char_add_str;
mod single_char_insert_string;
mod single_char_pattern;
mod single_char_push_string;
mod skip_while_next;
+mod stable_sort_primitive;
mod str_splitn;
mod string_extend_chars;
mod suspicious_map;
mod suspicious_splitn;
+mod suspicious_to_owned;
mod uninit_assumed_init;
+mod unit_hash;
mod unnecessary_filter_map;
mod unnecessary_fold;
mod unnecessary_iter_cloned;
mod unnecessary_join;
mod unnecessary_lazy_eval;
+mod unnecessary_sort_by;
mod unnecessary_to_owned;
mod unwrap_or_else_default;
mod unwrap_used;
mod useless_asref;
mod utils;
+mod vec_resize_to_zero;
+mod verbose_file_reads;
mod wrong_self_convention;
mod zst_offset;
use bind_instead_of_map::BindInsteadOfMap;
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, get_trait_def_id, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
+use clippy_utils::ty::{contains_adt_constructor, implements_trait, is_copy, is_type_diagnostic_item};
+use clippy_utils::{contains_return, is_trait_method, iter_input_pats, meets_msrv, msrvs, return_ty};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TraitItem, TraitItemKind};
+use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, TraitRef, Ty};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
-use rustc_typeck::hir_ty_to_ty;
declare_clippy_lint! {
/// ### What it does
@@ -119,6 +140,32 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
+ /// Checks for consecutive calls to `str::replace` (2 or more)
+ /// that can be collapsed into a single call.
+ ///
+ /// ### Why is this bad?
+ /// Consecutive `str::replace` calls scan the string multiple times
+ /// with repetitive code.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let hello = "hesuo worpd"
+ /// .replace('s', "l")
+ /// .replace("u", "l")
+ /// .replace('p', "l");
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l");
+ /// ```
+ #[clippy::version = "1.64.0"]
+ pub COLLAPSIBLE_STR_REPLACE,
+ perf,
+ "collapse consecutive calls to str::replace (2 or more) into a single call"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
/// Checks for usage of `_.cloned().<func>()` where call to `.cloned()` can be postponed.
///
/// ### Why is this bad?
@@ -173,7 +220,7 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
- /// Checks for `.unwrap()` calls on `Option`s and on `Result`s.
+ /// Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s.
///
/// ### Why is this bad?
/// It is better to handle the `None` or `Err` case,
@@ -204,6 +251,17 @@ declare_clippy_lint! {
/// option.expect("more helpful message");
/// result.expect("more helpful message");
/// ```
+ ///
+ /// If [expect_used](#expect_used) is enabled, instead:
+ /// ```rust,ignore
+ /// # let option = Some(1);
+ /// # let result: Result<usize, ()> = Ok(1);
+ /// option?;
+ ///
+ /// // or
+ ///
+ /// result?;
+ /// ```
#[clippy::version = "1.45.0"]
pub UNWRAP_USED,
restriction,
@@ -212,7 +270,7 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
- /// Checks for `.expect()` calls on `Option`s and `Result`s.
+ /// Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s.
///
/// ### Why is this bad?
/// Usually it is better to handle the `None` or `Err` case.
@@ -766,8 +824,9 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
/// Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
- /// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
- /// `unwrap_or_default` instead.
+ /// `.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`,
+ /// `.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()`
+ /// etc. instead.
///
/// ### Why is this bad?
/// The function will always be called and potentially
@@ -1997,6 +2056,55 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
+ /// Checks for the usage of `_.to_owned()`, on a `Cow<'_, _>`.
+ ///
+ /// ### Why is this bad?
+ /// Calling `to_owned()` on a `Cow` creates a clone of the `Cow`
+ /// itself, without taking ownership of the `Cow` contents (i.e.
+ /// it's equivalent to calling `Cow::clone`).
+ /// The similarly named `into_owned` method, on the other hand,
+ /// clones the `Cow` contents, effectively turning any `Cow::Borrowed`
+ /// into a `Cow::Owned`.
+ ///
+ /// Given the potential ambiguity, consider replacing `to_owned`
+ /// with `clone` for better readability or, if getting a `Cow::Owned`
+ /// was the original intent, using `into_owned` instead.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::borrow::Cow;
+ /// let s = "Hello world!";
+ /// let cow = Cow::Borrowed(s);
+ ///
+ /// let data = cow.to_owned();
+ /// assert!(matches!(data, Cow::Borrowed(_)))
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # use std::borrow::Cow;
+ /// let s = "Hello world!";
+ /// let cow = Cow::Borrowed(s);
+ ///
+ /// let data = cow.clone();
+ /// assert!(matches!(data, Cow::Borrowed(_)))
+ /// ```
+ /// or
+ /// ```rust
+ /// # use std::borrow::Cow;
+ /// let s = "Hello world!";
+ /// let cow = Cow::Borrowed(s);
+ ///
+ /// let data = cow.into_owned();
+ /// assert!(matches!(data, String))
+ /// ```
+ #[clippy::version = "1.65.0"]
+ pub SUSPICIOUS_TO_OWNED,
+ suspicious,
+ "calls to `to_owned` on a `Cow<'_, _>` might not do what they are expected"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
/// Checks for calls to [`splitn`]
/// (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and
/// related functions with either zero or one splits.
@@ -2258,7 +2366,7 @@ declare_clippy_lint! {
/// "1234".replace("12", "12");
/// "1234".replacen("12", "12", 1);
/// ```
- #[clippy::version = "1.62.0"]
+ #[clippy::version = "1.63.0"]
pub NO_EFFECT_REPLACE,
suspicious,
"replace with no effect"
@@ -2293,6 +2401,671 @@ declare_clippy_lint! {
more clearly with `if .. else ..`"
}
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// Checks for calls to `iter`, `iter_mut` or `into_iter` on collections containing a single item
+ ///
+ /// ### Why is this bad?
+ ///
+ /// It is simpler to use the once function from the standard library:
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let a = [123].iter();
+ /// let b = Some(123).into_iter();
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// use std::iter;
+ /// let a = iter::once(&123);
+ /// let b = iter::once(123);
+ /// ```
+ ///
+ /// ### Known problems
+ ///
+ /// The type of the resulting iterator might become incompatible with its usage
+ #[clippy::version = "1.64.0"]
+ pub ITER_ON_SINGLE_ITEMS,
+ nursery,
+ "Iterator for array of length 1"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// Checks for calls to `iter`, `iter_mut` or `into_iter` on empty collections
+ ///
+ /// ### Why is this bad?
+ ///
+ /// It is simpler to use the empty function from the standard library:
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// use std::{slice, option};
+ /// let a: slice::Iter<i32> = [].iter();
+ /// let f: option::IntoIter<i32> = None.into_iter();
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// use std::iter;
+ /// let a: iter::Empty<i32> = iter::empty();
+ /// let b: iter::Empty<i32> = iter::empty();
+ /// ```
+ ///
+ /// ### Known problems
+ ///
+ /// The type of the resulting iterator might become incompatible with its usage
+ #[clippy::version = "1.64.0"]
+ pub ITER_ON_EMPTY_COLLECTIONS,
+ nursery,
+ "Iterator for empty array"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for naive byte counts
+ ///
+ /// ### Why is this bad?
+ /// The [`bytecount`](https://crates.io/crates/bytecount)
+ /// crate has methods to count your bytes faster, especially for large slices.
+ ///
+ /// ### Known problems
+ /// If you have predominantly small slices, the
+ /// `bytecount::count(..)` method may actually be slower. However, if you can
+ /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be
+ /// faster in those cases.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # let vec = vec![1_u8];
+ /// let count = vec.iter().filter(|x| **x == 0u8).count();
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust,ignore
+ /// # let vec = vec![1_u8];
+ /// let count = bytecount::count(&vec, 0u8);
+ /// ```
+ #[clippy::version = "pre 1.29.0"]
+ pub NAIVE_BYTECOUNT,
+ pedantic,
+ "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// It checks for `str::bytes().count()` and suggests replacing it with
+ /// `str::len()`.
+ ///
+ /// ### Why is this bad?
+ /// `str::bytes().count()` is longer and may not be as performant as using
+ /// `str::len()`.
+ ///
+ /// ### Example
+ /// ```rust
+ /// "hello".bytes().count();
+ /// String::from("hello").bytes().count();
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// "hello".len();
+ /// String::from("hello").len();
+ /// ```
+ #[clippy::version = "1.62.0"]
+ pub BYTES_COUNT_TO_LEN,
+ complexity,
+ "Using `bytes().count()` when `len()` performs the same functionality"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for calls to `ends_with` with possible file extensions
+ /// and suggests to use a case-insensitive approach instead.
+ ///
+ /// ### Why is this bad?
+ /// `ends_with` is case-sensitive and may not detect files with a valid extension.
+ ///
+ /// ### Example
+ /// ```rust
+ /// fn is_rust_file(filename: &str) -> bool {
+ /// filename.ends_with(".rs")
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// fn is_rust_file(filename: &str) -> bool {
+ /// let filename = std::path::Path::new(filename);
+ /// filename.extension()
+ /// .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
+ /// }
+ /// ```
+ #[clippy::version = "1.51.0"]
+ pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+ pedantic,
+ "Checks for calls to ends_with with case-sensitive file extensions"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for using `x.get(0)` instead of
+ /// `x.first()`.
+ ///
+ /// ### Why is this bad?
+ /// Using `x.first()` is easier to read and has the same
+ /// result.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let x = vec![2, 3, 5];
+ /// let first_element = x.get(0);
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust
+ /// let x = vec![2, 3, 5];
+ /// let first_element = x.first();
+ /// ```
+ #[clippy::version = "1.63.0"]
+ pub GET_FIRST,
+ style,
+ "Using `x.get(0)` when `x.first()` is simpler"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// Finds patterns that reimplement `Option::ok_or`.
+ ///
+ /// ### Why is this bad?
+ ///
+ /// Concise code helps focusing on behavior instead of boilerplate.
+ ///
+ /// ### Examples
+ /// ```rust
+ /// let foo: Option<i32> = None;
+ /// foo.map_or(Err("error"), |v| Ok(v));
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust
+ /// let foo: Option<i32> = None;
+ /// foo.ok_or("error");
+ /// ```
+ #[clippy::version = "1.49.0"]
+ pub MANUAL_OK_OR,
+ pedantic,
+ "finds patterns that can be encoded more concisely with `Option::ok_or`"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usage of `map(|x| x.clone())` or
+ /// dereferencing closures for `Copy` types, on `Iterator` or `Option`,
+ /// and suggests `cloned()` or `copied()` instead
+ ///
+ /// ### Why is this bad?
+ /// Readability, this can be written more concisely
+ ///
+ /// ### Example
+ /// ```rust
+ /// let x = vec![42, 43];
+ /// let y = x.iter();
+ /// let z = y.map(|i| *i);
+ /// ```
+ ///
+ /// The correct use would be:
+ ///
+ /// ```rust
+ /// let x = vec![42, 43];
+ /// let y = x.iter();
+ /// let z = y.cloned();
+ /// ```
+ #[clippy::version = "pre 1.29.0"]
+ pub MAP_CLONE,
+ style,
+ "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for instances of `map_err(|_| Some::Enum)`
+ ///
+ /// ### Why is this bad?
+ /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error
+ ///
+ /// ### Example
+ /// Before:
+ /// ```rust
+ /// use std::fmt;
+ ///
+ /// #[derive(Debug)]
+ /// enum Error {
+ /// Indivisible,
+ /// Remainder(u8),
+ /// }
+ ///
+ /// impl fmt::Display for Error {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// match self {
+ /// Error::Indivisible => write!(f, "could not divide input by three"),
+ /// Error::Remainder(remainder) => write!(
+ /// f,
+ /// "input is not divisible by three, remainder = {}",
+ /// remainder
+ /// ),
+ /// }
+ /// }
+ /// }
+ ///
+ /// impl std::error::Error for Error {}
+ ///
+ /// fn divisible_by_3(input: &str) -> Result<(), Error> {
+ /// input
+ /// .parse::<i32>()
+ /// .map_err(|_| Error::Indivisible)
+ /// .map(|v| v % 3)
+ /// .and_then(|remainder| {
+ /// if remainder == 0 {
+ /// Ok(())
+ /// } else {
+ /// Err(Error::Remainder(remainder as u8))
+ /// }
+ /// })
+ /// }
+ /// ```
+ ///
+ /// After:
+ /// ```rust
+ /// use std::{fmt, num::ParseIntError};
+ ///
+ /// #[derive(Debug)]
+ /// enum Error {
+ /// Indivisible(ParseIntError),
+ /// Remainder(u8),
+ /// }
+ ///
+ /// impl fmt::Display for Error {
+ /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// match self {
+ /// Error::Indivisible(_) => write!(f, "could not divide input by three"),
+ /// Error::Remainder(remainder) => write!(
+ /// f,
+ /// "input is not divisible by three, remainder = {}",
+ /// remainder
+ /// ),
+ /// }
+ /// }
+ /// }
+ ///
+ /// impl std::error::Error for Error {
+ /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ /// match self {
+ /// Error::Indivisible(source) => Some(source),
+ /// _ => None,
+ /// }
+ /// }
+ /// }
+ ///
+ /// fn divisible_by_3(input: &str) -> Result<(), Error> {
+ /// input
+ /// .parse::<i32>()
+ /// .map_err(Error::Indivisible)
+ /// .map(|v| v % 3)
+ /// .and_then(|remainder| {
+ /// if remainder == 0 {
+ /// Ok(())
+ /// } else {
+ /// Err(Error::Remainder(remainder as u8))
+ /// }
+ /// })
+ /// }
+ /// ```
+ #[clippy::version = "1.48.0"]
+ pub MAP_ERR_IGNORE,
+ restriction,
+ "`map_err` should not ignore the original error"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for `&mut Mutex::lock` calls
+ ///
+ /// ### Why is this bad?
+ /// `Mutex::lock` is less efficient than
+ /// calling `Mutex::get_mut`. In addition you also have a statically
+ /// guarantee that the mutex isn't locked, instead of just a runtime
+ /// guarantee.
+ ///
+ /// ### Example
+ /// ```rust
+ /// use std::sync::{Arc, Mutex};
+ ///
+ /// let mut value_rc = Arc::new(Mutex::new(42_u8));
+ /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
+ ///
+ /// let mut value = value_mutex.lock().unwrap();
+ /// *value += 1;
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// use std::sync::{Arc, Mutex};
+ ///
+ /// let mut value_rc = Arc::new(Mutex::new(42_u8));
+ /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
+ ///
+ /// let value = value_mutex.get_mut().unwrap();
+ /// *value += 1;
+ /// ```
+ #[clippy::version = "1.49.0"]
+ pub MUT_MUTEX_LOCK,
+ style,
+ "`&mut Mutex::lock` does unnecessary locking"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for duplicate open options as well as combinations
+ /// that make no sense.
+ ///
+ /// ### Why is this bad?
+ /// In the best case, the code will be harder to read than
+ /// necessary. I don't know the worst case.
+ ///
+ /// ### Example
+ /// ```rust
+ /// use std::fs::OpenOptions;
+ ///
+ /// OpenOptions::new().read(true).truncate(true);
+ /// ```
+ #[clippy::version = "pre 1.29.0"]
+ pub NONSENSICAL_OPEN_OPTIONS,
+ correctness,
+ "nonsensical combination of options for opening a file"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ ///* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push)
+ /// calls on `PathBuf` that can cause overwrites.
+ ///
+ /// ### Why is this bad?
+ /// Calling `push` with a root path at the start can overwrite the
+ /// previous defined path.
+ ///
+ /// ### Example
+ /// ```rust
+ /// use std::path::PathBuf;
+ ///
+ /// let mut x = PathBuf::from("/foo");
+ /// x.push("/bar");
+ /// assert_eq!(x, PathBuf::from("/bar"));
+ /// ```
+ /// Could be written:
+ ///
+ /// ```rust
+ /// use std::path::PathBuf;
+ ///
+ /// let mut x = PathBuf::from("/foo");
+ /// x.push("bar");
+ /// assert_eq!(x, PathBuf::from("/foo/bar"));
+ /// ```
+ #[clippy::version = "1.36.0"]
+ pub PATH_BUF_PUSH_OVERWRITE,
+ nursery,
+ "calling `push` with file system root on `PathBuf` can overwrite it"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for zipping a collection with the range of
+ /// `0.._.len()`.
+ ///
+ /// ### Why is this bad?
+ /// The code is better expressed with `.enumerate()`.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # let x = vec![1];
+ /// let _ = x.iter().zip(0..x.len());
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust
+ /// # let x = vec![1];
+ /// let _ = x.iter().enumerate();
+ /// ```
+ #[clippy::version = "pre 1.29.0"]
+ pub RANGE_ZIP_WITH_LEN,
+ complexity,
+ "zipping iterator with a range when `enumerate()` would do"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usage of `.repeat(1)` and suggest the following method for each types.
+ /// - `.to_string()` for `str`
+ /// - `.clone()` for `String`
+ /// - `.to_vec()` for `slice`
+ ///
+ /// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if
+ /// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))
+ ///
+ /// ### Why is this bad?
+ /// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning
+ /// the string is the intention behind this, `clone()` should be used.
+ ///
+ /// ### Example
+ /// ```rust
+ /// fn main() {
+ /// let x = String::from("hello world").repeat(1);
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// fn main() {
+ /// let x = String::from("hello world").clone();
+ /// }
+ /// ```
+ #[clippy::version = "1.47.0"]
+ pub REPEAT_ONCE,
+ complexity,
+ "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// When sorting primitive values (integers, bools, chars, as well
+ /// as arrays, slices, and tuples of such items), it is typically better to
+ /// use an unstable sort than a stable sort.
+ ///
+ /// ### Why is this bad?
+ /// Typically, using a stable sort consumes more memory and cpu cycles.
+ /// Because values which compare equal are identical, preserving their
+ /// relative order (the guarantee that a stable sort provides) means
+ /// nothing, while the extra costs still apply.
+ ///
+ /// ### Known problems
+ ///
+ /// As pointed out in
+ /// [issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241),
+ /// a stable sort can instead be significantly faster for certain scenarios
+ /// (eg. when a sorted vector is extended with new data and resorted).
+ ///
+ /// For more information and benchmarking results, please refer to the
+ /// issue linked above.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let mut vec = vec![2, 1, 3];
+ /// vec.sort();
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let mut vec = vec![2, 1, 3];
+ /// vec.sort_unstable();
+ /// ```
+ #[clippy::version = "1.47.0"]
+ pub STABLE_SORT_PRIMITIVE,
+ pedantic,
+ "use of sort() when sort_unstable() is equivalent"
+}
+
+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),
+ /// }
+ /// ```
+ #[clippy::version = "1.58.0"]
+ pub UNIT_HASH,
+ correctness,
+ "hashing a unit value, which does nothing"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Detects uses of `Vec::sort_by` passing in a closure
+ /// which compares the two arguments, either directly or indirectly.
+ ///
+ /// ### Why is this bad?
+ /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if
+ /// possible) than to use `Vec::sort_by` and a more complicated
+ /// closure.
+ ///
+ /// ### Known problems
+ /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already
+ /// imported by a use statement, then it will need to be added manually.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # struct A;
+ /// # impl A { fn foo(&self) {} }
+ /// # let mut vec: Vec<A> = Vec::new();
+ /// vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # struct A;
+ /// # impl A { fn foo(&self) {} }
+ /// # let mut vec: Vec<A> = Vec::new();
+ /// vec.sort_by_key(|a| a.foo());
+ /// ```
+ #[clippy::version = "1.46.0"]
+ pub UNNECESSARY_SORT_BY,
+ complexity,
+ "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Finds occurrences of `Vec::resize(0, an_int)`
+ ///
+ /// ### Why is this bad?
+ /// This is probably an argument inversion mistake.
+ ///
+ /// ### Example
+ /// ```rust
+ /// vec!(1, 2, 3, 4, 5).resize(0, 5)
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust
+ /// vec!(1, 2, 3, 4, 5).clear()
+ /// ```
+ #[clippy::version = "1.46.0"]
+ pub VEC_RESIZE_TO_ZERO,
+ correctness,
+ "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for use of File::read_to_end and File::read_to_string.
+ ///
+ /// ### Why is this bad?
+ /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values.
+ /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html)
+ ///
+ /// ### Example
+ /// ```rust,no_run
+ /// # use std::io::Read;
+ /// # use std::fs::File;
+ /// let mut f = File::open("foo.txt").unwrap();
+ /// let mut bytes = Vec::new();
+ /// f.read_to_end(&mut bytes).unwrap();
+ /// ```
+ /// Can be written more concisely as
+ /// ```rust,no_run
+ /// # use std::fs;
+ /// let mut bytes = fs::read("foo.txt").unwrap();
+ /// ```
+ #[clippy::version = "1.44.0"]
+ pub VERBOSE_FILE_READS,
+ restriction,
+ "use of `File::read_to_end` or `File::read_to_string`"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// Checks for iterating a map (`HashMap` or `BTreeMap`) and
+ /// ignoring either the keys or values.
+ ///
+ /// ### Why is this bad?
+ ///
+ /// Readability. There are `keys` and `values` methods that
+ /// can be used to express that we only need the keys or the values.
+ ///
+ /// ### Example
+ ///
+ /// ```
+ /// # use std::collections::HashMap;
+ /// let map: HashMap<u32, u32> = HashMap::new();
+ /// let values = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
+ /// ```
+ ///
+ /// Use instead:
+ /// ```
+ /// # use std::collections::HashMap;
+ /// let map: HashMap<u32, u32> = HashMap::new();
+ /// let values = map.values().collect::<Vec<_>>();
+ /// ```
+ #[clippy::version = "1.65.0"]
+ pub ITER_KV_MAP,
+ complexity,
+ "iterating on map using `iter` when `keys` or `values` would do"
+}
+
pub struct Methods {
avoid_breaking_exported_api: bool,
msrv: Option<RustcVersion>,
@@ -2336,6 +3109,7 @@ impl_lint_pass!(Methods => [
CLONE_ON_COPY,
CLONE_ON_REF_PTR,
CLONE_DOUBLE_REF,
+ COLLAPSIBLE_STR_REPLACE,
ITER_OVEREAGER_CLONED,
CLONED_INSTEAD_OF_COPIED,
FLAT_MAP_OPTION,
@@ -2382,6 +3156,7 @@ impl_lint_pass!(Methods => [
FROM_ITER_INSTEAD_OF_COLLECT,
INSPECT_FOR_EACH,
IMPLICIT_CLONE,
+ SUSPICIOUS_TO_OWNED,
SUSPICIOUS_SPLITN,
MANUAL_STR_REPEAT,
EXTEND_WITH_DRAIN,
@@ -2395,14 +3170,36 @@ impl_lint_pass!(Methods => [
NEEDLESS_OPTION_TAKE,
NO_EFFECT_REPLACE,
OBFUSCATED_IF_ELSE,
+ ITER_ON_SINGLE_ITEMS,
+ ITER_ON_EMPTY_COLLECTIONS,
+ NAIVE_BYTECOUNT,
+ BYTES_COUNT_TO_LEN,
+ CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+ GET_FIRST,
+ MANUAL_OK_OR,
+ MAP_CLONE,
+ MAP_ERR_IGNORE,
+ MUT_MUTEX_LOCK,
+ NONSENSICAL_OPEN_OPTIONS,
+ PATH_BUF_PUSH_OVERWRITE,
+ RANGE_ZIP_WITH_LEN,
+ REPEAT_ONCE,
+ STABLE_SORT_PRIMITIVE,
+ UNIT_HASH,
+ UNNECESSARY_SORT_BY,
+ VEC_RESIZE_TO_ZERO,
+ VERBOSE_FILE_READS,
+ ITER_KV_MAP,
]);
/// Extracts a method call name, args, and `Span` of the method name.
-fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span)> {
- if let ExprKind::MethodCall(path, args, _) = recv.kind {
- if !args.iter().any(|e| e.span.from_expansion()) {
+fn method_call<'tcx>(
+ recv: &'tcx hir::Expr<'tcx>,
+) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span)> {
+ if let ExprKind::MethodCall(path, receiver, args, _) = recv.kind {
+ if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() {
let name = path.ident.name.as_str();
- return Some((name, args, path.ident.span));
+ return Some((name, receiver, args, path.ident.span));
}
}
None
@@ -2420,17 +3217,17 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
hir::ExprKind::Call(func, args) => {
from_iter_instead_of_collect::check(cx, expr, args, func);
},
- hir::ExprKind::MethodCall(method_call, args, _) => {
+ hir::ExprKind::MethodCall(method_call, receiver, args, _) => {
let method_span = method_call.ident.span;
- or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
- expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
- clone_on_copy::check(cx, expr, method_call.ident.name, args);
- clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args);
- inefficient_to_string::check(cx, expr, method_call.ident.name, args);
- single_char_add_str::check(cx, expr, args);
- into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args);
- single_char_pattern::check(cx, expr, method_call.ident.name, args);
- unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv);
+ or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
+ expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
+ clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args);
+ clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args);
+ inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args);
+ single_char_add_str::check(cx, expr, receiver, args);
+ into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver);
+ single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args);
+ unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv);
},
hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
let mut info = BinaryExprInfo {
@@ -2451,70 +3248,64 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
return;
}
let name = impl_item.ident.name.as_str();
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
let item = cx.tcx.hir().expect_item(parent);
- let self_ty = cx.tcx.type_of(item.def_id);
+ let self_ty = cx.tcx.type_of(item.owner_id);
let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
- if_chain! {
- if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind;
- if let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next();
-
- let method_sig = cx.tcx.fn_sig(impl_item.def_id);
+ if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind {
+ let method_sig = cx.tcx.fn_sig(impl_item.owner_id);
let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
-
- let first_arg_ty = method_sig.inputs().iter().next();
-
- // check conventions w.r.t. conversion method names and predicates
- if let Some(first_arg_ty) = first_arg_ty;
-
- then {
- // if this impl block implements a trait, lint in trait definition instead
- if !implements_trait && cx.access_levels.is_exported(impl_item.def_id) {
- // check missing trait implementations
- for method_config in &TRAIT_METHODS {
- if name == method_config.method_name &&
- sig.decl.inputs.len() == method_config.param_count &&
- method_config.output_type.matches(&sig.decl.output) &&
- method_config.self_kind.matches(cx, self_ty, *first_arg_ty) &&
- fn_header_equals(method_config.fn_header, sig.header) &&
- method_config.lifetime_param_cond(impl_item)
- {
- span_lint_and_help(
- cx,
- SHOULD_IMPLEMENT_TRAIT,
- impl_item.span,
- &format!(
- "method `{}` can be confused for the standard trait method `{}::{}`",
- method_config.method_name,
- method_config.trait_name,
- method_config.method_name
- ),
- None,
- &format!(
- "consider implementing the trait `{}` or choosing a less ambiguous method name",
- method_config.trait_name
- )
- );
- }
+ let first_arg_ty_opt = method_sig.inputs().iter().next().copied();
+ // if this impl block implements a trait, lint in trait definition instead
+ if !implements_trait && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
+ // check missing trait implementations
+ for method_config in &TRAIT_METHODS {
+ if name == method_config.method_name
+ && sig.decl.inputs.len() == method_config.param_count
+ && method_config.output_type.matches(&sig.decl.output)
+ // in case there is no first arg, since we already have checked the number of arguments
+ // it's should be always true
+ && first_arg_ty_opt.map_or(true, |first_arg_ty| method_config
+ .self_kind.matches(cx, self_ty, first_arg_ty)
+ )
+ && fn_header_equals(method_config.fn_header, sig.header)
+ && method_config.lifetime_param_cond(impl_item)
+ {
+ span_lint_and_help(
+ cx,
+ SHOULD_IMPLEMENT_TRAIT,
+ impl_item.span,
+ &format!(
+ "method `{}` can be confused for the standard trait method `{}::{}`",
+ method_config.method_name, method_config.trait_name, method_config.method_name
+ ),
+ None,
+ &format!(
+ "consider implementing the trait `{}` or choosing a less ambiguous method name",
+ method_config.trait_name
+ ),
+ );
}
}
+ }
- if sig.decl.implicit_self.has_implicit_self()
+ if sig.decl.implicit_self.has_implicit_self()
&& !(self.avoid_breaking_exported_api
- && cx.access_levels.is_exported(impl_item.def_id))
+ && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id))
+ && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next()
+ && let Some(first_arg_ty) = first_arg_ty_opt
{
wrong_self_convention::check(
cx,
name,
self_ty,
- *first_arg_ty,
+ first_arg_ty,
first_arg.pat.span,
implements_trait,
false
);
}
- }
}
// if this impl block implements a trait, lint in trait definition instead
@@ -2530,7 +3321,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
if contains_adt_constructor(ret_ty, self_adt) {
return;
}
- } else if contains_ty(ret_ty, self_ty) {
+ } else if ret_ty.contains(self_ty) {
return;
}
@@ -2539,16 +3330,16 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
// one of the associated types must be Self
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
- let assoc_ty = match projection_predicate.term {
- ty::Term::Ty(ty) => ty,
- ty::Term::Const(_c) => continue,
+ let assoc_ty = match projection_predicate.term.unpack() {
+ ty::TermKind::Ty(ty) => ty,
+ ty::TermKind::Const(_c) => continue,
};
// walk the associated type and check for Self
if let Some(self_adt) = self_ty.ty_adt_def() {
if contains_adt_constructor(assoc_ty, self_adt) {
return;
}
- } else if contains_ty(assoc_ty, self_ty) {
+ } else if assoc_ty.contains(self_ty) {
return;
}
}
@@ -2579,7 +3370,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
then {
let first_arg_span = first_arg_ty.span;
let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
- let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder();
+ let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
+ .self_ty()
+ .skip_binder();
wrong_self_convention::check(
cx,
item.ident.name.as_str(),
@@ -2587,7 +3380,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
first_arg_ty,
first_arg_span,
false,
- true
+ true,
);
}
}
@@ -2596,8 +3389,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
if item.ident.name == sym::new;
if let TraitItemKind::Fn(_, _) = item.kind;
let ret_ty = return_ty(cx, item.hir_id());
- let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder();
- if !contains_ty(ret_ty, self_ty);
+ let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
+ .self_ty()
+ .skip_binder();
+ if !ret_ty.contains(self_ty);
then {
span_lint(
@@ -2616,7 +3411,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
impl Methods {
#[allow(clippy::too_many_lines)]
fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if let Some((name, [recv, args @ ..], span)) = method_call(expr) {
+ if let Some((name, recv, args, span)) = method_call(expr) {
match (name, args) {
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
zst_offset::check(cx, expr, recv);
@@ -2636,35 +3431,43 @@ impl Methods {
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
("collect", []) => match method_call(recv) {
- Some((name @ ("cloned" | "copied"), [recv2], _)) => {
+ Some((name @ ("cloned" | "copied"), recv2, [], _)) => {
iter_cloned_collect::check(cx, name, expr, recv2);
},
- Some(("map", [m_recv, m_arg], _)) => {
+ Some(("map", m_recv, [m_arg], _)) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
},
- Some(("take", [take_self_arg, take_arg], _)) => {
+ Some(("take", take_self_arg, [take_arg], _)) => {
if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
}
},
_ => {},
},
- ("count", []) => match method_call(recv) {
- Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
- Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
+ ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
+ Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
+ Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _)) => {
iter_count::check(cx, expr, recv2, name2);
},
- Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
+ Some(("map", _, [arg], _)) => suspicious_map::check(cx, expr, recv, arg),
+ Some(("filter", recv2, [arg], _)) => bytecount::check(cx, expr, recv2, arg),
+ Some(("bytes", recv2, [], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
_ => {},
},
("drain", [arg]) => {
iter_with_drain::check(cx, expr, recv, span, arg);
},
+ ("ends_with", [arg]) => {
+ if let ExprKind::MethodCall(.., span) = expr.kind {
+ case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg);
+ }
+ },
("expect", [_]) => match method_call(recv) {
- Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
- Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
- _ => expect_used::check(cx, expr, recv, self.allow_expect_in_tests),
+ Some(("ok", recv, [], _)) => ok_expect::check(cx, expr, recv),
+ Some(("err", recv, [], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
+ _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
},
+ ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
("extend", [arg]) => {
string_extend_chars::check(cx, expr, recv, arg);
extend_with_drain::check(cx, expr, recv, arg);
@@ -2681,36 +3484,56 @@ impl Methods {
flat_map_option::check(cx, expr, arg, span);
},
("flatten", []) => match method_call(recv) {
- Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
- Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
+ Some(("map", recv, [map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
+ Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
_ => {},
},
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
("for_each", [_]) => {
- if let Some(("inspect", [_, _], span2)) = method_call(recv) {
+ if let Some(("inspect", _, [_], span2)) = method_call(recv) {
inspect_for_each::check(cx, expr, span2);
}
},
- ("get", [arg]) => get_last_with_len::check(cx, expr, recv, arg),
+ ("get", [arg]) => {
+ get_first::check(cx, expr, recv, arg);
+ get_last_with_len::check(cx, expr, recv, arg);
+ },
("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
+ ("hash", [arg]) => {
+ unit_hash::check(cx, expr, recv, arg);
+ },
("is_file", []) => filetype_is_file::check(cx, expr, recv),
("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),
("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
+ ("iter" | "iter_mut" | "into_iter", []) => {
+ iter_on_single_or_empty_collections::check(cx, expr, name, recv);
+ },
("join", [join_arg]) => {
- if let Some(("collect", _, span)) = method_call(recv) {
+ if let Some(("collect", _, _, span)) = method_call(recv) {
unnecessary_join::check(cx, expr, recv, join_arg, span);
}
},
("last", []) | ("skip", [_]) => {
- if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
+ if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
}
}
},
+ ("lock", []) => {
+ mut_mutex_lock::check(cx, expr, recv, span);
+ },
(name @ ("map" | "map_err"), [m_arg]) => {
- if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
+ if name == "map" {
+ map_clone::check(cx, expr, recv, m_arg, self.msrv);
+ if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _)) = method_call(recv) {
+ iter_kv_map::check(cx, map_name, expr, recv2, m_arg);
+ }
+ } else {
+ map_err_ignore::check(cx, expr, m_arg);
+ }
+ if let Some((name, recv2, args, span2)) = method_call(recv) {
match (name, args) {
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
@@ -2725,9 +3548,12 @@ impl Methods {
}
map_identity::check(cx, expr, recv, m_arg, name, span);
},
- ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
+ ("map_or", [def, map]) => {
+ option_map_or_none::check(cx, expr, recv, def, map);
+ manual_ok_or::check(cx, expr, recv, def, map);
+ },
("next", []) => {
- if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
+ if let Some((name2, recv2, args2, _)) = method_call(recv) {
match (name2, args2) {
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
@@ -2740,18 +3566,53 @@ impl Methods {
}
},
("nth", [n_arg]) => match method_call(recv) {
- Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
- Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
- Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
- Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
+ Some(("bytes", recv2, [], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
+ Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
+ Some(("iter", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
+ Some(("iter_mut", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
},
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
+ ("open", [_]) => {
+ open_options::check(cx, expr, recv);
+ },
("or_else", [arg]) => {
if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
}
},
+ ("push", [arg]) => {
+ path_buf_push_overwrite::check(cx, expr, arg);
+ },
+ ("read_to_end", [_]) => {
+ verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_END_MSG);
+ },
+ ("read_to_string", [_]) => {
+ verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG);
+ },
+ ("repeat", [arg]) => {
+ repeat_once::check(cx, expr, recv, arg);
+ },
+ (name @ ("replace" | "replacen"), [arg1, arg2] | [arg1, arg2, _]) => {
+ no_effect_replace::check(cx, expr, arg1, arg2);
+
+ // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint
+ if name == "replace" && let Some(("replace", ..)) = method_call(recv) {
+ collapsible_str_replace::check(cx, expr, arg1, arg2);
+ }
+ },
+ ("resize", [count_arg, default_arg]) => {
+ vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span);
+ },
+ ("sort", []) => {
+ stable_sort_primitive::check(cx, expr, recv);
+ },
+ ("sort_by", [arg]) => {
+ unnecessary_sort_by::check(cx, expr, recv, arg, false);
+ },
+ ("sort_unstable_by", [arg]) => {
+ unnecessary_sort_by::check(cx, expr, recv, arg, true);
+ },
("splitn" | "rsplitn", [count_arg, pat_arg]) => {
if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count);
@@ -2765,7 +3626,7 @@ impl Methods {
},
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
("take", [_arg]) => {
- if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
+ if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
}
@@ -2778,46 +3639,56 @@ impl Methods {
}
unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
},
- ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
+ ("to_owned", []) => {
+ if !suspicious_to_owned::check(cx, expr, recv) {
+ implicit_clone::check(cx, name, expr, recv);
+ }
+ },
+ ("to_os_string" | "to_path_buf" | "to_vec", []) => {
implicit_clone::check(cx, name, expr, recv);
},
("unwrap", []) => {
match method_call(recv) {
- Some(("get", [recv, get_arg], _)) => {
+ Some(("get", recv, [get_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, false);
},
- Some(("get_mut", [recv, get_arg], _)) => {
+ Some(("get_mut", recv, [get_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, true);
},
- Some(("or", [recv, or_arg], or_span)) => {
+ Some(("or", recv, [or_arg], or_span)) => {
or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
},
_ => {},
}
- unwrap_used::check(cx, expr, recv, self.allow_unwrap_in_tests);
+ unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests);
},
+ ("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
("unwrap_or", [u_arg]) => match method_call(recv) {
- Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
+ Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _)) => {
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
},
- Some(("map", [m_recv, m_arg], span)) => {
+ Some(("map", m_recv, [m_arg], span)) => {
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
},
- Some(("then_some", [t_recv, t_arg], _)) => {
+ Some(("then_some", t_recv, [t_arg], _)) => {
obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
},
_ => {},
},
("unwrap_or_else", [u_arg]) => match method_call(recv) {
- Some(("map", [recv, map_arg], _))
+ Some(("map", recv, [map_arg], _))
if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
_ => {
unwrap_or_else_default::check(cx, expr, recv, u_arg);
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
},
},
- ("replace" | "replacen", [arg1, arg2] | [arg1, arg2, _]) => {
- no_effect_replace::check(cx, expr, arg1, arg2);
+ ("zip", [arg]) => {
+ if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
+ && name.ident.name == sym::iter
+ {
+ range_zip_with_len::check(cx, expr, iter_recv, arg);
+ }
},
_ => {},
}
@@ -2826,7 +3697,7 @@ impl Methods {
}
fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
- if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call(recv) {
+ if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span)) = method_call(recv) {
search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
}
}
@@ -2924,7 +3795,6 @@ const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
ShouldImplTraitCase::new("std::clone::Clone", "clone", 1, FN_HEADER, SelfKind::Ref, OutType::Any, true),
ShouldImplTraitCase::new("std::cmp::Ord", "cmp", 2, FN_HEADER, SelfKind::Ref, OutType::Any, true),
- // FIXME: default doesn't work
ShouldImplTraitCase::new("std::default::Default", "default", 0, FN_HEADER, SelfKind::No, OutType::Any, true),
ShouldImplTraitCase::new("std::ops::Deref", "deref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
@@ -2952,7 +3822,7 @@ enum SelfKind {
Value,
Ref,
RefMut,
- No,
+ No, // When we want the first argument type to be different than `Self`
}
impl SelfKind {
@@ -2978,14 +3848,13 @@ impl SelfKind {
return m == mutability && t == parent_ty;
}
- let trait_path = match mutability {
- hir::Mutability::Not => &paths::ASREF_TRAIT,
- hir::Mutability::Mut => &paths::ASMUT_TRAIT,
+ let trait_sym = match mutability {
+ hir::Mutability::Not => sym::AsRef,
+ hir::Mutability::Mut => sym::AsMut,
};
- let trait_def_id = match get_trait_def_id(cx, trait_path) {
- Some(did) => did,
- None => return false,
+ let Some(trait_def_id) = cx.tcx.get_diagnostic_item(trait_sym) else {
+ return false
};
implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
new file mode 100644
index 000000000..b9593b368
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
@@ -0,0 +1,31 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::{expr_custom_deref_adjustment, ty::is_type_diagnostic_item};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, Mutability};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_span::{sym, Span};
+
+use super::MUT_MUTEX_LOCK;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) {
+ if_chain! {
+ if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut));
+ if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind();
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id);
+ if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
+ if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Mutex);
+ then {
+ span_lint_and_sugg(
+ cx,
+ MUT_MUTEX_LOCK,
+ name_span,
+ "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference",
+ "change this to",
+ "get_mut".to_owned(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs b/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
index d64a9f320..646fc4a7b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -15,7 +15,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
let result_type = cx.typeck_results().expr_ty(recv);
if let Some(error_type) = get_error_type(cx, result_type);
- if has_debug_impl(error_type, cx);
+ if has_debug_impl(cx, error_type);
then {
span_lint_and_help(
@@ -37,10 +37,3 @@ fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
_ => None,
}
}
-
-/// This checks whether a given type is known to implement Debug.
-fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
- cx.tcx
- .get_diagnostic_item(sym::Debug)
- .map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
-}
diff --git a/src/tools/clippy/clippy_lints/src/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index 5a0b50420..597af853d 100644
--- a/src/tools/clippy/clippy_lints/src/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -3,43 +3,19 @@ use clippy_utils::paths;
use clippy_utils::ty::match_type;
use rustc_ast::ast::LitKind;
use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_lint::LateContext;
use rustc_span::source_map::{Span, Spanned};
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for duplicate open options as well as combinations
- /// that make no sense.
- ///
- /// ### Why is this bad?
- /// In the best case, the code will be harder to read than
- /// necessary. I don't know the worst case.
- ///
- /// ### Example
- /// ```rust
- /// use std::fs::OpenOptions;
- ///
- /// OpenOptions::new().read(true).truncate(true);
- /// ```
- #[clippy::version = "pre 1.29.0"]
- pub NONSENSICAL_OPEN_OPTIONS,
- correctness,
- "nonsensical combination of options for opening a file"
-}
-
-declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]);
+use super::NONSENSICAL_OPEN_OPTIONS;
-impl<'tcx> LateLintPass<'tcx> for OpenOptions {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
- if let ExprKind::MethodCall(path, [self_arg, ..], _) = &e.kind {
- let obj_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
- if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) {
- let mut options = Vec::new();
- get_open_options(cx, self_arg, &mut options);
- check_open_options(cx, &options, e.span);
- }
- }
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && match_type(cx, cx.tcx.type_of(impl_id), &paths::OPEN_OPTIONS)
+ {
+ let mut options = Vec::new();
+ get_open_options(cx, recv, &mut options);
+ check_open_options(cx, &options, e.span);
}
}
@@ -60,12 +36,12 @@ enum OpenOption {
}
fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
- if let ExprKind::MethodCall(path, arguments, _) = argument.kind {
- let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs();
+ if let ExprKind::MethodCall(path, receiver, arguments, _) = argument.kind {
+ let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
// Only proceed if this is a call on some object of type std::fs::OpenOptions
- if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 {
- let argument_option = match arguments[1].kind {
+ if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && !arguments.is_empty() {
+ let argument_option = match arguments[0].kind {
ExprKind::Lit(ref span) => {
if let Spanned {
node: LitKind::Bool(lit),
@@ -101,7 +77,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec
_ => (),
}
- get_open_options(cx, &arguments[0], options);
+ get_open_options(cx, receiver, options);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index 20cad0f18..742483e6b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -32,8 +32,7 @@ pub(super) fn check<'tcx>(
return;
}
- let deref_aliases: [&[&str]; 9] = [
- &paths::DEREF_TRAIT_METHOD,
+ let deref_aliases: [&[&str]; 8] = [
&paths::DEREF_MUT_TRAIT_METHOD,
&paths::CSTRING_AS_C_STR,
&paths::OS_STRING_AS_OS_STR,
@@ -45,31 +44,33 @@ pub(super) fn check<'tcx>(
];
let is_deref = match map_arg.kind {
- hir::ExprKind::Path(ref expr_qpath) => cx
- .qpath_res(expr_qpath, map_arg.hir_id)
- .opt_def_id()
- .map_or(false, |fun_def_id| {
- deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
- }),
+ hir::ExprKind::Path(ref expr_qpath) => {
+ cx.qpath_res(expr_qpath, map_arg.hir_id)
+ .opt_def_id()
+ .map_or(false, |fun_def_id| {
+ cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id)
+ || deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
+ })
+ },
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
let closure_body = cx.tcx.hir().body(body);
- let closure_expr = peel_blocks(&closure_body.value);
+ let closure_expr = peel_blocks(closure_body.value);
match &closure_expr.kind {
- hir::ExprKind::MethodCall(_, args, _) => {
+ hir::ExprKind::MethodCall(_, receiver, [], _) => {
if_chain! {
- if args.len() == 1;
- if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id);
+ if path_to_local_id(receiver, closure_body.params[0].pat.hir_id);
let adj = cx
.typeck_results()
- .expr_adjustments(&args[0])
+ .expr_adjustments(receiver)
.iter()
.map(|x| &x.kind)
.collect::<Box<[_]>>();
if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
then {
let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
- deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
+ cx.tcx.is_diagnostic_item(sym::deref_method, method_did)
+ || deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
} else {
false
}
@@ -99,13 +100,12 @@ pub(super) fn check<'tcx>(
format!(".as_ref().map({})", snippet(cx, map_arg.span, ".."))
};
let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" };
- let hint = format!("{}.{}()", snippet(cx, as_ref_recv.span, ".."), method_hint);
- let suggestion = format!("try using {} instead", method_hint);
+ let hint = format!("{}.{method_hint}()", snippet(cx, as_ref_recv.span, ".."));
+ let suggestion = format!("try using {method_hint} instead");
let msg = format!(
- "called `{0}` on an Option value. This can be done more directly \
- by calling `{1}` instead",
- current_method, hint
+ "called `{current_method}` on an Option value. This can be done more directly \
+ by calling `{hint}` instead"
);
span_lint_and_sugg(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
index 5a39b82b0..3a23ecc50 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_lang_ctor, path_def_id};
+use clippy_utils::{is_res_lang_ctor, path_def_id, path_res};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::LangItem::{OptionNone, OptionSome};
@@ -51,22 +51,12 @@ pub(super) fn check<'tcx>(
return;
}
- let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = def_arg.kind {
- is_lang_ctor(cx, qpath, OptionNone)
- } else {
- return;
- };
-
- if !default_arg_is_none {
+ if !is_res_lang_ctor(cx, path_res(cx, def_arg), OptionNone) {
// nothing to lint!
return;
}
- let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_arg.kind {
- is_lang_ctor(cx, qpath, OptionSome)
- } else {
- false
- };
+ let f_arg_is_some = is_res_lang_ctor(cx, path_res(cx, map_arg), OptionSome);
if is_option {
let self_snippet = snippet(cx, recv.span, "..");
@@ -74,7 +64,7 @@ pub(super) fn check<'tcx>(
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = map_arg.kind;
let arg_snippet = snippet(cx, fn_decl_span, "..");
let body = cx.tcx.hir().body(body);
- if let Some((func, [arg_char])) = reduce_unit_expression(&body.value);
+ if let Some((func, [arg_char])) = reduce_unit_expression(body.value);
if let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id));
if Some(id) == cx.tcx.lang_items().option_some_variant();
then {
@@ -87,7 +77,7 @@ pub(super) fn check<'tcx>(
expr.span,
msg,
"try using `map` instead",
- format!("{0}.map({1} {2})", self_snippet, arg_snippet,func_snippet),
+ format!("{self_snippet}.map({arg_snippet} {func_snippet})"),
Applicability::MachineApplicable,
);
}
@@ -102,7 +92,7 @@ pub(super) fn check<'tcx>(
expr.span,
msg,
"try using `and_then` instead",
- format!("{0}.and_then({1})", self_snippet, func_snippet),
+ format!("{self_snippet}.and_then({func_snippet})"),
Applicability::MachineApplicable,
);
} else if f_arg_is_some {
@@ -115,7 +105,7 @@ pub(super) fn check<'tcx>(
expr.span,
msg,
"try using `ok` instead",
- format!("{0}.ok()", self_snippet),
+ format!("{self_snippet}.ok()"),
Applicability::MachineApplicable,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
index 6c641af59..30421a6dd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -65,9 +65,8 @@ pub(super) fn check<'tcx>(
"map_or(<a>, <f>)"
};
let msg = &format!(
- "called `map(<f>).unwrap_or({})` on an `Option` value. \
- This can be done more directly by calling `{}` instead",
- arg, suggest
+ "called `map(<f>).unwrap_or({arg})` on an `Option` value. \
+ This can be done more directly by calling `{suggest}` instead"
);
span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| {
@@ -78,14 +77,14 @@ pub(super) fn check<'tcx>(
map_span,
String::from(if unwrap_snippet_none { "and_then" } else { "map_or" }),
),
- (expr.span.with_lo(unwrap_recv.span.hi()), String::from("")),
+ (expr.span.with_lo(unwrap_recv.span.hi()), String::new()),
];
if !unwrap_snippet_none {
- suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{}, ", unwrap_snippet)));
+ suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, ")));
}
- diag.multipart_suggestion(&format!("use `{}` instead", suggest), suggestion, applicability);
+ diag.multipart_suggestion(&format!("use `{suggest}` instead"), suggestion, applicability);
});
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 6af134019..991d3dd53 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -1,14 +1,14 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::eager_or_lazy::switch_to_lazy_eval;
use clippy_utils::source::{snippet, snippet_with_macro_callsite};
-use clippy_utils::ty::{implements_trait, match_type};
-use clippy_utils::{contains_return, is_trait_item, last_path_segment, paths};
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::{contains_return, is_trait_item, last_path_segment};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::source_map::Span;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::{kw, sym, Symbol};
use std::borrow::Cow;
use super::OR_FUN_CALL;
@@ -20,9 +20,11 @@ pub(super) fn check<'tcx>(
expr: &hir::Expr<'_>,
method_span: Span,
name: &str,
+ receiver: &'tcx hir::Expr<'_>,
args: &'tcx [hir::Expr<'_>],
) {
- /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
+ /// Checks for `unwrap_or(T::new())`, `unwrap_or(T::default())`,
+ /// `or_insert(T::new())` or `or_insert(T::default())`.
#[allow(clippy::too_many_arguments)]
fn check_unwrap_or_default(
cx: &LateContext<'_>,
@@ -42,7 +44,11 @@ pub(super) fn check<'tcx>(
if_chain! {
if !or_has_args;
- if name == "unwrap_or";
+ if let Some(sugg) = match name {
+ "unwrap_or" => Some("unwrap_or_default"),
+ "or_insert" => Some("or_default"),
+ _ => None,
+ };
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;
@@ -56,9 +62,9 @@ pub(super) fn check<'tcx>(
cx,
OR_FUN_CALL,
method_span.with_hi(span.hi()),
- &format!("use of `{}` followed by a call to `{}`", name, path),
+ &format!("use of `{name}` followed by a call to `{path}`"),
"try this",
- "unwrap_or_default()".to_string(),
+ format!("{sugg}()"),
Applicability::MachineApplicable,
);
@@ -82,11 +88,11 @@ pub(super) fn check<'tcx>(
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"),
+ const KNOW_TYPES: [(Symbol, bool, &[&str], &str); 4] = [
+ (sym::BTreeEntry, false, &["or_insert"], "with"),
+ (sym::HashMapEntry, false, &["or_insert"], "with"),
+ (sym::Option, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
+ (sym::Result, true, &["or", "unwrap_or"], "else"),
];
if_chain! {
@@ -98,7 +104,7 @@ pub(super) fn check<'tcx>(
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));
+ KNOW_TYPES.iter().find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0));
if poss.contains(&name);
@@ -115,17 +121,16 @@ pub(super) fn check<'tcx>(
macro_expanded_snipped = snippet(cx, snippet_span, "..");
match macro_expanded_snipped.strip_prefix("$crate::vec::") {
Some(stripped) => Cow::from(stripped),
- None => macro_expanded_snipped
+ None => macro_expanded_snipped,
}
- }
- else {
+ } else {
not_macro_argument_snippet
}
};
if use_lambda {
let l_arg = if fn_has_arguments { "_" } else { "" };
- format!("|{}| {}", l_arg, snippet).into()
+ format!("|{l_arg}| {snippet}").into()
} else {
snippet
}
@@ -135,16 +140,16 @@ pub(super) fn check<'tcx>(
cx,
OR_FUN_CALL,
span_replace_word,
- &format!("use of `{}` followed by a function call", name),
+ &format!("use of `{name}` followed by a function call"),
"try this",
- format!("{}_{}({})", name, suffix, sugg),
+ format!("{name}_{suffix}({sugg})"),
Applicability::HasPlaceholders,
);
}
}
}
- if let [self_arg, arg] = args {
+ if let [arg] = args {
let inner_arg = if let hir::ExprKind::Block(
hir::Block {
stmts: [],
@@ -163,11 +168,11 @@ pub(super) fn check<'tcx>(
let or_has_args = !or_args.is_empty();
if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
let fun_span = if or_has_args { None } else { Some(fun.span) };
- check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span);
+ check_general_case(cx, name, method_span, receiver, arg, expr.span, fun_span);
}
},
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
- check_general_case(cx, name, method_span, self_arg, arg, expr.span, None);
+ check_general_case(cx, name, method_span, receiver, arg, expr.span, None);
},
_ => (),
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
index be5768c35..55ba6e262 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
@@ -1,6 +1,6 @@
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{diagnostics::span_lint_and_sugg, is_lang_ctor};
+use clippy_utils::{diagnostics::span_lint_and_sugg, is_res_lang_ctor, path_res};
use rustc_errors::Applicability;
use rustc_hir::{lang_items::LangItem, Expr, ExprKind};
use rustc_lint::LateContext;
@@ -58,8 +58,7 @@ pub(super) fn check<'tcx>(
fn get_content_if_ctor_matches(cx: &LateContext<'_>, expr: &Expr<'_>, item: LangItem) -> Option<Span> {
if let ExprKind::Call(some_expr, [arg]) = expr.kind
- && let ExprKind::Path(qpath) = &some_expr.kind
- && is_lang_ctor(cx, qpath, item)
+ && is_res_lang_ctor(cx, path_res(cx, some_expr), item)
{
Some(arg.span)
} else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
new file mode 100644
index 000000000..0cc28c0dc
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
@@ -0,0 +1,37 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
+use std::path::{Component, Path};
+
+use super::PATH_BUF_PUSH_OVERWRITE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
+ if_chain! {
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+ if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
+ if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::PathBuf);
+ if let ExprKind::Lit(ref lit) = arg.kind;
+ if let LitKind::Str(ref path_lit, _) = lit.node;
+ if let pushed_path = Path::new(path_lit.as_str());
+ if let Some(pushed_path_lit) = pushed_path.to_str();
+ if pushed_path.has_root();
+ if let Some(root) = pushed_path.components().next();
+ if root == Component::RootDir;
+ then {
+ span_lint_and_sugg(
+ cx,
+ PATH_BUF_PUSH_OVERWRITE,
+ lit.span,
+ "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition",
+ "try",
+ format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
new file mode 100644
index 000000000..867a3b402
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
@@ -0,0 +1,34 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::source::snippet;
+use clippy_utils::{higher, SpanlessEq};
+use clippy_utils::{is_integer_const, is_trait_method};
+use if_chain::if_chain;
+use rustc_hir::{Expr, ExprKind, QPath};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::RANGE_ZIP_WITH_LEN;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, zip_arg: &'tcx Expr<'_>) {
+ if_chain! {
+ if is_trait_method(cx, expr, sym::Iterator);
+ // range expression in `.zip()` call: `0..x.len()`
+ if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
+ if is_integer_const(cx, start, 0);
+ // `.len()` call
+ if let ExprKind::MethodCall(len_path, len_recv, [], _) = end.kind;
+ if len_path.ident.name == sym::len;
+ // `.iter()` and `.len()` called on same `Path`
+ if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind;
+ if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_recv.kind;
+ if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments);
+ then {
+ span_lint(cx,
+ RANGE_ZIP_WITH_LEN,
+ expr.span,
+ &format!("it is more idiomatic to use `{}.iter().enumerate()`",
+ snippet(cx, recv.span, "_"))
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
new file mode 100644
index 000000000..0a14f9216
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
@@ -0,0 +1,52 @@
+use clippy_utils::consts::{constant_context, Constant};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::REPEAT_ONCE;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ recv: &'tcx Expr<'_>,
+ repeat_arg: &'tcx Expr<'_>,
+) {
+ if constant_context(cx, cx.typeck_results()).expr(repeat_arg) == Some(Constant::Int(1)) {
+ let ty = cx.typeck_results().expr_ty(recv).peel_refs();
+ if ty.is_str() {
+ span_lint_and_sugg(
+ cx,
+ REPEAT_ONCE,
+ expr.span,
+ "calling `repeat(1)` on str",
+ "consider using `.to_string()` instead",
+ format!("{}.to_string()", snippet(cx, recv.span, r#""...""#)),
+ Applicability::MachineApplicable,
+ );
+ } else if ty.builtin_index().is_some() {
+ span_lint_and_sugg(
+ cx,
+ REPEAT_ONCE,
+ expr.span,
+ "calling `repeat(1)` on slice",
+ "consider using `.to_vec()` instead",
+ format!("{}.to_vec()", snippet(cx, recv.span, r#""...""#)),
+ Applicability::MachineApplicable,
+ );
+ } else if is_type_diagnostic_item(cx, ty, sym::String) {
+ span_lint_and_sugg(
+ cx,
+ REPEAT_ONCE,
+ expr.span,
+ "calling `repeat(1)` on a string literal",
+ "consider using `.clone()` instead",
+ format!("{}.clone()", snippet(cx, recv.span, r#""...""#)),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
index 7572ba3fe..324c9c17b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
@@ -30,10 +30,7 @@ pub(super) fn check<'tcx>(
let option_check_method = if is_some { "is_some" } else { "is_none" };
// lint if caller of search is an Iterator
if is_trait_method(cx, is_some_recv, sym::Iterator) {
- let msg = format!(
- "called `{}()` after searching an `Iterator` with `{}`",
- option_check_method, search_method
- );
+ let msg = format!("called `{option_check_method}()` after searching an `Iterator` with `{search_method}`");
let search_snippet = snippet(cx, search_arg.span, "..");
if search_snippet.lines().count() <= 1 {
// suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
@@ -86,8 +83,7 @@ pub(super) fn check<'tcx>(
&msg,
"use `!_.any()` instead",
format!(
- "!{}.any({})",
- iter,
+ "!{iter}.any({})",
any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
),
applicability,
@@ -119,7 +115,7 @@ pub(super) fn check<'tcx>(
if is_string_or_str_slice(search_recv);
if is_string_or_str_slice(search_arg);
then {
- let msg = format!("called `{}()` after calling `find()` on a string", option_check_method);
+ let msg = format!("called `{option_check_method}()` after calling `find()` on a string");
match option_check_method {
"is_some" => {
let mut applicability = Applicability::MachineApplicable;
@@ -130,7 +126,7 @@ pub(super) fn check<'tcx>(
method_span.with_hi(expr.span.hi()),
&msg,
"use `contains()` instead",
- format!("contains({})", find_arg),
+ format!("contains({find_arg})"),
applicability,
);
},
@@ -144,7 +140,7 @@ pub(super) fn check<'tcx>(
expr.span,
&msg,
"use `!_.contains()` instead",
- format!("!{}.contains({})", string, find_arg),
+ format!("!{string}.contains({find_arg})"),
applicability,
);
},
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs
index 9a5fabcf7..81450fd8c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs
@@ -3,12 +3,12 @@ use clippy_utils::{match_def_path, paths};
use rustc_hir as hir;
use rustc_lint::LateContext;
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
- single_char_push_string::check(cx, expr, args);
+ single_char_push_string::check(cx, expr, receiver, args);
} else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) {
- single_char_insert_string::check(cx, expr, args);
+ single_char_insert_string::check(cx, expr, receiver, args);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs
index 6cdc954c0..44a7ad394 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs
@@ -8,13 +8,13 @@ use rustc_lint::LateContext;
use super::SINGLE_CHAR_ADD_STR;
/// lint for length-1 `str`s as argument for `insert_str`
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
let mut applicability = Applicability::MachineApplicable;
- if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) {
+ if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
let base_string_snippet =
- snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability);
- let pos_arg = snippet_with_applicability(cx, args[1].span, "..", &mut applicability);
- let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string);
+ snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability);
+ let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
+ let sugg = format!("{base_string_snippet}.insert({pos_arg}, {extension_string})");
span_lint_and_sugg(
cx,
SINGLE_CHAR_ADD_STR,
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
index bf9006c69..4221c52d5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
@@ -10,37 +10,43 @@ use rustc_span::symbol::Symbol;
use super::SINGLE_CHAR_PATTERN;
const PATTERN_METHODS: [(&str, usize); 24] = [
- ("contains", 1),
- ("starts_with", 1),
- ("ends_with", 1),
- ("find", 1),
- ("rfind", 1),
- ("split", 1),
- ("split_inclusive", 1),
- ("rsplit", 1),
- ("split_terminator", 1),
- ("rsplit_terminator", 1),
- ("splitn", 2),
- ("rsplitn", 2),
- ("split_once", 1),
- ("rsplit_once", 1),
- ("matches", 1),
- ("rmatches", 1),
- ("match_indices", 1),
- ("rmatch_indices", 1),
- ("strip_prefix", 1),
- ("strip_suffix", 1),
- ("trim_start_matches", 1),
- ("trim_end_matches", 1),
- ("replace", 1),
- ("replacen", 1),
+ ("contains", 0),
+ ("starts_with", 0),
+ ("ends_with", 0),
+ ("find", 0),
+ ("rfind", 0),
+ ("split", 0),
+ ("split_inclusive", 0),
+ ("rsplit", 0),
+ ("split_terminator", 0),
+ ("rsplit_terminator", 0),
+ ("splitn", 1),
+ ("rsplitn", 1),
+ ("split_once", 0),
+ ("rsplit_once", 0),
+ ("matches", 0),
+ ("rmatches", 0),
+ ("match_indices", 0),
+ ("rmatch_indices", 0),
+ ("strip_prefix", 0),
+ ("strip_suffix", 0),
+ ("trim_start_matches", 0),
+ ("trim_end_matches", 0),
+ ("replace", 0),
+ ("replacen", 0),
];
/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
-pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ _expr: &hir::Expr<'_>,
+ method_name: Symbol,
+ receiver: &hir::Expr<'_>,
+ args: &[hir::Expr<'_>],
+) {
for &(method, pos) in &PATTERN_METHODS {
if_chain! {
- if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(&args[0]).kind();
+ if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind();
if *ty.kind() == ty::Str;
if method_name.as_str() == method && args.len() > pos;
let arg = &args[pos];
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs
index 0237d39cb..0698bd6a0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs
@@ -8,12 +8,12 @@ use rustc_lint::LateContext;
use super::SINGLE_CHAR_ADD_STR;
/// lint for length-1 `str`s as argument for `push_str`
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
let mut applicability = Applicability::MachineApplicable;
- if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
+ if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) {
let base_string_snippet =
- snippet_with_applicability(cx, args[0].span.source_callsite(), "..", &mut applicability);
- let sugg = format!("{}.push({})", base_string_snippet, extension_string);
+ snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability);
+ let sugg = format!("{base_string_snippet}.push({extension_string})");
span_lint_and_sugg(
cx,
SINGLE_CHAR_ADD_STR,
diff --git a/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
new file mode 100644
index 000000000..09c8ca4cb
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
@@ -0,0 +1,31 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_slice_of_primitives;
+use clippy_utils::source::snippet_with_context;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+
+use super::STABLE_SORT_PRIMITIVE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && cx.tcx.type_of(impl_id).is_slice()
+ && let Some(slice_type) = is_slice_of_primitives(cx, recv)
+ {
+ span_lint_and_then(
+ cx,
+ STABLE_SORT_PRIMITIVE,
+ e.span,
+ &format!("used `sort` on primitive type `{slice_type}`"),
+ |diag| {
+ let mut app = Applicability::MachineApplicable;
+ let recv_snip = snippet_with_context(cx, recv.span, e.span.ctxt(), "..", &mut app).0;
+ diag.span_suggestion(e.span, "try", format!("{recv_snip}.sort_unstable()"), app);
+ diag.note(
+ "an unstable sort typically performs faster without any observable difference for this data type",
+ );
+ },
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 4ac738272..1acac5914 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -2,11 +2,11 @@ use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet_with_context;
use clippy_utils::usage::local_used_after_expr;
-use clippy_utils::visitors::expr_visitor;
+use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
use clippy_utils::{is_diag_item_method, match_def_path, meets_msrv, msrvs, path_to_local_id, paths};
+use core::ops::ControlFlow;
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::intravisit::Visitor;
use rustc_hir::{
BindingAnnotation, Expr, ExprKind, HirId, LangItem, Local, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind,
};
@@ -130,7 +130,7 @@ fn check_manual_split_once_indirect(
let ctxt = expr.span.ctxt();
let mut parents = cx.tcx.hir().parent_iter(expr.hir_id);
if let (_, Node::Local(local)) = parents.next()?
- && let PatKind::Binding(BindingAnnotation::Mutable, iter_binding_id, iter_ident, None) = local.pat.kind
+ && let PatKind::Binding(BindingAnnotation::MUT, iter_binding_id, iter_ident, None) = local.pat.kind
&& let (iter_stmt_id, Node::Stmt(_)) = parents.next()?
&& let (_, Node::Block(enclosing_block)) = parents.next()?
@@ -211,26 +211,23 @@ fn indirect_usage<'tcx>(
binding: HirId,
ctxt: SyntaxContext,
) -> Option<IndirectUsage<'tcx>> {
- if let StmtKind::Local(Local {
- pat:
- Pat {
- kind: PatKind::Binding(BindingAnnotation::Unannotated, _, ident, None),
- ..
- },
+ if let StmtKind::Local(&Local {
+ pat: Pat {
+ kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None),
+ ..
+ },
init: Some(init_expr),
hir_id: local_hir_id,
..
}) = stmt.kind
{
let mut path_to_binding = None;
- expr_visitor(cx, |expr| {
- if path_to_local_id(expr, binding) {
- path_to_binding = Some(expr);
+ let _: Option<!> = for_each_expr_with_closures(cx, init_expr, |e| {
+ if path_to_local_id(e, binding) {
+ path_to_binding = Some(e);
}
-
- path_to_binding.is_none()
- })
- .visit_expr(init_expr);
+ ControlFlow::Continue(Descend::from(path_to_binding.is_none()))
+ });
let mut parents = cx.tcx.hir().parent_iter(path_to_binding?.hir_id);
let iter_usage = parse_iter_usage(cx, ctxt, &mut parents)?;
@@ -251,7 +248,7 @@ fn indirect_usage<'tcx>(
..
} = iter_usage
{
- if parent_id == *local_hir_id {
+ if parent_id == local_hir_id {
return Some(IndirectUsage {
name: ident.name,
span: stmt.span,
@@ -292,9 +289,7 @@ fn parse_iter_usage<'tcx>(
) -> Option<IterUsage> {
let (kind, span) = match iter.next() {
Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
- let (name, args) = if let ExprKind::MethodCall(name, [_, args @ ..], _) = e.kind {
- (name, args)
- } else {
+ let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind else {
return None;
};
let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
@@ -327,7 +322,7 @@ fn parse_iter_usage<'tcx>(
} else {
if_chain! {
if let Some((_, Node::Expr(next_expr))) = iter.next();
- if let ExprKind::MethodCall(next_name, [_], _) = next_expr.kind;
+ if let ExprKind::MethodCall(next_name, _, [], _) = next_expr.kind;
if next_name.ident.name == sym::next;
if next_expr.span.ctxt() == ctxt;
if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id);
@@ -367,7 +362,7 @@ fn parse_iter_usage<'tcx>(
}
},
_ if e.span.ctxt() != ctxt => (None, span),
- ExprKind::MethodCall(name, [_], _)
+ ExprKind::MethodCall(name, _, [], _)
if name.ident.name == sym::unwrap
&& cx
.typeck_results()
diff --git a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
index d06658f2a..6974260f7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
@@ -16,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
return;
}
if let Some(arglists) = method_chain_args(arg, &["chars"]) {
- let target = &arglists[0][0];
+ let target = &arglists[0].0;
let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
let ref_str = if *self_ty.kind() == ty::Str {
""
@@ -34,9 +34,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
"calling `.extend(_.chars())`",
"try this",
format!(
- "{}.push_str({}{})",
+ "{}.push_str({ref_str}{})",
snippet_with_applicability(cx, recv.span, "..", &mut applicability),
- ref_str,
snippet_with_applicability(cx, target.span, "..", &mut applicability)
),
applicability,
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
index 9c3375bf3..851cdf544 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
@@ -15,9 +15,9 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hi
if let Some(def_id) = cx.tcx.hir().opt_local_def_id(closure.hir_id);
if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(def_id);
let closure_body = cx.tcx.hir().body(body_id);
- if !cx.typeck_results().expr_ty(&closure_body.value).is_unit();
+ if !cx.typeck_results().expr_ty(closure_body.value).is_unit();
then {
- if let Some(map_mutated_vars) = mutated_variables(&closure_body.value, cx) {
+ if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) {
// A variable is used mutably inside of the closure. Suppress the lint.
if !map_mutated_vars.is_empty() {
return;
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
index 55567d862..219a9edd6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
@@ -24,10 +24,10 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
}
let (msg, note_msg) = if count == 0 {
- (format!("`{}` called with `0` splits", method_name),
+ (format!("`{method_name}` called with `0` splits"),
"the resulting iterator will always return `None`")
} else {
- (format!("`{}` called with `1` split", method_name),
+ (format!("`{method_name}` called with `1` split"),
if self_ty.is_slice() {
"the resulting iterator will always return the entire slice followed by `None`"
} else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
new file mode 100644
index 000000000..15c1c618c
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
@@ -0,0 +1,36 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_diag_trait_item;
+use clippy_utils::source::snippet_with_context;
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_span::sym;
+
+use super::SUSPICIOUS_TO_OWNED;
+
+pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -> bool {
+ if_chain! {
+ if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+ if is_diag_trait_item(cx, method_def_id, sym::ToOwned);
+ let input_type = cx.typeck_results().expr_ty(expr);
+ if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind();
+ if cx.tcx.is_diagnostic_item(sym::Cow, adt.did());
+ then {
+ let mut app = Applicability::MaybeIncorrect;
+ let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
+ span_lint_and_sugg(
+ cx,
+ SUSPICIOUS_TO_OWNED,
+ expr.span,
+ &format!("this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"),
+ "consider using, depending on intent",
+ format!("{recv_snip}.clone()` or `{recv_snip}.into_owned()"),
+ app,
+ );
+ return true;
+ }
+ }
+ false
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs b/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
index 77d21f1d3..a1c629473 100644
--- a/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_expr_diagnostic_item, ty::is_uninit_value_valid_for_ty};
+use clippy_utils::{is_path_diagnostic_item, ty::is_uninit_value_valid_for_ty};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
if_chain! {
if let hir::ExprKind::Call(callee, args) = recv.kind;
if args.is_empty();
- if is_expr_diagnostic_item(cx, callee, sym::maybe_uninit_uninit);
+ if is_path_diagnostic_item(cx, callee, sym::maybe_uninit_uninit);
if !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr));
then {
span_lint(
diff --git a/src/tools/clippy/clippy_lints/src/methods/unit_hash.rs b/src/tools/clippy/clippy_lints/src/methods/unit_hash.rs
new file mode 100644
index 000000000..3c7955bc4
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/unit_hash.rs
@@ -0,0 +1,29 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_trait_method;
+use clippy_utils::source::snippet;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::UNIT_HASH;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
+ if is_trait_method(cx, expr, sym::Hash) && cx.typeck_results().expr_ty(recv).is_unit() {
+ 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, arg.span, ".."),),
+ Applicability::MaybeIncorrect,
+ );
+ diag.note("the implementation of `Hash` for `()` is a no-op");
+ },
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
index bafa6fc58..1cef6226a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -2,9 +2,10 @@ use super::utils::clone_or_copy_needed;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::is_copy;
use clippy_utils::usage::mutated_variables;
-use clippy_utils::{is_lang_ctor, is_trait_method, path_to_local_id};
+use clippy_utils::visitors::{for_each_expr, Descend};
+use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id};
+use core::ops::ControlFlow;
use rustc_hir as hir;
-use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_lint::LateContext;
use rustc_middle::ty;
@@ -13,7 +14,7 @@ use rustc_span::sym;
use super::UNNECESSARY_FILTER_MAP;
use super::UNNECESSARY_FIND_MAP;
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, name: &str) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>, name: &str) {
if !is_trait_method(cx, expr, sym::Iterator) {
return;
}
@@ -21,22 +22,27 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind {
let body = cx.tcx.hir().body(body);
let arg_id = body.params[0].pat.hir_id;
- let mutates_arg =
- mutated_variables(&body.value, cx).map_or(true, |used_mutably| used_mutably.contains(&arg_id));
- let (clone_or_copy_needed, _) = clone_or_copy_needed(cx, body.params[0].pat, &body.value);
+ let mutates_arg = mutated_variables(body.value, cx).map_or(true, |used_mutably| used_mutably.contains(&arg_id));
+ let (clone_or_copy_needed, _) = clone_or_copy_needed(cx, body.params[0].pat, body.value);
- let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, &body.value);
+ let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, body.value);
- let mut return_visitor = ReturnVisitor::new(cx, arg_id);
- return_visitor.visit_expr(&body.value);
- found_mapping |= return_visitor.found_mapping;
- found_filtering |= return_visitor.found_filtering;
+ let _: Option<!> = for_each_expr(body.value, |e| {
+ if let hir::ExprKind::Ret(Some(e)) = &e.kind {
+ let (found_mapping_res, found_filtering_res) = check_expression(cx, arg_id, e);
+ found_mapping |= found_mapping_res;
+ found_filtering |= found_filtering_res;
+ ControlFlow::Continue(Descend::No)
+ } else {
+ ControlFlow::Continue(Descend::Yes)
+ }
+ });
let in_ty = cx.typeck_results().node_type(body.params[0].hir_id);
let sugg = if !found_filtering {
if name == "filter_map" { "map" } else { "map(..).next()" }
} else if !found_mapping && !mutates_arg && (!clone_or_copy_needed || is_copy(cx, in_ty)) {
- match cx.typeck_results().expr_ty(&body.value).kind() {
+ match cx.typeck_results().expr_ty(body.value).kind() {
ty::Adt(adt, subst)
if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) =>
{
@@ -55,22 +61,20 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<
UNNECESSARY_FIND_MAP
},
expr.span,
- &format!("this `.{}` can be written more simply using `.{}`", name, sugg),
+ &format!("this `.{name}` can be written more simply using `.{sugg}`"),
);
}
}
// returns (found_mapping, found_filtering)
fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tcx hir::Expr<'_>) -> (bool, bool) {
- match &expr.kind {
+ match expr.kind {
hir::ExprKind::Call(func, args) => {
- if let hir::ExprKind::Path(ref path) = func.kind {
- if is_lang_ctor(cx, path, OptionSome) {
- if path_to_local_id(&args[0], arg_id) {
- return (false, false);
- }
- return (true, false);
+ if is_res_lang_ctor(cx, path_res(cx, func), OptionSome) {
+ if path_to_local_id(&args[0], arg_id) {
+ return (false, false);
}
+ return (true, false);
}
(true, true)
},
@@ -81,7 +85,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc
hir::ExprKind::Match(_, arms, _) => {
let mut found_mapping = false;
let mut found_filtering = false;
- for arm in *arms {
+ for arm in arms {
let (m, f) = check_expression(cx, arg_id, arm.body);
found_mapping |= m;
found_filtering |= f;
@@ -94,39 +98,9 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc
let else_check = check_expression(cx, arg_id, else_arm);
(if_check.0 | else_check.0, if_check.1 | else_check.1)
},
- hir::ExprKind::Path(path) if is_lang_ctor(cx, path, OptionNone) => (false, true),
+ hir::ExprKind::Path(ref path) if is_res_lang_ctor(cx, cx.qpath_res(path, expr.hir_id), OptionNone) => {
+ (false, true)
+ },
_ => (true, true),
}
}
-
-struct ReturnVisitor<'a, 'tcx> {
- cx: &'a LateContext<'tcx>,
- arg_id: hir::HirId,
- // Found a non-None return that isn't Some(input)
- found_mapping: bool,
- // Found a return that isn't Some
- found_filtering: bool,
-}
-
-impl<'a, 'tcx> ReturnVisitor<'a, 'tcx> {
- fn new(cx: &'a LateContext<'tcx>, arg_id: hir::HirId) -> ReturnVisitor<'a, 'tcx> {
- ReturnVisitor {
- cx,
- arg_id,
- found_mapping: false,
- found_filtering: false,
- }
- }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for ReturnVisitor<'a, 'tcx> {
- fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
- if let hir::ExprKind::Ret(Some(expr)) = &expr.kind {
- let (found_mapping, found_filtering) = check_expression(self.cx, self.arg_id, expr);
- self.found_mapping |= found_mapping;
- self.found_filtering |= found_filtering;
- } else {
- walk_expr(self, expr);
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index c3531d4d0..aa87dead3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -31,7 +31,7 @@ pub(super) fn check(
// Extract the body of the closure passed to fold
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind;
let closure_body = cx.tcx.hir().body(body);
- let closure_expr = peel_blocks(&closure_body.value);
+ let closure_expr = peel_blocks(closure_body.value);
// Check if the closure body is of the form `acc <op> some_expr(x)`
if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind;
@@ -49,15 +49,12 @@ pub(super) fn check(
let mut applicability = Applicability::MachineApplicable;
let sugg = if replacement_has_args {
format!(
- "{replacement}(|{s}| {r})",
- replacement = replacement_method_name,
- s = second_arg_ident,
+ "{replacement_method_name}(|{second_arg_ident}| {r})",
r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability),
)
} else {
format!(
- "{replacement}()",
- replacement = replacement_method_name,
+ "{replacement_method_name}()",
)
};
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
index 19037093e..1966a85f7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -43,7 +43,7 @@ pub fn check_for_loop_iter(
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
then {
let snippet = if_chain! {
- if let ExprKind::MethodCall(maybe_iter_method_name, [collection], _) = receiver.kind;
+ if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind;
if maybe_iter_method_name.ident.name == sym::iter;
if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
@@ -68,7 +68,7 @@ pub fn check_for_loop_iter(
cx,
UNNECESSARY_TO_OWNED,
expr.span,
- &format!("unnecessary use of `{}`", method_name),
+ &format!("unnecessary use of `{method_name}`"),
|diag| {
// If `check_into_iter_call_arg` called `check_for_loop_iter` because a call to
// a `to_owned`-like function was removed, then the next suggestion may be
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 1876c7fb9..0e73459ad 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{eager_or_lazy, usage};
+use clippy_utils::{eager_or_lazy, is_from_proc_macro, usage};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -18,6 +18,10 @@ pub(super) fn check<'tcx>(
arg: &'tcx hir::Expr<'_>,
simplify_using: &str,
) {
+ if is_from_proc_macro(cx, expr) {
+ return;
+ }
+
let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option);
let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
let is_bool = cx.typeck_results().expr_ty(recv).is_bool();
@@ -54,12 +58,12 @@ pub(super) fn check<'tcx>(
// This is a duplicate of what's happening in clippy_lints::methods::method_call,
// which isn't ideal, We want to get the method call span,
// but prefer to avoid changing the signature of the function itself.
- if let hir::ExprKind::MethodCall(_, _, span) = expr.kind {
+ if let hir::ExprKind::MethodCall(.., span) = expr.kind {
span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| {
diag.span_suggestion(
span,
- &format!("use `{}(..)` instead", simplify_using),
- format!("{}({})", simplify_using, snippet(cx, body_expr.span, "..")),
+ &format!("use `{simplify_using}(..)` instead"),
+ format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")),
applicability,
);
});
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
index ea5aadbbc..ed5a75b0f 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -1,51 +1,17 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_trait_method;
use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::ty::implements_trait;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::LateContext;
use rustc_middle::ty::{self, subst::GenericArgKind};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
use rustc_span::symbol::Ident;
use std::iter;
-declare_clippy_lint! {
- /// ### What it does
- /// Detects uses of `Vec::sort_by` passing in a closure
- /// which compares the two arguments, either directly or indirectly.
- ///
- /// ### Why is this bad?
- /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if
- /// possible) than to use `Vec::sort_by` and a more complicated
- /// closure.
- ///
- /// ### Known problems
- /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already
- /// imported by a use statement, then it will need to be added manually.
- ///
- /// ### Example
- /// ```rust
- /// # struct A;
- /// # impl A { fn foo(&self) {} }
- /// # let mut vec: Vec<A> = Vec::new();
- /// vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
- /// ```
- /// Use instead:
- /// ```rust
- /// # struct A;
- /// # impl A { fn foo(&self) {} }
- /// # let mut vec: Vec<A> = Vec::new();
- /// vec.sort_by_key(|a| a.foo());
- /// ```
- #[clippy::version = "1.46.0"]
- pub UNNECESSARY_SORT_BY,
- complexity,
- "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer"
-}
-
-declare_lint_pass!(UnnecessarySortBy => [UNNECESSARY_SORT_BY]);
+use super::UNNECESSARY_SORT_BY;
enum LintTrigger {
Sort(SortDetection),
@@ -54,7 +20,6 @@ enum LintTrigger {
struct SortDetection {
vec_name: String,
- unstable: bool,
}
struct SortByKeyDetection {
@@ -62,7 +27,6 @@ struct SortByKeyDetection {
closure_arg: String,
closure_body: String,
reverse: bool,
- unstable: bool,
}
/// Detect if the two expressions are mirrored (identical, except one
@@ -86,9 +50,13 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident
// The two exprs are method calls.
// Check to see that the function is the same and the arguments are mirrored
// This is enough because the receiver of the method is listed in the arguments
- (ExprKind::MethodCall(left_segment, left_args, _), ExprKind::MethodCall(right_segment, right_args, _)) => {
+ (
+ ExprKind::MethodCall(left_segment, left_receiver, left_args, _),
+ ExprKind::MethodCall(right_segment, right_receiver, right_args, _),
+ ) => {
left_segment.ident == right_segment.ident
&& iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
+ && mirrored_exprs(left_receiver, a_ident, right_receiver, b_ident)
},
// Two tuples with mirrored contents
(ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => {
@@ -150,20 +118,20 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident
}
}
-fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
+fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) -> Option<LintTrigger> {
if_chain! {
- if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind;
- if let name = name_ident.ident.name.to_ident_string();
- if name == "sort_by" || name == "sort_unstable_by";
- if let [vec, Expr { kind: ExprKind::Closure(Closure { body: closure_body_id, .. }), .. }] = args;
- if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::Vec);
- if let closure_body = cx.tcx.hir().body(*closure_body_id);
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+ if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
+ if cx.tcx.type_of(impl_id).is_slice();
+ if let ExprKind::Closure(&Closure { body, .. }) = arg.kind;
+ if let closure_body = cx.tcx.hir().body(body);
if let &[
Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
] = &closure_body.params;
- if let ExprKind::MethodCall(method_path, [ref left_expr, ref right_expr], _) = &closure_body.value.kind;
+ if let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind;
if method_path.ident.name == sym::cmp;
+ if is_trait_method(cx, closure_body.value, sym::Ord);
then {
let (closure_body, closure_arg, reverse) = if mirrored_exprs(
left_expr,
@@ -177,19 +145,18 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
} else {
return None;
};
- let vec_name = Sugg::hir(cx, &args[0], "..").to_string();
- let unstable = name == "sort_unstable_by";
+ let vec_name = Sugg::hir(cx, recv, "..").to_string();
if_chain! {
- if let ExprKind::Path(QPath::Resolved(_, Path {
- segments: [PathSegment { ident: left_name, .. }], ..
- })) = &left_expr.kind;
- if left_name == left_ident;
- if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| {
- implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])
- });
+ if let ExprKind::Path(QPath::Resolved(_, Path {
+ segments: [PathSegment { ident: left_name, .. }], ..
+ })) = &left_expr.kind;
+ if left_name == left_ident;
+ if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| {
+ implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])
+ });
then {
- return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }));
+ return Some(LintTrigger::Sort(SortDetection { vec_name }));
}
}
@@ -199,7 +166,6 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
closure_arg,
closure_body,
reverse,
- unstable,
}));
}
}
@@ -213,46 +179,50 @@ fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
}
-impl LateLintPass<'_> for UnnecessarySortBy {
- fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- match detect_lint(cx, expr) {
- Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg(
- cx,
- UNNECESSARY_SORT_BY,
- expr.span,
- "use Vec::sort_by_key here instead",
- "try",
- format!(
- "{}.sort{}_by_key(|{}| {})",
- trigger.vec_name,
- if trigger.unstable { "_unstable" } else { "" },
- trigger.closure_arg,
- if trigger.reverse {
- format!("std::cmp::Reverse({})", trigger.closure_body)
- } else {
- trigger.closure_body.to_string()
- },
- ),
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ recv: &'tcx Expr<'_>,
+ arg: &'tcx Expr<'_>,
+ is_unstable: bool,
+) {
+ match detect_lint(cx, expr, recv, arg) {
+ Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg(
+ cx,
+ UNNECESSARY_SORT_BY,
+ expr.span,
+ "use Vec::sort_by_key here instead",
+ "try",
+ format!(
+ "{}.sort{}_by_key(|{}| {})",
+ trigger.vec_name,
+ if is_unstable { "_unstable" } else { "" },
+ trigger.closure_arg,
if trigger.reverse {
- Applicability::MaybeIncorrect
+ format!("std::cmp::Reverse({})", trigger.closure_body)
} else {
- Applicability::MachineApplicable
+ trigger.closure_body.to_string()
},
),
- Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg(
- cx,
- UNNECESSARY_SORT_BY,
- expr.span,
- "use Vec::sort here instead",
- "try",
- format!(
- "{}.sort{}()",
- trigger.vec_name,
- if trigger.unstable { "_unstable" } else { "" },
- ),
- Applicability::MachineApplicable,
+ if trigger.reverse {
+ Applicability::MaybeIncorrect
+ } else {
+ Applicability::MachineApplicable
+ },
+ ),
+ Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg(
+ cx,
+ UNNECESSARY_SORT_BY,
+ expr.span,
+ "use Vec::sort here instead",
+ "try",
+ format!(
+ "{}.sort{}()",
+ trigger.vec_name,
+ if is_unstable { "_unstable" } else { "" },
),
- None => {},
- }
+ Applicability::MachineApplicable,
+ ),
+ None => {},
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index b3276f139..3566fe9a0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -2,21 +2,23 @@ use super::implicit_clone::is_clone_like;
use super::unnecessary_iter_cloned::{self, is_into_iter};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{
- contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs,
-};
+use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
+use clippy_utils::visitors::find_all_ret_expressions;
+use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
use clippy_utils::{meets_msrv, msrvs};
-
-use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item};
use rustc_errors::Applicability;
-use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind};
+use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node};
+use rustc_hir_typeck::{FnCtxt, Inherited};
+use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
+use rustc_middle::ty::EarlyBinder;
+use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
use rustc_semver::RustcVersion;
use rustc_span::{sym, Symbol};
+use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
use std::cmp::max;
use super::UNNECESSARY_TO_OWNED;
@@ -25,16 +27,17 @@ pub fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'tcx>,
method_name: Symbol,
- args: &'tcx [Expr<'tcx>],
+ receiver: &'tcx Expr<'_>,
+ args: &'tcx [Expr<'_>],
msrv: Option<RustcVersion>,
) {
if_chain! {
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if let [receiver] = args;
+ if args.is_empty();
then {
if is_cloned_or_copied(cx, method_name, method_def_id) {
unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
- } else if is_to_owned_like(cx, method_name, method_def_id) {
+ } else if is_to_owned_like(cx, expr, method_name, method_def_id) {
// At this point, we know the call is of a `to_owned`-like function. The functions
// `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary
// based on its context, that is, whether it is a referent in an `AddrOf` expression, an
@@ -129,12 +132,11 @@ fn check_addr_of_expr(
cx,
UNNECESSARY_TO_OWNED,
parent.span,
- &format!("unnecessary use of `{}`", method_name),
+ &format!("unnecessary use of `{method_name}`"),
"use",
format!(
- "{:&>width$}{}",
+ "{:&>width$}{receiver_snippet}",
"",
- receiver_snippet,
width = n_target_refs - n_receiver_refs
),
Applicability::MachineApplicable,
@@ -151,7 +153,7 @@ fn check_addr_of_expr(
cx,
UNNECESSARY_TO_OWNED,
parent.span,
- &format!("unnecessary use of `{}`", method_name),
+ &format!("unnecessary use of `{method_name}`"),
"use",
receiver_snippet,
Applicability::MachineApplicable,
@@ -161,7 +163,7 @@ fn check_addr_of_expr(
cx,
UNNECESSARY_TO_OWNED,
expr.span.with_lo(receiver.span.hi()),
- &format!("unnecessary use of `{}`", method_name),
+ &format!("unnecessary use of `{method_name}`"),
"remove this",
String::new(),
Applicability::MachineApplicable,
@@ -178,9 +180,9 @@ fn check_addr_of_expr(
cx,
UNNECESSARY_TO_OWNED,
parent.span,
- &format!("unnecessary use of `{}`", method_name),
+ &format!("unnecessary use of `{method_name}`"),
"use",
- format!("{}.as_ref()", receiver_snippet),
+ format!("{receiver_snippet}.as_ref()"),
Applicability::MachineApplicable,
);
return true;
@@ -225,9 +227,9 @@ fn check_into_iter_call_arg(
cx,
UNNECESSARY_TO_OWNED,
parent.span,
- &format!("unnecessary use of `{}`", method_name),
+ &format!("unnecessary use of `{method_name}`"),
"use",
- format!("{}.iter().{}()", receiver_snippet, cloned_or_copied),
+ format!("{receiver_snippet}.iter().{cloned_or_copied}()"),
Applicability::MaybeIncorrect,
);
return true;
@@ -246,12 +248,12 @@ fn check_other_call_arg<'tcx>(
) -> bool {
if_chain! {
if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
- if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, maybe_call);
+ if let Some((callee_def_id, _, recv, call_args)) = get_callee_substs_and_args(cx, maybe_call);
let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
- if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id);
+ if let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id);
if let Some(input) = fn_sig.inputs().get(i);
let (input, n_refs) = peel_mid_ty_refs(*input);
- if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input);
+ if let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input);
if let Some(sized_def_id) = cx.tcx.lang_items().sized_trait();
if let [trait_predicate] = trait_predicates
.iter()
@@ -259,49 +261,22 @@ fn check_other_call_arg<'tcx>(
.collect::<Vec<_>>()[..];
if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef);
+ if trait_predicate.def_id() == deref_trait_id || trait_predicate.def_id() == as_ref_trait_id;
let receiver_ty = cx.typeck_results().expr_ty(receiver);
- // If the callee has type parameters, they could appear in `projection_predicate.ty` or the
- // types of `trait_predicate.trait_ref.substs`.
- if if trait_predicate.def_id() == deref_trait_id {
- if let [projection_predicate] = projection_predicates[..] {
- let normalized_ty =
- cx.tcx
- .subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
- implements_trait(cx, receiver_ty, deref_trait_id, &[])
- && get_associated_type(cx, receiver_ty, deref_trait_id, "Target")
- .map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty)
- } else {
- false
- }
- } else if trait_predicate.def_id() == as_ref_trait_id {
- let composed_substs = compose_substs(
- cx,
- &trait_predicate.trait_ref.substs.iter().skip(1).collect::<Vec<_>>()[..],
- call_substs,
- );
- implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs)
- } else {
- false
- };
+ if can_change_type(cx, maybe_arg, receiver_ty);
// We can't add an `&` when the trait is `Deref` because `Target = &T` won't match
// `Target = T`.
if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id;
- let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 });
- // If the trait is `AsRef` and the input type variable `T` occurs in the output type, then
- // `T` must not be instantiated with a reference
- // (https://github.com/rust-lang/rust-clippy/issues/8507).
- if (n_refs == 0 && !receiver_ty.is_ref())
- || trait_predicate.def_id() != as_ref_trait_id
- || !contains_ty(fn_sig.output(), input);
+ let n_refs = max(n_refs, usize::from(!is_copy(cx, receiver_ty)));
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
then {
span_lint_and_sugg(
cx,
UNNECESSARY_TO_OWNED,
maybe_arg.span,
- &format!("unnecessary use of `{}`", method_name),
+ &format!("unnecessary use of `{method_name}`"),
"use",
- format!("{:&>width$}{}", "", receiver_snippet, width = n_refs),
+ format!("{:&>n_refs$}{receiver_snippet}", ""),
Applicability::MachineApplicable,
);
return true;
@@ -331,22 +306,22 @@ fn skip_addr_of_ancestors<'tcx>(
fn get_callee_substs_and_args<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'tcx>,
-) -> Option<(DefId, SubstsRef<'tcx>, &'tcx [Expr<'tcx>])> {
+) -> Option<(DefId, SubstsRef<'tcx>, Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>])> {
if_chain! {
if let ExprKind::Call(callee, args) = expr.kind;
let callee_ty = cx.typeck_results().expr_ty(callee);
if let ty::FnDef(callee_def_id, _) = callee_ty.kind();
then {
let substs = cx.typeck_results().node_substs(callee.hir_id);
- return Some((*callee_def_id, substs, args));
+ return Some((*callee_def_id, substs, None, args));
}
}
if_chain! {
- if let ExprKind::MethodCall(_, args, _) = expr.kind;
+ if let ExprKind::MethodCall(_, recv, args, _) = expr.kind;
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
then {
let substs = cx.typeck_results().node_substs(expr.hir_id);
- return Some((method_def_id, substs, args));
+ return Some((method_def_id, substs, Some(recv), args));
}
}
None
@@ -360,25 +335,15 @@ fn get_input_traits_and_projections<'tcx>(
) -> (Vec<TraitPredicate<'tcx>>, Vec<ProjectionPredicate<'tcx>>) {
let mut trait_predicates = Vec::new();
let mut projection_predicates = Vec::new();
- for (predicate, _) in cx.tcx.predicates_of(callee_def_id).predicates.iter() {
- // `substs` should have 1 + n elements. The first is the type on the left hand side of an
- // `as`. The remaining n are trait parameters.
- let is_input_substs = |substs: SubstsRef<'tcx>| {
- if_chain! {
- if let Some(arg) = substs.iter().next();
- if let GenericArgKind::Type(arg_ty) = arg.unpack();
- if arg_ty == input;
- then { true } else { false }
- }
- };
+ for predicate in cx.tcx.param_env(callee_def_id).caller_bounds() {
match predicate.kind().skip_binder() {
PredicateKind::Trait(trait_predicate) => {
- if is_input_substs(trait_predicate.trait_ref.substs) {
+ if trait_predicate.trait_ref.self_ty() == input {
trait_predicates.push(trait_predicate);
}
},
PredicateKind::Projection(projection_predicate) => {
- if is_input_substs(projection_predicate.projection_ty.substs) {
+ if projection_predicate.projection_ty.self_ty() == input {
projection_predicates.push(projection_predicate);
}
},
@@ -388,22 +353,105 @@ fn get_input_traits_and_projections<'tcx>(
(trait_predicates, projection_predicates)
}
-/// Composes two substitutions by applying the latter to the types of the former.
-fn compose_substs<'tcx>(
- cx: &LateContext<'tcx>,
- left: &[GenericArg<'tcx>],
- right: SubstsRef<'tcx>,
-) -> Vec<GenericArg<'tcx>> {
- left.iter()
- .map(|arg| {
- if let GenericArgKind::Type(arg_ty) = arg.unpack() {
- let normalized_ty = cx.tcx.subst_and_normalize_erasing_regions(right, cx.param_env, arg_ty);
- GenericArg::from(normalized_ty)
- } else {
- *arg
+fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<'a>) -> bool {
+ for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
+ match node {
+ Node::Stmt(_) => return true,
+ Node::Block(..) => continue,
+ Node::Item(item) => {
+ if let ItemKind::Fn(_, _, body_id) = &item.kind
+ && let output_ty = return_ty(cx, item.hir_id())
+ && let local_def_id = cx.tcx.hir().local_def_id(item.hir_id())
+ && Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
+ let fn_ctxt = FnCtxt::new(inherited, cx.param_env, item.hir_id());
+ fn_ctxt.can_coerce(ty, output_ty)
+ }) {
+ if has_lifetime(output_ty) && has_lifetime(ty) {
+ return false;
+ }
+ let body = cx.tcx.hir().body(*body_id);
+ let body_expr = &body.value;
+ let mut count = 0;
+ return find_all_ret_expressions(cx, body_expr, |_| { count += 1; count <= 1 });
+ }
}
- })
- .collect()
+ Node::Expr(parent_expr) => {
+ if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr)
+ {
+ if cx.tcx.lang_items().require(LangItem::IntoFutureIntoFuture) == Ok(callee_def_id) {
+ return false;
+ }
+
+ let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+ if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
+ && let Some(param_ty) = fn_sig.inputs().get(arg_index)
+ && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind()
+ {
+ if fn_sig
+ .inputs()
+ .iter()
+ .enumerate()
+ .filter(|(i, _)| *i != arg_index)
+ .any(|(_, ty)| ty.contains(*param_ty))
+ {
+ return false;
+ }
+
+ let mut trait_predicates = cx.tcx.param_env(callee_def_id)
+ .caller_bounds().iter().filter(|predicate| {
+ if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder()
+ && trait_predicate.trait_ref.self_ty() == *param_ty {
+ true
+ } else {
+ false
+ }
+ });
+
+ let new_subst = cx.tcx.mk_substs(
+ call_substs.iter()
+ .enumerate()
+ .map(|(i, t)|
+ if i == (*param_index as usize) {
+ GenericArg::from(ty)
+ } else {
+ t
+ }));
+
+ if trait_predicates.any(|predicate| {
+ let predicate = EarlyBinder(predicate).subst(cx.tcx, new_subst);
+ let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate);
+ !cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation)
+ }) {
+ return false;
+ }
+
+ let output_ty = fn_sig.output();
+ if output_ty.contains(*param_ty) {
+ if let Ok(new_ty) = cx.tcx.try_subst_and_normalize_erasing_regions(
+ new_subst, cx.param_env, output_ty) {
+ expr = parent_expr;
+ ty = new_ty;
+ continue;
+ }
+ return false;
+ }
+
+ return true;
+ }
+ } else if let ExprKind::Block(..) = parent_expr.kind {
+ continue;
+ }
+ return false;
+ },
+ _ => return false,
+ }
+ }
+
+ false
+}
+
+fn has_lifetime(ty: Ty<'_>) -> bool {
+ ty.walk().any(|t| matches!(t.unpack(), GenericArgKind::Lifetime(_)))
}
/// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`.
@@ -414,10 +462,10 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id:
/// Returns true if the named method can be used to convert the receiver to its "owned"
/// representation.
-fn is_to_owned_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
+fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool {
is_clone_like(cx, method_name.as_str(), method_def_id)
|| is_cow_into_owned(cx, method_name, method_def_id)
- || is_to_string(cx, method_name, method_def_id)
+ || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id)
}
/// Returns true if the named method is `Cow::into_owned`.
@@ -425,7 +473,27 @@ fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: D
method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow)
}
-/// Returns true if the named method is `ToString::to_string`.
-fn is_to_string(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
- method_name == sym::to_string && is_diag_trait_item(cx, method_def_id, sym::ToString)
+/// Returns true if the named method is `ToString::to_string` and it's called on a type that
+/// is string-like i.e. implements `AsRef<str>` or `Deref<str>`.
+fn is_to_string_on_string_like<'a>(
+ cx: &LateContext<'_>,
+ call_expr: &'a Expr<'a>,
+ method_name: Symbol,
+ method_def_id: DefId,
+) -> bool {
+ if method_name != sym::to_string || !is_diag_trait_item(cx, method_def_id, sym::ToString) {
+ return false;
+ }
+
+ if let Some(substs) = cx.typeck_results().node_substs_opt(call_expr.hir_id)
+ && let [generic_arg] = substs.as_slice()
+ && let GenericArgKind::Type(ty) = generic_arg.unpack()
+ && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
+ && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
+ && (implements_trait(cx, ty, deref_trait_id, &[cx.tcx.types.str_.into()]) ||
+ implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) {
+ true
+ } else {
+ false
+ }
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs
index f3af281d6..045f739e6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs
@@ -5,10 +5,11 @@ use clippy_utils::{
diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability,
ty::is_type_diagnostic_item,
};
+use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_span::{sym, symbol};
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
@@ -25,7 +26,7 @@ pub(super) fn check<'tcx>(
if_chain! {
if is_option || is_result;
- if is_default_equivalent_call(cx, u_arg);
+ if closure_body_returns_empty_to_string(cx, u_arg) || is_default_equivalent_call(cx, u_arg);
then {
let mut applicability = Applicability::MachineApplicable;
@@ -44,3 +45,22 @@ pub(super) fn check<'tcx>(
}
}
}
+
+fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
+ if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
+ let body = cx.tcx.hir().body(body);
+
+ if body.params.is_empty()
+ && let hir::Expr{ kind, .. } = &body.value
+ && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind
+ && ident == &symbol::Ident::from_str("to_string")
+ && let hir::Expr{ kind, .. } = self_arg
+ && let hir::ExprKind::Lit(lit) = kind
+ && let LitKind::Str(symbol::kw::Empty, _) = lit.node
+ {
+ return true;
+ }
+ }
+
+ false
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
index 5c7610149..ee17f2d78 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
@@ -1,40 +1,53 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_in_test_function;
use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_in_test_function, is_lint_allowed};
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::sym;
-use super::UNWRAP_USED;
+use super::{EXPECT_USED, UNWRAP_USED};
-/// lint use of `unwrap()` for `Option`s and `Result`s
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) {
+/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`.
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ expr: &hir::Expr<'_>,
+ recv: &hir::Expr<'_>,
+ is_err: bool,
+ allow_unwrap_in_tests: bool,
+) {
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
- let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
- Some((UNWRAP_USED, "an Option", "None"))
+ let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
+ Some((UNWRAP_USED, "an Option", "None", ""))
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
- Some((UNWRAP_USED, "a Result", "Err"))
+ Some((UNWRAP_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an "))
} else {
None
};
+ let method_suffix = if is_err { "_err" } else { "" };
+
if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
return;
}
- if let Some((lint, kind, none_value)) = mess {
+ if let Some((lint, kind, none_value, none_prefix)) = mess {
+ let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
+ format!(
+ "if you don't want to handle the `{none_value}` case gracefully, consider \
+ using `expect{method_suffix}()` to provide a better panic message"
+ )
+ } else {
+ format!("if this value is {none_prefix}`{none_value}`, it will panic")
+ };
+
span_lint_and_help(
cx,
lint,
expr.span,
- &format!("used `unwrap()` on `{}` value", kind,),
+ &format!("used `unwrap{method_suffix}()` on `{kind}` value"),
None,
- &format!(
- "if you don't want to handle the `{}` case gracefully, consider \
- using `expect()` to provide a better panic message",
- none_value,
- ),
+ &help,
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index ca5d33ee8..c1139d84e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -1,11 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::walk_ptrs_ty_depth;
-use clippy_utils::{get_parent_expr, match_trait_method, paths};
+use clippy_utils::{get_parent_expr, is_trait_method};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
+use rustc_span::sym;
use super::USELESS_ASREF;
@@ -13,7 +14,7 @@ use super::USELESS_ASREF;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, recvr: &hir::Expr<'_>) {
// when we get here, we've already checked that the call name is "as_ref" or "as_mut"
// check if the call is to the actual `AsRef` or `AsMut` trait
- if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) {
+ if is_trait_method(cx, expr, sym::AsRef) || is_trait_method(cx, expr, sym::AsMut) {
// check if the type after `as_ref` or `as_mut` is the same as before
let rcv_ty = cx.typeck_results().expr_ty(recvr);
let res_ty = cx.typeck_results().expr_ty(expr);
@@ -35,7 +36,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
cx,
USELESS_ASREF,
expr.span,
- &format!("this call to `{}` does nothing", call_name),
+ &format!("this call to `{call_name}` does nothing"),
"try this",
snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(),
applicability,
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index 3015531e8..ae6b165fd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -28,7 +28,7 @@ pub(super) fn derefs_to_slice<'tcx>(
}
}
- if let hir::ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind {
+ if let hir::ExprKind::MethodCall(path, self_arg, ..) = &expr.kind {
if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(self_arg)) {
Some(self_arg)
} else {
@@ -139,9 +139,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
self.addr_of_exprs.push(parent);
return;
},
- ExprKind::MethodCall(_, args, _) => {
+ ExprKind::MethodCall(.., args, _) => {
if_chain! {
- if args.iter().skip(1).all(|arg| !self.is_binding(arg));
+ if args.iter().all(|arg| !self.is_binding(arg));
if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id);
let method_ty = self.cx.tcx.type_of(method_def_id);
let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder();
diff --git a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
new file mode 100644
index 000000000..02d8364cb
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
@@ -0,0 +1,45 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::is_type_diagnostic_item;
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::source_map::Spanned;
+use rustc_span::{sym, Span};
+
+use super::VEC_RESIZE_TO_ZERO;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ count_arg: &'tcx Expr<'_>,
+ default_arg: &'tcx Expr<'_>,
+ name_span: Span,
+) {
+ if_chain! {
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+ if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
+ if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Vec);
+ if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = count_arg.kind;
+ if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = default_arg.kind;
+ then {
+ let method_call_span = expr.span.with_lo(name_span.lo());
+ span_lint_and_then(
+ cx,
+ VEC_RESIZE_TO_ZERO,
+ expr.span,
+ "emptying a vector with `resize`",
+ |db| {
+ db.help("the arguments may be inverted...");
+ db.span_suggestion(
+ method_call_span,
+ "...or you can empty the vector with",
+ "clear()".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
new file mode 100644
index 000000000..2fe5ae9a9
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
@@ -0,0 +1,28 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_trait_method;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_hir::{Expr, ExprKind, QPath};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::VERBOSE_FILE_READS;
+
+pub(super) const READ_TO_END_MSG: (&str, &str) = ("use of `File::read_to_end`", "consider using `fs::read` instead");
+pub(super) const READ_TO_STRING_MSG: (&str, &str) = (
+ "use of `File::read_to_string`",
+ "consider using `fs::read_to_string` instead",
+);
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ recv: &'tcx Expr<'_>,
+ (msg, help): (&str, &str),
+) {
+ if is_trait_method(cx, expr, sym::IoRead)
+ && matches!(recv.kind, ExprKind::Path(QPath::Resolved(None, _)))
+ && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(recv).peel_refs(), sym::File)
+ {
+ span_lint_and_help(cx, VERBOSE_FILE_READS, expr.span, msg, None, help);
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
index 4b368d3ff..1fbf783b8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
@@ -61,20 +61,20 @@ impl Convention {
impl fmt::Display for Convention {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match *self {
- Self::Eq(this) => format!("`{}`", this).fmt(f),
- Self::StartsWith(this) => format!("`{}*`", this).fmt(f),
- Self::EndsWith(this) => format!("`*{}`", this).fmt(f),
- Self::NotEndsWith(this) => format!("`~{}`", this).fmt(f),
+ Self::Eq(this) => format!("`{this}`").fmt(f),
+ Self::StartsWith(this) => format!("`{this}*`").fmt(f),
+ Self::EndsWith(this) => format!("`*{this}`").fmt(f),
+ Self::NotEndsWith(this) => format!("`~{this}`").fmt(f),
Self::IsSelfTypeCopy(is_true) => {
format!("`self` type is{} `Copy`", if is_true { "" } else { " not" }).fmt(f)
},
Self::ImplementsTrait(is_true) => {
let (negation, s_suffix) = if is_true { ("", "s") } else { (" does not", "") };
- format!("method{} implement{} a trait", negation, s_suffix).fmt(f)
+ format!("method{negation} implement{s_suffix} a trait").fmt(f)
},
Self::IsTraitItem(is_true) => {
let suffix = if is_true { " is" } else { " is not" };
- format!("method{} a trait item", suffix).fmt(f)
+ format!("method{suffix} a trait item").fmt(f)
},
}
}
@@ -138,8 +138,7 @@ pub(super) fn check<'tcx>(
WRONG_SELF_CONVENTION,
first_arg_span,
&format!(
- "{} usually take {}",
- suggestion,
+ "{suggestion} usually take {}",
&self_kinds
.iter()
.map(|k| k.description())
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index a081cde85..4f967755b 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -1,7 +1,6 @@
use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{match_trait_method, paths};
-use if_chain::if_chain;
+use clippy_utils::is_trait_method;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -75,45 +74,49 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
.qpath_res(qpath, path.hir_id)
.opt_def_id()
.and_then(|def_id| match cx.tcx.get_diagnostic_name(def_id) {
- Some(sym::cmp_min) => fetch_const(cx, args, MinMax::Min),
- Some(sym::cmp_max) => fetch_const(cx, args, MinMax::Max),
+ Some(sym::cmp_min) => fetch_const(cx, None, args, MinMax::Min),
+ Some(sym::cmp_max) => fetch_const(cx, None, args, MinMax::Max),
_ => None,
})
} else {
None
}
},
- ExprKind::MethodCall(path, args, _) => {
- if_chain! {
- if let [obj, _] = args;
- if cx.typeck_results().expr_ty(obj).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
- then {
- if path.ident.name == sym!(max) {
- fetch_const(cx, args, MinMax::Max)
- } else if path.ident.name == sym!(min) {
- fetch_const(cx, args, MinMax::Min)
- } else {
- None
- }
+ ExprKind::MethodCall(path, receiver, args @ [_], _) => {
+ if cx.typeck_results().expr_ty(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord) {
+ if path.ident.name == sym!(max) {
+ fetch_const(cx, Some(receiver), args, MinMax::Max)
+ } else if path.ident.name == sym!(min) {
+ fetch_const(cx, Some(receiver), args, MinMax::Min)
} else {
None
}
+ } else {
+ None
}
},
_ => None,
}
}
-fn fetch_const<'a>(cx: &LateContext<'_>, args: &'a [Expr<'a>], m: MinMax) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
- if args.len() != 2 {
+fn fetch_const<'a>(
+ cx: &LateContext<'_>,
+ receiver: Option<&'a Expr<'a>>,
+ args: &'a [Expr<'a>],
+ m: MinMax,
+) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
+ let mut args = receiver.into_iter().chain(args);
+ let first_arg = args.next()?;
+ let second_arg = args.next()?;
+ if args.next().is_some() {
return None;
}
- constant_simple(cx, cx.typeck_results(), &args[0]).map_or_else(
- || constant_simple(cx, cx.typeck_results(), &args[1]).map(|c| (m, c, &args[0])),
+ constant_simple(cx, cx.typeck_results(), first_arg).map_or_else(
+ || constant_simple(cx, cx.typeck_results(), second_arg).map(|c| (m, c, first_arg)),
|c| {
- if constant_simple(cx, cx.typeck_results(), &args[1]).is_none() {
+ if constant_simple(cx, cx.typeck_results(), second_arg).is_none() {
// otherwise ignore
- Some((m, c, &args[1]))
+ Some((m, c, second_arg))
} else {
None
}
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 8224e80c9..516dee20f 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -1,12 +1,11 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::source::{snippet, snippet_opt};
use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
- self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt,
- StmtKind, TyKind,
+ self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind,
+ Stmt, StmtKind, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
@@ -15,7 +14,7 @@ use rustc_span::hygiene::DesugaringKind;
use rustc_span::source_map::{ExpnKind, Span};
use clippy_utils::sugg::Sugg;
-use clippy_utils::{get_parent_expr, in_constant, iter_input_pats, last_path_segment, SpanlessEq};
+use clippy_utils::{get_parent_expr, in_constant, is_integer_literal, iter_input_pats, last_path_segment, SpanlessEq};
declare_clippy_lint! {
/// ### What it does
@@ -146,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
return;
}
for arg in iter_input_pats(decl, body) {
- if let PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) = arg.pat.kind {
+ if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind {
span_lint(
cx,
TOPLEVEL_REF_ARG,
@@ -162,9 +161,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
if_chain! {
if !in_external_macro(cx.tcx.sess, stmt.span);
if let StmtKind::Local(local) = stmt.kind;
- if let PatKind::Binding(an, .., name, None) = local.pat.kind;
+ if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind;
if let Some(init) = local.init;
- if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut;
then {
// use the macro callsite when the init span (but not the whole local span)
// comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];`
@@ -173,13 +171,13 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
} else {
Sugg::hir(cx, init, "..")
};
- let (mutopt, initref) = if an == BindingAnnotation::RefMut {
+ let (mutopt, initref) = if mutabl == Mutability::Mut {
("mut ", sugg_init.mut_addr())
} else {
("", sugg_init.addr())
};
let tyopt = if let Some(ty) = local.ty {
- format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, ".."))
+ format!(": &{mutopt}{ty}", ty=snippet(cx, ty.span, ".."))
} else {
String::new()
};
@@ -196,8 +194,6 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
format!(
"let {name}{tyopt} = {initref};",
name=snippet(cx, name.span, ".."),
- tyopt=tyopt,
- initref=initref,
),
Applicability::MachineApplicable,
);
@@ -223,8 +219,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
stmt.span,
"replace it with",
format!(
- "if {} {{ {}; }}",
- sugg,
+ "if {sugg} {{ {}; }}",
&snippet(cx, b.span, ".."),
),
Applicability::MachineApplicable, // snippet
@@ -276,9 +271,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
USED_UNDERSCORE_BINDING,
expr.span,
&format!(
- "used binding `{}` which is prefixed with an underscore. A leading \
- underscore signals that a binding will not be used",
- binding
+ "used binding `{binding}` which is prefixed with an underscore. A leading \
+ underscore signals that a binding will not be used"
),
);
}
@@ -319,8 +313,7 @@ fn non_macro_local(cx: &LateContext<'_>, res: def::Res) -> bool {
fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) {
if_chain! {
if let TyKind::Ptr(ref mut_ty) = ty.kind;
- if let ExprKind::Lit(ref lit) = e.kind;
- if let LitKind::Int(0, _) = lit.node;
+ if is_integer_literal(e, 0);
if !in_constant(cx, e.hir_id);
then {
let (msg, sugg_fn) = match mut_ty.mutbl {
@@ -329,12 +322,12 @@ fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>)
};
let (sugg, appl) = if let TyKind::Infer = mut_ty.ty.kind {
- (format!("{}()", sugg_fn), Applicability::MachineApplicable)
+ (format!("{sugg_fn}()"), Applicability::MachineApplicable)
} else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) {
- (format!("{}::<{}>()", sugg_fn, mut_ty_snip), Applicability::MachineApplicable)
+ (format!("{sugg_fn}::<{mut_ty_snip}>()"), Applicability::MachineApplicable)
} else {
// `MaybeIncorrect` as type inference may not work with the suggested code
- (format!("{}()", sugg_fn), Applicability::MaybeIncorrect)
+ (format!("{sugg_fn}()"), Applicability::MaybeIncorrect)
};
span_lint_and_sugg(cx, ZERO_PTR, span, msg, "try", sugg, appl);
}
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
index 1165c19a0..27e7f8505 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
@@ -6,9 +6,7 @@ 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 {
+ let Some(maybe_last_sep_idx) = lit_snip.len().checked_sub(suffix.len() + 1) else {
return; // It's useless so shouldn't lint.
};
// Do not lint when literal is unsuffixed.
@@ -18,9 +16,9 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &s
cx,
SEPARATED_LITERAL_SUFFIX,
lit.span,
- &format!("{} type suffix should not be separated by an underscore", sugg_type),
+ &format!("{sugg_type} type suffix should not be separated by an underscore"),
"remove the underscore",
- format!("{}{}", &lit_snip[..maybe_last_sep_idx], suffix),
+ format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]),
Applicability::MachineApplicable,
);
} else {
@@ -28,9 +26,9 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &s
cx,
UNSEPARATED_LITERAL_SUFFIX,
lit.span,
- &format!("{} type suffix should be separated by an underscore", sugg_type),
+ &format!("{sugg_type} type suffix should be separated by an underscore"),
"add an underscore",
- format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
+ format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]),
Applicability::MachineApplicable,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs b/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
index 80e242131..263ee1e94 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
@@ -5,9 +5,7 @@ use rustc_lint::EarlyContext;
use super::MIXED_CASE_HEX_LITERALS;
pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, suffix: &str, lit_snip: &str) {
- let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
- val
- } else {
+ let Some(maybe_last_sep_idx) = lit_snip.len().checked_sub(suffix.len() + 1) else {
return; // It's useless so shouldn't lint.
};
if maybe_last_sep_idx <= 2 {
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
index 704918c0b..c8227ca44 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -357,9 +357,8 @@ impl EarlyLintPass for MiscEarlyLints {
DUPLICATE_UNDERSCORE_ARGUMENT,
*correspondence,
&format!(
- "`{}` already exists, having another argument having almost the same \
- name makes code comprehension and documentation more difficult",
- arg_name
+ "`{arg_name}` already exists, having another argument having almost the same \
+ name makes code comprehension and documentation more difficult"
),
);
}
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs
index 525dbf775..d7bb0616a 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs
@@ -1,18 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use rustc_ast::ast::{BindingMode, Mutability, Pat, PatKind};
+use rustc_ast::ast::{Pat, PatKind};
use rustc_errors::Applicability;
use rustc_lint::EarlyContext;
use super::REDUNDANT_PATTERN;
pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
- if let PatKind::Ident(left, ident, Some(ref right)) = pat.kind {
- let left_binding = match left {
- BindingMode::ByRef(Mutability::Mut) => "ref mut ",
- BindingMode::ByRef(Mutability::Not) => "ref ",
- BindingMode::ByValue(..) => "",
- };
-
+ if let PatKind::Ident(ann, ident, Some(ref right)) = pat.kind {
if let PatKind::Wild = right.kind {
span_lint_and_sugg(
cx,
@@ -23,7 +17,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
ident.name, ident.name,
),
"try",
- format!("{}{}", left_binding, ident.name),
+ format!("{}{}", ann.prefix_str(), ident.name),
Applicability::MachineApplicable,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
index fff533167..676e5d40b 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
@@ -27,7 +27,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
pat.span,
"all the struct fields are matched to a wildcard pattern, consider using `..`",
None,
- &format!("try with `{} {{ .. }}` instead", type_name),
+ &format!("try with `{type_name} {{ .. }}` instead"),
);
return;
}
@@ -63,7 +63,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
"you matched a field with a wildcard pattern, consider using `..` \
instead",
None,
- &format!("try with `{} {{ {}, .. }}`", type_name, normal[..].join(", ")),
+ &format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", ")),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
index df044538f..7c4ae746e 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
@@ -46,7 +46,7 @@ fn span_lint(cx: &EarlyContext<'_>, span: Span, only_one: bool) {
"these patterns are unneeded as the `..` pattern can match those elements"
},
if only_one { "remove it" } else { "remove them" },
- "".to_string(),
+ String::new(),
Applicability::MachineApplicable,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs b/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs
index 4963bba82..9ead43ea4 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs
@@ -6,6 +6,7 @@ use rustc_lint::EarlyContext;
use super::ZERO_PREFIXED_LITERAL;
pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str) {
+ let trimmed_lit_snip = lit_snip.trim_start_matches(|c| c == '_' || c == '0');
span_lint_and_then(
cx,
ZERO_PREFIXED_LITERAL,
@@ -15,15 +16,18 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str) {
diag.span_suggestion(
lit.span,
"if you mean to use a decimal constant, remove the `0` to avoid confusion",
- lit_snip.trim_start_matches(|c| c == '_' || c == '0').to_string(),
- Applicability::MaybeIncorrect,
- );
- diag.span_suggestion(
- lit.span,
- "if you mean to use an octal constant, use `0o`",
- format!("0o{}", lit_snip.trim_start_matches(|c| c == '_' || c == '0')),
+ trimmed_lit_snip.to_string(),
Applicability::MaybeIncorrect,
);
+ // do not advise to use octal form if the literal cannot be expressed in base 8.
+ if !lit_snip.contains(|c| c == '8' || c == '9') {
+ diag.span_suggestion(
+ lit.span,
+ "if you mean to use an octal constant, use `0o`",
+ format!("0o{trimmed_lit_snip}"),
+ Applicability::MaybeIncorrect,
+ );
+ }
},
);
}
diff --git a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
index f763e0d24..9de4b56b7 100644
--- a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
+++ b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
@@ -40,7 +40,7 @@ declare_clippy_lint! {
/// }
/// impl<A, B> Foo<A, B> {}
/// ```
- #[clippy::version = "1.62.0"]
+ #[clippy::version = "1.63.0"]
pub MISMATCHING_TYPE_PARAM_ORDER,
pedantic,
"type parameter positioned inconsistently between type def and impl block"
@@ -70,9 +70,8 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch {
// find the type that the Impl is for
// only lint on struct/enum/union for now
- let defid = match path.res {
- Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, defid) => defid,
- _ => return,
+ let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, defid) = path.res else {
+ return
};
// get the names of the generic parameters in the type
@@ -91,10 +90,9 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch {
let type_name = segment.ident;
for (i, (impl_param_name, impl_param_span)) in impl_params.iter().enumerate() {
if mismatch_param_name(i, impl_param_name, &type_param_names_hashmap) {
- let msg = format!("`{}` has a similarly named generic type parameter `{}` in its declaration, but in a different order",
- type_name, impl_param_name);
- let help = format!("try `{}`, or a name that does not conflict with `{}`'s generic params",
- type_param_names[i], type_name);
+ let msg = format!("`{type_name}` has a similarly named generic type parameter `{impl_param_name}` in its declaration, but in a different order");
+ let help = format!("try `{}`, or a name that does not conflict with `{type_name}`'s generic params",
+ type_param_names[i]);
span_lint_and_help(
cx,
MISMATCHING_TYPE_PARAM_ORDER,
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index 16d65966c..71cc0d0a8 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -1,17 +1,19 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::qualify_min_const_fn::is_min_const_fn;
use clippy_utils::ty::has_drop;
-use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method};
+use clippy_utils::{
+ fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, meets_msrv, msrvs, trait_ref_of_method,
+};
use rustc_hir as hir;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
+use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
-use rustc_typeck::hir_ty_to_ty;
declare_clippy_lint! {
/// ### What it does
@@ -86,10 +88,10 @@ impl MissingConstForFn {
impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
fn check_fn(
&mut self,
- cx: &LateContext<'_>,
- kind: FnKind<'_>,
+ cx: &LateContext<'tcx>,
+ kind: FnKind<'tcx>,
_: &FnDecl<'_>,
- _: &Body<'_>,
+ body: &Body<'tcx>,
span: Span,
hir_id: HirId,
) {
@@ -124,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
FnKind::Method(_, sig, ..) => {
if trait_ref_of_method(cx, def_id).is_some()
|| already_const(sig.header)
- || method_accepts_dropable(cx, sig.decl.inputs)
+ || method_accepts_droppable(cx, sig.decl.inputs)
{
return;
}
@@ -134,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
// Const fns are not allowed as methods in a trait.
{
- let parent = cx.tcx.hir().get_parent_item(hir_id);
+ let parent = cx.tcx.hir().get_parent_item(hir_id).def_id;
if parent != CRATE_DEF_ID {
if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent) {
if let hir::ItemKind::Trait(..) = &item.kind {
@@ -144,6 +146,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
}
}
+ if is_from_proc_macro(cx, &(&kind, body, hir_id, span)) {
+ return;
+ }
+
let mir = cx.tcx.optimized_mir(def_id);
if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) {
@@ -159,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
/// Returns true if any of the method parameters is a type that implements `Drop`. The method
/// can't be made const then, because `drop` can't be const-evaluated.
-fn method_accepts_dropable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool {
+fn method_accepts_droppable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool {
// If any of the params are droppable, return true
param_tys.iter().any(|hir_ty| {
let ty_ty = hir_ty_to_ty(cx.tcx, hir_ty);
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 88ba00292..2a63681db 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -7,7 +7,8 @@
use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint;
-use rustc_ast::ast;
+use clippy_utils::is_from_proc_macro;
+use rustc_ast::ast::{self, MetaItem, MetaItemKind};
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::DefIdTree;
@@ -57,6 +58,20 @@ impl MissingDoc {
*self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
}
+ fn has_include(meta: Option<MetaItem>) -> bool {
+ if_chain! {
+ if let Some(meta) = meta;
+ if let MetaItemKind::List(list) = meta.kind;
+ if let Some(meta) = list.get(0);
+ if let Some(name) = meta.ident();
+ then {
+ name.name == sym::include
+ } else {
+ false
+ }
+ }
+ }
+
fn check_missing_docs_attrs(
&self,
cx: &LateContext<'_>,
@@ -80,13 +95,15 @@ impl MissingDoc {
return;
}
- let has_doc = attrs.iter().any(|a| a.doc_str().is_some());
+ let has_doc = attrs
+ .iter()
+ .any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
if !has_doc {
span_lint(
cx,
MISSING_DOCS_IN_PRIVATE_ITEMS,
sp,
- &format!("missing documentation for {} {}", article, desc),
+ &format!("missing documentation for {article} {desc}"),
);
}
}
@@ -114,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
hir::ItemKind::Fn(..) => {
// ignore main()
if it.ident.name == sym::main {
- let at_root = cx.tcx.local_parent(it.def_id) == CRATE_DEF_ID;
+ let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID;
if at_root {
return;
}
@@ -138,22 +155,26 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
| hir::ItemKind::Use(..) => return,
};
- let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
+ let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
let attrs = cx.tcx.hir().attrs(it.hir_id());
- self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
+ if !is_from_proc_macro(cx, it) {
+ self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
+ }
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
- let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
+ let (article, desc) = cx.tcx.article_and_description(trait_item.owner_id.to_def_id());
let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
- self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
+ if !is_from_proc_macro(cx, trait_item) {
+ self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
+ }
}
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
// If the method is an impl for a trait, don't doc.
- if let Some(cid) = cx.tcx.associated_item(impl_item.def_id).impl_container(cx.tcx) {
+ if let Some(cid) = cx.tcx.associated_item(impl_item.owner_id).impl_container(cx.tcx) {
if cx.tcx.impl_trait_ref(cid).is_some() {
return;
}
@@ -161,20 +182,26 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
return;
}
- let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
+ let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
- self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
+ if !is_from_proc_macro(cx, impl_item) {
+ self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
+ }
}
fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) {
if !sf.is_positional() {
let attrs = cx.tcx.hir().attrs(sf.hir_id);
- self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
+ if !is_from_proc_macro(cx, sf) {
+ self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
+ }
}
}
fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
let attrs = cx.tcx.hir().attrs(v.id);
- self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
+ if !is_from_proc_macro(cx, v) {
+ self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
index 3d0a23822..872679f25 100644
--- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
@@ -58,7 +58,8 @@ impl_lint_pass!(ImportRename => [MISSING_ENFORCED_IMPORT_RENAMES]);
impl LateLintPass<'_> for ImportRename {
fn check_crate(&mut self, cx: &LateContext<'_>) {
for Rename { path, rename } in &self.conf_renames {
- if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &path.split("::").collect::<Vec<_>>()) {
+ let segs = path.split("::").collect::<Vec<_>>();
+ if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, None) {
self.renames.insert(id, Symbol::intern(rename));
}
}
@@ -90,9 +91,7 @@ impl LateLintPass<'_> for ImportRename {
"this import should be renamed",
"try",
format!(
- "{} as {}",
- import,
- name,
+ "{import} as {name}",
),
Applicability::MachineApplicable,
);
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 07bc2ca5d..758ce47cf 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -65,7 +65,7 @@ fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp
cx,
MISSING_INLINE_IN_PUBLIC_ITEMS,
sp,
- &format!("missing `#[inline]` for {}", desc),
+ &format!("missing `#[inline]` for {desc}"),
);
}
}
@@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
return;
}
- if !cx.access_levels.is_exported(it.def_id) {
+ if !cx.effective_visibilities.is_exported(it.owner_id.def_id) {
return;
}
match it.kind {
@@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
match tit_.kind {
hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {},
hir::TraitItemKind::Fn(..) => {
- if cx.tcx.impl_defaultness(tit.id.def_id).has_value() {
+ if cx.tcx.impl_defaultness(tit.id.owner_id).has_value() {
// trait method with default body needs inline in case
// an impl is not provided
let desc = "a default trait method";
@@ -142,16 +142,16 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
}
// If the item being implemented is not exported, then we don't need #[inline]
- if !cx.access_levels.is_exported(impl_item.def_id) {
+ if !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
return;
}
let desc = match impl_item.kind {
hir::ImplItemKind::Fn(..) => "a method",
- hir::ImplItemKind::Const(..) | hir::ImplItemKind::TyAlias(_) => return,
+ hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) => return,
};
- let assoc_item = cx.tcx.associated_item(impl_item.def_id);
+ let assoc_item = cx.tcx.associated_item(impl_item.owner_id);
let container_id = assoc_item.container_id(cx.tcx);
let trait_def_id = match assoc_item.container {
TraitContainer => Some(container_id),
@@ -159,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
};
if let Some(trait_def_id) = trait_def_id {
- if trait_def_id.is_local() && !cx.access_levels.is_exported(impl_item.def_id) {
+ if trait_def_id.is_local() && !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
// If a trait is being implemented for an item, and the
// trait is not exported, we don't need #[inline]
return;
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
new file mode 100644
index 000000000..68af8a672
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -0,0 +1,98 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_lint_allowed;
+use clippy_utils::macros::span_is_local;
+use rustc_hir::def_id::DefIdMap;
+use rustc_hir::{Impl, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::AssocItem;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks if a provided method is used implicitly by a trait
+ /// implementation. A usage example would be a wrapper where every method
+ /// should perform some operation before delegating to the inner type's
+ /// implemenation.
+ ///
+ /// This lint should typically be enabled on a specific trait `impl` item
+ /// rather than globally.
+ ///
+ /// ### Why is this bad?
+ /// Indicates that a method is missing.
+ ///
+ /// ### Example
+ /// ```rust
+ /// trait Trait {
+ /// fn required();
+ ///
+ /// fn provided() {}
+ /// }
+ ///
+ /// # struct Type;
+ /// #[warn(clippy::missing_trait_methods)]
+ /// impl Trait for Type {
+ /// fn required() { /* ... */ }
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// trait Trait {
+ /// fn required();
+ ///
+ /// fn provided() {}
+ /// }
+ ///
+ /// # struct Type;
+ /// #[warn(clippy::missing_trait_methods)]
+ /// impl Trait for Type {
+ /// fn required() { /* ... */ }
+ ///
+ /// fn provided() { /* ... */ }
+ /// }
+ /// ```
+ #[clippy::version = "1.66.0"]
+ pub MISSING_TRAIT_METHODS,
+ restriction,
+ "trait implementation uses default provided method"
+}
+declare_lint_pass!(MissingTraitMethods => [MISSING_TRAIT_METHODS]);
+
+impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+ if !is_lint_allowed(cx, MISSING_TRAIT_METHODS, item.hir_id())
+ && span_is_local(item.span)
+ && let ItemKind::Impl(Impl {
+ items,
+ of_trait: Some(trait_ref),
+ ..
+ }) = item.kind
+ && let Some(trait_id) = trait_ref.trait_def_id()
+ {
+ let mut provided: DefIdMap<&AssocItem> = cx
+ .tcx
+ .provided_trait_methods(trait_id)
+ .map(|assoc| (assoc.def_id, assoc))
+ .collect();
+
+ for impl_item in *items {
+ if let Some(def_id) = impl_item.trait_item_def_id {
+ provided.remove(&def_id);
+ }
+ }
+
+ for assoc in provided.values() {
+ let source_map = cx.tcx.sess.source_map();
+ let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id));
+
+ span_lint_and_help(
+ cx,
+ MISSING_TRAIT_METHODS,
+ source_map.guess_head_span(item.span),
+ &format!("missing trait method provided by default: `{}`", assoc.name),
+ Some(definition_span),
+ "implement the method",
+ );
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index a2419c277..675297634 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -190,10 +190,7 @@ fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
if parent_id == cur_id {
break;
}
- let parent_node = match map.find(parent_id) {
- Some(parent) => parent,
- None => break,
- };
+ let Some(parent_node) = map.find(parent_id) else { break };
let stop_early = match parent_node {
Node::Expr(expr) => check_expr(vis, expr),
diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs
index 0a3936572..0742943df 100644
--- a/src/tools/clippy/clippy_lints/src/module_style.rs
+++ b/src/tools/clippy/clippy_lints/src/module_style.rs
@@ -2,7 +2,7 @@ use rustc_ast::ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{FileName, RealFileName, SourceFile, Span, SyntaxContext};
+use rustc_span::{FileName, SourceFile, Span, SyntaxContext};
use std::ffi::OsStr;
use std::path::{Component, Path};
@@ -79,7 +79,7 @@ impl EarlyLintPass for ModStyle {
let files = cx.sess().source_map().files();
- let RealFileName::LocalPath(trim_to_src) = &cx.sess().opts.working_dir else { return };
+ let Some(trim_to_src) = cx.sess().opts.working_dir.local_path() else { return };
// `folder_segments` is all unique folder path segments `path/to/foo.rs` gives
// `[path, to]` but not foo
@@ -90,7 +90,7 @@ impl EarlyLintPass for ModStyle {
// `{ foo => path/to/foo.rs, .. }
let mut file_map = FxHashMap::default();
for file in files.iter() {
- if let FileName::Real(RealFileName::LocalPath(lp)) = &file.name {
+ if let FileName::Real(name) = &file.name && let Some(lp) = name.local_path() {
let path = if lp.is_relative() {
lp
} else if let Ok(relative) = lp.strip_prefix(trim_to_src) {
@@ -117,12 +117,8 @@ impl EarlyLintPass for ModStyle {
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();
- },
+ format!("`mod.rs` files are required, found `{}`", path.display()),
+ |lint| lint.help(format!("move `{}` to `{}`", path.display(), correct.display(),)),
);
}
}
@@ -156,11 +152,8 @@ fn check_self_named_mod_exists(cx: &EarlyContext<'_>, path: &Path, file: &Source
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();
- },
+ format!("`mod.rs` files are not allowed, found `{}`", path.display()),
+ |lint| lint.help(format!("move `{}` to `{}`", path.display(), mod_file.display())),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/multi_assignments.rs b/src/tools/clippy/clippy_lints/src/multi_assignments.rs
new file mode 100644
index 000000000..81eb1a085
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/multi_assignments.rs
@@ -0,0 +1,65 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for nested assignments.
+ ///
+ /// ### Why is this bad?
+ /// While this is in most cases already a type mismatch,
+ /// the result of an assignment being `()` can throw off people coming from languages like python or C,
+ /// where such assignments return a copy of the assigned value.
+ ///
+ /// ### Example
+ /// ```rust
+ ///# let (a, b);
+ /// a = b = 42;
+ /// ```
+ /// Use instead:
+ /// ```rust
+ ///# let (a, b);
+ /// b = 42;
+ /// a = b;
+ /// ```
+ #[clippy::version = "1.65.0"]
+ pub MULTI_ASSIGNMENTS,
+ suspicious,
+ "instead of using `a = b = c;` use `a = c; b = c;`"
+}
+
+declare_lint_pass!(MultiAssignments => [MULTI_ASSIGNMENTS]);
+
+fn strip_paren_blocks(expr: &Expr) -> &Expr {
+ match &expr.kind {
+ ExprKind::Paren(e) => strip_paren_blocks(e),
+ ExprKind::Block(b, _) => {
+ if let [
+ Stmt {
+ kind: StmtKind::Expr(e),
+ ..
+ },
+ ] = &b.stmts[..]
+ {
+ strip_paren_blocks(e)
+ } else {
+ expr
+ }
+ },
+ _ => expr,
+ }
+}
+
+impl EarlyLintPass for MultiAssignments {
+ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+ if let ExprKind::Assign(target, source, _) = &expr.kind {
+ if let ExprKind::Assign(_target, _source, _) = &strip_paren_blocks(target).kind {
+ span_lint(cx, MULTI_ASSIGNMENTS, expr.span, "assignments don't nest intuitively");
+ };
+ if let ExprKind::Assign(_target, _source, _) = &strip_paren_blocks(source).kind {
+ span_lint(cx, MULTI_ASSIGNMENTS, expr.span, "assignments don't nest intuitively");
+ }
+ };
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index 4db103bbc..4b62dcdff 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) {
if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind {
- if trait_ref_of_method(cx, item.def_id).is_none() {
+ if trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
check_sig(cx, item.hir_id(), sig.decl);
}
}
@@ -136,12 +136,14 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
/// [`Hash`] or [`Ord`].
fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bool {
match *ty.kind() {
- Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || is_interior_mutable_type(cx, inner_ty, span),
+ Ref(_, inner_ty, mutbl) => {
+ mutbl == hir::Mutability::Mut || is_interior_mutable_type(cx, inner_ty, span)
+ }
Slice(inner_ty) => is_interior_mutable_type(cx, inner_ty, span),
Array(inner_ty, size) => {
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
&& is_interior_mutable_type(cx, inner_ty, span)
- },
+ }
Tuple(fields) => fields.iter().any(|ty| is_interior_mutable_type(cx, ty, span)),
Adt(def, substs) => {
// Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
@@ -167,9 +169,9 @@ fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Sp
} else {
!ty.has_escaping_bound_vars()
&& cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
- && !ty.is_freeze(cx.tcx.at(span), cx.param_env)
+ && !ty.is_freeze(cx.tcx, cx.param_env)
}
- },
+ }
_ => false,
}
}
diff --git a/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs
deleted file mode 100644
index b7f981faa..000000000
--- a/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, Mutability};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for `&mut Mutex::lock` calls
- ///
- /// ### Why is this bad?
- /// `Mutex::lock` is less efficient than
- /// calling `Mutex::get_mut`. In addition you also have a statically
- /// guarantee that the mutex isn't locked, instead of just a runtime
- /// guarantee.
- ///
- /// ### Example
- /// ```rust
- /// use std::sync::{Arc, Mutex};
- ///
- /// let mut value_rc = Arc::new(Mutex::new(42_u8));
- /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
- ///
- /// let mut value = value_mutex.lock().unwrap();
- /// *value += 1;
- /// ```
- /// Use instead:
- /// ```rust
- /// use std::sync::{Arc, Mutex};
- ///
- /// let mut value_rc = Arc::new(Mutex::new(42_u8));
- /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
- ///
- /// let value = value_mutex.get_mut().unwrap();
- /// *value += 1;
- /// ```
- #[clippy::version = "1.49.0"]
- pub MUT_MUTEX_LOCK,
- style,
- "`&mut Mutex::lock` does unnecessary locking"
-}
-
-declare_lint_pass!(MutMutexLock => [MUT_MUTEX_LOCK]);
-
-impl<'tcx> LateLintPass<'tcx> for MutMutexLock {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>) {
- if_chain! {
- if let ExprKind::MethodCall(path, [self_arg, ..], _) = &ex.kind;
- if path.ident.name == sym!(lock);
- let ty = cx.typeck_results().expr_ty(self_arg);
- if let ty::Ref(_, inner_ty, Mutability::Mut) = ty.kind();
- if is_type_diagnostic_item(cx, *inner_ty, sym::Mutex);
- then {
- span_lint_and_sugg(
- cx,
- MUT_MUTEX_LOCK,
- path.ident.span,
- "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference",
- "change this to",
- "get_mut".to_owned(),
- Applicability::MaybeIncorrect,
- );
- }
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index f434a655f..4547ed7ea 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use std::iter;
@@ -43,18 +42,24 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
if let ExprKind::Path(ref path) = fn_expr.kind {
check_arguments(
cx,
- arguments,
+ arguments.iter().collect(),
cx.typeck_results().expr_ty(fn_expr),
&rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
"function",
);
}
},
- ExprKind::MethodCall(path, arguments, _) => {
+ ExprKind::MethodCall(path, receiver, arguments, _) => {
let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
let substs = cx.typeck_results().node_substs(e.hir_id);
let method_type = cx.tcx.bound_type_of(def_id).subst(cx.tcx, substs);
- check_arguments(cx, arguments, method_type, path.ident.as_str(), "method");
+ check_arguments(
+ cx,
+ std::iter::once(receiver).chain(arguments.iter()).collect(),
+ method_type,
+ path.ident.as_str(),
+ "method",
+ );
},
_ => (),
}
@@ -63,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
fn check_arguments<'tcx>(
cx: &LateContext<'tcx>,
- arguments: &[Expr<'_>],
+ arguments: Vec<&Expr<'_>>,
type_definition: Ty<'tcx>,
name: &str,
fn_kind: &str,
@@ -82,7 +87,7 @@ fn check_arguments<'tcx>(
cx,
UNNECESSARY_MUT_PASSED,
argument.span,
- &format!("the {} `{}` doesn't need a mutable reference", fn_kind, name),
+ &format!("the {fn_kind} `{name}` doesn't need a mutable reference"),
);
}
},
diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
index 44fdf84c6..d8647a991 100644
--- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
+++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
@@ -56,10 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall {
cx,
DEBUG_ASSERT_WITH_MUT_CALL,
span,
- &format!(
- "do not call a function with mutable arguments inside of `{}!`",
- macro_name
- ),
+ &format!("do not call a function with mutable arguments inside of `{macro_name}!`"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
index a98577093..09cb53331 100644
--- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
+++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
@@ -84,9 +84,8 @@ impl<'tcx> LateLintPass<'tcx> for Mutex {
let mutex_param = subst.type_at(0);
if let Some(atomic_name) = get_atomic_name(mutex_param) {
let msg = format!(
- "consider using an `{}` instead of a `Mutex` here; if you just want the locking \
- behavior and not the internal type, consider using `Mutex<()>`",
- atomic_name
+ "consider using an `{atomic_name}` instead of a `Mutex` here; if you just want the locking \
+ behavior and not the internal type, consider using `Mutex<()>`"
);
match *mutex_param.kind() {
ty::Uint(t) if t != ty::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
index 9838d3cad..f2ffac85b 100644
--- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use if_chain::if_chain;
-use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind};
+use rustc_ast::ast::{BindingAnnotation, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -120,14 +120,14 @@ impl EarlyLintPass for NeedlessArbitrarySelfType {
match &p.ty.kind {
TyKind::Path(None, path) => {
- if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind {
+ if let PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), _, _) = p.pat.kind {
check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl);
}
},
TyKind::Rptr(lifetime, mut_ty) => {
if_chain! {
if let TyKind::Path(None, path) = &mut_ty.ty.kind;
- if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind;
+ if let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind;
then {
check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl);
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
index 05c012b92..10c3ff026 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
@@ -1,6 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::snippet_with_applicability;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BindingAnnotation, Mutability, Node, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -8,36 +6,26 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
/// ### What it does
- /// Checks for bindings that destructure a reference and borrow the inner
+ /// Checks for bindings that needlessly destructure a reference and borrow the inner
/// value with `&ref`.
///
/// ### Why is this bad?
/// This pattern has no effect in almost all cases.
///
- /// ### Known problems
- /// In some cases, `&ref` is needed to avoid a lifetime mismatch error.
- /// Example:
- /// ```rust
- /// fn foo(a: &Option<String>, b: &Option<String>) {
- /// match (a, b) {
- /// (None, &ref c) | (&ref c, None) => (),
- /// (&Some(ref c), _) => (),
- /// };
- /// }
- /// ```
- ///
/// ### Example
/// ```rust
/// let mut v = Vec::<String>::new();
- /// # #[allow(unused)]
/// v.iter_mut().filter(|&ref a| a.is_empty());
+ ///
+ /// if let &[ref first, ref second] = v.as_slice() {}
/// ```
///
/// Use instead:
/// ```rust
/// let mut v = Vec::<String>::new();
- /// # #[allow(unused)]
/// v.iter_mut().filter(|a| a.is_empty());
+ ///
+ /// if let [first, second] = v.as_slice() {}
/// ```
#[clippy::version = "pre 1.29.0"]
pub NEEDLESS_BORROWED_REFERENCE,
@@ -54,34 +42,83 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
return;
}
- if_chain! {
- // Only lint immutable refs, because `&mut ref T` may be useful.
- if let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind;
+ // Do not lint patterns that are part of an OR `|` pattern, the binding mode must match in all arms
+ for (_, node) in cx.tcx.hir().parent_iter(pat.hir_id) {
+ let Node::Pat(pat) = node else { break };
+
+ if matches!(pat.kind, PatKind::Or(_)) {
+ return;
+ }
+ }
+
+ // Only lint immutable refs, because `&mut ref T` may be useful.
+ let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind else { return };
+ match sub_pat.kind {
// Check sub_pat got a `ref` keyword (excluding `ref mut`).
- if let PatKind::Binding(BindingAnnotation::Ref, .., spanned_name, _) = sub_pat.kind;
- let parent_id = cx.tcx.hir().get_parent_node(pat.hir_id);
- if let Some(parent_node) = cx.tcx.hir().find(parent_id);
- then {
- // do not recurse within patterns, as they may have other references
- // XXXManishearth we can relax this constraint if we only check patterns
- // with a single ref pattern inside them
- if let Node::Pat(_) = parent_node {
- return;
+ PatKind::Binding(BindingAnnotation::REF, _, ident, None) => {
+ span_lint_and_then(
+ cx,
+ NEEDLESS_BORROWED_REFERENCE,
+ pat.span,
+ "this pattern takes a reference on something that is being dereferenced",
+ |diag| {
+ // `&ref ident`
+ // ^^^^^
+ let span = pat.span.until(ident.span);
+ diag.span_suggestion_verbose(
+ span,
+ "try removing the `&ref` part",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ },
+ );
+ },
+ // Slices where each element is `ref`: `&[ref a, ref b, ..., ref z]`
+ PatKind::Slice(
+ before,
+ None
+ | Some(Pat {
+ kind: PatKind::Wild, ..
+ }),
+ after,
+ ) => {
+ let mut suggestions = Vec::new();
+
+ for element_pat in itertools::chain(before, after) {
+ if let PatKind::Binding(BindingAnnotation::REF, _, ident, None) = element_pat.kind {
+ // `&[..., ref ident, ...]`
+ // ^^^^
+ let span = element_pat.span.until(ident.span);
+ suggestions.push((span, String::new()));
+ } else {
+ return;
+ }
}
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_then(cx, NEEDLESS_BORROWED_REFERENCE, pat.span,
- "this pattern takes a reference on something that is being de-referenced",
- |diag| {
- let hint = snippet_with_applicability(cx, spanned_name.span, "..", &mut applicability).into_owned();
- diag.span_suggestion(
- pat.span,
- "try removing the `&ref` part and just keep",
- hint,
- applicability,
- );
- });
- }
+
+ if !suggestions.is_empty() {
+ span_lint_and_then(
+ cx,
+ NEEDLESS_BORROWED_REFERENCE,
+ pat.span,
+ "dereferencing a slice pattern where every element takes a reference",
+ |diag| {
+ // `&[...]`
+ // ^
+ let span = pat.span.until(sub_pat.span);
+ suggestions.push((span, String::new()));
+
+ diag.multipart_suggestion(
+ "try removing the `&` and `ref` parts",
+ suggestions,
+ Applicability::MachineApplicable,
+ );
+ },
+ );
+ }
+ },
+ _ => {},
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index 98a3bce1f..6f0e75546 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -309,7 +309,7 @@ fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str,
expr.span,
message,
None,
- &format!("{}\n{}", header, snip),
+ &format!("{header}\n{snip}"),
);
}
@@ -322,10 +322,7 @@ fn suggestion_snippet_for_continue_inside_if<'a>(cx: &EarlyContext<'_>, data: &'
let indent_if = indent_of(cx, data.if_expr.span).unwrap_or(0);
format!(
- "{indent}if {} {}\n{indent}{}",
- cond_code,
- continue_code,
- else_code,
+ "{indent}if {cond_code} {continue_code}\n{indent}{else_code}",
indent = " ".repeat(indent_if),
)
}
@@ -349,7 +346,7 @@ fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data:
let span = cx.sess().source_map().stmt_span(stmt.span, data.loop_block.span);
let snip = snippet_block(cx, span, "..", None).into_owned();
snip.lines()
- .map(|line| format!("{}{}", " ".repeat(indent), line))
+ .map(|line| format!("{}{line}", " ".repeat(indent)))
.collect::<Vec<_>>()
.join("\n")
})
@@ -358,10 +355,7 @@ fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data:
let indent_if = indent_of(cx, data.if_expr.span).unwrap_or(0);
format!(
- "{indent_if}if {} {}\n{indent}// merged code follows:\n{}\n{indent_if}}}",
- cond_code,
- block_code,
- to_annex,
+ "{indent_if}if {cond_code} {block_code}\n{indent}// merged code follows:\n{to_annex}\n{indent_if}}}",
indent = " ".repeat(indent),
indent_if = " ".repeat(indent_if),
)
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 10e188ecb..c3b633fd6 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -49,19 +49,18 @@ declare_lint_pass!(NeedlessForEach => [NEEDLESS_FOR_EACH]);
impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
- let expr = match stmt.kind {
- StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr,
- _ => return,
+ let (StmtKind::Expr(expr) | StmtKind::Semi(expr)) = stmt.kind else {
+ return
};
if_chain! {
// Check the method name is `for_each`.
- if let ExprKind::MethodCall(method_name, [for_each_recv, for_each_arg], _) = expr.kind;
+ if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind;
if method_name.ident.name == Symbol::intern("for_each");
// Check `for_each` is an associated function of `Iterator`.
if is_trait_method(cx, expr, sym::Iterator);
// Checks the receiver of `for_each` is also a method call.
- if let ExprKind::MethodCall(_, [iter_recv], _) = for_each_recv.kind;
+ if let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind;
// Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or
// `v.foo().iter().for_each()` must be skipped.
if matches!(
@@ -77,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
if let ExprKind::Block(..) = body.value.kind;
then {
let mut ret_collector = RetCollector::default();
- ret_collector.visit_expr(&body.value);
+ ret_collector.visit_expr(body.value);
// Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`.
if ret_collector.ret_in_loop {
diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
index ff2999b1f..67debe7e0 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -2,9 +2,9 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::path_to_local;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::needs_ordered_drop;
-use clippy_utils::visitors::{expr_visitor, expr_visitor_no_bodies, is_local_used};
+use clippy_utils::visitors::{for_each_expr, for_each_expr_with_closures, is_local_used};
+use core::ops::ControlFlow;
use rustc_errors::{Applicability, MultiSpan};
-use rustc_hir::intravisit::Visitor;
use rustc_hir::{
BindingAnnotation, Block, Expr, ExprKind, HirId, Local, LocalSource, MatchSource, Node, Pat, PatKind, Stmt,
StmtKind,
@@ -64,31 +64,25 @@ declare_clippy_lint! {
declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]);
fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> bool {
- let mut seen = false;
- expr_visitor(cx, |expr| {
- if let ExprKind::Assign(..) = expr.kind {
- seen = true;
+ for_each_expr_with_closures(cx, stmt, |e| {
+ if matches!(e.kind, ExprKind::Assign(..)) {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(())
}
-
- !seen
})
- .visit_stmt(stmt);
-
- seen
+ .is_some()
}
fn contains_let(cond: &Expr<'_>) -> bool {
- let mut seen = false;
- expr_visitor_no_bodies(|expr| {
- if let ExprKind::Let(_) = expr.kind {
- seen = true;
+ for_each_expr(cond, |e| {
+ if matches!(e.kind, ExprKind::Let(_)) {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(())
}
-
- !seen
})
- .visit_expr(cond);
-
- seen
+ .is_some()
}
fn stmt_needs_ordered_drop(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
@@ -186,10 +180,13 @@ fn assignment_suggestions<'tcx>(
let suggestions = assignments
.iter()
.flat_map(|assignment| {
- [
- assignment.span.until(assignment.rhs_span),
- assignment.rhs_span.shrink_to_hi().with_hi(assignment.span.hi()),
- ]
+ let mut spans = vec![assignment.span.until(assignment.rhs_span)];
+
+ if assignment.rhs_span.hi() != assignment.span.hi() {
+ spans.push(assignment.rhs_span.shrink_to_hi().with_hi(assignment.span.hi()));
+ }
+
+ spans
})
.map(|span| (span, String::new()))
.collect::<Vec<(Span, String)>>();
@@ -287,7 +284,7 @@ fn check<'tcx>(
diag.span_suggestion(
assign.lhs_span,
- &format!("declare `{}` here", binding_name),
+ &format!("declare `{binding_name}` here"),
let_snippet,
Applicability::MachineApplicable,
);
@@ -307,8 +304,8 @@ fn check<'tcx>(
diag.span_suggestion_verbose(
usage.stmt.span.shrink_to_lo(),
- &format!("declare `{}` here", binding_name),
- format!("{} = ", let_snippet),
+ &format!("declare `{binding_name}` here"),
+ format!("{let_snippet} = "),
applicability,
);
@@ -338,8 +335,8 @@ fn check<'tcx>(
diag.span_suggestion_verbose(
usage.stmt.span.shrink_to_lo(),
- &format!("declare `{}` here", binding_name),
- format!("{} = ", let_snippet),
+ &format!("declare `{binding_name}` here"),
+ format!("{let_snippet} = "),
applicability,
);
@@ -373,7 +370,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit {
if let Local {
init: None,
pat: &Pat {
- kind: PatKind::Binding(BindingAnnotation::Unannotated, binding_id, _, None),
+ kind: PatKind::Binding(BindingAnnotation::NONE, binding_id, _, None),
..
},
source: LocalSource::Normal,
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 0cbef1c95..b2e9ce5c9 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -8,8 +8,11 @@ use rustc_ast::ast::Attribute;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir::intravisit::FnKind;
-use rustc_hir::{BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Node, PatKind, QPath, TyKind};
+use rustc_hir::{
+ BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Mutability, Node, PatKind, QPath, TyKind,
+};
use rustc_hir::{HirIdMap, HirIdSet};
+use rustc_hir_typeck::expr_use_visitor as euv;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::FakeReadCause;
@@ -20,7 +23,6 @@ use rustc_span::{sym, Span};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::misc::can_type_implement_copy;
-use rustc_typeck::expr_use_visitor as euv;
use std::borrow::Cow;
declare_clippy_lint! {
@@ -136,10 +138,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
..
} = {
let mut ctx = MovedVariablesCtxt::default();
- cx.tcx.infer_ctxt().enter(|infcx| {
- euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results())
- .consume_body(body);
- });
+ let infcx = cx.tcx.infer_ctxt().build();
+ euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
ctx
};
@@ -171,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
(
preds.iter().any(|t| cx.tcx.is_diagnostic_item(sym::Borrow, t.def_id())),
!preds.is_empty() && {
- let ty_empty_region = cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_root_empty, ty);
+ let ty_empty_region = cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_erased, ty);
preds.iter().all(|t| {
let ty_params = t.trait_ref.substs.iter().skip(1).collect::<Vec<_>>();
implements_trait(cx, ty_empty_region, t.def_id(), &ty_params)
@@ -184,17 +184,14 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
if !is_self(arg);
if !ty.is_mutable_ptr();
if !is_copy(cx, ty);
+ if ty.is_sized(cx.tcx, cx.param_env);
if !allowed_traits.iter().any(|&t| implements_trait(cx, ty, t, &[]));
if !implements_borrow_trait;
if !all_borrowable_trait;
- if let PatKind::Binding(mode, canonical_id, ..) = arg.pat.kind;
+ if let PatKind::Binding(BindingAnnotation(_, Mutability::Not), canonical_id, ..) = arg.pat.kind;
if !moved_vars.contains(&canonical_id);
then {
- if mode == BindingAnnotation::Mutable || mode == BindingAnnotation::RefMut {
- continue;
- }
-
// Dereference suggestion
let sugg = |diag: &mut Diagnostic| {
if let ty::Adt(def, ..) = ty.kind() {
@@ -238,7 +235,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
snippet_opt(cx, span)
.map_or(
"change the call to".into(),
- |x| Cow::from(format!("change `{}` to", x)),
+ |x| Cow::from(format!("change `{x}` to")),
)
.as_ref(),
suggestion,
@@ -268,7 +265,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
snippet_opt(cx, span)
.map_or(
"change the call to".into(),
- |x| Cow::from(format!("change `{}` to", x))
+ |x| Cow::from(format!("change `{x}` to"))
)
.as_ref(),
suggestion,
@@ -343,5 +340,11 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {}
- fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+ fn fake_read(
+ &mut self,
+ _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
+ _: FakeReadCause,
+ _: HirId,
+ ) {
+ }
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index 8f85b0059..97c8cfbd3 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -1,11 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_lang_ctor;
+use clippy_utils::path_res;
use clippy_utils::source::snippet;
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::LangItem::{OptionSome, ResultOk};
+use rustc_hir::def::{DefKind, Res};
use rustc_hir::{AsyncGeneratorKind, Block, Body, Expr, ExprKind, GeneratorKind, LangItem, MatchSource, QPath};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::DefIdTree;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
@@ -112,11 +113,12 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
- if let ExprKind::Call(path, [arg]) = &expr.kind;
- if let ExprKind::Path(ref qpath) = &path.kind;
- let sugg_remove = if is_lang_ctor(cx, qpath, OptionSome) {
+ if let ExprKind::Call(path, [arg]) = expr.kind;
+ if let Res::Def(DefKind::Ctor(..), ctor_id) = path_res(cx, path);
+ if let Some(variant_id) = cx.tcx.opt_parent(ctor_id);
+ let sugg_remove = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) {
"Some()"
- } else if is_lang_ctor(cx, qpath, ResultOk) {
+ } else if cx.tcx.lang_items().result_ok_variant() == Some(variant_id) {
"Ok()"
} else {
return;
@@ -134,7 +136,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
NEEDLESS_QUESTION_MARK,
expr.span,
"question mark operator is useless here",
- &format!("try removing question mark and `{}`", sugg_remove),
+ &format!("try removing question mark and `{sugg_remove}`"),
format!("{}", snippet(cx, inner_expr.span, r#""...""#)),
Applicability::MachineApplicable,
);
diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
index a7e0e3578..5c2b96f5b 100644
--- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
@@ -1,11 +1,11 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::implements_trait;
-use clippy_utils::{self, get_trait_def_id, paths};
use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -47,18 +47,16 @@ declare_lint_pass!(NoNegCompOpForPartialOrd => [NEG_CMP_OP_ON_PARTIAL_ORD]);
impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
-
if !in_external_macro(cx.sess(), expr.span);
if let ExprKind::Unary(UnOp::Not, inner) = expr.kind;
if let ExprKind::Binary(ref op, left, _) = inner.kind;
if let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node;
then {
-
let ty = cx.typeck_results().expr_ty(left);
let implements_ord = {
- if let Some(id) = get_trait_def_id(cx, &paths::ORD) {
+ if let Some(id) = cx.tcx.get_diagnostic_item(sym::Ord) {
implements_trait(cx, ty, id, &[])
} else {
return;
@@ -81,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd {
"the use of negated comparison operators on partially ordered \
types produces code that is hard to read and refactor, please \
consider using the `partial_cmp` method instead, to make it \
- clear that the two values could be incomparable"
+ clear that the two values could be incomparable",
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index b087cfb36..fb9a4abd0 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -62,9 +62,9 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
let mut applicability = Applicability::MachineApplicable;
let snip = snippet_with_applicability(cx, exp.span, "..", &mut applicability);
let suggestion = if exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) {
- format!("-({})", snip)
+ format!("-({snip})")
} else {
- format!("-{}", snip)
+ format!("-{snip}")
};
span_lint_and_sugg(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 5c45ee6d9..54a3c82b7 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
// can't be implemented for unsafe new
return;
}
- if cx.tcx.is_doc_hidden(impl_item.def_id) {
+ if cx.tcx.is_doc_hidden(impl_item.owner_id.def_id) {
// shouldn't be implemented when it is hidden in docs
return;
}
@@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
if_chain! {
if sig.decl.inputs.is_empty();
if name == sym::new;
- if cx.access_levels.is_reachable(impl_item.def_id);
+ if cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id);
let self_def_id = cx.tcx.hir().get_parent_item(id);
let self_ty = cx.tcx.type_of(self_def_id);
if self_ty == return_ty(cx, id);
@@ -136,8 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
id,
impl_item.span,
&format!(
- "you should consider adding a `Default` implementation for `{}`",
- self_type_snip
+ "you should consider adding a `Default` implementation for `{self_type_snip}`"
),
|diag| {
diag.suggest_prepend_item(
@@ -161,9 +160,9 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
fn create_new_without_default_suggest_msg(self_type_snip: &str, generics_sugg: &str) -> String {
#[rustfmt::skip]
format!(
-"impl{} Default for {} {{
+"impl{generics_sugg} Default for {self_type_snip} {{
fn default() -> Self {{
Self::new()
}}
-}}", generics_sugg, self_type_snip)
+}}")
}
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 72c86f28b..2a3bd4ee6 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -13,14 +13,14 @@ use rustc_hir::def_id::DefId;
use rustc_hir::{
BodyId, Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp,
};
+use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass, Lint};
use rustc_middle::mir;
use rustc_middle::mir::interpret::{ConstValue, ErrorHandled};
use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{sym, InnerSpan, Span, DUMMY_SP};
-use rustc_typeck::hir_ty_to_ty;
+use rustc_span::{sym, InnerSpan, Span};
// FIXME: this is a correctness problem but there's no suitable
// warn-by-default category.
@@ -136,7 +136,7 @@ fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
// since it works when a pointer indirection involves (`Cell<*const T>`).
// Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
// but I'm not sure whether it's a decent way, if possible.
- cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env)
+ cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env)
}
fn is_value_unfrozen_raw<'tcx>(
@@ -149,6 +149,9 @@ fn is_value_unfrozen_raw<'tcx>(
// the fact that we have to dig into every structs to search enums
// leads us to the point checking `UnsafeCell` directly is the only option.
ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true,
+ // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the
+ // contained value.
+ ty::Adt(def, ..) if def.is_union() => false,
ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => {
let val = cx.tcx.destructure_mir_constant(cx.param_env, val);
val.fields.iter().any(|field| inner(cx, *field))
@@ -195,7 +198,7 @@ fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: D
let result = cx.tcx.const_eval_resolve(
cx.param_env,
- ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs),
+ mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs),
None,
);
is_value_unfrozen_raw(cx, result, ty)
@@ -286,7 +289,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind {
- let item_def_id = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let item_def_id = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
let item = cx.tcx.hir().expect_item(item_def_id);
match &item.kind {
@@ -300,7 +303,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
if let Some(of_trait_def_id) = of_trait_ref.trait_def_id();
if let Some(of_assoc_item) = cx
.tcx
- .associated_item(impl_item.def_id)
+ .associated_item(impl_item.owner_id)
.trait_item_def_id;
if cx
.tcx
@@ -354,9 +357,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
}
// Make sure it is a const item.
- let item_def_id = match cx.qpath_res(qpath, expr.hir_id) {
- Res::Def(DefKind::Const | DefKind::AssocConst, did) => did,
- _ => return,
+ let Res::Def(DefKind::Const | DefKind::AssocConst, item_def_id) = cx.qpath_res(qpath, expr.hir_id) else {
+ return
};
// Climb up to resolve any field access and explicit referencing.
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index b96af06b8..9f6917c14 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -15,6 +15,10 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for names that are very similar and thus confusing.
///
+ /// Note: this lint looks for similar names throughout each
+ /// scope. To allow it, you need to allow it on the scope
+ /// level, not on the name that is reported.
+ ///
/// ### Why is this bad?
/// It's hard to distinguish between names that differ only
/// by a single character.
@@ -108,10 +112,7 @@ impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> {
self.cx,
MANY_SINGLE_CHAR_NAMES,
span,
- &format!(
- "{} bindings with single-character names in scope",
- num_single_char_names
- ),
+ &format!("{num_single_char_names} bindings with single-character names in scope"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
index ed022b9d5..2ecb04874 100644
--- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
@@ -1,12 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
-use clippy_utils::ty::match_type;
+use clippy_utils::ty::{is_type_diagnostic_item, match_type};
use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -43,20 +44,19 @@ declare_lint_pass!(NonOctalUnixPermissions => [NON_OCTAL_UNIX_PERMISSIONS]);
impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
match &expr.kind {
- ExprKind::MethodCall(path, [func, param], _) => {
+ ExprKind::MethodCall(path, func, [param], _) => {
let obj_ty = cx.typeck_results().expr_ty(func).peel_refs();
if_chain! {
if (path.ident.name == sym!(mode)
&& (match_type(cx, obj_ty, &paths::OPEN_OPTIONS)
- || match_type(cx, obj_ty, &paths::DIR_BUILDER)))
+ || is_type_diagnostic_item(cx, obj_ty, sym::DirBuilder)))
|| (path.ident.name == sym!(set_mode) && match_type(cx, obj_ty, &paths::PERMISSIONS));
if let ExprKind::Lit(_) = param.kind;
then {
- let snip = match snippet_opt(cx, param.span) {
- Some(s) => s,
- _ => return,
+ let Some(snip) = snippet_opt(cx, param.span) else {
+ return
};
if !snip.starts_with("0o") {
@@ -71,16 +71,10 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE);
if let ExprKind::Lit(_) = param.kind;
-
+ if let Some(snip) = snippet_opt(cx, param.span);
+ if !snip.starts_with("0o");
then {
- let snip = match snippet_opt(cx, param.span) {
- Some(s) => s,
- _ => return,
- };
-
- if !snip.starts_with("0o") {
- show_error(cx, param);
- }
+ show_error(cx, param);
}
}
},
diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
index ddef7352d..714c0ff22 100644
--- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
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 Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
if let self_ty = ty_trait_ref.self_ty();
if let ty::Adt(adt_def, impl_trait_substs) = self_ty.kind();
then {
diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
index 4722c0310..6c909e5ed 100644
--- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
+++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
@@ -3,16 +3,17 @@ use std::{
hash::{Hash, Hasher},
};
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt;
use if_chain::if_chain;
use rustc_ast::ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::hygiene::{ExpnKind, MacroKind};
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
use serde::{de, Deserialize};
declare_clippy_lint! {
@@ -39,8 +40,8 @@ declare_clippy_lint! {
const BRACES: &[(&str, &str)] = &[("(", ")"), ("{", "}"), ("[", "]")];
-/// The (name, (open brace, close brace), source snippet)
-type MacroInfo<'a> = (Symbol, &'a (String, String), String);
+/// The (callsite span, (open brace, close brace), source snippet)
+type MacroInfo<'a> = (Span, &'a (String, String), String);
#[derive(Clone, Debug, Default)]
pub struct MacroBraces {
@@ -62,33 +63,29 @@ impl_lint_pass!(MacroBraces => [NONSTANDARD_MACRO_BRACES]);
impl EarlyLintPass for MacroBraces {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
- if let Some((name, braces, snip)) = is_offending_macro(cx, item.span, self) {
- let span = item.span.ctxt().outer_expn_data().call_site;
- emit_help(cx, snip, braces, name, span);
+ if let Some((span, braces, snip)) = is_offending_macro(cx, item.span, self) {
+ emit_help(cx, &snip, braces, span);
self.done.insert(span);
}
}
fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
- if let Some((name, braces, snip)) = is_offending_macro(cx, stmt.span, self) {
- let span = stmt.span.ctxt().outer_expn_data().call_site;
- emit_help(cx, snip, braces, name, span);
+ if let Some((span, braces, snip)) = is_offending_macro(cx, stmt.span, self) {
+ emit_help(cx, &snip, braces, span);
self.done.insert(span);
}
}
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
- if let Some((name, braces, snip)) = is_offending_macro(cx, expr.span, self) {
- let span = expr.span.ctxt().outer_expn_data().call_site;
- emit_help(cx, snip, braces, name, span);
+ if let Some((span, braces, snip)) = is_offending_macro(cx, expr.span, self) {
+ emit_help(cx, &snip, braces, span);
self.done.insert(span);
}
}
fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
- if let Some((name, braces, snip)) = is_offending_macro(cx, ty.span, self) {
- let span = ty.span.ctxt().outer_expn_data().call_site;
- emit_help(cx, snip, braces, name, span);
+ if let Some((span, braces, snip)) = is_offending_macro(cx, ty.span, self) {
+ emit_help(cx, &snip, braces, span);
self.done.insert(span);
}
}
@@ -102,48 +99,44 @@ fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a Mac
.last()
.map_or(false, |e| e.macro_def_id.map_or(false, DefId::is_local))
};
+ let span_call_site = span.ctxt().outer_expn_data().call_site;
if_chain! {
if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind;
let name = mac_name.as_str();
if let Some(braces) = mac_braces.macro_braces.get(name);
- if let Some(snip) = snippet_opt(cx, span.ctxt().outer_expn_data().call_site);
+ if let Some(snip) = snippet_opt(cx, span_call_site);
// we must check only invocation sites
// https://github.com/rust-lang/rust-clippy/issues/7422
- if snip.starts_with(&format!("{}!", name));
+ if snip.starts_with(&format!("{name}!"));
if unnested_or_local();
// make formatting consistent
let c = snip.replace(' ', "");
- if !c.starts_with(&format!("{}!{}", name, braces.0));
- if !mac_braces.done.contains(&span.ctxt().outer_expn_data().call_site);
+ if !c.starts_with(&format!("{name}!{}", braces.0));
+ if !mac_braces.done.contains(&span_call_site);
then {
- Some((mac_name, braces, snip))
+ Some((span_call_site, braces, snip))
} else {
None
}
}
}
-fn emit_help(cx: &EarlyContext<'_>, snip: String, braces: &(String, String), name: Symbol, span: Span) {
- let with_space = &format!("! {}", braces.0);
- let without_space = &format!("!{}", braces.0);
- let mut help = snip;
- for b in BRACES.iter().filter(|b| b.0 != braces.0) {
- help = help.replace(b.0, &braces.0).replace(b.1, &braces.1);
- // Only `{` traditionally has space before the brace
- if braces.0 != "{" && help.contains(with_space) {
- help = help.replace(with_space, without_space);
- } else if braces.0 == "{" && help.contains(without_space) {
- help = help.replace(without_space, with_space);
- }
+fn emit_help(cx: &EarlyContext<'_>, snip: &str, braces: &(String, String), span: Span) {
+ if let Some((macro_name, macro_args_str)) = snip.split_once('!') {
+ let mut macro_args = macro_args_str.trim().to_string();
+ // now remove the wrong braces
+ macro_args.remove(0);
+ macro_args.pop();
+ span_lint_and_sugg(
+ cx,
+ NONSTANDARD_MACRO_BRACES,
+ span,
+ &format!("use of irregular braces for `{macro_name}!` macro"),
+ "consider writing",
+ format!("{macro_name}!{}{macro_args}{}", braces.0, braces.1),
+ Applicability::MachineApplicable,
+ );
}
- span_lint_and_help(
- cx,
- NONSTANDARD_MACRO_BRACES,
- span,
- &format!("use of irregular braces for `{}!` macro", name),
- Some(span),
- &format!("consider writing `{}`", help),
- );
}
fn macro_braces(conf: FxHashSet<MacroMatcher>) -> FxHashMap<String, (String, String)> {
@@ -184,6 +177,10 @@ fn macro_braces(conf: FxHashSet<MacroMatcher>) -> FxHashMap<String, (String, Str
name: "vec",
braces: ("[", "]"),
),
+ macro_matcher!(
+ name: "matches",
+ braces: ("(", ")"),
+ ),
]
.into_iter()
.collect::<FxHashMap<_, _>>();
@@ -269,9 +266,7 @@ impl<'de> Deserialize<'de> for MacroMatcher {
.iter()
.find(|b| b.0 == brace)
.map(|(o, c)| ((*o).to_owned(), (*c).to_owned()))
- .ok_or_else(|| {
- de::Error::custom(&format!("expected one of `(`, `{{`, `[` found `{}`", brace))
- })?,
+ .ok_or_else(|| de::Error::custom(format!("expected one of `(`, `{{`, `[` found `{brace}`")))?,
})
}
}
diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
index 6ad6837f0..f380a5065 100644
--- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs
+++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
@@ -57,10 +57,10 @@ impl EarlyLintPass for OctalEscapes {
}
if let ExprKind::Lit(lit) = &expr.kind {
- if matches!(lit.token.kind, LitKind::Str) {
- check_lit(cx, &lit.token, lit.span, true);
- } else if matches!(lit.token.kind, LitKind::ByteStr) {
- check_lit(cx, &lit.token, lit.span, false);
+ if matches!(lit.token_lit.kind, LitKind::Str) {
+ check_lit(cx, &lit.token_lit, lit.span, true);
+ } else if matches!(lit.token_lit.kind, LitKind::ByteStr) {
+ check_lit(cx, &lit.token_lit, lit.span, false);
}
}
}
@@ -102,7 +102,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
// construct a replacement escape
// the maximum value is \077, or \x3f, so u8 is sufficient here
if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) {
- write!(suggest_1, "\\x{:02x}", n).unwrap();
+ write!(suggest_1, "\\x{n:02x}").unwrap();
}
// append the null byte as \x00 and the following digits literally
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index 413a740be..7722a476d 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -1,26 +1,18 @@
-use std::collections::VecDeque;
-
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_lint_allowed;
-use itertools::{izip, Itertools};
-use rustc_ast::{walk_list, Label, Mutability};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::{get_expr_use_or_unification_node, get_parent_node, path_def_id, path_to_local, path_to_local_id};
+use core::cell::Cell;
+use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
-use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
-use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
-use rustc_hir::intravisit::{walk_expr, walk_stmt, FnKind, Visitor};
-use rustc_hir::{
- Arm, Block, Body, Closure, Expr, ExprKind, Guard, HirId, ImplicitSelfKind, Let, Local, Pat, PatKind, Path,
- PathSegment, QPath, Stmt, StmtKind, TyKind, UnOp,
-};
+use rustc_hir::hir_id::HirIdMap;
+use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_middle::ty::{Ty, TyCtxt, TypeckResults};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::kw;
-use rustc_span::symbol::Ident;
+use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
+use rustc_middle::ty::{self, ConstKind};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::{kw, Ident};
use rustc_span::Span;
+use std::iter;
declare_clippy_lint! {
/// ### What it does
@@ -89,572 +81,315 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "1.61.0"]
pub ONLY_USED_IN_RECURSION,
- nursery,
+ complexity,
"arguments that is only used in recursion can be removed"
}
-declare_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]);
-
-impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
- fn check_fn(
- &mut self,
- cx: &LateContext<'tcx>,
- kind: FnKind<'tcx>,
- decl: &'tcx rustc_hir::FnDecl<'tcx>,
- body: &'tcx Body<'tcx>,
- _: Span,
- id: HirId,
- ) {
- if is_lint_allowed(cx, ONLY_USED_IN_RECURSION, id) {
- return;
- }
- if let FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) = kind {
- let def_id = id.owner.to_def_id();
- let data = cx.tcx.def_path(def_id).data;
-
- if data.len() > 1 {
- match data.get(data.len() - 2) {
- Some(DisambiguatedDefPathData {
- data: DefPathData::Impl,
- disambiguator,
- }) if *disambiguator != 0 => return,
- _ => {},
- }
- }
-
- let has_self = !matches!(decl.implicit_self, ImplicitSelfKind::None);
-
- let ty_res = cx.typeck_results();
- let param_span = body
- .params
- .iter()
- .flat_map(|param| {
- let mut v = Vec::new();
- param.pat.each_binding(|_, hir_id, span, ident| {
- v.push((hir_id, span, ident));
- });
- v
- })
- .skip(if has_self { 1 } else { 0 })
- .filter(|(_, _, ident)| !ident.name.as_str().starts_with('_'))
- .collect_vec();
-
- let params = body.params.iter().map(|param| param.pat).collect();
-
- let mut visitor = SideEffectVisit {
- graph: FxHashMap::default(),
- has_side_effect: FxHashSet::default(),
- ret_vars: Vec::new(),
- contains_side_effect: false,
- break_vars: FxHashMap::default(),
- params,
- fn_ident: ident,
- fn_def_id: def_id,
- is_method: matches!(kind, FnKind::Method(..)),
- has_self,
- ty_res,
- tcx: cx.tcx,
- visited_exprs: FxHashSet::default(),
- };
-
- visitor.visit_expr(&body.value);
- let vars = std::mem::take(&mut visitor.ret_vars);
- // this would set the return variables to side effect
- visitor.add_side_effect(vars);
-
- let mut queue = visitor.has_side_effect.iter().copied().collect::<VecDeque<_>>();
-
- // a simple BFS to check all the variables that have side effect
- while let Some(id) = queue.pop_front() {
- if let Some(next) = visitor.graph.get(&id) {
- for i in next {
- if !visitor.has_side_effect.contains(i) {
- visitor.has_side_effect.insert(*i);
- queue.push_back(*i);
- }
- }
- }
- }
-
- for (id, span, ident) in param_span {
- // if the variable is not used in recursion, it would be marked as unused
- if !visitor.has_side_effect.contains(&id) {
- let mut queue = VecDeque::new();
- let mut visited = FxHashSet::default();
-
- queue.push_back(id);
-
- // a simple BFS to check the graph can reach to itself
- // if it can't, it means the variable is never used in recursion
- while let Some(id) = queue.pop_front() {
- if let Some(next) = visitor.graph.get(&id) {
- for i in next {
- if !visited.contains(i) {
- visited.insert(id);
- queue.push_back(*i);
- }
- }
- }
- }
+impl_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]);
+
+#[derive(Clone, Copy)]
+enum FnKind {
+ Fn,
+ TraitFn,
+ // This is a hack. Ideally we would store a `SubstsRef<'tcx>` type here, but a lint pass must be `'static`.
+ // Substitutions are, however, interned. This allows us to store the pointer as a `usize` when comparing for
+ // equality.
+ ImplTraitFn(usize),
+}
- if visited.contains(&id) {
- span_lint_and_sugg(
- cx,
- ONLY_USED_IN_RECURSION,
- span,
- "parameter is only used in recursion",
- "if this is intentional, prefix with an underscore",
- format!("_{}", ident.name.as_str()),
- Applicability::MaybeIncorrect,
- );
- }
- }
- }
+struct Param {
+ /// The function this is a parameter for.
+ fn_id: DefId,
+ fn_kind: FnKind,
+ /// The index of this parameter.
+ idx: usize,
+ ident: Ident,
+ /// Whether this parameter should be linted. Set by `Params::flag_for_linting`.
+ apply_lint: Cell<bool>,
+ /// All the uses of this parameter.
+ uses: Vec<Usage>,
+}
+impl Param {
+ fn new(fn_id: DefId, fn_kind: FnKind, idx: usize, ident: Ident) -> Self {
+ Self {
+ fn_id,
+ fn_kind,
+ idx,
+ ident,
+ apply_lint: Cell::new(true),
+ uses: Vec::new(),
}
}
}
-pub fn is_primitive(ty: Ty<'_>) -> bool {
- let ty = ty.peel_refs();
- ty.is_primitive() || ty.is_str()
+#[derive(Debug)]
+struct Usage {
+ span: Span,
+ idx: usize,
}
-
-pub fn is_array(ty: Ty<'_>) -> bool {
- let ty = ty.peel_refs();
- ty.is_array() || ty.is_array_slice()
+impl Usage {
+ fn new(span: Span, idx: usize) -> Self {
+ Self { span, idx }
+ }
}
-/// This builds the graph of side effect.
-/// The edge `a -> b` means if `a` has side effect, `b` will have side effect.
-///
-/// There are some example in following code:
-/// ```rust, ignore
-/// let b = 1;
-/// let a = b; // a -> b
-/// let (c, d) = (a, b); // c -> b, d -> b
-///
-/// let e = if a == 0 { // e -> a
-/// c // e -> c
-/// } else {
-/// d // e -> d
-/// };
-/// ```
-pub struct SideEffectVisit<'tcx> {
- graph: FxHashMap<HirId, FxHashSet<HirId>>,
- has_side_effect: FxHashSet<HirId>,
- // bool for if the variable was dereferenced from mutable reference
- ret_vars: Vec<(HirId, bool)>,
- contains_side_effect: bool,
- // break label
- break_vars: FxHashMap<Ident, Vec<(HirId, bool)>>,
- params: Vec<&'tcx Pat<'tcx>>,
- fn_ident: Ident,
- fn_def_id: DefId,
- is_method: bool,
- has_self: bool,
- ty_res: &'tcx TypeckResults<'tcx>,
- tcx: TyCtxt<'tcx>,
- visited_exprs: FxHashSet<HirId>,
+/// The parameters being checked by the lint, indexed by both the parameter's `HirId` and the
+/// `DefId` of the function paired with the parameter's index.
+#[derive(Default)]
+struct Params {
+ params: Vec<Param>,
+ by_id: HirIdMap<usize>,
+ by_fn: FxHashMap<(DefId, usize), usize>,
}
-
-impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> {
- fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) {
- match s.kind {
- StmtKind::Local(Local {
- pat, init: Some(init), ..
- }) => {
- self.visit_pat_expr(pat, init, false);
- },
- StmtKind::Item(_) | StmtKind::Expr(_) | StmtKind::Semi(_) => {
- walk_stmt(self, s);
- },
- StmtKind::Local(_) => {},
- }
- self.ret_vars.clear();
+impl Params {
+ fn insert(&mut self, param: Param, id: HirId) {
+ let idx = self.params.len();
+ self.by_id.insert(id, idx);
+ self.by_fn.insert((param.fn_id, param.idx), idx);
+ self.params.push(param);
}
- fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
- if !self.visited_exprs.insert(ex.hir_id) {
- return;
- }
- match ex.kind {
- ExprKind::Array(exprs) | ExprKind::Tup(exprs) => {
- self.ret_vars = exprs
- .iter()
- .flat_map(|expr| {
- self.visit_expr(expr);
- std::mem::take(&mut self.ret_vars)
- })
- .collect();
- },
- ExprKind::Call(callee, args) => self.visit_fn(callee, args),
- ExprKind::MethodCall(path, args, _) => self.visit_method_call(path, args),
- ExprKind::Binary(_, lhs, rhs) => {
- self.visit_bin_op(lhs, rhs);
- },
- ExprKind::Unary(op, expr) => self.visit_un_op(op, expr),
- ExprKind::Let(Let { pat, init, .. }) => self.visit_pat_expr(pat, init, false),
- ExprKind::If(bind, then_expr, else_expr) => {
- self.visit_if(bind, then_expr, else_expr);
- },
- ExprKind::Match(expr, arms, _) => self.visit_match(expr, arms),
- // since analysing the closure is not easy, just set all variables in it to side-effect
- ExprKind::Closure(&Closure { body, .. }) => {
- let body = self.tcx.hir().body(body);
- self.visit_body(body);
- let vars = std::mem::take(&mut self.ret_vars);
- self.add_side_effect(vars);
- },
- ExprKind::Loop(block, label, _, _) | ExprKind::Block(block, label) => {
- self.visit_block_label(block, label);
- },
- ExprKind::Assign(bind, expr, _) => {
- self.visit_assign(bind, expr);
- },
- ExprKind::AssignOp(_, bind, expr) => {
- self.visit_assign(bind, expr);
- self.visit_bin_op(bind, expr);
- },
- ExprKind::Field(expr, _) => {
- self.visit_expr(expr);
- if matches!(self.ty_res.expr_ty(expr).kind(), ty::Ref(_, _, Mutability::Mut)) {
- self.ret_vars.iter_mut().for_each(|(_, b)| *b = true);
- }
- },
- ExprKind::Index(expr, index) => {
- self.visit_expr(expr);
- let mut vars = std::mem::take(&mut self.ret_vars);
- self.visit_expr(index);
- self.ret_vars.append(&mut vars);
-
- if !is_array(self.ty_res.expr_ty(expr)) {
- self.add_side_effect(self.ret_vars.clone());
- } else if matches!(self.ty_res.expr_ty(expr).kind(), ty::Ref(_, _, Mutability::Mut)) {
- self.ret_vars.iter_mut().for_each(|(_, b)| *b = true);
- }
- },
- ExprKind::Break(dest, Some(expr)) => {
- self.visit_expr(expr);
- if let Some(label) = dest.label {
- self.break_vars
- .entry(label.ident)
- .or_insert(Vec::new())
- .append(&mut self.ret_vars);
- }
- self.contains_side_effect = true;
- },
- ExprKind::Ret(Some(expr)) => {
- self.visit_expr(expr);
- let vars = std::mem::take(&mut self.ret_vars);
- self.add_side_effect(vars);
- self.contains_side_effect = true;
- },
- ExprKind::Break(_, None) | ExprKind::Continue(_) | ExprKind::Ret(None) => {
- self.contains_side_effect = true;
- },
- ExprKind::Struct(_, exprs, expr) => {
- let mut ret_vars = exprs
- .iter()
- .flat_map(|field| {
- self.visit_expr(field.expr);
- std::mem::take(&mut self.ret_vars)
- })
- .collect();
-
- walk_list!(self, visit_expr, expr);
- self.ret_vars.append(&mut ret_vars);
- },
- _ => walk_expr(self, ex),
+ fn remove_by_id(&mut self, id: HirId) {
+ if let Some(param) = self.get_by_id_mut(id) {
+ param.uses = Vec::new();
+ let key = (param.fn_id, param.idx);
+ self.by_fn.remove(&key);
+ self.by_id.remove(&id);
}
}
- fn visit_path(&mut self, path: &'tcx Path<'tcx>, _id: HirId) {
- if let Res::Local(id) = path.res {
- self.ret_vars.push((id, false));
- }
+ fn get_by_id_mut(&mut self, id: HirId) -> Option<&mut Param> {
+ self.params.get_mut(*self.by_id.get(&id)?)
}
-}
-impl<'tcx> SideEffectVisit<'tcx> {
- fn visit_assign(&mut self, lhs: &'tcx Expr<'tcx>, rhs: &'tcx Expr<'tcx>) {
- // Just support array and tuple unwrapping for now.
- //
- // ex) `(a, b) = (c, d);`
- // The graph would look like this:
- // a -> c
- // b -> d
- //
- // This would minimize the connection of the side-effect graph.
- match (&lhs.kind, &rhs.kind) {
- (ExprKind::Array(lhs), ExprKind::Array(rhs)) | (ExprKind::Tup(lhs), ExprKind::Tup(rhs)) => {
- // if not, it is a compile error
- debug_assert!(lhs.len() == rhs.len());
- izip!(*lhs, *rhs).for_each(|(lhs, rhs)| self.visit_assign(lhs, rhs));
- },
- // in other assigns, we have to connect all each other
- // because they can be connected somehow
- _ => {
- self.visit_expr(lhs);
- let lhs_vars = std::mem::take(&mut self.ret_vars);
- self.visit_expr(rhs);
- let rhs_vars = std::mem::take(&mut self.ret_vars);
- self.connect_assign(&lhs_vars, &rhs_vars, false);
- },
- }
+ fn get_by_fn(&self, id: DefId, idx: usize) -> Option<&Param> {
+ self.params.get(*self.by_fn.get(&(id, idx))?)
}
- fn visit_block_label(&mut self, block: &'tcx Block<'tcx>, label: Option<Label>) {
- self.visit_block(block);
- let _ = label.and_then(|label| {
- self.break_vars
- .remove(&label.ident)
- .map(|mut break_vars| self.ret_vars.append(&mut break_vars))
- });
- }
-
- fn visit_bin_op(&mut self, lhs: &'tcx Expr<'tcx>, rhs: &'tcx Expr<'tcx>) {
- self.visit_expr(lhs);
- let mut ret_vars = std::mem::take(&mut self.ret_vars);
- self.visit_expr(rhs);
- self.ret_vars.append(&mut ret_vars);
-
- // the binary operation between non primitive values are overloaded operators
- // so they can have side-effects
- if !is_primitive(self.ty_res.expr_ty(lhs)) || !is_primitive(self.ty_res.expr_ty(rhs)) {
- self.ret_vars.iter().for_each(|id| {
- self.has_side_effect.insert(id.0);
- });
- self.contains_side_effect = true;
- }
+ fn clear(&mut self) {
+ self.params.clear();
+ self.by_id.clear();
+ self.by_fn.clear();
}
- fn visit_un_op(&mut self, op: UnOp, expr: &'tcx Expr<'tcx>) {
- self.visit_expr(expr);
- let ty = self.ty_res.expr_ty(expr);
- // dereferencing a reference has no side-effect
- if !is_primitive(ty) && !matches!((op, ty.kind()), (UnOp::Deref, ty::Ref(..))) {
- self.add_side_effect(self.ret_vars.clone());
- }
-
- if matches!((op, ty.kind()), (UnOp::Deref, ty::Ref(_, _, Mutability::Mut))) {
- self.ret_vars.iter_mut().for_each(|(_, b)| *b = true);
+ /// Sets the `apply_lint` flag on each parameter.
+ fn flag_for_linting(&mut self) {
+ // Stores the list of parameters currently being resolved. Needed to avoid cycles.
+ let mut eval_stack = Vec::new();
+ for param in &self.params {
+ self.try_disable_lint_for_param(param, &mut eval_stack);
}
}
- fn visit_pat_expr(&mut self, pat: &'tcx Pat<'tcx>, expr: &'tcx Expr<'tcx>, connect_self: bool) {
- match (&pat.kind, &expr.kind) {
- (PatKind::Tuple(pats, _), ExprKind::Tup(exprs)) => {
- self.ret_vars = izip!(*pats, *exprs)
- .flat_map(|(pat, expr)| {
- self.visit_pat_expr(pat, expr, connect_self);
- std::mem::take(&mut self.ret_vars)
- })
- .collect();
- },
- (PatKind::Slice(front_exprs, _, back_exprs), ExprKind::Array(exprs)) => {
- let mut vars = izip!(*front_exprs, *exprs)
- .flat_map(|(pat, expr)| {
- self.visit_pat_expr(pat, expr, connect_self);
- std::mem::take(&mut self.ret_vars)
- })
- .collect();
- self.ret_vars = izip!(back_exprs.iter().rev(), exprs.iter().rev())
- .flat_map(|(pat, expr)| {
- self.visit_pat_expr(pat, expr, connect_self);
- std::mem::take(&mut self.ret_vars)
- })
- .collect();
- self.ret_vars.append(&mut vars);
- },
- _ => {
- let mut lhs_vars = Vec::new();
- pat.each_binding(|_, id, _, _| lhs_vars.push((id, false)));
- self.visit_expr(expr);
- let rhs_vars = std::mem::take(&mut self.ret_vars);
- self.connect_assign(&lhs_vars, &rhs_vars, connect_self);
- self.ret_vars = rhs_vars;
- },
+ // Use by calling `flag_for_linting`.
+ fn try_disable_lint_for_param(&self, param: &Param, eval_stack: &mut Vec<usize>) -> bool {
+ if !param.apply_lint.get() {
+ true
+ } else if param.uses.is_empty() {
+ // Don't lint on unused parameters.
+ param.apply_lint.set(false);
+ true
+ } else if eval_stack.contains(&param.idx) {
+ // Already on the evaluation stack. Returning false will continue to evaluate other dependencies.
+ false
+ } else {
+ eval_stack.push(param.idx);
+ // Check all cases when used at a different parameter index.
+ // Needed to catch cases like: `fn f(x: u32, y: u32) { f(y, x) }`
+ for usage in param.uses.iter().filter(|u| u.idx != param.idx) {
+ if self
+ .get_by_fn(param.fn_id, usage.idx)
+ // If the parameter can't be found, then it's used for more than just recursion.
+ .map_or(true, |p| self.try_disable_lint_for_param(p, eval_stack))
+ {
+ param.apply_lint.set(false);
+ eval_stack.pop();
+ return true;
+ }
+ }
+ eval_stack.pop();
+ false
}
}
+}
- fn visit_fn(&mut self, callee: &'tcx Expr<'tcx>, args: &'tcx [Expr<'tcx>]) {
- self.visit_expr(callee);
- let mut ret_vars = std::mem::take(&mut self.ret_vars);
- self.add_side_effect(ret_vars.clone());
-
- let mut is_recursive = false;
-
- if_chain! {
- if !self.has_self;
- if let ExprKind::Path(QPath::Resolved(_, path)) = callee.kind;
- if let Res::Def(DefKind::Fn, def_id) = path.res;
- if self.fn_def_id == def_id;
- then {
- is_recursive = true;
- }
- }
+#[derive(Default)]
+pub struct OnlyUsedInRecursion {
+ /// Track the top-level body entered. Needed to delay reporting when entering nested bodies.
+ entered_body: Option<HirId>,
+ params: Params,
+}
- if_chain! {
- if !self.has_self && self.is_method;
- if let ExprKind::Path(QPath::TypeRelative(ty, segment)) = callee.kind;
- if segment.ident == self.fn_ident;
- if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
- if let Res::SelfTy{ .. } = path.res;
- then {
- is_recursive = true;
- }
+impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
+ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) {
+ if body.value.span.from_expansion() {
+ return;
}
-
- if is_recursive {
- izip!(self.params.clone(), args).for_each(|(pat, expr)| {
- self.visit_pat_expr(pat, expr, true);
- self.ret_vars.clear();
- });
- } else {
- // This would set arguments used in closure that does not have side-effect.
- // Closure itself can be detected whether there is a side-effect, but the
- // value of variable that is holding closure can change.
- // So, we just check the variables.
- self.ret_vars = args
- .iter()
- .flat_map(|expr| {
- self.visit_expr(expr);
- std::mem::take(&mut self.ret_vars)
- })
- .collect_vec()
- .into_iter()
- .map(|id| {
- self.has_side_effect.insert(id.0);
- id
- })
- .collect();
- self.contains_side_effect = true;
+ // `skip_params` is either `0` or `1` to skip the `self` parameter in trait functions.
+ // It can't be renamed, and it can't be removed without removing it from multiple functions.
+ let (fn_id, fn_kind, skip_params) = match get_parent_node(cx.tcx, body.value.hir_id) {
+ Some(Node::Item(i)) => (i.owner_id.to_def_id(), FnKind::Fn, 0),
+ Some(Node::TraitItem(&TraitItem {
+ kind: TraitItemKind::Fn(ref sig, _),
+ owner_id,
+ ..
+ })) => (
+ owner_id.to_def_id(),
+ FnKind::TraitFn,
+ usize::from(sig.decl.implicit_self.has_implicit_self()),
+ ),
+ Some(Node::ImplItem(&ImplItem {
+ kind: ImplItemKind::Fn(ref sig, _),
+ owner_id,
+ ..
+ })) => {
+ #[allow(trivial_casts)]
+ if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into())
+ && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+ && let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id
+ {
+ (
+ trait_item_id,
+ FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.substs) as *const _ as usize),
+ usize::from(sig.decl.implicit_self.has_implicit_self()),
+ )
+ } else {
+ (owner_id.to_def_id(), FnKind::Fn, 0)
+ }
+ },
+ _ => return,
+ };
+ body.params
+ .iter()
+ .enumerate()
+ .skip(skip_params)
+ .filter_map(|(idx, p)| match p.pat.kind {
+ PatKind::Binding(_, id, ident, None) if !ident.as_str().starts_with('_') => {
+ Some((id, Param::new(fn_id, fn_kind, idx, ident)))
+ },
+ _ => None,
+ })
+ .for_each(|(id, param)| self.params.insert(param, id));
+ if self.entered_body.is_none() {
+ self.entered_body = Some(body.value.hir_id);
}
-
- self.ret_vars.append(&mut ret_vars);
}
- fn visit_method_call(&mut self, path: &'tcx PathSegment<'tcx>, args: &'tcx [Expr<'tcx>]) {
- if_chain! {
- if self.is_method;
- if path.ident == self.fn_ident;
- if let ExprKind::Path(QPath::Resolved(_, path)) = args.first().unwrap().kind;
- if let Res::Local(..) = path.res;
- let ident = path.segments.last().unwrap().ident;
- if ident.name == kw::SelfLower;
- then {
- izip!(self.params.clone(), args.iter())
- .for_each(|(pat, expr)| {
- self.visit_pat_expr(pat, expr, true);
- self.ret_vars.clear();
- });
- } else {
- self.ret_vars = args
- .iter()
- .flat_map(|expr| {
- self.visit_expr(expr);
- std::mem::take(&mut self.ret_vars)
- })
- .collect_vec()
- .into_iter()
- .map(|a| {
- self.has_side_effect.insert(a.0);
- a
- })
- .collect();
- self.contains_side_effect = true;
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) {
+ if let Some(id) = path_to_local(e)
+ && let Some(param) = self.params.get_by_id_mut(id)
+ {
+ let typeck = cx.typeck_results();
+ let span = e.span;
+ let mut e = e;
+ loop {
+ match get_expr_use_or_unification_node(cx.tcx, e) {
+ None | Some((Node::Stmt(_), _)) => return,
+ Some((Node::Expr(parent), child_id)) => match parent.kind {
+ // Recursive call. Track which index the parameter is used in.
+ ExprKind::Call(callee, args)
+ if path_def_id(cx, callee).map_or(false, |id| {
+ id == param.fn_id
+ && has_matching_substs(param.fn_kind, typeck.node_substs(callee.hir_id))
+ }) =>
+ {
+ if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) {
+ param.uses.push(Usage::new(span, idx));
+ }
+ return;
+ },
+ ExprKind::MethodCall(_, receiver, args, _)
+ if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| {
+ id == param.fn_id
+ && has_matching_substs(param.fn_kind, typeck.node_substs(parent.hir_id))
+ }) =>
+ {
+ if let Some(idx) = iter::once(receiver).chain(args).position(|arg| arg.hir_id == child_id) {
+ param.uses.push(Usage::new(span, idx));
+ }
+ return;
+ },
+ // Assignment to a parameter is fine.
+ ExprKind::Assign(lhs, _, _) | ExprKind::AssignOp(_, lhs, _) if lhs.hir_id == child_id => {
+ return;
+ },
+ // Parameter update e.g. `x = x + 1`
+ ExprKind::Assign(lhs, rhs, _) | ExprKind::AssignOp(_, lhs, rhs)
+ if rhs.hir_id == child_id && path_to_local_id(lhs, id) =>
+ {
+ return;
+ },
+ // Side-effect free expressions. Walk to the parent expression.
+ ExprKind::Binary(_, lhs, rhs)
+ if typeck.expr_ty(lhs).is_primitive() && typeck.expr_ty(rhs).is_primitive() =>
+ {
+ e = parent;
+ continue;
+ },
+ ExprKind::Unary(_, arg) if typeck.expr_ty(arg).is_primitive() => {
+ e = parent;
+ continue;
+ },
+ ExprKind::AddrOf(..) | ExprKind::Cast(..) => {
+ e = parent;
+ continue;
+ },
+ // Only allow field accesses without auto-deref
+ ExprKind::Field(..) if typeck.adjustments().get(child_id).is_none() => {
+ e = parent;
+ continue
+ }
+ _ => (),
+ },
+ _ => (),
+ }
+ self.params.remove_by_id(id);
+ return;
}
}
}
- fn visit_if(&mut self, bind: &'tcx Expr<'tcx>, then_expr: &'tcx Expr<'tcx>, else_expr: Option<&'tcx Expr<'tcx>>) {
- let contains_side_effect = self.contains_side_effect;
- self.contains_side_effect = false;
- self.visit_expr(bind);
- let mut vars = std::mem::take(&mut self.ret_vars);
- self.visit_expr(then_expr);
- let mut then_vars = std::mem::take(&mut self.ret_vars);
- walk_list!(self, visit_expr, else_expr);
- if self.contains_side_effect {
- self.add_side_effect(vars.clone());
- }
- self.contains_side_effect |= contains_side_effect;
- self.ret_vars.append(&mut vars);
- self.ret_vars.append(&mut then_vars);
- }
-
- fn visit_match(&mut self, expr: &'tcx Expr<'tcx>, arms: &'tcx [Arm<'tcx>]) {
- self.visit_expr(expr);
- let mut expr_vars = std::mem::take(&mut self.ret_vars);
- self.ret_vars = arms
- .iter()
- .flat_map(|arm| {
- let contains_side_effect = self.contains_side_effect;
- self.contains_side_effect = false;
- // this would visit `expr` multiple times
- // but couldn't think of a better way
- self.visit_pat_expr(arm.pat, expr, false);
- let mut vars = std::mem::take(&mut self.ret_vars);
- let _ = arm.guard.as_ref().map(|guard| {
- self.visit_expr(match guard {
- Guard::If(expr) | Guard::IfLet(Let { init: expr, .. }) => expr,
- });
- vars.append(&mut self.ret_vars);
- });
- self.visit_expr(arm.body);
- if self.contains_side_effect {
- self.add_side_effect(vars.clone());
- self.add_side_effect(expr_vars.clone());
+ fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) {
+ if self.entered_body == Some(body.value.hir_id) {
+ self.entered_body = None;
+ self.params.flag_for_linting();
+ for param in &self.params.params {
+ if param.apply_lint.get() {
+ span_lint_and_then(
+ cx,
+ ONLY_USED_IN_RECURSION,
+ param.ident.span,
+ "parameter is only used in recursion",
+ |diag| {
+ if param.ident.name != kw::SelfLower {
+ diag.span_suggestion(
+ param.ident.span,
+ "if this is intentional, prefix it with an underscore",
+ format!("_{}", param.ident.name),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ diag.span_note(
+ param.uses.iter().map(|x| x.span).collect::<Vec<_>>(),
+ "parameter used here",
+ );
+ },
+ );
}
- self.contains_side_effect |= contains_side_effect;
- vars.append(&mut self.ret_vars);
- vars
- })
- .collect();
- self.ret_vars.append(&mut expr_vars);
- }
-
- fn connect_assign(&mut self, lhs: &[(HirId, bool)], rhs: &[(HirId, bool)], connect_self: bool) {
- // if mutable dereference is on assignment it can have side-effect
- // (this can lead to parameter mutable dereference and change the original value)
- // too hard to detect whether this value is from parameter, so this would all
- // check mutable dereference assignment to side effect
- lhs.iter().filter(|(_, b)| *b).for_each(|(id, _)| {
- self.has_side_effect.insert(*id);
- self.contains_side_effect = true;
- });
-
- // there is no connection
- if lhs.is_empty() || rhs.is_empty() {
- return;
- }
-
- // by connected rhs in cycle, the connections would decrease
- // from `n * m` to `n + m`
- // where `n` and `m` are length of `lhs` and `rhs`.
-
- // unwrap is possible since rhs is not empty
- let rhs_first = rhs.first().unwrap();
- for (id, _) in lhs.iter() {
- if connect_self || *id != rhs_first.0 {
- self.graph
- .entry(*id)
- .or_insert_with(FxHashSet::default)
- .insert(rhs_first.0);
}
+ self.params.clear();
}
-
- let rhs = rhs.iter();
- izip!(rhs.clone().cycle().skip(1), rhs).for_each(|(from, to)| {
- if connect_self || from.0 != to.0 {
- self.graph.entry(from.0).or_insert_with(FxHashSet::default).insert(to.0);
- }
- });
}
+}
- fn add_side_effect(&mut self, v: Vec<(HirId, bool)>) {
- for (id, _) in v {
- self.has_side_effect.insert(id);
- self.contains_side_effect = true;
- }
+fn has_matching_substs(kind: FnKind, substs: SubstsRef<'_>) -> bool {
+ match kind {
+ FnKind::Fn => true,
+ FnKind::TraitFn => substs.iter().enumerate().all(|(idx, subst)| match subst.unpack() {
+ GenericArgKind::Lifetime(_) => true,
+ GenericArgKind::Type(ty) => matches!(*ty.kind(), ty::Param(ty) if ty.index as usize == idx),
+ GenericArgKind::Const(c) => matches!(c.kind(), ConstKind::Param(c) if c.index as usize == idx),
+ }),
+ #[allow(trivial_casts)]
+ FnKind::ImplTraitFn(expected_substs) => substs as *const _ as usize == expected_substs,
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
index 1ec4240af..d29ca37ea 100644
--- a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs
@@ -34,13 +34,12 @@ pub(super) fn check<'tcx>(
};
let help = format!(
- "because `{}` is the {} value for this type, {}",
+ "because `{}` is the {} value for this type, {conclusion}",
snippet(cx, culprit.expr.span, "x"),
match culprit.which {
ExtremeType::Minimum => "minimum",
ExtremeType::Maximum => "maximum",
- },
- conclusion
+ }
);
span_lint_and_help(cx, ABSURD_EXTREME_COMPARISONS, expr.span, msg, None, &help);
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic.rs
deleted file mode 100644
index 800cf249f..000000000
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-#![allow(
- // False positive
- clippy::match_same_arms
-)]
-
-use super::ARITHMETIC;
-use clippy_utils::{consts::constant_simple, diagnostics::span_lint};
-use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::impl_lint_pass;
-use rustc_span::source_map::Span;
-
-const HARD_CODED_ALLOWED: &[&str] = &["std::num::Saturating", "std::string::String", "std::num::Wrapping"];
-
-#[derive(Debug)]
-pub struct Arithmetic {
- allowed: FxHashSet<String>,
- // Used to check whether expressions are constants, such as in enum discriminants and consts
- const_span: Option<Span>,
- expr_span: Option<Span>,
-}
-
-impl_lint_pass!(Arithmetic => [ARITHMETIC]);
-
-impl Arithmetic {
- #[must_use]
- pub fn new(mut allowed: FxHashSet<String>) -> Self {
- allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from));
- Self {
- allowed,
- const_span: None,
- expr_span: None,
- }
- }
-
- /// Checks if the given `expr` has any of the inner `allowed` elements.
- fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
- self.allowed.contains(
- cx.typeck_results()
- .expr_ty(expr)
- .to_string()
- .split('<')
- .next()
- .unwrap_or_default(),
- )
- }
-
- fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
- span_lint(cx, ARITHMETIC, expr.span, "arithmetic detected");
- self.expr_span = Some(expr.span);
- }
-}
-
-impl<'tcx> LateLintPass<'tcx> for Arithmetic {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if self.expr_span.is_some() {
- return;
- }
- if let Some(span) = self.const_span && span.contains(expr.span) {
- return;
- }
- match &expr.kind {
- hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => {
- let (
- hir::BinOpKind::Add
- | hir::BinOpKind::Sub
- | hir::BinOpKind::Mul
- | hir::BinOpKind::Div
- | hir::BinOpKind::Rem
- | hir::BinOpKind::Shl
- | hir::BinOpKind::Shr
- ) = op.node else {
- return;
- };
- if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) {
- return;
- }
- self.issue_lint(cx, expr);
- },
- hir::ExprKind::Unary(hir::UnOp::Neg, _) => {
- // CTFE already takes care of things like `-1` that do not overflow.
- if constant_simple(cx, cx.typeck_results(), expr).is_none() {
- self.issue_lint(cx, expr);
- }
- },
- _ => {},
- }
- }
-
- fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
- let body_owner = cx.tcx.hir().body_owner_def_id(body.id());
- match cx.tcx.hir().body_owner_kind(body_owner) {
- hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => {
- let body_span = cx.tcx.def_span(body_owner);
- if let Some(span) = self.const_span && span.contains(body_span) {
- return;
- }
- self.const_span = Some(body_span);
- },
- hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => {},
- }
- }
-
- fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
- let body_owner = cx.tcx.hir().body_owner(body.id());
- let body_span = cx.tcx.hir().span(body_owner);
- if let Some(span) = self.const_span && span.contains(body_span) {
- return;
- }
- self.const_span = None;
- }
-
- fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if Some(expr.span) == self.expr_span {
- self.expr_span = None;
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
new file mode 100644
index 000000000..8827daaa3
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -0,0 +1,198 @@
+use super::ARITHMETIC_SIDE_EFFECTS;
+use clippy_utils::{consts::constant_simple, diagnostics::span_lint};
+use rustc_ast as ast;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Ty;
+use rustc_session::impl_lint_pass;
+use rustc_span::source_map::{Span, Spanned};
+
+const HARD_CODED_ALLOWED: &[&str] = &[
+ "&str",
+ "f32",
+ "f64",
+ "std::num::Saturating",
+ "std::num::Wrapping",
+ "std::string::String",
+];
+
+#[derive(Debug)]
+pub struct ArithmeticSideEffects {
+ allowed: FxHashSet<String>,
+ // Used to check whether expressions are constants, such as in enum discriminants and consts
+ const_span: Option<Span>,
+ expr_span: Option<Span>,
+}
+
+impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]);
+
+impl ArithmeticSideEffects {
+ #[must_use]
+ pub fn new(mut allowed: FxHashSet<String>) -> Self {
+ allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from));
+ Self {
+ allowed,
+ const_span: None,
+ expr_span: None,
+ }
+ }
+
+ /// Assuming that `expr` is a literal integer, checks operators (+=, -=, *, /) in a
+ /// non-constant environment that won't overflow.
+ fn has_valid_op(op: &Spanned<hir::BinOpKind>, expr: &hir::Expr<'_>) -> bool {
+ if let hir::ExprKind::Lit(ref lit) = expr.kind &&
+ let ast::LitKind::Int(value, _) = lit.node
+ {
+ match (&op.node, value) {
+ (hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
+ (hir::BinOpKind::Add | hir::BinOpKind::Sub, 0)
+ | (hir::BinOpKind::Div | hir::BinOpKind::Rem, _)
+ | (hir::BinOpKind::Mul, 0 | 1) => true,
+ _ => false,
+ }
+ } else {
+ false
+ }
+ }
+
+ /// Checks if the given `expr` has any of the inner `allowed` elements.
+ fn is_allowed_ty(&self, ty: Ty<'_>) -> bool {
+ self.allowed
+ .contains(ty.to_string().split('<').next().unwrap_or_default())
+ }
+
+ // For example, 8i32 or &i64::MAX.
+ fn is_integral(ty: Ty<'_>) -> bool {
+ ty.peel_refs().is_integral()
+ }
+
+ // Common entry-point to avoid code duplication.
+ fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
+ let msg = "arithmetic operation that can potentially result in unexpected side-effects";
+ span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, msg);
+ self.expr_span = Some(expr.span);
+ }
+
+ /// If `expr` does not match any variant of `LiteralIntegerTy`, returns `None`.
+ fn literal_integer<'expr, 'tcx>(expr: &'expr hir::Expr<'tcx>) -> Option<LiteralIntegerTy<'expr, 'tcx>> {
+ if matches!(expr.kind, hir::ExprKind::Lit(_)) {
+ return Some(LiteralIntegerTy::Value(expr));
+ }
+ if let hir::ExprKind::AddrOf(.., inn) = expr.kind && let hir::ExprKind::Lit(_) = inn.kind {
+ return Some(LiteralIntegerTy::Ref(inn));
+ }
+ None
+ }
+
+ /// Manages when the lint should be triggered. Operations in constant environments, hard coded
+ /// types, custom allowed types and non-constant operations that won't overflow are ignored.
+ fn manage_bin_ops<'tcx>(
+ &mut self,
+ cx: &LateContext<'tcx>,
+ expr: &hir::Expr<'tcx>,
+ op: &Spanned<hir::BinOpKind>,
+ lhs: &hir::Expr<'tcx>,
+ rhs: &hir::Expr<'tcx>,
+ ) {
+ if constant_simple(cx, cx.typeck_results(), expr).is_some() {
+ return;
+ }
+ if !matches!(
+ op.node,
+ hir::BinOpKind::Add
+ | hir::BinOpKind::Sub
+ | hir::BinOpKind::Mul
+ | hir::BinOpKind::Div
+ | hir::BinOpKind::Rem
+ | hir::BinOpKind::Shl
+ | hir::BinOpKind::Shr
+ ) {
+ return;
+ };
+ let lhs_ty = cx.typeck_results().expr_ty(lhs);
+ let rhs_ty = cx.typeck_results().expr_ty(rhs);
+ let lhs_and_rhs_have_the_same_ty = lhs_ty == rhs_ty;
+ if lhs_and_rhs_have_the_same_ty && self.is_allowed_ty(lhs_ty) && self.is_allowed_ty(rhs_ty) {
+ return;
+ }
+ let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
+ match (Self::literal_integer(lhs), Self::literal_integer(rhs)) {
+ (None, Some(lit_int_ty)) | (Some(lit_int_ty), None) => Self::has_valid_op(op, lit_int_ty.into()),
+ (Some(LiteralIntegerTy::Value(_)), Some(LiteralIntegerTy::Value(_))) => true,
+ (None, None) | (Some(_), Some(_)) => false,
+ }
+ } else {
+ false
+ };
+ if !has_valid_op {
+ self.issue_lint(cx, expr);
+ }
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) {
+ if self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) {
+ return;
+ }
+ match &expr.kind {
+ hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => {
+ self.manage_bin_ops(cx, expr, op, lhs, rhs);
+ },
+ hir::ExprKind::Unary(hir::UnOp::Neg, _) => {
+ if constant_simple(cx, cx.typeck_results(), expr).is_none() {
+ self.issue_lint(cx, expr);
+ }
+ },
+ _ => {},
+ }
+ }
+
+ fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
+ let body_owner = cx.tcx.hir().body_owner(body.id());
+ let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner);
+ let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id);
+ if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind {
+ let body_span = cx.tcx.hir().span_with_body(body_owner);
+ if let Some(span) = self.const_span && span.contains(body_span) {
+ return;
+ }
+ self.const_span = Some(body_span);
+ }
+ }
+
+ fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
+ let body_owner = cx.tcx.hir().body_owner(body.id());
+ let body_span = cx.tcx.hir().span(body_owner);
+ if let Some(span) = self.const_span && span.contains(body_span) {
+ return;
+ }
+ self.const_span = None;
+ }
+
+ fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+ if Some(expr.span) == self.expr_span {
+ self.expr_span = None;
+ }
+ }
+}
+
+/// Tells if an expression is a integer declared by value or by reference.
+///
+/// If `LiteralIntegerTy::Ref`, then the contained value will be `hir::ExprKind::Lit` rather
+/// than `hirExprKind::Addr`.
+enum LiteralIntegerTy<'expr, 'tcx> {
+ /// For example, `&199`
+ Ref(&'expr hir::Expr<'tcx>),
+ /// For example, `1` or `i32::MAX`
+ Value(&'expr hir::Expr<'tcx>),
+}
+
+impl<'expr, 'tcx> From<LiteralIntegerTy<'expr, 'tcx>> for &'expr hir::Expr<'tcx> {
+ fn from(from: LiteralIntegerTy<'expr, 'tcx>) -> Self {
+ match from {
+ LiteralIntegerTy::Ref(elem) | LiteralIntegerTy::Value(elem) => elem,
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
index 945a09a64..ee9fd9406 100644
--- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
@@ -2,16 +2,17 @@ use clippy_utils::binop_traits;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::implements_trait;
+use clippy_utils::visitors::for_each_expr;
use clippy_utils::{eq_expr_value, trait_ref_of_method};
+use core::ops::ControlFlow;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
-use rustc_hir::intravisit::{walk_expr, Visitor};
+use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_lint::LateContext;
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::BorrowKind;
use rustc_trait_selection::infer::TyCtxtInferExt;
-use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use super::ASSIGN_OP_PATTERN;
@@ -28,7 +29,7 @@ pub(super) fn check<'tcx>(
if_chain! {
if let Some((_, lang_item)) = binop_traits(op.node);
if let Ok(trait_id) = cx.tcx.lang_items().require(lang_item);
- let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id);
+ let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id).def_id;
if trait_ref_of_method(cx, parent_fn)
.map_or(true, |t| t.path.res.def_id() != trait_id);
if implements_trait(cx, ty, trait_id, &[rty.into()]);
@@ -55,7 +56,7 @@ pub(super) fn check<'tcx>(
diag.span_suggestion(
expr.span,
"replace it with",
- format!("{} {}= {}", snip_a, op.node.as_str(), snip_r),
+ format!("{snip_a} {}= {snip_r}", op.node.as_str()),
Applicability::MachineApplicable,
);
}
@@ -65,15 +66,19 @@ pub(super) fn check<'tcx>(
}
};
- let mut visitor = ExprVisitor {
- assignee,
- counter: 0,
- cx,
- };
-
- walk_expr(&mut visitor, e);
+ let mut found = false;
+ let found_multiple = for_each_expr(e, |e| {
+ if eq_expr_value(cx, assignee, e) {
+ if found {
+ return ControlFlow::Break(());
+ }
+ found = true;
+ }
+ ControlFlow::Continue(())
+ })
+ .is_some();
- if visitor.counter == 1 {
+ if found && !found_multiple {
// a = a op b
if eq_expr_value(cx, assignee, l) {
lint(assignee, r);
@@ -98,22 +103,6 @@ pub(super) fn check<'tcx>(
}
}
-struct ExprVisitor<'a, 'tcx> {
- assignee: &'a hir::Expr<'a>,
- counter: u8,
- cx: &'a LateContext<'tcx>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> {
- fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
- if eq_expr_value(self.cx, self.assignee, expr) {
- self.counter += 1;
- }
-
- walk_expr(self, expr);
- }
-}
-
fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet {
struct S(hir::HirIdSet);
impl Delegate<'_> for S {
@@ -134,16 +123,15 @@ fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet
}
let mut s = S(hir::HirIdSet::default());
- cx.tcx.infer_ctxt().enter(|infcx| {
- let mut v = ExprUseVisitor::new(
- &mut s,
- &infcx,
- cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
- cx.param_env,
- cx.typeck_results(),
- );
- v.consume_expr(e);
- });
+ let infcx = cx.tcx.infer_ctxt().build();
+ let mut v = ExprUseVisitor::new(
+ &mut s,
+ &infcx,
+ cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
+ cx.param_env,
+ cx.typeck_results(),
+ );
+ v.consume_expr(e);
s.0
}
@@ -167,15 +155,14 @@ fn mut_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet
}
let mut s = S(hir::HirIdSet::default());
- cx.tcx.infer_ctxt().enter(|infcx| {
- let mut v = ExprUseVisitor::new(
- &mut s,
- &infcx,
- cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
- cx.param_env,
- cx.typeck_results(),
- );
- v.consume_expr(e);
- });
+ let infcx = cx.tcx.infer_ctxt().build();
+ let mut v = ExprUseVisitor::new(
+ &mut s,
+ &infcx,
+ cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
+ cx.param_env,
+ cx.typeck_results(),
+ );
+ v.consume_expr(e);
s.0
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
index 74387fbc8..1369b3e74 100644
--- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
@@ -64,10 +64,7 @@ fn check_bit_mask(
cx,
BAD_BIT_MASK,
span,
- &format!(
- "incompatible bit mask: `_ & {}` can never be equal to `{}`",
- mask_value, cmp_value
- ),
+ &format!("incompatible bit mask: `_ & {mask_value}` can never be equal to `{cmp_value}`"),
);
}
} else if mask_value == 0 {
@@ -80,10 +77,7 @@ fn check_bit_mask(
cx,
BAD_BIT_MASK,
span,
- &format!(
- "incompatible bit mask: `_ | {}` can never be equal to `{}`",
- mask_value, cmp_value
- ),
+ &format!("incompatible bit mask: `_ | {mask_value}` can never be equal to `{cmp_value}`"),
);
}
},
@@ -96,10 +90,7 @@ fn check_bit_mask(
cx,
BAD_BIT_MASK,
span,
- &format!(
- "incompatible bit mask: `_ & {}` will always be lower than `{}`",
- mask_value, cmp_value
- ),
+ &format!("incompatible bit mask: `_ & {mask_value}` will always be lower than `{cmp_value}`"),
);
} else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
@@ -111,10 +102,7 @@ fn check_bit_mask(
cx,
BAD_BIT_MASK,
span,
- &format!(
- "incompatible bit mask: `_ | {}` will never be lower than `{}`",
- mask_value, cmp_value
- ),
+ &format!("incompatible bit mask: `_ | {mask_value}` will never be lower than `{cmp_value}`"),
);
} else {
check_ineffective_lt(cx, span, mask_value, cmp_value, "|");
@@ -130,10 +118,7 @@ fn check_bit_mask(
cx,
BAD_BIT_MASK,
span,
- &format!(
- "incompatible bit mask: `_ & {}` will never be higher than `{}`",
- mask_value, cmp_value
- ),
+ &format!("incompatible bit mask: `_ & {mask_value}` will never be higher than `{cmp_value}`"),
);
} else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
@@ -145,10 +130,7 @@ fn check_bit_mask(
cx,
BAD_BIT_MASK,
span,
- &format!(
- "incompatible bit mask: `_ | {}` will always be higher than `{}`",
- mask_value, cmp_value
- ),
+ &format!("incompatible bit mask: `_ | {mask_value}` will always be higher than `{cmp_value}`"),
);
} else {
check_ineffective_gt(cx, span, mask_value, cmp_value, "|");
@@ -167,10 +149,7 @@ fn check_ineffective_lt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op:
cx,
INEFFECTIVE_BIT_MASK,
span,
- &format!(
- "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
- op, m, c
- ),
+ &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"),
);
}
}
@@ -181,10 +160,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op:
cx,
INEFFECTIVE_BIT_MASK,
span,
- &format!(
- "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
- op, m, c
- ),
+ &format!("ineffective bit mask: `x {op} {m}` compared to `{c}`, is the same as x compared directly"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
index e1f9b5906..24aeb82a3 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::{match_any_def_paths, path_def_id, paths};
+use clippy_utils::{match_def_path, path_def_id, paths};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::LateContext;
@@ -38,7 +38,7 @@ fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'t
fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
let typeck = cx.typeck_results();
let (arg, arg_span) = match expr.kind {
- ExprKind::MethodCall(.., [arg], _)
+ ExprKind::MethodCall(_, arg, [], _)
if typeck
.type_dependent_def_id(expr.hir_id)
.and_then(|id| cx.tcx.trait_of_item(id))
@@ -49,13 +49,15 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
(arg, arg.span)
},
ExprKind::Call(path, [arg])
- if path_def_id(cx, path)
- .and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM]))
- .map_or(false, |idx| match idx {
- 0 => true,
- 1 => !is_copy(cx, typeck.expr_ty(expr)),
- _ => false,
- }) =>
+ if path_def_id(cx, path).map_or(false, |id| {
+ if match_def_path(cx, id, &paths::FROM_STR_METHOD) {
+ true
+ } else if cx.tcx.lang_items().from_fn() == Some(id) {
+ !is_copy(cx, typeck.expr_ty(expr))
+ } else {
+ false
+ }
+ }) =>
{
(arg, arg.span)
},
@@ -99,7 +101,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
let expr_snip;
let eq_impl;
if with_deref.is_implemented() {
- expr_snip = format!("*{}", arg_snip);
+ expr_snip = format!("*{arg_snip}");
eq_impl = with_deref;
} else {
expr_snip = arg_snip.to_string();
@@ -121,17 +123,15 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
};
if eq_impl.ty_eq_other {
hint = format!(
- "{}{}{}",
- expr_snip,
+ "{expr_snip}{}{}",
snippet(cx, cmp_span, ".."),
snippet(cx, other.span, "..")
);
} else {
hint = format!(
- "{}{}{}",
+ "{}{}{expr_snip}",
snippet(cx, other.span, ".."),
- snippet(cx, cmp_span, ".."),
- expr_snip
+ snippet(cx, cmp_span, "..")
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
index 0d067d1e1..49e662cac 100644
--- a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
@@ -17,7 +17,7 @@ pub(crate) fn check<'tcx>(
right: &'tcx Expr<'_>,
) {
if op == BinOpKind::Div
- && let ExprKind::MethodCall(method_path, [self_arg], _) = left.kind
+ && let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration)
&& let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right)
{
@@ -31,12 +31,11 @@ pub(crate) fn check<'tcx>(
cx,
DURATION_SUBSEC,
expr.span,
- &format!("calling `{}()` is more concise than this calculation", suggested_fn),
+ &format!("calling `{suggested_fn}()` is more concise than this calculation"),
"try",
format!(
- "{}.{}()",
- snippet_with_applicability(cx, self_arg.span, "_", &mut applicability),
- suggested_fn
+ "{}.{suggested_fn}()",
+ snippet_with_applicability(cx, self_arg.span, "_", &mut applicability)
),
applicability,
);
diff --git a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
index 44cf0bb06..67913f739 100644
--- a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
@@ -22,7 +22,7 @@ pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
cx,
EQ_OP,
lhs.span.to(rhs.span),
- &format!("identical args used in this `{}!` macro call", macro_name),
+ &format!("identical args used in this `{macro_name}!` macro call"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
index 0ef793443..97ddcdb24 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
@@ -113,7 +113,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
}
if_chain! {
- if let ExprKind::MethodCall(method_name, [ref self_arg, ..], _) = expr.kind;
+ if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind;
if sym!(signum) == method_name.ident.name;
// Check that the receiver of the signum() is a float (expressions[0] is the receiver of
// the method call)
diff --git a/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs b/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs
index 0024384d9..ae805147f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs
@@ -47,18 +47,14 @@ fn lint_misrefactored_assign_op(
if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) {
let a = &sugg::Sugg::hir(cx, assignee, "..");
let r = &sugg::Sugg::hir(cx, rhs, "..");
- let long = format!("{} = {}", snip_a, sugg::make_binop(op.into(), a, r));
+ let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r));
diag.span_suggestion(
expr.span,
&format!(
- "did you mean `{} = {} {} {}` or `{}`? Consider replacing it with",
- snip_a,
- snip_a,
- op.as_str(),
- snip_r,
- long
+ "did you mean `{snip_a} = {snip_a} {} {snip_r}` or `{long}`? Consider replacing it with",
+ op.as_str()
),
- format!("{} {}= {}", snip_a, op.as_str(), snip_r),
+ format!("{snip_a} {}= {snip_r}", op.as_str()),
Applicability::MaybeIncorrect,
);
diag.span_suggestion(
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index bb6d99406..b8a20d5eb 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -21,7 +21,7 @@ mod ptr_eq;
mod self_assignment;
mod verbose_bit_mask;
-pub(crate) mod arithmetic;
+pub(crate) mod arithmetic_side_effects;
use rustc_hir::{Body, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
@@ -61,25 +61,29 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
- /// Checks for any kind of arithmetic operation of any type.
+ /// Checks any kind of arithmetic operation of any type.
///
/// Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust
/// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
- /// or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered
- /// away.
+ /// or can panic (`/`, `%`).
+ ///
+ /// Known safe built-in types like `Wrapping` or `Saturating`, floats, operations in constant
+ /// environments, allowed types and non-constant operations that won't overflow are ignored.
///
/// ### Why is this bad?
- /// Integer overflow will trigger a panic in debug builds or will wrap in
- /// release mode. Division by zero will cause a panic in either mode. In some applications one
- /// wants explicitly checked, wrapping or saturating arithmetic.
+ /// For integers, overflow will trigger a panic in debug builds or wrap the result in
+ /// release mode; division by zero will cause a panic in either mode. As a result, it is
+ /// desirable to explicitly call checked, wrapping or saturating arithmetic methods.
///
/// #### Example
/// ```rust
- /// # let a = 0;
- /// a + 1;
+ /// // `n` can be any number, including `i32::MAX`.
+ /// fn foo(n: i32) -> i32 {
+ /// n + 1
+ /// }
/// ```
///
- /// Third-party types also tend to overflow.
+ /// Third-party types can also overflow or present unwanted side-effects.
///
/// #### Example
/// ```ignore,rust
@@ -88,11 +92,11 @@ declare_clippy_lint! {
/// ```
///
/// ### Allowed types
- /// Custom allowed types can be specified through the "arithmetic-allowed" filter.
+ /// Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter.
#[clippy::version = "1.64.0"]
- pub ARITHMETIC,
+ pub ARITHMETIC_SIDE_EFFECTS,
restriction,
- "any arithmetic expression that could overflow or panic"
+ "any arithmetic expression that can cause side effects like overflows or panics"
}
declare_clippy_lint! {
@@ -785,7 +789,7 @@ pub struct Operators {
}
impl_lint_pass!(Operators => [
ABSURD_EXTREME_COMPARISONS,
- ARITHMETIC,
+ ARITHMETIC_SIDE_EFFECTS,
INTEGER_ARITHMETIC,
FLOAT_ARITHMETIC,
ASSIGN_OP_PATTERN,
diff --git a/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs b/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs
index e902235a0..ab5fb1787 100644
--- a/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs
@@ -27,7 +27,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Exp
if let Some(lhs_snip) = snippet_opt(cx, lhs.span)
&& let Some(rhs_snip) = snippet_opt(cx, rhs.span)
{
- let sugg = format!("{} {} {}", lhs_snip, op_str, rhs_snip);
+ let sugg = format!("{lhs_snip} {op_str} {rhs_snip}");
diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
}
},
diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
index b6097710d..0830a106f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
@@ -1,5 +1,6 @@
use clippy_utils::consts::constant_simple;
use clippy_utils::diagnostics::span_lint;
+use clippy_utils::is_integer_literal;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::source_map::Span;
@@ -50,11 +51,9 @@ impl Context {
hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind {
hir::ExprKind::Lit(_lit) => (),
hir::ExprKind::Unary(hir::UnOp::Neg, expr) => {
- if let hir::ExprKind::Lit(lit) = &expr.kind {
- if let rustc_ast::ast::LitKind::Int(1, _) = lit.node {
- span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
- self.expr_id = Some(expr.hir_id);
- }
+ if is_integer_literal(expr, 1) {
+ span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
+ self.expr_id = Some(expr.hir_id);
}
},
_ => {
diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
index 1805672e3..71b31b5e4 100644
--- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
@@ -185,7 +185,7 @@ fn in_impl<'tcx>(
if let ItemKind::Impl(item) = &item.kind;
if let Some(of_trait) = &item.of_trait;
if let Some(seg) = of_trait.path.segments.last();
- if let Some(Res::Def(_, trait_id)) = seg.res;
+ if let Res::Def(_, trait_id) = seg.res;
if trait_id == bin_op;
if let Some(generic_args) = seg.args;
if let Some(GenericArg::Type(other_ty)) = generic_args.args.last();
@@ -204,7 +204,7 @@ fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: Ty<'_>, hir_ty: &rustc_hir
if let ty::Adt(adt_def, _) = middle_ty.kind();
if let Some(local_did) = adt_def.did().as_local();
let item = cx.tcx.hir().expect_item(local_did);
- let middle_ty_id = item.def_id.to_def_id();
+ let middle_ty_id = item.owner_id.to_def_id();
if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
if let Res::Def(_, hir_ty_id) = path.res;
diff --git a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs
index 1aefc2741..1229c202f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs
@@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(
expr.span,
LINT_MSG,
"try",
- format!("std::ptr::eq({}, {})", left_snip, right_snip),
+ format!("std::ptr::eq({left_snip}, {right_snip})"),
Applicability::MachineApplicable,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs b/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs
index 9d6bec05b..7c9d5320a 100644
--- a/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/self_assignment.rs
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, lhs: &'tcx
cx,
SELF_ASSIGNMENT,
e.span,
- &format!("self-assignment of `{}` to `{}`", rhs, lhs),
+ &format!("self-assignment of `{rhs}` to `{lhs}`"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs
index ff85fd554..fbf65e92b 100644
--- a/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs
@@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(
diag.span_suggestion(
e.span,
"try",
- format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()),
+ format!("{sugg}.trailing_zeros() >= {}", n.count_ones()),
Applicability::MaybeIncorrect,
);
},
diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
index 3f5286ba0..d9ee031c9 100644
--- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
@@ -37,9 +37,9 @@ declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]);
impl EarlyLintPass for OptionEnvUnwrap {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
if_chain! {
- if let ExprKind::MethodCall(path_segment, args, _) = &expr.kind;
+ if let ExprKind::MethodCall(path_segment, receiver, _, _) = &expr.kind;
if matches!(path_segment.ident.name, sym::expect | sym::unwrap);
- if let ExprKind::Call(caller, _) = &args[0].kind;
+ if let ExprKind::Call(caller, _) = &receiver.kind;
if is_direct_expn_of(caller.span, "option_env").is_some();
then {
span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index 44f153cff..4eb42da1f 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -1,21 +1,22 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{
- can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_lang_ctor, peel_blocks,
+ can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_res_lang_ctor, peel_blocks,
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, Expr, ExprKind, Mutability, PatKind, Path, QPath, UnOp};
+use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
+use rustc_hir::{
+ def::Res, Arm, BindingAnnotation, Expr, ExprKind, MatchSource, Mutability, Pat, 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
+ /// Lints usage of `if let Some(v) = ... { y } else { x }` and
+ /// `match .. { Some(v) => y, None/_ => x }` which are 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).
@@ -39,6 +40,10 @@ declare_clippy_lint! {
/// } else {
/// 5
/// };
+ /// let _ = match optional {
+ /// Some(val) => val + 1,
+ /// None => 5
+ /// };
/// let _ = if let Some(foo) = optional {
/// foo
/// } else {
@@ -53,11 +58,14 @@ declare_clippy_lint! {
/// # let optional: Option<u32> = Some(0);
/// # fn do_complicated_function() -> u32 { 5 };
/// let _ = optional.map_or(5, |foo| foo);
+ /// let _ = optional.map_or(5, |val| val + 1);
/// let _ = optional.map_or_else(||{
/// let y = do_complicated_function();
/// y*y
/// }, |foo| foo);
/// ```
+ // FIXME: Before moving this lint out of nursery, the lint name needs to be updated. It now also
+ // covers matches and `Result`.
#[clippy::version = "1.47.0"]
pub OPTION_IF_LET_ELSE,
nursery,
@@ -66,19 +74,21 @@ declare_clippy_lint! {
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 OptionIfLetElseOccurrence {
+/// A struct containing information about occurrences of construct that this lint detects
+///
+/// Such as:
+///
+/// ```ignore
+/// if let Some(..) = {..} else {..}
+/// ```
+/// or
+/// ```ignore
+/// match x {
+/// Some(..) => {..},
+/// None/_ => {..}
+/// }
+/// ```
+struct OptionOccurrence {
option: String,
method_sugg: String,
some_expr: String,
@@ -99,43 +109,38 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo
)
}
-/// If this expression is the option if let/else construct we're detecting, then
-/// this function returns an `OptionIfLetElseOccurrence` 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<OptionIfLetElseOccurrence> {
+fn try_get_option_occurrence<'tcx>(
+ cx: &LateContext<'tcx>,
+ pat: &Pat<'tcx>,
+ expr: &Expr<'_>,
+ if_then: &'tcx Expr<'_>,
+ if_else: &'tcx Expr<'_>,
+) -> Option<OptionOccurrence> {
+ let cond_expr = match expr.kind {
+ ExprKind::Unary(UnOp::Deref, inner_expr) | ExprKind::AddrOf(_, _, inner_expr) => inner_expr,
+ _ => expr,
+ };
+ let inner_pat = try_get_inner_pat(cx, pat)?;
if_chain! {
- if !expr.span.from_expansion(); // 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, None) = &inner_pat.kind;
+ if let PatKind::Binding(bind_annotation, _, id, None) = 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 capture_mut = if bind_annotation == BindingAnnotation::MUT { "mut " } else { "" };
let some_body = peel_blocks(if_then);
let none_body = peel_blocks(if_else);
let method_sugg = if eager_or_lazy::switch_to_eager_eval(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 {
+ let (as_ref, as_mut) = match &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,
+ _ => (bind_annotation == BindingAnnotation::REF, bind_annotation == BindingAnnotation::REF_MUT),
};
+
// 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.
@@ -154,30 +159,102 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
}
}
}
- Some(OptionIfLetElseOccurrence {
+
+ return Some(OptionOccurrence {
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_with_macro_callsite(cx, some_body, "..")),
+ some_expr: format!("|{capture_mut}{capture_name}| {}", Sugg::hir_with_macro_callsite(cx, some_body, "..")),
none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir_with_macro_callsite(cx, none_body, "..")),
- })
+ });
+ }
+ }
+
+ None
+}
+
+fn try_get_inner_pat<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<&'tcx Pat<'tcx>> {
+ if let PatKind::TupleStruct(ref qpath, [inner_pat], ..) = pat.kind {
+ let res = cx.qpath_res(qpath, pat.hir_id);
+ if is_res_lang_ctor(cx, res, OptionSome) || is_res_lang_ctor(cx, res, ResultOk) {
+ return Some(inner_pat);
+ }
+ }
+ None
+}
+
+/// If this expression is the option if let/else construct we're detecting, then
+/// this function returns an `OptionOccurrence` 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<OptionOccurrence> {
+ 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) {
+ return try_get_option_occurrence(cx, let_pat, let_expr, if_then, if_else);
+ }
+ }
+ None
+}
+
+fn detect_option_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionOccurrence> {
+ if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind {
+ if let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) {
+ return try_get_option_occurrence(cx, let_pat, ex, if_then, if_else);
+ }
+ }
+ None
+}
+
+fn try_convert_match<'tcx>(
+ cx: &LateContext<'tcx>,
+ arms: &[Arm<'tcx>],
+) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
+ if arms.len() == 2 {
+ return if is_none_or_err_arm(cx, &arms[1]) {
+ Some((arms[0].pat, arms[0].body, arms[1].body))
+ } else if is_none_or_err_arm(cx, &arms[0]) {
+ Some((arms[1].pat, arms[1].body, arms[0].body))
} else {
None
- }
+ };
+ }
+ None
+}
+
+fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
+ match arm.pat.kind {
+ PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
+ PatKind::TupleStruct(ref qpath, [first_pat], _) => {
+ is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr)
+ && matches!(first_pat.kind, PatKind::Wild)
+ },
+ PatKind::Wild => true,
+ _ => false,
}
}
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) {
+ // Don't lint macros and constants
+ if expr.span.from_expansion() || in_constant(cx, expr.hir_id) {
+ return;
+ }
+
+ let detection = detect_option_if_let_else(cx, expr).or_else(|| detect_option_match(cx, expr));
+ if let Some(det) = detection {
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(),
+ format!("use Option::{} instead of an if let/else", det.method_sugg).as_str(),
"try",
format!(
"{}.{}({}, {})",
- detection.option, detection.method_sugg, detection.none_expr, detection.some_expr,
+ det.option, det.method_sugg, det.none_expr, det.some_expr
),
Applicability::MaybeIncorrect,
);
diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
index 21acf003d..efec12489 100644
--- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
@@ -2,9 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::return_ty;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::visitors::expr_visitor_no_bodies;
+use clippy_utils::visitors::{for_each_expr, Descend};
+use core::ops::ControlFlow;
use rustc_hir as hir;
-use rustc_hir::intravisit::{FnKind, Visitor};
+use rustc_hir::intravisit::FnKind;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span};
@@ -58,18 +59,20 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn {
fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) {
let mut panics = Vec::new();
- expr_visitor_no_bodies(|expr| {
- let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return true };
+ let _: Option<!> = for_each_expr(body.value, |e| {
+ let Some(macro_call) = root_macro_call_first_node(cx, e) else {
+ return ControlFlow::Continue(Descend::Yes);
+ };
if matches!(
cx.tcx.item_name(macro_call.def_id).as_str(),
"unimplemented" | "unreachable" | "panic" | "todo" | "assert" | "assert_eq" | "assert_ne"
) {
panics.push(macro_call.span);
- return false;
+ ControlFlow::Continue(Descend::No)
+ } else {
+ ControlFlow::Continue(Descend::Yes)
}
- true
- })
- .visit_expr(&body.value);
+ });
if !panics.is_empty() {
span_lint_and_then(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
new file mode 100644
index 000000000..f60d9d65b
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
@@ -0,0 +1,81 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_ast::ast::{Item, ItemKind};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks whether partial fields of a struct are public.
+ ///
+ /// Either make all fields of a type public, or make none of them public
+ ///
+ /// ### Why is this bad?
+ /// Most types should either be:
+ /// * Abstract data types: complex objects with opaque implementation which guard
+ /// interior invariants and expose intentionally limited API to the outside world.
+ /// * Data: relatively simple objects which group a bunch of related attributes together.
+ ///
+ /// ### Example
+ /// ```rust
+ /// pub struct Color {
+ /// pub r: u8,
+ /// pub g: u8,
+ /// b: u8,
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// pub struct Color {
+ /// pub r: u8,
+ /// pub g: u8,
+ /// pub b: u8,
+ /// }
+ /// ```
+ #[clippy::version = "1.66.0"]
+ pub PARTIAL_PUB_FIELDS,
+ restriction,
+ "partial fields of a struct are public"
+}
+declare_lint_pass!(PartialPubFields => [PARTIAL_PUB_FIELDS]);
+
+impl EarlyLintPass for PartialPubFields {
+ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+ let ItemKind::Struct(ref st, _) = item.kind else {
+ return;
+ };
+
+ let mut fields = st.fields().iter();
+ let Some(first_field) = fields.next() else {
+ // Empty struct.
+ return;
+ };
+ let all_pub = first_field.vis.kind.is_pub();
+ let all_priv = !all_pub;
+
+ let msg = "mixed usage of pub and non-pub fields";
+
+ for field in fields {
+ if all_priv && field.vis.kind.is_pub() {
+ span_lint_and_help(
+ cx,
+ PARTIAL_PUB_FIELDS,
+ field.vis.span,
+ msg,
+ None,
+ "consider using private field here",
+ );
+ return;
+ } else if all_pub && !field.vis.kind.is_pub() {
+ span_lint_and_help(
+ cx,
+ PARTIAL_PUB_FIELDS,
+ field.vis.span,
+ msg,
+ None,
+ "consider using public field here",
+ );
+ return;
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
index 09ac514d0..5aa3c6f2f 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
@@ -36,7 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if_chain! {
if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind;
- if !cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
+ if !cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived);
if let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
if trait_ref.path.res.def_id() == eq_trait;
then {
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
new file mode 100644
index 000000000..6810a2431
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
@@ -0,0 +1,104 @@
+use clippy_utils::{
+ diagnostics::span_lint_and_sugg, is_res_lang_ctor, path_res, peel_hir_expr_refs, peel_ref_operators, sugg,
+ ty::is_type_diagnostic_item,
+};
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem};
+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 binary comparisons to a literal `Option::None`.
+ ///
+ /// ### Why is this bad?
+ ///
+ /// A programmer checking if some `foo` is `None` via a comparison `foo == None`
+ /// is usually inspired from other programming languages (e.g. `foo is None`
+ /// in Python).
+ /// Checking if a value of type `Option<T>` is (not) equal to `None` in that
+ /// way relies on `T: PartialEq` to do the comparison, which is unneeded.
+ ///
+ /// ### Example
+ /// ```rust
+ /// fn foo(f: Option<u32>) -> &'static str {
+ /// if f != None { "yay" } else { "nay" }
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// fn foo(f: Option<u32>) -> &'static str {
+ /// if f.is_some() { "yay" } else { "nay" }
+ /// }
+ /// ```
+ #[clippy::version = "1.64.0"]
+ pub PARTIALEQ_TO_NONE,
+ style,
+ "Binary comparison to `Option<T>::None` relies on `T: PartialEq`, which is unneeded"
+}
+declare_lint_pass!(PartialeqToNone => [PARTIALEQ_TO_NONE]);
+
+impl<'tcx> LateLintPass<'tcx> for PartialeqToNone {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+ // Skip expanded code, as we have no control over it anyway...
+ if e.span.from_expansion() {
+ return;
+ }
+
+ // If the expression is of type `Option`
+ let is_ty_option =
+ |expr: &Expr<'_>| is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr).peel_refs(), sym::Option);
+
+ // If the expression is a literal `Option::None`
+ let is_none_ctor = |expr: &Expr<'_>| {
+ !expr.span.from_expansion()
+ && is_res_lang_ctor(cx, path_res(cx, peel_hir_expr_refs(expr).0), LangItem::OptionNone)
+ };
+
+ let mut applicability = Applicability::MachineApplicable;
+
+ if let ExprKind::Binary(op, left_side, right_side) = e.kind {
+ // All other comparisons (e.g. `>= None`) have special meaning wrt T
+ let is_eq = match op.node {
+ BinOpKind::Eq => true,
+ BinOpKind::Ne => false,
+ _ => return,
+ };
+
+ // We are only interested in comparisons between `Option` and a literal `Option::None`
+ let scrutinee = match (
+ is_none_ctor(left_side) && is_ty_option(right_side),
+ is_none_ctor(right_side) && is_ty_option(left_side),
+ ) {
+ (true, false) => right_side,
+ (false, true) => left_side,
+ _ => return,
+ };
+
+ // Peel away refs/derefs (as long as we don't cross manual deref impls), as
+ // autoref/autoderef will take care of those
+ let sugg = format!(
+ "{}.{}",
+ sugg::Sugg::hir_with_applicability(cx, peel_ref_operators(cx, scrutinee), "..", &mut applicability)
+ .maybe_par(),
+ if is_eq { "is_none()" } else { "is_some()" }
+ );
+
+ span_lint_and_sugg(
+ cx,
+ PARTIALEQ_TO_NONE,
+ e.span,
+ "binary comparison to literal `Option::None`",
+ if is_eq {
+ "use `Option::is_none()` instead"
+ } else {
+ "use `Option::is_some()` instead"
+ },
+ sugg,
+ applicability,
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 5fa4fd748..f9fd36456 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -139,7 +139,7 @@ impl<'tcx> PassByRefOrValue {
}
fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) {
- if self.avoid_breaking_exported_api && cx.access_levels.is_exported(def_id) {
+ if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
return;
}
@@ -209,7 +209,7 @@ impl<'tcx> PassByRefOrValue {
cx,
TRIVIALLY_COPY_PASS_BY_REF,
input.span,
- &format!("this argument ({} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", size, self.ref_min_size),
+ &format!("this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", self.ref_min_size),
"consider passing by value instead",
value_type,
Applicability::Unspecified,
@@ -221,7 +221,7 @@ impl<'tcx> PassByRefOrValue {
// if function has a body and parameter is annotated with mut, ignore
if let Some(param) = fn_body.and_then(|body| body.params.get(index)) {
match param.pat.kind {
- PatKind::Binding(BindingAnnotation::Unannotated, _, _, _) => {},
+ PatKind::Binding(BindingAnnotation::NONE, _, _, _) => {},
_ => continue,
}
}
@@ -237,7 +237,7 @@ impl<'tcx> PassByRefOrValue {
cx,
LARGE_TYPES_PASSED_BY_VALUE,
input.span,
- &format!("this argument ({} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", size, self.value_max_size),
+ &format!("this argument ({size} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", self.value_max_size),
"consider passing by reference instead",
format!("&{}", snippet(cx, input.span, "_")),
Applicability::MaybeIncorrect,
@@ -261,7 +261,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
}
if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
- self.check_poly_fn(cx, item.def_id, method_sig.decl, None);
+ self.check_poly_fn(cx, item.owner_id.def_id, method_sig.decl, None);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
deleted file mode 100644
index 3f940ce61..000000000
--- a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
+++ /dev/null
@@ -1,74 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
-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::symbol::sym;
-use std::path::{Component, Path};
-
-declare_clippy_lint! {
- /// ### What it does
- ///* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push)
- /// calls on `PathBuf` that can cause overwrites.
- ///
- /// ### Why is this bad?
- /// Calling `push` with a root path at the start can overwrite the
- /// previous defined path.
- ///
- /// ### Example
- /// ```rust
- /// use std::path::PathBuf;
- ///
- /// let mut x = PathBuf::from("/foo");
- /// x.push("/bar");
- /// assert_eq!(x, PathBuf::from("/bar"));
- /// ```
- /// Could be written:
- ///
- /// ```rust
- /// use std::path::PathBuf;
- ///
- /// let mut x = PathBuf::from("/foo");
- /// x.push("bar");
- /// assert_eq!(x, PathBuf::from("/foo/bar"));
- /// ```
- #[clippy::version = "1.36.0"]
- pub PATH_BUF_PUSH_OVERWRITE,
- nursery,
- "calling `push` with file system root on `PathBuf` can overwrite it"
-}
-
-declare_lint_pass!(PathBufPushOverwrite => [PATH_BUF_PUSH_OVERWRITE]);
-
-impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if_chain! {
- if let ExprKind::MethodCall(path, args, _) = expr.kind;
- if path.ident.name == sym!(push);
- if args.len() == 2;
- if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), sym::PathBuf);
- if let Some(get_index_arg) = args.get(1);
- if let ExprKind::Lit(ref lit) = get_index_arg.kind;
- if let LitKind::Str(ref path_lit, _) = lit.node;
- if let pushed_path = Path::new(path_lit.as_str());
- if let Some(pushed_path_lit) = pushed_path.to_str();
- if pushed_path.has_root();
- if let Some(root) = pushed_path.components().next();
- if root == Component::RootDir;
- then {
- span_lint_and_sugg(
- cx,
- PATH_BUF_PUSH_OVERWRITE,
- lit.span,
- "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition",
- "try",
- format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')),
- Applicability::MachineApplicable,
- );
- }
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs
index cc0533c9f..e6e3ad05a 100644
--- a/src/tools/clippy/clippy_lints/src/precedence.rs
+++ b/src/tools/clippy/clippy_lints/src/precedence.rs
@@ -109,12 +109,12 @@ impl EarlyLintPass for Precedence {
let mut arg = operand;
let mut all_odd = true;
- while let ExprKind::MethodCall(path_segment, args, _) = &arg.kind {
+ while let ExprKind::MethodCall(path_segment, receiver, _, _) = &arg.kind {
let path_segment_str = path_segment.ident.name.as_str();
all_odd &= ALLOWED_ODD_FUNCTIONS
.iter()
.any(|odd_function| **odd_function == *path_segment_str);
- arg = args.first().expect("A method always has a receiver.");
+ arg = receiver;
}
if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 3c5ea2d94..0d74c90a8 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -15,13 +15,17 @@ use rustc_hir::{
ImplItemKind, ItemKind, Lifetime, LifetimeName, Mutability, Node, Param, ParamName, PatKind, QPath, TraitFn,
TraitItem, TraitItemKind, TyKind, Unsafety,
};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::{Obligation, ObligationCause};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Binder, ExistentialPredicate, List, PredicateKind, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::sym;
use rustc_span::symbol::Symbol;
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use std::fmt;
use std::iter;
@@ -160,7 +164,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
check_mut_from_ref(cx, sig, None);
for arg in check_fn_args(
cx,
- cx.tcx.fn_sig(item.def_id).skip_binder().inputs(),
+ cx.tcx.fn_sig(item.owner_id).skip_binder().inputs(),
sig.decl.inputs,
&[],
)
@@ -184,7 +188,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
let (item_id, sig, is_trait_item) = match parents.next() {
Some((_, Node::Item(i))) => {
if let ItemKind::Fn(sig, ..) = &i.kind {
- (i.def_id, sig, false)
+ (i.owner_id, sig, false)
} else {
return;
}
@@ -196,14 +200,14 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
return;
}
if let ImplItemKind::Fn(sig, _) = &i.kind {
- (i.def_id, sig, false)
+ (i.owner_id, sig, false)
} else {
return;
}
},
Some((_, Node::TraitItem(i))) => {
if let TraitItemKind::Fn(sig, _) = &i.kind {
- (i.def_id, sig, true)
+ (i.owner_id, sig, true)
} else {
return;
}
@@ -384,6 +388,17 @@ enum DerefTy<'tcx> {
Slice(Option<Span>, Ty<'tcx>),
}
impl<'tcx> DerefTy<'tcx> {
+ fn ty(&self, cx: &LateContext<'tcx>) -> Ty<'tcx> {
+ match *self {
+ Self::Str => cx.tcx.types.str_,
+ Self::Path => cx.tcx.mk_adt(
+ cx.tcx.adt_def(cx.tcx.get_diagnostic_item(sym::Path).unwrap()),
+ List::empty(),
+ ),
+ Self::Slice(_, ty) => cx.tcx.mk_slice(ty),
+ }
+ }
+
fn argless_str(&self) -> &'static str {
match *self {
Self::Str => "str",
@@ -463,7 +478,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
diag.span_suggestion(
hir_ty.span,
"change this to",
- format!("&{}{}", mutability.prefix_str(), ty_name),
+ format!("&{}{ty_name}", mutability.prefix_str()),
Applicability::Unspecified,
);
}
@@ -507,7 +522,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
if let Some(args) = args
&& !args.is_empty()
&& body.map_or(true, |body| {
- sig.header.unsafety == Unsafety::Unsafe || contains_unsafe_block(cx, &body.value)
+ sig.header.unsafety == Unsafety::Unsafe || contains_unsafe_block(cx, body.value)
})
{
span_lint_and_then(
@@ -552,9 +567,8 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
}
// Check if this is local we care about
- let args_idx = match path_to_local(e).and_then(|id| self.bindings.get(&id)) {
- Some(&i) => i,
- None => return walk_expr(self, e),
+ let Some(&args_idx) = path_to_local(e).and_then(|id| self.bindings.get(&id)) else {
+ return walk_expr(self, e);
};
let args = &self.args[args_idx];
let result = &mut self.results[args_idx];
@@ -571,7 +585,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
Some((Node::Stmt(_), _)) => (),
Some((Node::Local(l), _)) => {
// Only trace simple bindings. e.g `let x = y;`
- if let PatKind::Binding(BindingAnnotation::Unannotated, id, _, None) = l.pat.kind {
+ if let PatKind::Binding(BindingAnnotation::NONE, id, _, None) = l.pat.kind {
self.bindings.insert(id, args_idx);
} else {
set_skip_flag();
@@ -582,6 +596,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
if expr_sig(self.cx, f).and_then(|sig| sig.input(i)).map_or(true, |ty| {
match *ty.skip_binder().peel_refs().kind() {
+ ty::Dynamic(preds, _, _) => !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds),
ty::Param(_) => true,
ty::Adt(def, _) => def.did() == args.ty_did,
_ => false,
@@ -591,8 +606,11 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
set_skip_flag();
}
},
- ExprKind::MethodCall(name, expr_args @ [self_arg, ..], _) => {
- let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
+ ExprKind::MethodCall(name, self_arg, expr_args, _) => {
+ let i = std::iter::once(self_arg)
+ .chain(expr_args.iter())
+ .position(|arg| arg.hir_id == child_id)
+ .unwrap_or(0);
if i == 0 {
// Check if the method can be renamed.
let name = name.ident.as_str();
@@ -606,14 +624,15 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
}
}
- let id = if let Some(x) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) {
- x
- } else {
+ let Some(id) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) else {
set_skip_flag();
return;
};
match *self.cx.tcx.fn_sig(id).skip_binder().inputs()[i].peel_refs().kind() {
+ ty::Dynamic(preds, _, _) if !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds) => {
+ set_skip_flag();
+ },
ty::Param(_) => {
set_skip_flag();
},
@@ -644,7 +663,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
.filter_map(|(i, arg)| {
let param = &body.params[arg.idx];
match param.pat.kind {
- PatKind::Binding(BindingAnnotation::Unannotated, id, _, None)
+ PatKind::Binding(BindingAnnotation::NONE, id, _, None)
if !is_lint_allowed(cx, PTR_ARG, param.hir_id) =>
{
Some((id, i))
@@ -661,12 +680,36 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
results,
skip_count,
};
- v.visit_expr(&body.value);
+ v.visit_expr(body.value);
v.results
}
+fn matches_preds<'tcx>(
+ cx: &LateContext<'tcx>,
+ ty: Ty<'tcx>,
+ preds: &'tcx [Binder<'tcx, ExistentialPredicate<'tcx>>],
+) -> bool {
+ let infcx = cx.tcx.infer_ctxt().build();
+ preds.iter().all(|&p| match cx.tcx.erase_late_bound_regions(p) {
+ ExistentialPredicate::Trait(p) => infcx
+ .type_implements_trait(p.def_id, ty, p.substs, cx.param_env)
+ .must_apply_modulo_regions(),
+ ExistentialPredicate::Projection(p) => infcx.predicate_must_hold_modulo_regions(&Obligation::new(
+ ObligationCause::dummy(),
+ cx.param_env,
+ cx.tcx.mk_predicate(Binder::bind_with_vars(
+ PredicateKind::Projection(p.with_self_ty(cx.tcx, ty)),
+ List::empty(),
+ )),
+ )),
+ ExistentialPredicate::AutoTrait(p) => infcx
+ .type_implements_trait(p, ty, List::empty(), cx.param_env)
+ .must_apply_modulo_regions(),
+ })
+}
+
fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
- if let TyKind::Rptr(ref lt, ref m) = ty.kind {
+ if let TyKind::Rptr(lt, ref m) = ty.kind {
Some((lt, m.mutbl, ty.span))
} else {
None
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
index b907f38af..72dda67c7 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
@@ -49,18 +49,16 @@ declare_lint_pass!(PtrOffsetWithCast => [PTR_OFFSET_WITH_CAST]);
impl<'tcx> LateLintPass<'tcx> for PtrOffsetWithCast {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// Check if the expressions is a ptr.offset or ptr.wrapping_offset method call
- let (receiver_expr, arg_expr, method) = match expr_as_ptr_offset_call(cx, expr) {
- Some(call_arg) => call_arg,
- None => return,
+ let Some((receiver_expr, arg_expr, method)) = expr_as_ptr_offset_call(cx, expr) else {
+ return
};
// Check if the argument to the method call is a cast from usize
- let cast_lhs_expr = match expr_as_cast_from_usize(cx, arg_expr) {
- Some(cast_lhs_expr) => cast_lhs_expr,
- None => return,
+ let Some(cast_lhs_expr) = expr_as_cast_from_usize(cx, arg_expr) else {
+ return
};
- let msg = format!("use of `{}` with a `usize` casted to an `isize`", method);
+ let msg = format!("use of `{method}` with a `usize` casted to an `isize`");
if let Some(sugg) = build_suggestion(cx, method, receiver_expr, cast_lhs_expr) {
span_lint_and_sugg(
cx,
@@ -93,7 +91,7 @@ fn expr_as_ptr_offset_call<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>,
) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> {
- if let ExprKind::MethodCall(path_segment, [arg_0, arg_1, ..], _) = &expr.kind {
+ if let ExprKind::MethodCall(path_segment, arg_0, [arg_1, ..], _) = &expr.kind {
if is_expr_ty_raw_ptr(cx, arg_0) {
if path_segment.ident.name == sym::offset {
return Some((arg_0, arg_1, Method::Offset));
@@ -124,7 +122,7 @@ fn build_suggestion<'tcx>(
) -> Option<String> {
let receiver = snippet_opt(cx, receiver_expr.span)?;
let cast_lhs = snippet_opt(cx, cast_lhs_expr.span)?;
- Some(format!("{}.{}({})", receiver, method.suggestion(), cast_lhs))
+ Some(format!("{receiver}.{}({cast_lhs})", method.suggestion()))
}
#[derive(Copy, Clone)]
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index fd0a53839..bb86fb3b7 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -3,13 +3,14 @@ use clippy_utils::higher;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{
- eq_expr_value, get_parent_node, is_else_clause, is_lang_ctor, path_to_local, path_to_local_id, peel_blocks,
- peel_blocks_with_stmt,
+ eq_expr_value, get_parent_node, in_constant, is_else_clause, is_res_lang_ctor, path_to_local, path_to_local_id,
+ peel_blocks, peel_blocks_with_stmt,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
+use rustc_hir::def::Res;
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
-use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, PathSegment, QPath};
+use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, Node, PatKind, PathSegment, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -58,7 +59,7 @@ enum IfBlockType<'hir> {
/// Contains: let_pat_qpath (Xxx), let_pat_type, let_pat_sym (a), let_expr (b), if_then (c),
/// if_else (d)
IfLet(
- &'hir QPath<'hir>,
+ Res,
Ty<'hir>,
Symbol,
&'hir Expr<'hir>,
@@ -86,24 +87,23 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex
if_chain! {
if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
if !is_else_clause(cx.tcx, expr);
- if let ExprKind::MethodCall(segment, args, _) = &cond.kind;
- if let Some(caller) = args.get(0);
+ if let ExprKind::MethodCall(segment, caller, ..) = &cond.kind;
let caller_ty = cx.typeck_results().expr_ty(caller);
let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else);
if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block);
then {
let mut applicability = Applicability::MachineApplicable;
let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability);
- let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx.at(caller.span), cx.param_env) &&
+ let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) &&
!matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..));
let sugg = if let Some(else_inner) = r#else {
if eq_expr_value(cx, caller, peel_blocks(else_inner)) {
- format!("Some({}?)", receiver_str)
+ format!("Some({receiver_str}?)")
} else {
return;
}
} else {
- format!("{}{}?;", receiver_str, if by_ref { ".as_ref()" } else { "" })
+ format!("{receiver_str}{}?;", if by_ref { ".as_ref()" } else { "" })
};
span_lint_and_sugg(
@@ -123,22 +123,28 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
if_chain! {
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr);
if !is_else_clause(cx.tcx, expr);
- if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind;
- if let PatKind::Binding(annot, bind_id, ident, _) = field.kind;
+ if let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind;
+ if ddpos.as_opt_usize().is_none();
+ if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind;
let caller_ty = cx.typeck_results().expr_ty(let_expr);
- let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else);
+ let if_block = IfBlockType::IfLet(
+ cx.qpath_res(path1, let_pat.hir_id),
+ caller_ty,
+ ident.name,
+ let_expr,
+ if_then,
+ if_else
+ );
if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id))
|| is_early_return(sym::Result, cx, &if_block);
if if_else.map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))).filter(|e| *e).is_none();
then {
let mut applicability = Applicability::MachineApplicable;
let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
- let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_)));
let sugg = format!(
- "{}{}?{}",
- receiver_str,
- if by_ref { ".as_ref()" } else { "" },
+ "{receiver_str}{}?{}",
+ if by_ref == ByRef::Yes { ".as_ref()" } else { "" },
if requires_semi { ";" } else { "" }
);
span_lint_and_sugg(
@@ -167,21 +173,21 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_
_ => false,
}
},
- IfBlockType::IfLet(qpath, let_expr_ty, let_pat_sym, let_expr, if_then, if_else) => {
+ IfBlockType::IfLet(res, let_expr_ty, let_pat_sym, let_expr, if_then, if_else) => {
is_type_diagnostic_item(cx, let_expr_ty, smbl)
&& match smbl {
sym::Option => {
// We only need to check `if let Some(x) = option` not `if let None = option`,
// because the later one will be suggested as `if option.is_none()` thus causing conflict.
- is_lang_ctor(cx, qpath, OptionSome)
+ is_res_lang_ctor(cx, res, OptionSome)
&& if_else.is_some()
&& expr_return_none_or_err(smbl, cx, if_else.unwrap(), let_expr, None)
},
sym::Result => {
- (is_lang_ctor(cx, qpath, ResultOk)
+ (is_res_lang_ctor(cx, res, ResultOk)
&& if_else.is_some()
&& expr_return_none_or_err(smbl, cx, if_else.unwrap(), let_expr, Some(let_pat_sym)))
- || is_lang_ctor(cx, qpath, ResultErr)
+ || is_res_lang_ctor(cx, res, ResultErr)
&& expr_return_none_or_err(smbl, cx, if_then, let_expr, Some(let_pat_sym))
},
_ => false,
@@ -200,7 +206,7 @@ fn expr_return_none_or_err(
match peel_blocks_with_stmt(expr).kind {
ExprKind::Ret(Some(ret_expr)) => expr_return_none_or_err(smbl, cx, ret_expr, cond_expr, err_sym),
ExprKind::Path(ref qpath) => match smbl {
- sym::Option => is_lang_ctor(cx, qpath, OptionNone),
+ sym::Option => is_res_lang_ctor(cx, cx.qpath_res(qpath, expr.hir_id), OptionNone),
sym::Result => path_to_local(expr).is_some() && path_to_local(expr) == path_to_local(cond_expr),
_ => false,
},
@@ -225,7 +231,9 @@ fn expr_return_none_or_err(
impl<'tcx> LateLintPass<'tcx> for QuestionMark {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- check_is_none_or_err_and_early_return(cx, expr);
- check_if_let_some_or_err_and_early_return(cx, expr);
+ if !in_constant(cx, expr.hir_id) {
+ check_is_none_or_err_and_early_return(cx, expr);
+ check_if_let_some_or_err_and_early_return(cx, expr);
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 547d4da81..c6fbb5e80 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -1,48 +1,22 @@
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::higher;
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, path_to_local};
-use clippy_utils::{higher, SpanlessEq};
use if_chain::if_chain;
use rustc_ast::ast::RangeLimits;
use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind, HirId, PathSegment, QPath};
+use rustc_hir::{BinOpKind, Expr, ExprKind, HirId};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
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;
declare_clippy_lint! {
/// ### What it does
- /// Checks for zipping a collection with the range of
- /// `0.._.len()`.
- ///
- /// ### Why is this bad?
- /// The code is better expressed with `.enumerate()`.
- ///
- /// ### Example
- /// ```rust
- /// # let x = vec![1];
- /// let _ = x.iter().zip(0..x.len());
- /// ```
- ///
- /// Use instead:
- /// ```rust
- /// # let x = vec![1];
- /// let _ = x.iter().enumerate();
- /// ```
- #[clippy::version = "pre 1.29.0"]
- pub RANGE_ZIP_WITH_LEN,
- complexity,
- "zipping iterator with a range when `enumerate()` would do"
-}
-
-declare_clippy_lint! {
- /// ### What it does
/// Checks for exclusive ranges where 1 is added to the
/// upper bound, e.g., `x..(y+1)`.
///
@@ -198,7 +172,6 @@ impl Ranges {
}
impl_lint_pass!(Ranges => [
- RANGE_ZIP_WITH_LEN,
RANGE_PLUS_ONE,
RANGE_MINUS_ONE,
REVERSED_EMPTY_RANGES,
@@ -207,16 +180,10 @@ impl_lint_pass!(Ranges => [
impl<'tcx> LateLintPass<'tcx> for Ranges {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- match expr.kind {
- ExprKind::MethodCall(path, args, _) => {
- check_range_zip_with_len(cx, path, args, expr.span);
- },
- ExprKind::Binary(ref op, l, r) => {
- if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) {
- check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
- }
- },
- _ => {},
+ if let ExprKind::Binary(ref op, l, r) = expr.kind {
+ if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) {
+ check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
+ }
}
check_exclusive_range_plus_one(cx, expr);
@@ -276,9 +243,9 @@ fn check_possible_range_contains(
cx,
MANUAL_RANGE_CONTAINS,
span,
- &format!("manual `{}::contains` implementation", range_type),
+ &format!("manual `{range_type}::contains` implementation"),
"use",
- format!("({}{}{}{}).contains(&{})", lo, space, range_op, hi, name),
+ format!("({lo}{space}{range_op}{hi}).contains(&{name})"),
applicability,
);
} else if !combine_and && ord == Some(l.ord) {
@@ -306,9 +273,9 @@ fn check_possible_range_contains(
cx,
MANUAL_RANGE_CONTAINS,
span,
- &format!("manual `!{}::contains` implementation", range_type),
+ &format!("manual `!{range_type}::contains` implementation"),
"use",
- format!("!({}{}{}{}).contains(&{})", lo, space, range_op, hi, name),
+ format!("!({lo}{space}{range_op}{hi}).contains(&{name})"),
applicability,
);
}
@@ -380,37 +347,10 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R
None
}
-fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: &[Expr<'_>], span: Span) {
- if_chain! {
- if path.ident.as_str() == "zip";
- if let [iter, zip_arg] = args;
- // `.iter()` call
- if let ExprKind::MethodCall(iter_path, iter_args, _) = iter.kind;
- if iter_path.ident.name == sym::iter;
- // range expression in `.zip()` call: `0..x.len()`
- if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
- if is_integer_const(cx, start, 0);
- // `.len()` call
- if let ExprKind::MethodCall(len_path, len_args, _) = end.kind;
- if len_path.ident.name == sym::len && len_args.len() == 1;
- // `.iter()` and `.len()` called on same `Path`
- if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_args[0].kind;
- if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind;
- if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments);
- then {
- span_lint(cx,
- RANGE_ZIP_WITH_LEN,
- span,
- &format!("it is more idiomatic to use `{}.iter().enumerate()`",
- snippet(cx, iter_args[0].span, "_"))
- );
- }
- }
-}
-
// exclusive range plus one: `x..(y+1)`
fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
+ if expr.span.can_be_used_for_suggestions();
if let Some(higher::Range {
start,
end: Some(end),
@@ -418,14 +358,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
}) = higher::Range::hir(expr);
if let Some(y) = y_plus_one(cx, end);
then {
- let span = if expr.span.from_expansion() {
- expr.span
- .ctxt()
- .outer_expn_data()
- .call_site
- } else {
- expr.span
- };
+ let span = expr.span;
span_lint_and_then(
cx,
RANGE_PLUS_ONE,
@@ -439,14 +372,14 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
diag.span_suggestion(
span,
"use",
- format!("({}..={})", start, end),
+ format!("({start}..={end})"),
Applicability::MaybeIncorrect,
);
} else {
diag.span_suggestion(
span,
"use",
- format!("{}..={}", start, end),
+ format!("{start}..={end}"),
Applicability::MachineApplicable, // snippet
);
}
@@ -460,6 +393,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
// inclusive range minus one: `x..=(y-1)`
fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
+ if expr.span.can_be_used_for_suggestions();
if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::Range::hir(expr);
if let Some(y) = y_minus_one(cx, end);
then {
@@ -474,7 +408,7 @@ fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
diag.span_suggestion(
expr.span,
"use",
- format!("{}..{}", start, end),
+ format!("{start}..{end}"),
Applicability::MachineApplicable, // snippet
);
},
@@ -552,7 +486,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
expr.span,
"consider using the following if you are attempting to iterate over this \
range in reverse",
- format!("({}{}{}).rev()", end_snippet, dots, start_snippet),
+ format!("({end_snippet}{dots}{start_snippet}).rev()"),
Applicability::MaybeIncorrect,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
index 8db8c4e9b..e82aa3a7b 100644
--- a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
+++ b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
@@ -41,7 +41,7 @@ declare_clippy_lint! {
/// let data = std::rc::Rc::new("some data".to_string());
/// let v = vec![data; 100];
/// ```
- #[clippy::version = "1.62.0"]
+ #[clippy::version = "1.63.0"]
pub RC_CLONE_IN_VEC_INIT,
suspicious,
"initializing reference-counted pointer in `vec![elem; len]`"
diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
index 9538a8104..fa1078588 100644
--- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
@@ -2,9 +2,10 @@ use clippy_utils::{
diagnostics::{span_lint, span_lint_and_sugg},
higher::{get_vec_init_kind, VecInitKind},
source::snippet,
- visitors::expr_visitor_no_bodies,
+ visitors::for_each_expr,
};
-use hir::{intravisit::Visitor, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind};
+use core::ops::ControlFlow;
+use hir::{Expr, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
@@ -58,10 +59,8 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
&& let PatKind::Binding(_, _, ident, _) = pat.kind
&& let Some(vec_init_kind) = get_vec_init_kind(cx, init)
{
- // finds use of `_.read(&mut v)`
- let mut read_found = false;
- let mut visitor = expr_visitor_no_bodies(|expr| {
- if let ExprKind::MethodCall(path, [_self, arg], _) = expr.kind
+ let visitor = |expr: &Expr<'_>| {
+ if let ExprKind::MethodCall(path, _, [arg], _) = expr.kind
&& let PathSegment { ident: read_or_read_exact, .. } = *path
&& matches!(read_or_read_exact.as_str(), "read" | "read_exact")
&& let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind
@@ -69,27 +68,22 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
&& let [inner_seg] = inner_path.segments
&& ident.name == inner_seg.ident.name
{
- read_found = true;
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(())
}
- !read_found
- });
+ };
- let next_stmt_span;
- if idx == block.stmts.len() - 1 {
+ let (read_found, next_stmt_span) =
+ if let Some(next_stmt) = block.stmts.get(idx + 1) {
+ // case { .. stmt; stmt; .. }
+ (for_each_expr(next_stmt, visitor).is_some(), next_stmt.span)
+ } else if let Some(e) = block.expr {
// case { .. stmt; expr }
- if let Some(e) = block.expr {
- visitor.visit_expr(e);
- next_stmt_span = e.span;
- } else {
- return;
- }
+ (for_each_expr(e, visitor).is_some(), e.span)
} else {
- // case { .. stmt; stmt; .. }
- let next_stmt = &block.stmts[idx + 1];
- visitor.visit_stmt(next_stmt);
- next_stmt_span = next_stmt.span;
- }
- drop(visitor);
+ return
+ };
if read_found && !next_stmt_span.from_expansion() {
let applicability = Applicability::MaybeIncorrect;
@@ -101,9 +95,8 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
next_stmt_span,
"reading zero byte data to `Vec`",
"try",
- format!("{}.resize({}, 0); {}",
+ format!("{}.resize({len}, 0); {}",
ident.as_str(),
- len,
snippet(cx, next_stmt_span, "..")
),
applicability,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index eddca6045..aedbe08e3 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -1,25 +1,18 @@
use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
+use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth};
use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths};
use if_chain::if_chain;
-use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{def_id, Body, FnDecl, HirId};
-use rustc_index::bit_set::{BitSet, HybridBitSet};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::mir::{
- self, traversal,
- visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _},
- Mutability,
-};
-use rustc_middle::ty::{self, visit::TypeVisitor, Ty};
-use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis, ResultsCursor};
+use rustc_middle::mir;
+use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::{BytePos, Span};
use rustc_span::sym;
-use std::ops::ControlFlow;
macro_rules! unwrap_or_continue {
($x:expr) => {
@@ -89,23 +82,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
let mir = cx.tcx.optimized_mir(def_id.to_def_id());
- let possible_origin = {
- let mut vis = PossibleOriginVisitor::new(mir);
- vis.visit_body(mir);
- vis.into_map(cx)
- };
- let maybe_storage_live_result = MaybeStorageLive
- .into_engine(cx.tcx, mir)
- .pass_name("redundant_clone")
- .iterate_to_fixpoint()
- .into_results_cursor(mir);
- let mut possible_borrower = {
- let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
- vis.visit_body(mir);
- vis.into_map(cx, maybe_storage_live_result)
- };
-
- for (bb, bbdata) in mir.basic_blocks().iter_enumerated() {
+ let mut possible_borrower = PossibleBorrowerMap::new(cx, mir);
+
+ for (bb, bbdata) in mir.basic_blocks.iter_enumerated() {
let terminator = bbdata.terminator();
if terminator.source_info.span.from_expansion() {
@@ -186,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
unwrap_or_continue!(find_stmt_assigns_to(cx, mir, pred_arg, true, ps[0]));
let loc = mir::Location {
block: bb,
- statement_index: mir.basic_blocks()[bb].statements.len(),
+ statement_index: mir.basic_blocks[bb].statements.len(),
};
// This can be turned into `res = move local` if `arg` and `cloned` are not borrowed
@@ -310,7 +289,7 @@ fn find_stmt_assigns_to<'tcx>(
by_ref: bool,
bb: mir::BasicBlock,
) -> Option<(mir::Local, CannotMoveOut)> {
- let rvalue = mir.basic_blocks()[bb].statements.iter().rev().find_map(|stmt| {
+ let rvalue = mir.basic_blocks[bb].statements.iter().rev().find_map(|stmt| {
if let mir::StatementKind::Assign(box (mir::Place { local, .. }, v)) = &stmt.kind {
return if *local == to_local { Some(v) } else { None };
}
@@ -374,403 +353,40 @@ struct CloneUsage {
/// Whether the clone value is mutated.
clone_consumed_or_mutated: bool,
}
-fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>, bb: mir::BasicBlock) -> CloneUsage {
- struct V {
- cloned: mir::Local,
- clone: mir::Local,
- result: CloneUsage,
- }
- impl<'tcx> mir::visit::Visitor<'tcx> for V {
- fn visit_basic_block_data(&mut self, block: mir::BasicBlock, data: &mir::BasicBlockData<'tcx>) {
- let statements = &data.statements;
- for (statement_index, statement) in statements.iter().enumerate() {
- self.visit_statement(statement, mir::Location { block, statement_index });
- }
-
- self.visit_terminator(
- data.terminator(),
- mir::Location {
- block,
- statement_index: statements.len(),
- },
- );
- }
-
- fn visit_place(&mut self, place: &mir::Place<'tcx>, ctx: PlaceContext, loc: mir::Location) {
- let local = place.local;
-
- if local == self.cloned
- && !matches!(
- ctx,
- PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(_)
- )
- {
- self.result.cloned_used = true;
- self.result.cloned_consume_or_mutate_loc = self.result.cloned_consume_or_mutate_loc.or_else(|| {
- matches!(
- ctx,
- PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)
- | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
- )
- .then(|| loc)
- });
- } else if local == self.clone {
- match ctx {
- PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)
- | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
- self.result.clone_consumed_or_mutated = true;
- },
- _ => {},
- }
- }
- }
- }
-
- let init = CloneUsage {
- cloned_used: false,
- cloned_consume_or_mutate_loc: None,
- // Consider non-temporary clones consumed.
- // TODO: Actually check for mutation of non-temporaries.
- clone_consumed_or_mutated: mir.local_kind(clone) != mir::LocalKind::Temp,
- };
- traversal::ReversePostorder::new(mir, bb)
- .skip(1)
- .fold(init, |usage, (tbb, tdata)| {
- // Short-circuit
- if (usage.cloned_used && usage.clone_consumed_or_mutated) ||
- // Give up on loops
- tdata.terminator().successors().any(|s| s == bb)
- {
- return CloneUsage {
- cloned_used: true,
- clone_consumed_or_mutated: true,
- ..usage
- };
- }
-
- let mut v = V {
- cloned,
- clone,
- result: usage,
- };
- v.visit_basic_block_data(tbb, tdata);
- v.result
- })
-}
-
-/// Determines liveness of each local purely based on `StorageLive`/`Dead`.
-#[derive(Copy, Clone)]
-struct MaybeStorageLive;
-
-impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
- type Domain = BitSet<mir::Local>;
- const NAME: &'static str = "maybe_storage_live";
-
- fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
- // bottom = dead
- BitSet::new_empty(body.local_decls.len())
- }
-
- fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
- for arg in body.args_iter() {
- state.insert(arg);
- }
- }
-}
-
-impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
- type Idx = mir::Local;
- fn statement_effect(&self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, _: mir::Location) {
- match stmt.kind {
- mir::StatementKind::StorageLive(l) => trans.gen(l),
- mir::StatementKind::StorageDead(l) => trans.kill(l),
- _ => (),
- }
- }
-
- fn terminator_effect(
- &self,
- _trans: &mut impl GenKill<Self::Idx>,
- _terminator: &mir::Terminator<'tcx>,
- _loc: mir::Location,
- ) {
- }
-
- fn call_return_effect(
- &self,
- _trans: &mut impl GenKill<Self::Idx>,
- _block: mir::BasicBlock,
- _return_places: CallReturnPlaces<'_, 'tcx>,
- ) {
- // Nothing to do when a call returns successfully
- }
-}
-
-/// Collects the possible borrowers of each local.
-/// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
-/// possible borrowers of `a`.
-struct PossibleBorrowerVisitor<'a, 'tcx> {
- possible_borrower: TransitiveRelation,
- body: &'a mir::Body<'tcx>,
- cx: &'a LateContext<'tcx>,
- possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
-}
-
-impl<'a, 'tcx> PossibleBorrowerVisitor<'a, 'tcx> {
- fn new(
- cx: &'a LateContext<'tcx>,
- body: &'a mir::Body<'tcx>,
- possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
- ) -> Self {
- Self {
- possible_borrower: TransitiveRelation::default(),
- cx,
- body,
- possible_origin,
- }
- }
-
- fn into_map(
- self,
- cx: &LateContext<'tcx>,
- maybe_live: ResultsCursor<'tcx, 'tcx, MaybeStorageLive>,
- ) -> PossibleBorrowerMap<'a, 'tcx> {
- let mut map = FxHashMap::default();
- for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
- if is_copy(cx, self.body.local_decls[row].ty) {
- continue;
- }
-
- let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len());
- borrowers.remove(mir::Local::from_usize(0));
- if !borrowers.is_empty() {
- map.insert(row, borrowers);
- }
- }
-
- let bs = BitSet::new_empty(self.body.local_decls.len());
- PossibleBorrowerMap {
- map,
- maybe_live,
- bitset: (bs.clone(), bs),
- }
- }
-}
-
-impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> {
- fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
- let lhs = place.local;
- match rvalue {
- mir::Rvalue::Ref(_, _, borrowed) => {
- self.possible_borrower.add(borrowed.local, lhs);
- },
- other => {
- if ContainsRegion
- .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty)
- .is_continue()
- {
- return;
- }
- rvalue_locals(other, |rhs| {
- if lhs != rhs {
- self.possible_borrower.add(rhs, lhs);
- }
- });
- },
- }
- }
-
- fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) {
- if let mir::TerminatorKind::Call {
- args,
- destination: mir::Place { local: dest, .. },
- ..
- } = &terminator.kind
- {
- // TODO add doc
- // If the call returns something with lifetimes,
- // let's conservatively assume the returned value contains lifetime of all the arguments.
- // For example, given `let y: Foo<'a> = foo(x)`, `y` is considered to be a possible borrower of `x`.
-
- let mut immutable_borrowers = vec![];
- let mut mutable_borrowers = vec![];
-
- for op in args {
- match op {
- mir::Operand::Copy(p) | mir::Operand::Move(p) => {
- if let ty::Ref(_, _, Mutability::Mut) = self.body.local_decls[p.local].ty.kind() {
- mutable_borrowers.push(p.local);
- } else {
- immutable_borrowers.push(p.local);
- }
- },
- mir::Operand::Constant(..) => (),
- }
- }
-
- let mut mutable_variables: Vec<mir::Local> = mutable_borrowers
- .iter()
- .filter_map(|r| self.possible_origin.get(r))
- .flat_map(HybridBitSet::iter)
- .collect();
-
- if ContainsRegion.visit_ty(self.body.local_decls[*dest].ty).is_break() {
- mutable_variables.push(*dest);
- }
-
- for y in mutable_variables {
- for x in &immutable_borrowers {
- self.possible_borrower.add(*x, y);
- }
- for x in &mutable_borrowers {
- self.possible_borrower.add(*x, y);
- }
- }
- }
- }
-}
-
-/// Collect possible borrowed for every `&mut` local.
-/// For example, `_1 = &mut _2` generate _1: {_2,...}
-/// Known Problems: not sure all borrowed are tracked
-struct PossibleOriginVisitor<'a, 'tcx> {
- possible_origin: TransitiveRelation,
- body: &'a mir::Body<'tcx>,
-}
-
-impl<'a, 'tcx> PossibleOriginVisitor<'a, 'tcx> {
- fn new(body: &'a mir::Body<'tcx>) -> Self {
- Self {
- possible_origin: TransitiveRelation::default(),
- body,
- }
- }
-
- fn into_map(self, cx: &LateContext<'tcx>) -> FxHashMap<mir::Local, HybridBitSet<mir::Local>> {
- let mut map = FxHashMap::default();
- for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
- if is_copy(cx, self.body.local_decls[row].ty) {
- continue;
- }
-
- let mut borrowers = self.possible_origin.reachable_from(row, self.body.local_decls.len());
- borrowers.remove(mir::Local::from_usize(0));
- if !borrowers.is_empty() {
- map.insert(row, borrowers);
- }
- }
- map
- }
-}
-
-impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'a, 'tcx> {
- fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
- let lhs = place.local;
- match rvalue {
- // Only consider `&mut`, which can modify origin place
- mir::Rvalue::Ref(_, rustc_middle::mir::BorrowKind::Mut { .. }, borrowed) |
- // _2: &mut _;
- // _3 = move _2
- mir::Rvalue::Use(mir::Operand::Move(borrowed)) |
- // _3 = move _2 as &mut _;
- mir::Rvalue::Cast(_, mir::Operand::Move(borrowed), _)
- => {
- self.possible_origin.add(lhs, borrowed.local);
- },
- _ => {},
- }
- }
-}
-
-struct ContainsRegion;
-
-impl TypeVisitor<'_> for ContainsRegion {
- type BreakTy = ();
-
- fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow<Self::BreakTy> {
- ControlFlow::BREAK
- }
-}
-
-fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
- use rustc_middle::mir::Rvalue::{Aggregate, BinaryOp, Cast, CheckedBinaryOp, Repeat, UnaryOp, Use};
-
- let mut visit_op = |op: &mir::Operand<'_>| match op {
- mir::Operand::Copy(p) | mir::Operand::Move(p) => visit(p.local),
- mir::Operand::Constant(..) => (),
- };
-
- match rvalue {
- Use(op) | Repeat(op, _) | Cast(_, op, _) | UnaryOp(_, op) => visit_op(op),
- Aggregate(_, ops) => ops.iter().for_each(visit_op),
- BinaryOp(_, box (lhs, rhs)) | CheckedBinaryOp(_, box (lhs, rhs)) => {
- visit_op(lhs);
- visit_op(rhs);
+fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>, bb: mir::BasicBlock) -> CloneUsage {
+ if let Some((
+ LocalUsage {
+ local_use_locs: cloned_use_locs,
+ local_consume_or_mutate_locs: cloned_consume_or_mutate_locs,
},
- _ => (),
- }
-}
-
-/// Result of `PossibleBorrowerVisitor`.
-struct PossibleBorrowerMap<'a, 'tcx> {
- /// Mapping `Local -> its possible borrowers`
- map: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
- maybe_live: ResultsCursor<'a, 'tcx, MaybeStorageLive>,
- // Caches to avoid allocation of `BitSet` on every query
- bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
-}
-
-impl PossibleBorrowerMap<'_, '_> {
- /// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`.
- fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool {
- self.maybe_live.seek_after_primary_effect(at);
-
- self.bitset.0.clear();
- let maybe_live = &mut self.maybe_live;
- if let Some(bitset) = self.map.get(&borrowed) {
- for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) {
- self.bitset.0.insert(b);
- }
- } else {
- return false;
- }
-
- self.bitset.1.clear();
- for b in borrowers {
- self.bitset.1.insert(*b);
+ LocalUsage {
+ local_use_locs: _,
+ local_consume_or_mutate_locs: clone_consume_or_mutate_locs,
+ },
+ )) = visit_local_usage(
+ &[cloned, clone],
+ mir,
+ mir::Location {
+ block: bb,
+ statement_index: mir.basic_blocks[bb].statements.len(),
+ },
+ )
+ .map(|mut vec| (vec.remove(0), vec.remove(0)))
+ {
+ CloneUsage {
+ cloned_used: !cloned_use_locs.is_empty(),
+ cloned_consume_or_mutate_loc: cloned_consume_or_mutate_locs.first().copied(),
+ // Consider non-temporary clones consumed.
+ // TODO: Actually check for mutation of non-temporaries.
+ clone_consumed_or_mutated: mir.local_kind(clone) != mir::LocalKind::Temp
+ || !clone_consume_or_mutate_locs.is_empty(),
}
-
- self.bitset.0 == self.bitset.1
- }
-
- fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {
- self.maybe_live.seek_after_primary_effect(at);
- self.maybe_live.contains(local)
- }
-}
-
-#[derive(Default)]
-struct TransitiveRelation {
- relations: FxHashMap<mir::Local, Vec<mir::Local>>,
-}
-impl TransitiveRelation {
- fn add(&mut self, a: mir::Local, b: mir::Local) {
- self.relations.entry(a).or_default().push(b);
- }
-
- fn reachable_from(&self, a: mir::Local, domain_size: usize) -> HybridBitSet<mir::Local> {
- let mut seen = HybridBitSet::new_empty(domain_size);
- let mut stack = vec![a];
- while let Some(u) = stack.pop() {
- if let Some(edges) = self.relations.get(&u) {
- for &v in edges {
- if seen.insert(v) {
- stack.push(v);
- }
- }
- }
+ } else {
+ CloneUsage {
+ cloned_used: true,
+ cloned_consume_or_mutate_loc: None,
+ clone_consumed_or_mutated: true,
}
- seen
}
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index f5a93ceba..74eea6de4 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sugg::Sugg;
use if_chain::if_chain;
use rustc_ast::ast;
use rustc_ast::visit as ast_visit;
@@ -69,7 +69,7 @@ impl EarlyLintPass for RedundantClosureCall {
if_chain! {
if let ast::ExprKind::Call(ref paren, _) = expr.kind;
if let ast::ExprKind::Paren(ref closure) = paren.kind;
- if let ast::ExprKind::Closure(_, _, _, _, ref decl, ref block, _) = closure.kind;
+ if let ast::ExprKind::Closure(_, _, ref r#async, _, ref decl, ref block, _) = closure.kind;
then {
let mut visitor = ReturnVisitor::new();
visitor.visit_expr(block);
@@ -81,10 +81,19 @@ impl EarlyLintPass for RedundantClosureCall {
"try not to call a closure in the expression where it is declared",
|diag| {
if decl.inputs.is_empty() {
- let mut app = Applicability::MachineApplicable;
- let hint =
- snippet_with_applicability(cx, block.span, "..", &mut app).into_owned();
- diag.span_suggestion(expr.span, "try doing something like", hint, app);
+ let app = Applicability::MachineApplicable;
+ let mut hint = Sugg::ast(cx, block, "..");
+
+ if r#async.is_async() {
+ // `async x` is a syntax error, so it becomes `async { x }`
+ if !matches!(block.kind, ast::ExprKind::Block(_, _)) {
+ hint = hint.blockify();
+ }
+
+ hint = hint.asyncify();
+ }
+
+ diag.span_suggestion(expr.span, "try doing something like", hint.to_string(), app);
}
},
);
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index 323326381..26075e9f7 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -46,17 +46,17 @@ impl_lint_pass!(RedundantPubCrate => [REDUNDANT_PUB_CRATE]);
impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
if_chain! {
- if cx.tcx.visibility(item.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id());
- if !cx.access_levels.is_exported(item.def_id) && self.is_exported.last() == Some(&false);
+ if cx.tcx.visibility(item.owner_id.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id());
+ if !cx.effective_visibilities.is_exported(item.owner_id.def_id) && self.is_exported.last() == Some(&false);
if is_not_macro_export(item);
then {
let span = item.span.with_hi(item.ident.span.hi());
- let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id());
+ let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id());
span_lint_and_then(
cx,
REDUNDANT_PUB_CRATE,
span,
- &format!("pub(crate) {} inside private module", descr),
+ &format!("pub(crate) {descr} inside private module"),
|diag| {
diag.span_suggestion(
item.vis_span,
@@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
}
if let ItemKind::Mod { .. } = item.kind {
- self.is_exported.push(cx.access_levels.is_exported(item.def_id));
+ self.is_exported.push(cx.effective_visibilities.is_exported(item.owner_id.def_id));
}
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index db6c97f37..245a02ea2 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -11,6 +11,8 @@ use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::subst::GenericArg;
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use std::iter;
+
declare_clippy_lint! {
/// ### What it does
/// Checks for redundant slicing expressions which use the full range, and
@@ -125,23 +127,23 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
let sugg = if (deref_count != 0 || !reborrow_str.is_empty()) && needs_parens_for_prefix {
- format!("({}{}{})", reborrow_str, "*".repeat(deref_count), snip)
+ format!("({reborrow_str}{}{snip})", "*".repeat(deref_count))
} else {
- format!("{}{}{}", reborrow_str, "*".repeat(deref_count), snip)
+ format!("{reborrow_str}{}{snip}", "*".repeat(deref_count))
};
(lint, help_str, sugg)
} else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
cx.param_env,
- cx.tcx.mk_projection(target_id, cx.tcx.mk_substs([GenericArg::from(indexed_ty)].into_iter())),
+ cx.tcx.mk_projection(target_id, cx.tcx.mk_substs(iter::once(GenericArg::from(indexed_ty)))),
) {
if deref_ty == expr_ty {
let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
let sugg = if needs_parens_for_prefix {
- format!("(&{}{}*{})", mutability.prefix_str(), "*".repeat(indexed_ref_count), snip)
+ format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count))
} else {
- format!("&{}{}*{}", mutability.prefix_str(), "*".repeat(indexed_ref_count), snip)
+ format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count))
};
(DEREF_BY_SLICING_LINT, "dereference the original value instead", sugg)
} else {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
index f8801f769..60ba62c4a 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
@@ -48,15 +48,15 @@ impl_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]);
impl RedundantStaticLifetimes {
// Recursively visit types
- fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
+ fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
match ty.kind {
// Be careful of nested structures (arrays and tuples)
TyKind::Array(ref ty, _) | TyKind::Slice(ref ty) => {
- self.visit_type(ty, cx, reason);
+ Self::visit_type(ty, cx, reason);
},
TyKind::Tup(ref tup) => {
for tup_ty in tup {
- self.visit_type(tup_ty, cx, reason);
+ Self::visit_type(tup_ty, cx, reason);
}
},
// This is what we are looking for !
@@ -67,7 +67,7 @@ impl RedundantStaticLifetimes {
TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
if lifetime.ident.name == rustc_span::symbol::kw::StaticLifetime {
let snip = snippet(cx, borrow_type.ty.span, "<type>");
- let sugg = format!("&{}", snip);
+ let sugg = format!("&{snip}");
span_lint_and_then(
cx,
REDUNDANT_STATIC_LIFETIMES,
@@ -87,7 +87,7 @@ impl RedundantStaticLifetimes {
_ => {},
}
}
- self.visit_type(&borrow_type.ty, cx, reason);
+ Self::visit_type(&borrow_type.ty, cx, reason);
},
_ => {},
}
@@ -102,13 +102,13 @@ impl EarlyLintPass for RedundantStaticLifetimes {
if !item.span.from_expansion() {
if let ItemKind::Const(_, ref var_type, _) = item.kind {
- self.visit_type(var_type, cx, "constants have by default a `'static` lifetime");
+ Self::visit_type(var_type, cx, "constants have by default a `'static` lifetime");
// Don't check associated consts because `'static` cannot be elided on those (issue
// #2438)
}
if let ItemKind::Static(ref var_type, _, _) = item.kind {
- self.visit_type(var_type, cx, "statics have by default a `'static` lifetime");
+ Self::visit_type(var_type, cx, "statics have by default a `'static` lifetime");
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
index 909d6971a..f21b3ea6c 100644
--- a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
@@ -43,8 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
if mut_ty.mutbl == Mutability::Not;
if let TyKind::Path(ref qpath) = &mut_ty.ty.kind;
let last = last_path_segment(qpath);
- if let Some(res) = last.res;
- if let Some(def_id) = res.opt_def_id();
+ if let Some(def_id) = last.res.opt_def_id();
if cx.tcx.is_diagnostic_item(sym::Option, def_id);
if let Some(params) = last_path_segment(qpath).args ;
@@ -53,7 +52,8 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
GenericArg::Type(inner_ty) => Some(inner_ty),
_ => None,
});
- if let TyKind::Rptr(_, _) = inner_ty.kind;
+ if let TyKind::Rptr(_, ref inner_mut_ty) = inner_ty.kind;
+ if inner_mut_ty.mutbl == Mutability::Not;
then {
span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index f9a9b0691..1fda58fa5 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -57,21 +57,20 @@ declare_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]);
impl<'tcx> LateLintPass<'tcx> for Regex {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
- if let ExprKind::Call(fun, args) = expr.kind;
+ if let ExprKind::Call(fun, [arg]) = expr.kind;
if let ExprKind::Path(ref qpath) = fun.kind;
- if args.len() == 1;
if let Some(def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
then {
if match_def_path(cx, def_id, &paths::REGEX_NEW) ||
match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) {
- check_regex(cx, &args[0], true);
+ check_regex(cx, arg, true);
} else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) ||
match_def_path(cx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) {
- check_regex(cx, &args[0], false);
+ check_regex(cx, arg, false);
} else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) {
- check_set(cx, &args[0], true);
+ check_set(cx, arg, true);
} else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) {
- check_set(cx, &args[0], false);
+ check_set(cx, arg, false);
}
}
}
@@ -173,7 +172,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
);
},
Err(e) => {
- span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {}", e));
+ span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {e}"));
},
}
}
@@ -201,7 +200,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
);
},
Err(e) => {
- span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {}", e));
+ span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {e}"));
},
}
}
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index ba03ef937..76d6ad0b2 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -2,6 +2,7 @@
#[rustfmt::skip]
pub static RENAMED_LINTS: &[(&str, &str)] = &[
+ ("clippy::blacklisted_name", "clippy::disallowed_names"),
("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"),
("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"),
("clippy::box_vec", "clippy::box_collection"),
@@ -10,10 +11,11 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
("clippy::disallowed_method", "clippy::disallowed_methods"),
("clippy::disallowed_type", "clippy::disallowed_types"),
("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
- ("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles"),
- ("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"),
+ ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
+ ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
("clippy::identity_conversion", "clippy::useless_conversion"),
("clippy::if_let_some_result", "clippy::match_result_ok"),
+ ("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
("clippy::new_without_default_derive", "clippy::new_without_default"),
("clippy::option_and_then_some", "clippy::bind_instead_of_map"),
("clippy::option_expect_used", "clippy::expect_used"),
@@ -29,11 +31,13 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
("clippy::to_string_in_display", "clippy::recursive_format_impl"),
("clippy::zero_width_space", "clippy::invisible_characters"),
("clippy::drop_bounds", "drop_bounds"),
+ ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
("clippy::into_iter_on_array", "array_into_iter"),
("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
("clippy::invalid_ref", "invalid_value"),
("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
("clippy::panic_params", "non_fmt_panics"),
+ ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
("clippy::unknown_clippy_lints", "unknown_lints"),
("clippy::unused_label", "unused_labels"),
diff --git a/src/tools/clippy/clippy_lints/src/repeat_once.rs b/src/tools/clippy/clippy_lints/src/repeat_once.rs
deleted file mode 100644
index 898c70ace..000000000
--- a/src/tools/clippy/clippy_lints/src/repeat_once.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-use clippy_utils::consts::{constant_context, Constant};
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for usage of `.repeat(1)` and suggest the following method for each types.
- /// - `.to_string()` for `str`
- /// - `.clone()` for `String`
- /// - `.to_vec()` for `slice`
- ///
- /// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if
- /// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))
- ///
- /// ### Why is this bad?
- /// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning
- /// the string is the intention behind this, `clone()` should be used.
- ///
- /// ### Example
- /// ```rust
- /// fn main() {
- /// let x = String::from("hello world").repeat(1);
- /// }
- /// ```
- /// Use instead:
- /// ```rust
- /// fn main() {
- /// let x = String::from("hello world").clone();
- /// }
- /// ```
- #[clippy::version = "1.47.0"]
- pub REPEAT_ONCE,
- complexity,
- "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
-}
-
-declare_lint_pass!(RepeatOnce => [REPEAT_ONCE]);
-
-impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
- fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
- if_chain! {
- if let ExprKind::MethodCall(path, [receiver, count], _) = &expr.kind;
- if path.ident.name == sym!(repeat);
- if constant_context(cx, cx.typeck_results()).expr(count) == Some(Constant::Int(1));
- if !receiver.span.from_expansion();
- then {
- let ty = cx.typeck_results().expr_ty(receiver).peel_refs();
- if ty.is_str() {
- span_lint_and_sugg(
- cx,
- REPEAT_ONCE,
- expr.span,
- "calling `repeat(1)` on str",
- "consider using `.to_string()` instead",
- format!("{}.to_string()", snippet(cx, receiver.span, r#""...""#)),
- Applicability::MachineApplicable,
- );
- } else if ty.builtin_index().is_some() {
- span_lint_and_sugg(
- cx,
- REPEAT_ONCE,
- expr.span,
- "calling `repeat(1)` on slice",
- "consider using `.to_vec()` instead",
- format!("{}.to_vec()", snippet(cx, receiver.span, r#""...""#)),
- Applicability::MachineApplicable,
- );
- } else if is_type_diagnostic_item(cx, ty, sym::String) {
- span_lint_and_sugg(
- cx,
- REPEAT_ONCE,
- expr.span,
- "calling `repeat(1)` on a string literal",
- "consider using `.clone()` instead",
- format!("{}.clone()", snippet(cx, receiver.span, r#""...""#)),
- Applicability::MachineApplicable,
- );
- }
- }
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
index 60be6bd33..b77faf732 100644
--- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
@@ -74,7 +74,7 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa
if !in_external_macro(cx.sess(), span);
if decl.implicit_self.has_implicit_self();
// We only show this warning for public exported methods.
- if cx.access_levels.is_exported(fn_def);
+ if cx.effective_visibilities.is_exported(fn_def);
// We don't want to emit this lint if the `#[must_use]` attribute is already there.
if !cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::must_use));
if cx.tcx.visibility(fn_def.to_def_id()).is_public();
@@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for ReturnSelfNotMustUse {
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
if let TraitItemKind::Fn(ref sig, _) = item.kind {
- check_method(cx, sig.decl, item.def_id, item.span, item.hir_id());
+ check_method(cx, sig.decl, item.owner_id.def_id, item.span, item.hir_id());
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 1d9a2abf7..2b2a41d16 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -1,17 +1,17 @@
-use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::source::{snippet_opt, snippet_with_context};
+use clippy_utils::visitors::{for_each_expr, Descend};
use clippy_utils::{fn_def_id, path_to_local_id};
+use core::ops::ControlFlow;
use if_chain::if_chain;
-use rustc_ast::ast::Attribute;
use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
+use rustc_hir::intravisit::FnKind;
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
-use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -74,6 +74,27 @@ enum RetReplacement {
Unit,
}
+impl RetReplacement {
+ fn sugg_help(self) -> &'static str {
+ match self {
+ Self::Empty => "remove `return`",
+ Self::Block => "replace `return` with an empty block",
+ Self::Unit => "replace `return` with a unit value",
+ }
+ }
+}
+
+impl ToString for RetReplacement {
+ fn to_string(&self) -> String {
+ match *self {
+ Self::Empty => "",
+ Self::Block => "{}",
+ Self::Unit => "()",
+ }
+ .to_string()
+ }
+}
+
declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN]);
impl<'tcx> LateLintPass<'tcx> for Return {
@@ -141,30 +162,35 @@ impl<'tcx> LateLintPass<'tcx> for Return {
} else {
RetReplacement::Empty
};
- check_final_expr(cx, &body.value, Some(body.value.span), replacement);
+ check_final_expr(cx, body.value, vec![], replacement);
},
FnKind::ItemFn(..) | FnKind::Method(..) => {
- if let ExprKind::Block(block, _) = body.value.kind {
- check_block_return(cx, block);
- }
+ check_block_return(cx, &body.value.kind, vec![]);
},
}
}
}
-fn attr_is_cfg(attr: &Attribute) -> bool {
- attr.meta_item_list().is_some() && attr.has_name(sym::cfg)
-}
-
-fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) {
- if let Some(expr) = block.expr {
- check_final_expr(cx, expr, Some(expr.span), RetReplacement::Empty);
- } else if let Some(stmt) = block.stmts.iter().last() {
- match stmt.kind {
- StmtKind::Expr(expr) | StmtKind::Semi(expr) => {
- check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty);
- },
- _ => (),
+// if `expr` is a block, check if there are needless returns in it
+fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, semi_spans: Vec<Span>) {
+ if let ExprKind::Block(block, _) = expr_kind {
+ if let Some(block_expr) = block.expr {
+ check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty);
+ } else if let Some(stmt) = block.stmts.iter().last() {
+ match stmt.kind {
+ StmtKind::Expr(expr) => {
+ check_final_expr(cx, expr, semi_spans, RetReplacement::Empty);
+ },
+ StmtKind::Semi(semi_expr) => {
+ let mut semi_spans_and_this_one = semi_spans;
+ // we only want the span containing the semicolon so we can remove it later. From `entry.rs:382`
+ if let Some(semicolon_span) = stmt.span.trim_start(semi_expr.span) {
+ semi_spans_and_this_one.push(semicolon_span);
+ check_final_expr(cx, semi_expr, semi_spans_and_this_one, RetReplacement::Empty);
+ }
+ },
+ _ => (),
+ }
}
}
}
@@ -172,37 +198,31 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) {
fn check_final_expr<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'tcx>,
- span: Option<Span>,
+ semi_spans: Vec<Span>, /* containing all the places where we would need to remove semicolons if finding an
+ * needless return */
replacement: RetReplacement,
) {
- match expr.kind {
+ let peeled_drop_expr = expr.peel_drop_temps();
+ match &peeled_drop_expr.kind {
// simple return is always "bad"
ExprKind::Ret(ref inner) => {
- // allow `#[cfg(a)] return a; #[cfg(b)] return b;`
- let attrs = cx.tcx.hir().attrs(expr.hir_id);
- if !attrs.iter().any(attr_is_cfg) {
+ if cx.tcx.hir().attrs(expr.hir_id).is_empty() {
let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
if !borrows {
emit_return_lint(
cx,
- inner.map_or(expr.hir_id, |inner| inner.hir_id),
- span.expect("`else return` is not possible"),
+ peeled_drop_expr.span,
+ semi_spans,
inner.as_ref().map(|i| i.span),
replacement,
);
}
}
},
- // a whole block? check it!
- ExprKind::Block(block, _) => {
- check_block_return(cx, block);
- },
ExprKind::If(_, then, else_clause_opt) => {
- if let ExprKind::Block(ifblock, _) = then.kind {
- check_block_return(cx, ifblock);
- }
+ check_block_return(cx, &then.kind, semi_spans.clone());
if let Some(else_clause) = else_clause_opt {
- check_final_expr(cx, else_clause, None, RetReplacement::Empty);
+ check_block_return(cx, &else_clause.kind, semi_spans);
}
},
// a match expr, check all arms
@@ -211,123 +231,61 @@ fn check_final_expr<'tcx>(
// (except for unit type functions) so we don't match it
ExprKind::Match(_, arms, MatchSource::Normal) => {
for arm in arms.iter() {
- check_final_expr(cx, arm.body, Some(arm.body.span), RetReplacement::Unit);
+ check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit);
}
},
- ExprKind::DropTemps(expr) => check_final_expr(cx, expr, None, RetReplacement::Empty),
- _ => (),
+ // if it's a whole block, check it
+ other_expr_kind => check_block_return(cx, other_expr_kind, semi_spans),
}
}
fn emit_return_lint(
cx: &LateContext<'_>,
- emission_place: HirId,
ret_span: Span,
+ semi_spans: Vec<Span>,
inner_span: Option<Span>,
replacement: RetReplacement,
) {
if ret_span.from_expansion() {
return;
}
- match inner_span {
- Some(inner_span) => {
- let mut applicability = Applicability::MachineApplicable;
- span_lint_hir_and_then(
- cx,
- NEEDLESS_RETURN,
- emission_place,
- ret_span,
- "unneeded `return` statement",
- |diag| {
- let (snippet, _) = snippet_with_context(cx, inner_span, ret_span.ctxt(), "..", &mut applicability);
- diag.span_suggestion(ret_span, "remove `return`", snippet, applicability);
- },
- );
- },
- None => match replacement {
- RetReplacement::Empty => {
- span_lint_hir_and_then(
- cx,
- NEEDLESS_RETURN,
- emission_place,
- ret_span,
- "unneeded `return` statement",
- |diag| {
- diag.span_suggestion(
- ret_span,
- "remove `return`",
- String::new(),
- Applicability::MachineApplicable,
- );
- },
- );
- },
- RetReplacement::Block => {
- span_lint_hir_and_then(
- cx,
- NEEDLESS_RETURN,
- emission_place,
- ret_span,
- "unneeded `return` statement",
- |diag| {
- diag.span_suggestion(
- ret_span,
- "replace `return` with an empty block",
- "{}".to_string(),
- Applicability::MachineApplicable,
- );
- },
- );
- },
- RetReplacement::Unit => {
- span_lint_hir_and_then(
- cx,
- NEEDLESS_RETURN,
- emission_place,
- ret_span,
- "unneeded `return` statement",
- |diag| {
- diag.span_suggestion(
- ret_span,
- "replace `return` with a unit value",
- "()".to_string(),
- Applicability::MachineApplicable,
- );
- },
- );
- },
+ let mut applicability = Applicability::MachineApplicable;
+ let return_replacement = inner_span.map_or_else(
+ || replacement.to_string(),
+ |inner_span| {
+ let (snippet, _) = snippet_with_context(cx, inner_span, ret_span.ctxt(), "..", &mut applicability);
+ snippet.to_string()
},
- }
+ );
+ let sugg_help = if inner_span.is_some() {
+ "remove `return`"
+ } else {
+ replacement.sugg_help()
+ };
+ span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
+ diag.span_suggestion_hidden(ret_span, sugg_help, return_replacement, applicability);
+ // for each parent statement, we need to remove the semicolon
+ for semi_stmt_span in semi_spans {
+ diag.tool_only_span_suggestion(semi_stmt_span, "remove this semicolon", "", applicability);
+ }
+ });
}
fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
- let mut visitor = BorrowVisitor { cx, borrows: false };
- walk_expr(&mut visitor, expr);
- visitor.borrows
-}
-
-struct BorrowVisitor<'a, 'tcx> {
- cx: &'a LateContext<'tcx>,
- borrows: bool,
-}
-
-impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> {
- fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
- if self.borrows || expr.span.from_expansion() {
- return;
- }
-
- if let Some(def_id) = fn_def_id(self.cx, expr) {
- self.borrows = self
- .cx
+ for_each_expr(expr, |e| {
+ if let Some(def_id) = fn_def_id(cx, e)
+ && cx
.tcx
.fn_sig(def_id)
- .output()
.skip_binder()
+ .output()
.walk()
- .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
+ .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
+ {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(Descend::from(!expr.span.from_expansion()))
}
-
- walk_expr(self, expr);
- }
+ })
+ .is_some()
}
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index 20184d54b..caab5851b 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
let mut map = FxHashMap::<Res, ExistingName>::default();
for id in cx.tcx.hir().items() {
- if matches!(cx.tcx.def_kind(id.def_id), DefKind::Impl)
+ if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl)
&& let item = cx.tcx.hir().item(id)
&& let ItemKind::Impl(Impl {
items,
@@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
|diag| {
diag.span_note(
trait_method_span,
- &format!("existing `{}` defined here", method_name),
+ &format!("existing `{method_name}` defined here"),
);
},
);
@@ -151,7 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
// iterate on trait_spans?
diag.span_note(
trait_spans[0],
- &format!("existing `{}` defined here", method_name),
+ &format!("existing `{method_name}` defined here"),
);
},
);
diff --git a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
index d07c26d7c..71b387c66 100644
--- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
+++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::return_ty;
-use clippy_utils::ty::{contains_adt_constructor, contains_ty};
+use clippy_utils::ty::contains_adt_constructor;
use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -51,9 +51,9 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
_ => return,
}
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
let item = cx.tcx.hir().expect_item(parent);
- let self_ty = cx.tcx.type_of(item.def_id);
+ let self_ty = cx.tcx.type_of(item.owner_id);
let ret_ty = return_ty(cx, impl_item.hir_id());
// Do not check trait impls
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
if !contains_adt_constructor(ret_ty, self_adt) {
return;
}
- } else if !contains_ty(ret_ty, self_ty) {
+ } else if !ret_ty.contains(self_ty) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
index 729694da4..66638eed9 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned {
}
let sugg = sugg::Sugg::hir_with_macro_callsite(cx, expr, "..");
- let suggestion = format!("{0};", sugg);
+ let suggestion = format!("{sugg};");
span_lint_and_sugg(
cx,
SEMICOLON_IF_NOTHING_RETURNED,
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 5dcdab5b8..87f966ced 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -106,10 +106,7 @@ impl_lint_pass!(Shadow => [SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED]);
impl<'tcx> LateLintPass<'tcx> for Shadow {
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
- let (id, ident) = match pat.kind {
- PatKind::Binding(_, hir_id, ident, _) => (hir_id, ident),
- _ => return,
- };
+ let PatKind::Binding(_, id, ident, _) = pat.kind else { return };
if pat.span.desugaring_kind().is_some() {
return;
diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
index bfb9f0d01..ac4e29e9d 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
@@ -108,7 +108,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
};
if_chain! {
// Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods
- if let ExprKind::MethodCall(method_path, [ptr_self, .., count], _) = expr.kind;
+ if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind;
let method_ident = method_path.ident.as_str();
if METHODS.iter().any(|m| *m == method_ident);
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 2c8aa17e8..760399231 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -1,9 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{get_enclosing_block, is_expr_path_def_path, path_to_local, path_to_local_id, paths, SpanlessEq};
+use clippy_utils::{
+ get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, SpanlessEq,
+};
use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor};
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, QPath, Stmt, StmtKind};
@@ -99,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
// Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)`
if_chain! {
if let StmtKind::Local(local) = stmt.kind;
- if let PatKind::Binding(BindingAnnotation::Mutable, local_id, _, None) = local.pat.kind;
+ if let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind;
if let Some(init) = local.init;
if let Some(len_arg) = Self::is_vec_with_capacity(cx, init);
@@ -174,7 +175,7 @@ impl SlowVectorInit {
diag.span_suggestion(
vec_alloc.allocation_expr.span,
"consider replace allocation with",
- format!("vec![0; {}]", len_expr),
+ format!("vec![0; {len_expr}]"),
Applicability::Unspecified,
);
});
@@ -201,7 +202,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) {
if_chain! {
if self.initialization_found;
- if let ExprKind::MethodCall(path, [self_arg, extend_arg], _) = expr.kind;
+ if let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind;
if path_to_local_id(self_arg, self.vec_alloc.local_id);
if path.ident.name == sym!(extend);
if self.is_repeat_take(extend_arg);
@@ -215,16 +216,15 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
/// Checks if the given expression is resizing a vector with 0
fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) {
if self.initialization_found
- && let ExprKind::MethodCall(path, [self_arg, len_arg, fill_arg], _) = expr.kind
+ && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind
&& path_to_local_id(self_arg, self.vec_alloc.local_id)
&& path.ident.name == sym!(resize)
// Check that is filled with 0
- && let ExprKind::Lit(ref lit) = fill_arg.kind
- && let LitKind::Int(0, _) = lit.node {
+ && is_integer_literal(fill_arg, 0) {
// Check that len expression is equals to `with_capacity` expression
if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
self.slow_expression = Some(InitializationType::Resize(expr));
- } else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" {
+ } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
self.slow_expression = Some(InitializationType::Resize(expr));
}
}
@@ -233,20 +233,15 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
/// Returns `true` if give expression is `repeat(0).take(...)`
fn is_repeat_take(&self, expr: &Expr<'_>) -> bool {
if_chain! {
- if let ExprKind::MethodCall(take_path, take_args, _) = expr.kind;
+ if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind;
if take_path.ident.name == sym!(take);
-
// Check that take is applied to `repeat(0)`
- if let Some(repeat_expr) = take_args.get(0);
- if self.is_repeat_zero(repeat_expr);
-
- if let Some(len_arg) = take_args.get(1);
-
+ if self.is_repeat_zero(recv);
then {
// Check that len expression is equals to `with_capacity` expression
if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
return true;
- } else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" {
+ } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
return true;
}
}
@@ -259,10 +254,8 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
fn is_repeat_zero(&self, expr: &Expr<'_>) -> bool {
if_chain! {
if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind;
- if is_expr_path_def_path(self.cx, fn_expr, &paths::ITER_REPEAT);
- if let ExprKind::Lit(ref lit) = repeat_arg.kind;
- if let LitKind::Int(0, _) = lit.node;
-
+ if is_path_diagnostic_item(self.cx, fn_expr, sym::iter_repeat);
+ if is_integer_literal(repeat_arg, 0);
then {
true
} else {
diff --git a/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
deleted file mode 100644
index a6c685df7..000000000
--- a/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{is_slice_of_primitives, sugg::Sugg};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
- /// ### What it does
- /// When sorting primitive values (integers, bools, chars, as well
- /// as arrays, slices, and tuples of such items), it is typically better to
- /// use an unstable sort than a stable sort.
- ///
- /// ### Why is this bad?
- /// Typically, using a stable sort consumes more memory and cpu cycles.
- /// Because values which compare equal are identical, preserving their
- /// relative order (the guarantee that a stable sort provides) means
- /// nothing, while the extra costs still apply.
- ///
- /// ### Known problems
- ///
- /// As pointed out in
- /// [issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241),
- /// a stable sort can instead be significantly faster for certain scenarios
- /// (eg. when a sorted vector is extended with new data and resorted).
- ///
- /// For more information and benchmarking results, please refer to the
- /// issue linked above.
- ///
- /// ### Example
- /// ```rust
- /// let mut vec = vec![2, 1, 3];
- /// vec.sort();
- /// ```
- /// Use instead:
- /// ```rust
- /// let mut vec = vec![2, 1, 3];
- /// vec.sort_unstable();
- /// ```
- #[clippy::version = "1.47.0"]
- pub STABLE_SORT_PRIMITIVE,
- pedantic,
- "use of sort() when sort_unstable() is equivalent"
-}
-
-declare_lint_pass!(StableSortPrimitive => [STABLE_SORT_PRIMITIVE]);
-
-/// The three "kinds" of sorts
-enum SortingKind {
- Vanilla,
- /* The other kinds of lint are currently commented out because they
- * can map distinct values to equal ones. If the key function is
- * provably one-to-one, or if the Cmp function conserves equality,
- * then they could be linted on, but I don't know if we can check
- * for that. */
-
- /* ByKey,
- * ByCmp, */
-}
-impl SortingKind {
- /// The name of the stable version of this kind of sort
- fn stable_name(&self) -> &str {
- match self {
- SortingKind::Vanilla => "sort",
- /* SortingKind::ByKey => "sort_by_key",
- * SortingKind::ByCmp => "sort_by", */
- }
- }
- /// The name of the unstable version of this kind of sort
- fn unstable_name(&self) -> &str {
- match self {
- SortingKind::Vanilla => "sort_unstable",
- /* SortingKind::ByKey => "sort_unstable_by_key",
- * SortingKind::ByCmp => "sort_unstable_by", */
- }
- }
- /// Takes the name of a function call and returns the kind of sort
- /// that corresponds to that function name (or None if it isn't)
- fn from_stable_name(name: &str) -> Option<SortingKind> {
- match name {
- "sort" => Some(SortingKind::Vanilla),
- // "sort_by" => Some(SortingKind::ByCmp),
- // "sort_by_key" => Some(SortingKind::ByKey),
- _ => None,
- }
- }
-}
-
-/// A detected instance of this lint
-struct LintDetection {
- slice_name: String,
- method: SortingKind,
- method_args: String,
- slice_type: String,
-}
-
-fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintDetection> {
- if_chain! {
- if let ExprKind::MethodCall(method_name, args, _) = &expr.kind;
- if let Some(slice) = &args.get(0);
- if let Some(method) = SortingKind::from_stable_name(method_name.ident.name.as_str());
- if let Some(slice_type) = is_slice_of_primitives(cx, slice);
- then {
- let args_str = args.iter().skip(1).map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::<Vec<String>>().join(", ");
- Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str, slice_type })
- } else {
- None
- }
- }
-}
-
-impl LateLintPass<'_> for StableSortPrimitive {
- fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- if let Some(detection) = detect_stable_sort_primitive(cx, expr) {
- span_lint_and_then(
- cx,
- STABLE_SORT_PRIMITIVE,
- expr.span,
- format!(
- "used `{}` on primitive type `{}`",
- detection.method.stable_name(),
- detection.slice_type,
- )
- .as_str(),
- |diag| {
- diag.span_suggestion(
- expr.span,
- "try",
- format!(
- "{}.{}({})",
- detection.slice_name,
- detection.method.unstable_name(),
- detection.method_args,
- ),
- Applicability::MachineApplicable,
- );
- diag.note(
- "an unstable sort typically performs faster without any observable difference for this data type",
- );
- },
- );
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
index ffd63cc68..d6b336bef 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -1,6 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_hir::def_id::DefId;
use rustc_hir::{def::Res, HirId, Path, PathSegment};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::DefIdTree;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, symbol::kw, Span};
@@ -94,6 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) {
if let Res::Def(_, def_id) = path.res
&& let Some(first_segment) = get_first_segment(path)
+ && is_stable(cx, def_id)
{
let (lint, msg, help) = match first_segment.ident.name {
sym::std => match cx.tcx.crate_name(def_id.krate) {
@@ -146,3 +149,22 @@ fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>>
_ => None,
}
}
+
+/// Checks if all ancestors of `def_id` are stable, to avoid linting
+/// [unstable moves](https://github.com/rust-lang/rust/pull/95956)
+fn is_stable(cx: &LateContext<'_>, mut def_id: DefId) -> bool {
+ loop {
+ if cx
+ .tcx
+ .lookup_stability(def_id)
+ .map_or(false, |stability| stability.is_unstable())
+ {
+ return false;
+ }
+
+ match cx.tcx.opt_parent(def_id) {
+ Some(parent) => def_id = parent,
+ None => return true,
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 22eb06b36..d356c99c8 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -262,7 +262,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
let (method_names, expressions, _) = method_calls(left, 1);
if method_names.len() == 1;
if expressions.len() == 1;
- if expressions[0].len() == 1;
+ if expressions[0].1.is_empty();
if method_names[0] == sym!(as_bytes);
// Check for slicer
@@ -270,7 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
then {
let mut applicability = Applicability::MachineApplicable;
- let string_expression = &expressions[0][0];
+ let string_expression = &expressions[0].0;
let snippet_app = snippet_with_applicability(
cx,
@@ -284,19 +284,19 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
e.span,
"calling a slice of `as_bytes()` with `from_utf8` should be not necessary",
"try",
- format!("Some(&{}[{}])", snippet_app, snippet(cx, right.span, "..")),
+ format!("Some(&{snippet_app}[{}])", snippet(cx, right.span, "..")),
applicability
)
}
}
if_chain! {
- if let ExprKind::MethodCall(path, args, _) = &e.kind;
+ if let ExprKind::MethodCall(path, receiver, ..) = &e.kind;
if path.ident.name == sym!(as_bytes);
- if let ExprKind::Lit(lit) = &args[0].kind;
+ if let ExprKind::Lit(lit) = &receiver.kind;
if let LitKind::Str(lit_content, _) = &lit.node;
then {
- let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#);
+ let callsite = snippet(cx, receiver.span.source_callsite(), r#""foo""#);
let mut applicability = Applicability::MachineApplicable;
if callsite.starts_with("include_str!") {
span_lint_and_sugg(
@@ -305,7 +305,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
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(
+ snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability).replacen(
"include_str",
"include_bytes",
1,
@@ -314,7 +314,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
);
} else if lit_content.as_str().is_ascii()
&& lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
- && !args[0].span.from_expansion()
+ && !receiver.span.from_expansion()
{
span_lint_and_sugg(
cx,
@@ -324,7 +324,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
"consider using a byte string literal instead",
format!(
"b{}",
- snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability)
+ snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
),
applicability,
);
@@ -333,9 +333,9 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
}
if_chain! {
- if let ExprKind::MethodCall(path, [recv], _) = &e.kind;
+ if let ExprKind::MethodCall(path, recv, [], _) = &e.kind;
if path.ident.name == sym!(into_bytes);
- if let ExprKind::MethodCall(path, [recv], _) = &recv.kind;
+ 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;
@@ -393,7 +393,7 @@ declare_lint_pass!(StrToString => [STR_TO_STRING]);
impl<'tcx> LateLintPass<'tcx> for StrToString {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
if_chain! {
- if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
+ 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();
@@ -443,7 +443,7 @@ declare_lint_pass!(StringToString => [STRING_TO_STRING]);
impl<'tcx> LateLintPass<'tcx> for StringToString {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
if_chain! {
- if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
+ 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);
@@ -487,11 +487,11 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
let tyckres = cx.typeck_results();
if_chain! {
- if let ExprKind::MethodCall(path, [split_recv], split_ws_span) = expr.kind;
+ if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind;
if path.ident.name == sym!(split_whitespace);
if let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id);
if cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id);
- if let ExprKind::MethodCall(path, [_trim_recv], trim_span) = split_recv.kind;
+ if let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind;
if let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str();
if let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id);
if is_one_of_trim_diagnostic_items(cx, trim_def_id);
@@ -500,8 +500,8 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace {
cx,
TRIM_SPLIT_WHITESPACE,
trim_span.with_hi(split_ws_span.lo()),
- &format!("found call to `str::{}` before `str::split_whitespace`", trim_fn_name),
- &format!("remove `{}()`", trim_fn_name),
+ &format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"),
+ &format!("remove `{trim_fn_name}()`"),
String::new(),
Applicability::MachineApplicable,
);
diff --git a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
index 7bc9cf742..03324c66e 100644
--- a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
@@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
if let ExprKind::Path(path) = &func.kind;
if let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id();
if match_libc_symbol(cx, did, "strlen");
- if let ExprKind::MethodCall(path, [self_arg], _) = recv.kind;
+ if let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind;
if !recv.span.from_expansion();
if path.ident.name == sym::as_ptr;
then {
@@ -79,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
span,
"using `libc::strlen` on a `CString` or `CStr` value",
"try this",
- format!("{}.{}().len()", val_name, method_name),
+ format!("{val_name}.{method_name}().len()"),
app,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index fe8859905..eef9bdc78 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -326,8 +326,7 @@ fn replace_left_sugg(
applicability: &mut Applicability,
) -> String {
format!(
- "{} {} {}",
- left_suggestion,
+ "{left_suggestion} {} {}",
binop.op.to_string(),
snippet_with_applicability(cx, binop.right.span, "..", applicability),
)
@@ -340,10 +339,9 @@ fn replace_right_sugg(
applicability: &mut Applicability,
) -> String {
format!(
- "{} {} {}",
+ "{} {} {right_suggestion}",
snippet_with_applicability(cx, binop.left.span, "..", applicability),
binop.op.to_string(),
- right_suggestion,
)
}
@@ -595,7 +593,7 @@ fn ident_difference_expr_with_base_location(
| (Unary(_, _), Unary(_, _))
| (Binary(_, _, _), Binary(_, _, _))
| (Tup(_), Tup(_))
- | (MethodCall(_, _, _), MethodCall(_, _, _))
+ | (MethodCall(_, _, _, _), MethodCall(_, _, _, _))
| (Call(_, _), Call(_, _))
| (ConstBlock(_), ConstBlock(_))
| (Array(_), Array(_))
@@ -676,9 +674,8 @@ fn suggestion_with_swapped_ident(
}
Some(format!(
- "{}{}{}",
+ "{}{new_ident}{}",
snippet_with_applicability(cx, expr.span.with_hi(current_ident.span.lo()), "..", applicability),
- new_ident,
snippet_with_applicability(cx, expr.span.with_lo(current_ident.span.hi()), "..", applicability),
))
})
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
index 4294464db..b57b484bd 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
@@ -1,8 +1,9 @@
use clippy_utils::diagnostics::span_lint;
+use clippy_utils::visitors::for_each_expr;
use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TRAITS};
+use core::ops::ControlFlow;
use if_chain::if_chain;
use rustc_hir as hir;
-use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -64,11 +65,11 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
// Check for more than one binary operation in the implemented function
// Linting when multiple operations are involved can result in false positives
- let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);
+ let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id;
if let hir::Node::ImplItem(impl_item) = cx.tcx.hir().get_by_def_id(parent_fn);
if let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind;
let body = cx.tcx.hir().body(body_id);
- let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);
+ let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id;
if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn);
let trait_id = trait_ref.path.res.def_id();
if ![binop_trait_id, op_assign_trait_id].contains(&trait_id);
@@ -78,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
]
.iter()
.find(|&(ts, _)| ts.iter().any(|&t| Ok(trait_id) == cx.tcx.lang_items().require(t)));
- if count_binops(&body.value) == 1;
+ if count_binops(body.value) == 1;
then {
span_lint(
cx,
@@ -92,25 +93,17 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
}
fn count_binops(expr: &hir::Expr<'_>) -> u32 {
- let mut visitor = BinaryExprVisitor::default();
- visitor.visit_expr(expr);
- visitor.nb_binops
-}
-
-#[derive(Default)]
-struct BinaryExprVisitor {
- nb_binops: u32,
-}
-
-impl<'tcx> Visitor<'tcx> for BinaryExprVisitor {
- fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
- match expr.kind {
+ let mut count = 0u32;
+ let _: Option<!> = for_each_expr(expr, |e| {
+ if matches!(
+ e.kind,
hir::ExprKind::Binary(..)
- | hir::ExprKind::Unary(hir::UnOp::Not | hir::UnOp::Neg, _)
- | hir::ExprKind::AssignOp(..) => self.nb_binops += 1,
- _ => {},
+ | hir::ExprKind::Unary(hir::UnOp::Not | hir::UnOp::Neg, _)
+ | hir::ExprKind::AssignOp(..)
+ ) {
+ count += 1;
}
-
- walk_expr(self, expr);
- }
+ ControlFlow::Continue(())
+ });
+ count
}
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 1885f3ca4..f46c21e12 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -96,7 +96,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
cx,
MANUAL_SWAP,
span,
- &format!("this looks like you are swapping elements of `{}` manually", slice),
+ &format!("this looks like you are swapping elements of `{slice}` manually"),
"try",
format!(
"{}.swap({}, {})",
@@ -121,16 +121,16 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
cx,
MANUAL_SWAP,
span,
- &format!("this looks like you are swapping `{}` and `{}` manually", first, second),
+ &format!("this looks like you are swapping `{first}` and `{second}` manually"),
|diag| {
diag.span_suggestion(
span,
"try",
- format!("{}::mem::swap({}, {})", sugg, first.mut_addr(), second.mut_addr()),
+ format!("{sugg}::mem::swap({}, {})", first.mut_addr(), second.mut_addr()),
applicability,
);
if !is_xor_based {
- diag.note(&format!("or maybe you should use `{}::mem::replace`?", sugg));
+ diag.note(&format!("or maybe you should use `{sugg}::mem::replace`?"));
}
},
);
@@ -182,7 +182,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
let rhs0 = Sugg::hir_opt(cx, rhs0);
let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) {
(
- format!(" `{}` and `{}`", first, second),
+ format!(" `{first}` and `{second}`"),
first.mut_addr().to_string(),
second.mut_addr().to_string(),
)
@@ -196,22 +196,19 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
span_lint_and_then(cx,
ALMOST_SWAPPED,
span,
- &format!("this looks like you are trying to swap{}", what),
+ &format!("this looks like you are trying to swap{what}"),
|diag| {
if !what.is_empty() {
diag.span_suggestion(
span,
"try",
format!(
- "{}::mem::swap({}, {})",
- sugg,
- lhs,
- rhs,
+ "{sugg}::mem::swap({lhs}, {rhs})",
),
Applicability::MaybeIncorrect,
);
diag.note(
- &format!("or maybe you should use `{}::mem::replace`?", sugg)
+ &format!("or maybe you should use `{sugg}::mem::replace`?")
);
}
});
diff --git a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
index 3cbbda80f..d085dda35 100644
--- a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
@@ -58,7 +58,7 @@ impl LateLintPass<'_> for SwapPtrToRef {
let mut app = Applicability::MachineApplicable;
let snip1 = snippet_with_context(cx, arg1_span.unwrap_or(arg1.span), ctxt, "..", &mut app).0;
let snip2 = snippet_with_context(cx, arg2_span.unwrap_or(arg2.span), ctxt, "..", &mut app).0;
- diag.span_suggestion(e.span, "use ptr::swap", format!("core::ptr::swap({}, {})", snip1, snip2), app);
+ diag.span_suggestion(e.span, "use ptr::swap", format!("core::ptr::swap({snip1}, {snip2})"), app);
}
}
);
diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
index aa6c01b3a..2512500a6 100644
--- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
@@ -39,19 +39,17 @@ declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]);
impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if_chain! {
- if let hir::ExprKind::MethodCall(is_some_path, is_some_args, _) = &expr.kind;
+ if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind;
if is_some_path.ident.name.as_str() == "is_some";
- if let [to_digit_expr] = &**is_some_args;
then {
let match_result = match &to_digit_expr.kind {
- hir::ExprKind::MethodCall(to_digits_path, to_digit_args, _) => {
+ hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => {
if_chain! {
- if let [char_arg, radix_arg] = &**to_digit_args;
if to_digits_path.ident.name.as_str() == "to_digit";
let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg);
if *char_arg_ty.kind() == ty::Char;
then {
- Some((true, char_arg, radix_arg))
+ Some((true, *char_arg, radix_arg))
} else {
None
}
@@ -59,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
}
hir::ExprKind::Call(to_digits_call, to_digit_args) => {
if_chain! {
- if let [char_arg, radix_arg] = &**to_digit_args;
+ if let [char_arg, radix_arg] = *to_digit_args;
if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind;
if let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id);
if let Some(to_digits_def_id) = to_digits_call_res.opt_def_id();
@@ -86,9 +84,9 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
"use of `.to_digit(..).is_some()`",
"try this",
if is_method_call {
- format!("{}.is_digit({})", char_arg_snip, radix_snip)
+ format!("{char_arg_snip}.is_digit({radix_snip})")
} else {
- format!("char::is_digit({}, {})", char_arg_snip, radix_snip)
+ format!("char::is_digit({char_arg_snip}, {radix_snip})")
},
applicability,
);
diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
index 58cc057a3..8cf3efc8d 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -46,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
None,
&format!(
"consider annotating `{}` with `#[repr(C)]` or another `repr` attribute",
- cx.tcx.def_path_str(item.def_id.to_def_id())
+ cx.tcx.def_path_str(item.owner_id.to_def_id())
),
);
}
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 0a42a31fb..b5f11b4ac 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -4,7 +4,7 @@ use clippy_utils::{SpanlessEq, SpanlessHash};
use core::hash::{Hash, Hasher};
use if_chain::if_chain;
use itertools::Itertools;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::unhash::UnhashMap;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
@@ -15,6 +15,7 @@ use rustc_hir::{
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{BytePos, Span};
+use std::collections::hash_map::Entry;
declare_clippy_lint! {
/// ### What it does
@@ -103,7 +104,6 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
self.check_type_repetition(cx, gen);
check_trait_bound_duplication(cx, gen);
- check_bounds_or_where_duplication(cx, gen);
}
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
@@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
if !bound_predicate.span.from_expansion();
if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
if let Some(PathSegment {
- res: Some(Res::SelfTy{ trait_: Some(def_id), alias_to: _ }), ..
+ res: Res::SelfTyParam { trait_: def_id }, ..
}) = segments.first();
if let Some(
Node::Item(
@@ -215,9 +215,8 @@ impl TraitBounds {
.map(|(_, _, span)| snippet_with_applicability(cx, span, "..", &mut applicability))
.join(" + ");
let hint_string = format!(
- "consider combining the bounds: `{}: {}`",
+ "consider combining the bounds: `{}: {trait_bounds}`",
snippet(cx, p.bounded_ty.span, "_"),
- trait_bounds,
);
span_lint_and_help(
cx,
@@ -234,35 +233,61 @@ impl TraitBounds {
}
fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
- if gen.span.from_expansion() || gen.params.is_empty() || gen.predicates.is_empty() {
+ if gen.span.from_expansion() {
return;
}
- let mut map = FxHashMap::<_, Vec<_>>::default();
- for predicate in gen.predicates {
+ // Explanation:
+ // fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+ // where T: Clone + Default, { unimplemented!(); }
+ // ^^^^^^^^^^^^^^^^^^
+ // |
+ // collects each of these where clauses into a set keyed by generic name and comparable trait
+ // eg. (T, Clone)
+ let where_predicates = gen
+ .predicates
+ .iter()
+ .filter_map(|pred| {
+ if_chain! {
+ if pred.in_where_clause();
+ if let WherePredicate::BoundPredicate(bound_predicate) = pred;
+ if let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind;
+ then {
+ return Some(
+ rollup_traits(cx, bound_predicate.bounds, "these where clauses contain repeated elements")
+ .into_iter().map(|(trait_ref, _)| (path.res, trait_ref)))
+ }
+ }
+ None
+ })
+ .flatten()
+ .collect::<FxHashSet<_>>();
+
+ // Explanation:
+ // fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z) ...
+ // ^^^^^^^^^^^^^^^^^^ ^^^^^^^
+ // |
+ // compare trait bounds keyed by generic name and comparable trait to collected where
+ // predicates eg. (T, Clone)
+ for predicate in gen.predicates.iter().filter(|pred| !pred.in_where_clause()) {
if_chain! {
- if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
+ if let WherePredicate::BoundPredicate(bound_predicate) = predicate;
if bound_predicate.origin != PredicateOrigin::ImplTrait;
if !bound_predicate.span.from_expansion();
- if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
- if let Some(segment) = segments.first();
+ if let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind;
then {
- for (res_where, _, span_where) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) {
- let trait_resolutions_direct = map.entry(segment.ident).or_default();
- if let Some((_, span_direct)) = trait_resolutions_direct
- .iter()
- .find(|(res_direct, _)| *res_direct == res_where) {
+ let traits = rollup_traits(cx, bound_predicate.bounds, "these bounds contain repeated elements");
+ for (trait_ref, span) in traits {
+ let key = (path.res, trait_ref);
+ if where_predicates.contains(&key) {
span_lint_and_help(
cx,
TRAIT_DUPLICATION_IN_BOUNDS,
- *span_direct,
+ span,
"this trait bound is already specified in the where clause",
None,
"consider removing this trait bound",
- );
- }
- else {
- trait_resolutions_direct.push((res_where, span_where));
+ );
}
}
}
@@ -270,23 +295,11 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
}
}
-#[derive(PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
struct ComparableTraitRef(Res, Vec<Res>);
-
-fn check_bounds_or_where_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
- if gen.span.from_expansion() {
- return;
- }
-
- for predicate in gen.predicates {
- if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate {
- let msg = if predicate.in_where_clause() {
- "these where clauses contain repeated elements"
- } else {
- "these bounds contain repeated elements"
- };
- rollup_traits(cx, bound_predicate.bounds, msg);
- }
+impl Default for ComparableTraitRef {
+ fn default() -> Self {
+ Self(Res::Err, Vec::new())
}
}
@@ -331,7 +344,7 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef {
)
}
-fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) {
+fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -> Vec<(ComparableTraitRef, Span)> {
let mut map = FxHashMap::default();
let mut repeated_res = false;
@@ -343,23 +356,33 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) {
}
};
+ let mut i = 0usize;
for bound in bounds.iter().filter_map(only_comparable_trait_refs) {
let (comparable_bound, span_direct) = bound;
- if map.insert(comparable_bound, span_direct).is_some() {
- repeated_res = true;
+ match map.entry(comparable_bound) {
+ Entry::Occupied(_) => repeated_res = true,
+ Entry::Vacant(e) => {
+ e.insert((span_direct, i));
+ i += 1;
+ },
}
}
+ // Put bounds in source order
+ let mut comparable_bounds = vec![Default::default(); map.len()];
+ for (k, (v, i)) in map {
+ comparable_bounds[i] = (k, v);
+ }
+
if_chain! {
if repeated_res;
if let [first_trait, .., last_trait] = bounds;
then {
let all_trait_span = first_trait.span().to(last_trait.span());
- let mut traits = map.values()
- .filter_map(|span| snippet_opt(cx, *span))
+ let traits = comparable_bounds.iter()
+ .filter_map(|&(_, span)| snippet_opt(cx, span))
.collect::<Vec<_>>();
- traits.sort_unstable();
let traits = traits.join(" + ");
span_lint_and_sugg(
@@ -373,4 +396,6 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) {
);
}
}
+
+ comparable_bounds
}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs
index 25d0543c8..c4b9d82fc 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs
@@ -13,10 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty
cx,
CROSSPOINTER_TRANSMUTE,
e.span,
- &format!(
- "transmute from a type (`{}`) to the type that it points to (`{}`)",
- from_ty, to_ty
- ),
+ &format!("transmute from a type (`{from_ty}`) to the type that it points to (`{to_ty}`)"),
);
true
},
@@ -25,10 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty
cx,
CROSSPOINTER_TRANSMUTE,
e.span,
- &format!(
- "transmute from a type (`{}`) to a pointer to that type (`{}`)",
- from_ty, to_ty
- ),
+ &format!("transmute from a type (`{from_ty}`) to a pointer to that type (`{to_ty}`)"),
);
true
},
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index 5f3e98144..424a6e926 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -9,6 +9,7 @@ mod transmute_ptr_to_ref;
mod transmute_ref_to_ref;
mod transmute_undefined_repr;
mod transmutes_expressible_as_ptr_casts;
+mod transmuting_null;
mod unsound_collection_transmute;
mod useless_transmute;
mod utils;
@@ -386,6 +387,28 @@ declare_clippy_lint! {
"transmute to or from a type with an undefined representation"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for transmute calls which would receive a null pointer.
+ ///
+ /// ### Why is this bad?
+ /// Transmuting a null pointer is undefined behavior.
+ ///
+ /// ### Known problems
+ /// Not all cases can be detected at the moment of this writing.
+ /// For example, variables which hold a null pointer and are then fed to a `transmute`
+ /// call, aren't detectable yet.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
+ /// ```
+ #[clippy::version = "1.35.0"]
+ pub TRANSMUTING_NULL,
+ correctness,
+ "transmutes from a null pointer to a reference, which is undefined behavior"
+}
+
pub struct Transmute {
msrv: Option<RustcVersion>,
}
@@ -404,6 +427,7 @@ impl_lint_pass!(Transmute => [
UNSOUND_COLLECTION_TRANSMUTE,
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
TRANSMUTE_UNDEFINED_REPR,
+ TRANSMUTING_NULL,
]);
impl Transmute {
#[must_use]
@@ -436,6 +460,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
| crosspointer_transmute::check(cx, e, from_ty, to_ty)
+ | transmuting_null::check(cx, e, arg, to_ty)
| transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv)
| transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
| transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
index 1bde977cf..5ecba512b 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
cx,
TRANSMUTE_FLOAT_TO_INT,
e.span,
- &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
+ &format!("transmute from a `{from_ty}` to a `{to_ty}`"),
|diag| {
let mut sugg = sugg::Sugg::hir(cx, arg, "..");
@@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(
if let ExprKind::Lit(lit) = &arg.kind;
if let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node;
then {
- let op = format!("{}{}", sugg, float_ty.name_str()).into();
+ let op = format!("{sugg}{}", float_ty.name_str()).into();
match sugg {
sugg::Sugg::MaybeParen(_) => sugg = sugg::Sugg::MaybeParen(op),
_ => sugg = sugg::Sugg::NonParen(op)
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs
index 8c50b58ca..58227c53d 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs
@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
cx,
TRANSMUTE_INT_TO_BOOL,
e.span,
- &format!("transmute from a `{}` to a `bool`", from_ty),
+ &format!("transmute from a `{from_ty}` to a `bool`"),
|diag| {
let arg = sugg::Sugg::hir(cx, arg, "..");
let zero = sugg::Sugg::NonParen(Cow::from("0"));
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs
index 9e1823c37..7d31c375f 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs
@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
cx,
TRANSMUTE_INT_TO_CHAR,
e.span,
- &format!("transmute from a `{}` to a `char`", from_ty),
+ &format!("transmute from a `{from_ty}` to a `char`"),
|diag| {
let arg = sugg::Sugg::hir(cx, arg, "..");
let arg = if let ty::Int(_) = from_ty.kind() {
@@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(
diag.span_suggestion(
e.span,
"consider using",
- format!("std::char::from_u32({}).unwrap()", arg),
+ format!("std::char::from_u32({arg}).unwrap()"),
Applicability::Unspecified,
);
},
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs
index b8703052e..cc3422edb 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs
@@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(
cx,
TRANSMUTE_INT_TO_FLOAT,
e.span,
- &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
+ &format!("transmute from a `{from_ty}` to a `{to_ty}`"),
|diag| {
let arg = sugg::Sugg::hir(cx, arg, "..");
let arg = if let ty::Int(int_ty) = from_ty.kind() {
@@ -36,7 +36,7 @@ pub(super) fn check<'tcx>(
diag.span_suggestion(
e.span,
"consider using",
- format!("{}::from_bits({})", to_ty, arg),
+ format!("{to_ty}::from_bits({arg})"),
Applicability::Unspecified,
);
},
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs
index 52d193d11..009d5a7c8 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs
@@ -31,13 +31,13 @@ pub(super) fn check<'tcx>(
cx,
TRANSMUTE_NUM_TO_BYTES,
e.span,
- &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
+ &format!("transmute from a `{from_ty}` to a `{to_ty}`"),
|diag| {
let arg = sugg::Sugg::hir(cx, arg, "..");
diag.span_suggestion(
e.span,
"consider using `to_ne_bytes()`",
- format!("{}.to_ne_bytes()", arg),
+ format!("{arg}.to_ne_bytes()"),
Applicability::Unspecified,
);
},
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
index 5eb03275b..12d0b866e 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
@@ -25,10 +25,7 @@ pub(super) fn check<'tcx>(
cx,
TRANSMUTE_PTR_TO_REF,
e.span,
- &format!(
- "transmute from a pointer type (`{}`) to a reference type (`{}`)",
- from_ty, to_ty
- ),
+ &format!("transmute from a pointer type (`{from_ty}`) to a reference type (`{to_ty}`)"),
|diag| {
let arg = sugg::Sugg::hir(cx, arg, "..");
let (deref, cast) = if *mutbl == Mutability::Mut {
@@ -41,26 +38,25 @@ pub(super) fn check<'tcx>(
let sugg = if let Some(ty) = get_explicit_type(path) {
let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app);
if meets_msrv(msrv, msrvs::POINTER_CAST) {
- format!("{}{}.cast::<{}>()", deref, arg.maybe_par(), ty_snip)
+ format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_par())
} else if from_ptr_ty.has_erased_regions() {
- sugg::make_unop(deref, arg.as_ty(format!("{} () as {} {}", cast, cast, ty_snip)))
- .to_string()
+ sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string()
} else {
- sugg::make_unop(deref, arg.as_ty(format!("{} {}", cast, ty_snip))).to_string()
+ sugg::make_unop(deref, arg.as_ty(format!("{cast} {ty_snip}"))).to_string()
}
} else if from_ptr_ty.ty == *to_ref_ty {
if from_ptr_ty.has_erased_regions() {
if meets_msrv(msrv, msrvs::POINTER_CAST) {
- format!("{}{}.cast::<{}>()", deref, arg.maybe_par(), to_ref_ty)
+ format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_par())
} else {
- sugg::make_unop(deref, arg.as_ty(format!("{} () as {} {}", cast, cast, to_ref_ty)))
+ sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}")))
.to_string()
}
} else {
sugg::make_unop(deref, arg).to_string()
}
} else {
- sugg::make_unop(deref, arg.as_ty(format!("{} {}", cast, to_ref_ty))).to_string()
+ sugg::make_unop(deref, arg.as_ty(format!("{cast} {to_ref_ty}"))).to_string()
};
diag.span_suggestion(e.span, "try", sugg, app);
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
index 707a11d36..afb7f2e13 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
@@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(
cx,
TRANSMUTE_BYTES_TO_STR,
e.span,
- &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
+ &format!("transmute from a `{from_ty}` to a `{to_ty}`"),
"consider using",
if const_context {
format!("std::str::from_utf8_unchecked{postfix}({snippet})")
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
index 20b348fc1..3d4bbbf64 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -3,11 +3,10 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::is_c_void;
use rustc_hir::Expr;
use rustc_lint::LateContext;
-use rustc_middle::ty::subst::{Subst, SubstsRef};
+use rustc_middle::ty::SubstsRef;
use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy};
-use rustc_span::Span;
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
e: &'tcx Expr<'_>,
@@ -18,116 +17,103 @@ pub(super) fn check<'tcx>(
let mut to_ty = cx.tcx.erase_regions(to_ty_orig);
while from_ty != to_ty {
- match reduce_refs(cx, e.span, from_ty, to_ty) {
- ReducedTys::FromFatPtr {
- unsized_ty,
- to_ty: to_sub_ty,
- } => match reduce_ty(cx, to_sub_ty) {
- ReducedTy::TypeErasure => break,
- ReducedTy::UnorderedFields(ty) if is_size_pair(ty) => break,
- ReducedTy::Ref(to_sub_ty) => {
- from_ty = unsized_ty;
- to_ty = to_sub_ty;
- continue;
- },
- _ => {
- span_lint_and_then(
- cx,
- TRANSMUTE_UNDEFINED_REPR,
- e.span,
- &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
- |diag| {
- if from_ty_orig.peel_refs() != unsized_ty {
- diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty));
- }
- },
- );
- return true;
- },
- },
- ReducedTys::ToFatPtr {
- unsized_ty,
- from_ty: from_sub_ty,
- } => match reduce_ty(cx, from_sub_ty) {
- ReducedTy::TypeErasure => break,
- ReducedTy::UnorderedFields(ty) if is_size_pair(ty) => break,
- ReducedTy::Ref(from_sub_ty) => {
- from_ty = from_sub_ty;
- to_ty = unsized_ty;
- continue;
- },
- _ => {
- span_lint_and_then(
- cx,
- TRANSMUTE_UNDEFINED_REPR,
- e.span,
- &format!("transmute to `{}` which has an undefined layout", to_ty_orig),
- |diag| {
- if to_ty_orig.peel_refs() != unsized_ty {
- diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty));
- }
- },
- );
- return true;
- },
- },
- ReducedTys::ToPtr {
- from_ty: from_sub_ty,
- to_ty: to_sub_ty,
- } => match reduce_ty(cx, from_sub_ty) {
- ReducedTy::UnorderedFields(from_ty) => {
- span_lint_and_then(
- cx,
- TRANSMUTE_UNDEFINED_REPR,
- e.span,
- &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
- |diag| {
- if from_ty_orig.peel_refs() != from_ty {
- diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
- }
- },
- );
- return true;
- },
- ReducedTy::Ref(from_sub_ty) => {
- from_ty = from_sub_ty;
- to_ty = to_sub_ty;
- continue;
- },
- _ => break,
- },
- ReducedTys::FromPtr {
- from_ty: from_sub_ty,
- to_ty: to_sub_ty,
- } => match reduce_ty(cx, to_sub_ty) {
- ReducedTy::UnorderedFields(to_ty) => {
- span_lint_and_then(
- cx,
- TRANSMUTE_UNDEFINED_REPR,
- e.span,
- &format!("transmute to `{}` which has an undefined layout", to_ty_orig),
- |diag| {
- if to_ty_orig.peel_refs() != to_ty {
- diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
- }
- },
- );
- return true;
- },
- ReducedTy::Ref(to_sub_ty) => {
- from_ty = from_sub_ty;
- to_ty = to_sub_ty;
- continue;
- },
- _ => break,
- },
- ReducedTys::Other {
- from_ty: from_sub_ty,
- to_ty: to_sub_ty,
- } => match (reduce_ty(cx, from_sub_ty), reduce_ty(cx, to_sub_ty)) {
- (ReducedTy::TypeErasure, _) | (_, ReducedTy::TypeErasure) => return false,
- (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
- let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs))
+ let reduced_tys = reduce_refs(cx, from_ty, to_ty);
+ match (reduce_ty(cx, reduced_tys.from_ty), reduce_ty(cx, reduced_tys.to_ty)) {
+ // Various forms of type erasure.
+ (ReducedTy::TypeErasure { raw_ptr_only: false }, _)
+ | (_, ReducedTy::TypeErasure { raw_ptr_only: false }) => return false,
+ (ReducedTy::TypeErasure { .. }, _) if reduced_tys.from_raw_ptr => return false,
+ (_, ReducedTy::TypeErasure { .. }) if reduced_tys.to_raw_ptr => return false,
+
+ // `Repr(C)` <-> unordered type.
+ // If the first field of the `Repr(C)` type matches then the transmute is ok
+ (
+ ReducedTy::OrderedFields(_, Some(from_sub_ty)),
+ ReducedTy::UnorderedFields(to_sub_ty),
+ )
+ | (
+ ReducedTy::UnorderedFields(from_sub_ty),
+ ReducedTy::OrderedFields(_, Some(to_sub_ty)),
+ ) => {
+ from_ty = from_sub_ty;
+ to_ty = to_sub_ty;
+ continue;
+ }
+ (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::Other(to_sub_ty))
+ if reduced_tys.to_fat_ptr =>
+ {
+ from_ty = from_sub_ty;
+ to_ty = to_sub_ty;
+ continue;
+ }
+ (ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty)))
+ if reduced_tys.from_fat_ptr =>
+ {
+ from_ty = from_sub_ty;
+ to_ty = to_sub_ty;
+ continue;
+ }
+
+ // ptr <-> ptr
+ (ReducedTy::Other(from_sub_ty), ReducedTy::Other(to_sub_ty))
+ if matches!(from_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_))
+ && matches!(to_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_)) =>
+ {
+ from_ty = from_sub_ty;
+ to_ty = to_sub_ty;
+ continue;
+ }
+
+ // fat ptr <-> (*size, *size)
+ (ReducedTy::Other(_), ReducedTy::UnorderedFields(to_ty))
+ if reduced_tys.from_fat_ptr && is_size_pair(to_ty) =>
+ {
+ return false;
+ }
+ (ReducedTy::UnorderedFields(from_ty), ReducedTy::Other(_))
+ if reduced_tys.to_fat_ptr && is_size_pair(from_ty) =>
+ {
+ return false;
+ }
+
+ // fat ptr -> some struct | some struct -> fat ptr
+ (ReducedTy::Other(_), _) if reduced_tys.from_fat_ptr => {
+ span_lint_and_then(
+ cx,
+ TRANSMUTE_UNDEFINED_REPR,
+ e.span,
+ &format!("transmute from `{from_ty_orig}` which has an undefined layout"),
+ |diag| {
+ if from_ty_orig.peel_refs() != from_ty.peel_refs() {
+ diag.note(&format!(
+ "the contained type `{from_ty}` has an undefined layout"
+ ));
+ }
+ },
+ );
+ return true;
+ }
+ (_, ReducedTy::Other(_)) if reduced_tys.to_fat_ptr => {
+ span_lint_and_then(
+ cx,
+ TRANSMUTE_UNDEFINED_REPR,
+ e.span,
+ &format!("transmute to `{to_ty_orig}` which has an undefined layout"),
+ |diag| {
+ if to_ty_orig.peel_refs() != to_ty.peel_refs() {
+ diag.note(&format!(
+ "the contained type `{to_ty}` has an undefined layout"
+ ));
+ }
+ },
+ );
+ return true;
+ }
+
+ (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty))
+ if from_ty != to_ty =>
+ {
+ let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs))
= (from_ty.kind(), to_ty.kind())
&& from_def == to_def
{
@@ -138,144 +124,148 @@ pub(super) fn check<'tcx>(
} else {
None
};
- span_lint_and_then(
- cx,
- TRANSMUTE_UNDEFINED_REPR,
- e.span,
- &format!(
- "transmute from `{}` to `{}`, both of which have an undefined layout",
- from_ty_orig, to_ty_orig
- ),
- |diag| {
- if let Some(same_adt_did) = same_adt_did {
+ span_lint_and_then(
+ cx,
+ TRANSMUTE_UNDEFINED_REPR,
+ e.span,
+ &format!(
+ "transmute from `{from_ty_orig}` to `{to_ty_orig}`, both of which have an undefined layout"
+ ),
+ |diag| {
+ if let Some(same_adt_did) = same_adt_did {
+ diag.note(&format!(
+ "two instances of the same generic type (`{}`) may have different layouts",
+ cx.tcx.item_name(same_adt_did)
+ ));
+ } else {
+ if from_ty_orig.peel_refs() != from_ty {
diag.note(&format!(
- "two instances of the same generic type (`{}`) may have different layouts",
- cx.tcx.item_name(same_adt_did)
+ "the contained type `{from_ty}` has an undefined layout"
));
- } else {
- if from_ty_orig.peel_refs() != from_ty {
- diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
- }
- if to_ty_orig.peel_refs() != to_ty {
- diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
- }
- }
- },
- );
- return true;
- },
- (
- ReducedTy::UnorderedFields(from_ty),
- ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_),
- ) => {
- span_lint_and_then(
- cx,
- TRANSMUTE_UNDEFINED_REPR,
- e.span,
- &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
- |diag| {
- if from_ty_orig.peel_refs() != from_ty {
- diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
}
- },
- );
- return true;
- },
- (
- ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_),
- ReducedTy::UnorderedFields(to_ty),
- ) => {
- span_lint_and_then(
- cx,
- TRANSMUTE_UNDEFINED_REPR,
- e.span,
- &format!("transmute into `{}` which has an undefined layout", to_ty_orig),
- |diag| {
if to_ty_orig.peel_refs() != to_ty {
- diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
+ diag.note(&format!(
+ "the contained type `{to_ty}` has an undefined layout"
+ ));
}
- },
- );
- return true;
- },
- (ReducedTy::Ref(from_sub_ty), ReducedTy::Ref(to_sub_ty)) => {
- from_ty = from_sub_ty;
- to_ty = to_sub_ty;
- continue;
- },
- (
- ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
- ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
- )
- | (
- ReducedTy::UnorderedFields(_) | ReducedTy::Param,
- ReducedTy::UnorderedFields(_) | ReducedTy::Param,
- ) => break,
- },
+ }
+ },
+ );
+ return true;
+ }
+ (
+ ReducedTy::UnorderedFields(from_ty),
+ ReducedTy::Other(_)
+ | ReducedTy::OrderedFields(..)
+ | ReducedTy::TypeErasure { raw_ptr_only: true },
+ ) => {
+ span_lint_and_then(
+ cx,
+ TRANSMUTE_UNDEFINED_REPR,
+ e.span,
+ &format!("transmute from `{from_ty_orig}` which has an undefined layout"),
+ |diag| {
+ if from_ty_orig.peel_refs() != from_ty {
+ diag.note(&format!(
+ "the contained type `{from_ty}` has an undefined layout"
+ ));
+ }
+ },
+ );
+ return true;
+ }
+ (
+ ReducedTy::Other(_)
+ | ReducedTy::OrderedFields(..)
+ | ReducedTy::TypeErasure { raw_ptr_only: true },
+ ReducedTy::UnorderedFields(to_ty),
+ ) => {
+ span_lint_and_then(
+ cx,
+ TRANSMUTE_UNDEFINED_REPR,
+ e.span,
+ &format!("transmute into `{to_ty_orig}` which has an undefined layout"),
+ |diag| {
+ if to_ty_orig.peel_refs() != to_ty {
+ diag.note(&format!(
+ "the contained type `{to_ty}` has an undefined layout"
+ ));
+ }
+ },
+ );
+ return true;
+ }
+ (
+ ReducedTy::OrderedFields(..)
+ | ReducedTy::Other(_)
+ | ReducedTy::TypeErasure { raw_ptr_only: true },
+ ReducedTy::OrderedFields(..)
+ | ReducedTy::Other(_)
+ | ReducedTy::TypeErasure { raw_ptr_only: true },
+ )
+ | (ReducedTy::UnorderedFields(_), ReducedTy::UnorderedFields(_)) => {
+ break;
+ }
}
}
false
}
-enum ReducedTys<'tcx> {
- FromFatPtr { unsized_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
- ToFatPtr { unsized_ty: Ty<'tcx>, from_ty: Ty<'tcx> },
- ToPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
- FromPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
- Other { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
+#[expect(clippy::struct_excessive_bools)]
+struct ReducedTys<'tcx> {
+ from_ty: Ty<'tcx>,
+ to_ty: Ty<'tcx>,
+ from_raw_ptr: bool,
+ to_raw_ptr: bool,
+ from_fat_ptr: bool,
+ to_fat_ptr: bool,
}
/// Remove references so long as both types are references.
fn reduce_refs<'tcx>(
cx: &LateContext<'tcx>,
- span: Span,
mut from_ty: Ty<'tcx>,
mut to_ty: Ty<'tcx>,
) -> ReducedTys<'tcx> {
- loop {
- return match (from_ty.kind(), to_ty.kind()) {
- (
- &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })),
- &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. })),
- ) => {
- from_ty = from_sub_ty;
- to_ty = to_sub_ty;
- continue;
- },
- (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })), _)
- if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) =>
- {
- ReducedTys::FromFatPtr { unsized_ty, to_ty }
- },
- (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })))
- if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) =>
- {
- ReducedTys::ToFatPtr { unsized_ty, from_ty }
- },
- (&(ty::Ref(_, from_ty, _) | ty::RawPtr(TypeAndMut { ty: from_ty, .. })), _) => {
- ReducedTys::FromPtr { from_ty, to_ty }
- },
- (_, &(ty::Ref(_, to_ty, _) | ty::RawPtr(TypeAndMut { ty: to_ty, .. }))) => {
- ReducedTys::ToPtr { from_ty, to_ty }
- },
- _ => ReducedTys::Other { from_ty, to_ty },
+ let mut from_raw_ptr = false;
+ let mut to_raw_ptr = false;
+ let (from_fat_ptr, to_fat_ptr) =
+ loop {
+ break match (from_ty.kind(), to_ty.kind()) {
+ (
+ &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })),
+ &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. })),
+ ) => {
+ from_raw_ptr = matches!(*from_ty.kind(), ty::RawPtr(_));
+ from_ty = from_sub_ty;
+ to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_));
+ to_ty = to_sub_ty;
+ continue;
+ }
+ (
+ &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })),
+ _,
+ ) if !unsized_ty.is_sized(cx.tcx, cx.param_env) => (true, false),
+ (
+ _,
+ &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })),
+ ) if !unsized_ty.is_sized(cx.tcx, cx.param_env) => (false, true),
+ _ => (false, false),
+ };
};
- }
+ ReducedTys { from_ty, to_ty, from_raw_ptr, to_raw_ptr, from_fat_ptr, to_fat_ptr }
}
enum ReducedTy<'tcx> {
/// The type can be used for type erasure.
- TypeErasure,
+ TypeErasure { raw_ptr_only: bool },
/// The type is a struct containing either zero non-zero sized fields, or multiple non-zero
/// sized fields with a defined order.
- OrderedFields(Ty<'tcx>),
+ /// The second value is the first non-zero sized type.
+ OrderedFields(Ty<'tcx>, Option<Ty<'tcx>>),
/// The type is a struct containing multiple non-zero sized fields with no defined order.
UnorderedFields(Ty<'tcx>),
- /// The type is a reference to the contained type.
- Ref(Ty<'tcx>),
- /// The type is a generic parameter.
- Param,
/// Any other type.
Other(Ty<'tcx>),
}
@@ -285,23 +275,25 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
loop {
ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty);
return match *ty.kind() {
- ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => ReducedTy::TypeErasure,
+ ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => {
+ ReducedTy::TypeErasure { raw_ptr_only: false }
+ }
ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
ty = sub_ty;
continue;
- },
- ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure,
+ }
+ ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure { raw_ptr_only: false },
ty::Tuple(args) => {
let mut iter = args.iter();
let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
- return ReducedTy::OrderedFields(ty);
+ return ReducedTy::OrderedFields(ty, None);
};
if iter.all(|ty| is_zero_sized_ty(cx, ty)) {
ty = sized_ty;
continue;
}
ReducedTy::UnorderedFields(ty)
- },
+ }
ty::Adt(def, substs) if def.is_struct() => {
let mut iter = def
.non_enum_variant()
@@ -309,27 +301,27 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
.iter()
.map(|f| cx.tcx.bound_type_of(f.did).subst(cx.tcx, substs));
let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
- return ReducedTy::TypeErasure;
+ return ReducedTy::TypeErasure { raw_ptr_only: false };
};
if iter.all(|ty| is_zero_sized_ty(cx, ty)) {
ty = sized_ty;
continue;
}
if def.repr().inhibit_struct_field_reordering_opt() {
- ReducedTy::OrderedFields(ty)
+ ReducedTy::OrderedFields(ty, Some(sized_ty))
} else {
ReducedTy::UnorderedFields(ty)
}
- },
- ty::Adt(def, _) if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) => {
- ReducedTy::TypeErasure
- },
+ }
+ ty::Adt(def, _)
+ if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) =>
+ {
+ ReducedTy::TypeErasure { raw_ptr_only: false }
+ }
// TODO: Check if the conversion to or from at least one of a union's fields is valid.
- ty::Adt(def, _) if def.is_union() => ReducedTy::TypeErasure,
- ty::Foreign(_) => ReducedTy::TypeErasure,
- ty::Ref(_, ty, _) => ReducedTy::Ref(ty),
- ty::RawPtr(ty) => ReducedTy::Ref(ty.ty),
- ty::Param(_) => ReducedTy::Param,
+ ty::Adt(def, _) if def.is_union() => ReducedTy::TypeErasure { raw_ptr_only: false },
+ ty::Foreign(_) | ty::Param(_) => ReducedTy::TypeErasure { raw_ptr_only: false },
+ ty::Int(_) | ty::Uint(_) => ReducedTy::TypeErasure { raw_ptr_only: true },
_ => ReducedTy::Other(ty),
};
}
@@ -364,7 +356,11 @@ fn same_except_params<'tcx>(subs1: SubstsRef<'tcx>, subs2: SubstsRef<'tcx>) -> b
for (ty1, ty2) in subs1.types().zip(subs2.types()).filter(|(ty1, ty2)| ty1 != ty2) {
match (ty1.kind(), ty2.kind()) {
(ty::Param(_), _) | (_, ty::Param(_)) => (),
- (ty::Adt(adt1, subs1), ty::Adt(adt2, subs2)) if adt1 == adt2 && same_except_params(subs1, subs2) => (),
+ (ty::Adt(adt1, subs1), ty::Adt(adt2, subs2))
+ if adt1 == adt2 && same_except_params(subs1, subs2) =>
+ {
+ ()
+ }
_ => return false,
}
}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
index 626d7cd46..6b444922a 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
@@ -21,10 +21,7 @@ pub(super) fn check<'tcx>(
cx,
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
e.span,
- &format!(
- "transmute from `{}` to `{}` which could be expressed as a pointer cast instead",
- from_ty, to_ty
- ),
+ &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
|diag| {
if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
let sugg = arg.as_ty(&to_ty.to_string()).to_string();
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
new file mode 100644
index 000000000..19ce5ae72
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
@@ -0,0 +1,50 @@
+use clippy_utils::consts::{constant_context, Constant};
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+use rustc_span::symbol::sym;
+
+use super::TRANSMUTING_NULL;
+
+const LINT_MSG: &str = "transmuting a known null pointer into a reference";
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, to_ty: Ty<'tcx>) -> bool {
+ if !to_ty.is_ref() {
+ return false;
+ }
+
+ // Catching transmute over constants that resolve to `null`.
+ let mut const_eval_context = constant_context(cx, cx.typeck_results());
+ if let ExprKind::Path(ref _qpath) = arg.kind &&
+ let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg) &&
+ x == 0
+ {
+ span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
+ return true;
+ }
+
+ // Catching:
+ // `std::mem::transmute(0 as *const i32)`
+ if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind && is_integer_literal(inner_expr, 0) {
+ span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
+ return true;
+ }
+
+ // Catching:
+ // `std::mem::transmute(std::ptr::null::<i32>())`
+ if let ExprKind::Call(func1, []) = arg.kind &&
+ is_path_diagnostic_item(cx, func1, sym::ptr_null)
+ {
+ span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
+ return true;
+ }
+
+ // FIXME:
+ // Also catch transmutations of variables which are known nulls.
+ // To do this, MIR const propagation seems to be the better tool.
+ // Whenever MIR const prop routines are more developed, this will
+ // become available. As of this writing (25/03/19) it is not yet.
+ false
+}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs
index 831b0d450..b1445311b 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs
@@ -37,10 +37,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty
cx,
UNSOUND_COLLECTION_TRANSMUTE,
e.span,
- &format!(
- "transmute from `{}` to `{}` with mismatched layout is unsound",
- from_ty, to_ty
- ),
+ &format!("transmute from `{from_ty}` to `{to_ty}` with mismatched layout is unsound"),
);
true
} else {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
index 8122cd716..f919bbd5a 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
@@ -21,7 +21,7 @@ pub(super) fn check<'tcx>(
cx,
USELESS_TRANSMUTE,
e.span,
- &format!("transmute from a type (`{}`) to itself", from_ty),
+ &format!("transmute from a type (`{from_ty}`) to itself"),
);
true
},
diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
index 74927570b..641cdf5d3 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
@@ -1,8 +1,9 @@
use rustc_hir::Expr;
+use rustc_hir_typeck::{cast, FnCtxt, Inherited};
use rustc_lint::LateContext;
use rustc_middle::ty::{cast::CastKind, Ty};
use rustc_span::DUMMY_SP;
-use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited};
+use rustc_hir as hir;
// check if the component types of the transmuted collection and the result have different ABI,
// size or alignment
@@ -42,10 +43,10 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>(
/// messages. This function will panic if that occurs.
fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option<CastKind> {
let hir_id = e.hir_id;
- let local_def_id = hir_id.owner;
+ let local_def_id = hir_id.owner.def_id;
Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
- let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id);
+ let fn_ctxt = FnCtxt::new(inherited, cx.param_env, hir_id);
// If we already have errors, we can't be sure we can pointer cast.
assert!(
@@ -53,10 +54,10 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>
"Newly created FnCtxt contained errors"
);
- if let Ok(check) = CastCheck::new(
+ if let Ok(check) = cast::CastCheck::new(
&fn_ctxt, e, from_ty, to_ty,
// We won't show any error to the user, so we don't care what the span is here.
- DUMMY_SP, DUMMY_SP,
+ DUMMY_SP, DUMMY_SP, hir::Constness::NotConst,
) {
let res = check.do_check(&fn_ctxt);
diff --git a/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs
index 2118f3d69..d1965565b 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs
@@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty
cx,
WRONG_TRANSMUTE,
e.span,
- &format!("transmute from a `{}` to a pointer", from_ty),
+ &format!("transmute from a `{from_ty}` to a pointer"),
);
true
},
diff --git a/src/tools/clippy/clippy_lints/src/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmuting_null.rs
deleted file mode 100644
index 7939dfedc..000000000
--- a/src/tools/clippy/clippy_lints/src/transmuting_null.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-use clippy_utils::consts::{constant_context, Constant};
-use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_expr_diagnostic_item;
-use if_chain::if_chain;
-use rustc_ast::LitKind;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::sym;
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for transmute calls which would receive a null pointer.
- ///
- /// ### Why is this bad?
- /// Transmuting a null pointer is undefined behavior.
- ///
- /// ### Known problems
- /// Not all cases can be detected at the moment of this writing.
- /// For example, variables which hold a null pointer and are then fed to a `transmute`
- /// call, aren't detectable yet.
- ///
- /// ### Example
- /// ```rust
- /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
- /// ```
- #[clippy::version = "1.35.0"]
- pub TRANSMUTING_NULL,
- correctness,
- "transmutes from a null pointer to a reference, which is undefined behavior"
-}
-
-declare_lint_pass!(TransmutingNull => [TRANSMUTING_NULL]);
-
-const LINT_MSG: &str = "transmuting a known null pointer into a reference";
-
-impl<'tcx> LateLintPass<'tcx> for TransmutingNull {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if in_external_macro(cx.sess(), expr.span) {
- return;
- }
-
- if_chain! {
- if let ExprKind::Call(func, [arg]) = expr.kind;
- if is_expr_diagnostic_item(cx, func, sym::transmute);
-
- then {
- // Catching transmute over constants that resolve to `null`.
- let mut const_eval_context = constant_context(cx, cx.typeck_results());
- if_chain! {
- if let ExprKind::Path(ref _qpath) = arg.kind;
- if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg);
- if x == 0;
- then {
- span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
- }
- }
-
- // Catching:
- // `std::mem::transmute(0 as *const i32)`
- if_chain! {
- if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind;
- if let ExprKind::Lit(ref lit) = inner_expr.kind;
- if let LitKind::Int(0, _) = lit.node;
- then {
- span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
- }
- }
-
- // Catching:
- // `std::mem::transmute(std::ptr::null::<i32>())`
- if_chain! {
- if let ExprKind::Call(func1, []) = arg.kind;
- if is_expr_diagnostic_item(cx, func1, sym::ptr_null);
- then {
- span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
- }
- }
-
- // FIXME:
- // Also catch transmutations of variables which are known nulls.
- // To do this, MIR const propagation seems to be the better tool.
- // Whenever MIR const prop routines are more developed, this will
- // become available. As of this writing (25/03/19) it is not yet.
- }
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
index 94945b2e1..9c6629958 100644
--- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -49,15 +49,15 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
let inner_snippet = snippet(cx, inner.span, "..");
let suggestion = match &inner.kind {
TyKind::TraitObject(bounds, lt_bound, _) if bounds.len() > 1 || !lt_bound.is_elided() => {
- format!("&{}({})", ltopt, &inner_snippet)
+ format!("&{ltopt}({})", &inner_snippet)
},
TyKind::Path(qpath)
if get_bounds_if_impl_trait(cx, qpath, inner.hir_id)
.map_or(false, |bounds| bounds.len() > 1) =>
{
- format!("&{}({})", ltopt, &inner_snippet)
+ format!("&{ltopt}({})", &inner_snippet)
},
- _ => format!("&{}{}", ltopt, &inner_snippet),
+ _ => format!("&{ltopt}{}", &inner_snippet),
};
span_lint_and_sugg(
cx,
@@ -104,7 +104,7 @@ fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id:
if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did);
if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
if synthetic;
- if let Some(generics) = cx.tcx.hir().get_generics(id.owner);
+ if let Some(generics) = cx.tcx.hir().get_generics(id.owner.def_id);
if let Some(pred) = generics.bounds_for_param(did.expect_local()).next();
then {
Some(pred.bounds)
diff --git a/src/tools/clippy/clippy_lints/src/types/box_collection.rs b/src/tools/clippy/clippy_lints/src/types/box_collection.rs
index ba51404d2..08020ce66 100644
--- a/src/tools/clippy/clippy_lints/src/types/box_collection.rs
+++ b/src/tools/clippy/clippy_lints/src/types/box_collection.rs
@@ -16,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
_ => "<..>",
};
- let box_content = format!("{outer}{generic}", outer = item_type);
+ let box_content = format!("{item_type}{generic}");
span_lint_and_help(
cx,
BOX_COLLECTION,
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 353a6f6b8..f6de87b05 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -313,13 +313,13 @@ impl_lint_pass!(Types => [BOX_COLLECTION, VEC_BOX, OPTION_OPTION, LINKEDLIST, BO
impl<'tcx> LateLintPass<'tcx> for Types {
fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
let is_in_trait_impl =
- if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(id)) {
+ if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(id).def_id) {
matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
} else {
false
};
- let is_exported = cx.access_levels.is_exported(cx.tcx.hir().local_def_id(id));
+ let is_exported = cx.effective_visibilities.is_exported(cx.tcx.hir().local_def_id(id));
self.check_fn_decl(
cx,
@@ -333,7 +333,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
}
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
- let is_exported = cx.access_levels.is_exported(item.def_id);
+ let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
match item.kind {
ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => self.check_ty(
@@ -352,8 +352,10 @@ impl<'tcx> LateLintPass<'tcx> for Types {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
match item.kind {
ImplItemKind::Const(ty, _) => {
- let is_in_trait_impl = if let Some(hir::Node::Item(item)) =
- cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(item.hir_id()))
+ let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx
+ .tcx
+ .hir()
+ .find_by_def_id(cx.tcx.hir().get_parent_item(item.hir_id()).def_id)
{
matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
} else {
@@ -372,12 +374,12 @@ impl<'tcx> LateLintPass<'tcx> for Types {
// Methods are covered by check_fn.
// Type aliases are ignored because oftentimes it's impossible to
// make type alias declaration in trait simpler, see #1013
- ImplItemKind::Fn(..) | ImplItemKind::TyAlias(..) => (),
+ ImplItemKind::Fn(..) | ImplItemKind::Type(..) => (),
}
}
fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
- let is_exported = cx.access_levels.is_exported(cx.tcx.hir().local_def_id(field.hir_id));
+ let is_exported = cx.effective_visibilities.is_exported(cx.tcx.hir().local_def_id(field.hir_id));
self.check_ty(
cx,
@@ -390,7 +392,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &TraitItem<'_>) {
- let is_exported = cx.access_levels.is_exported(item.def_id);
+ let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
let context = CheckTyContext {
is_exported,
@@ -535,7 +537,7 @@ impl Types {
QPath::LangItem(..) => {},
}
},
- TyKind::Rptr(ref lt, ref mut_ty) => {
+ TyKind::Rptr(lt, ref mut_ty) => {
context.is_nested_call = true;
if !borrowed_box::check(cx, hir_ty, lt, mut_ty) {
self.check_ty(cx, mut_ty.ty, context);
diff --git a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
index 4d72a29e8..fa567b9b2 100644
--- a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
+++ b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
@@ -9,6 +9,7 @@ use rustc_span::symbol::sym;
use super::RC_BUFFER;
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
+ let app = Applicability::Unspecified;
if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
if let Some(alternate) = match_buffer_type(cx, qpath) {
span_lint_and_sugg(
@@ -17,8 +18,8 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
hir_ty.span,
"usage of `Rc<T>` when T is a buffer type",
"try",
- format!("Rc<{}>", alternate),
- Applicability::MachineApplicable,
+ format!("Rc<{alternate}>"),
+ app,
);
} else {
let Some(ty) = qpath_generic_tys(qpath).next() else { return false };
@@ -26,15 +27,12 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
if !cx.tcx.is_diagnostic_item(sym::Vec, id) {
return false;
}
- let qpath = match &ty.kind {
- TyKind::Path(qpath) => qpath,
- _ => return false,
- };
+ let TyKind::Path(qpath) = &ty.kind else { return false };
let inner_span = match qpath_generic_tys(qpath).next() {
Some(ty) => ty.span,
None => return false,
};
- let mut applicability = Applicability::MachineApplicable;
+ let mut applicability = app;
span_lint_and_sugg(
cx,
RC_BUFFER,
@@ -45,7 +43,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
"Rc<[{}]>",
snippet_with_applicability(cx, inner_span, "..", &mut applicability)
),
- Applicability::MachineApplicable,
+ app,
);
return true;
}
@@ -57,23 +55,20 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
hir_ty.span,
"usage of `Arc<T>` when T is a buffer type",
"try",
- format!("Arc<{}>", alternate),
- Applicability::MachineApplicable,
+ format!("Arc<{alternate}>"),
+ app,
);
} else if let Some(ty) = qpath_generic_tys(qpath).next() {
let Some(id) = path_def_id(cx, ty) else { return false };
if !cx.tcx.is_diagnostic_item(sym::Vec, id) {
return false;
}
- let qpath = match &ty.kind {
- TyKind::Path(qpath) => qpath,
- _ => return false,
- };
+ let TyKind::Path(qpath) = &ty.kind else { return false };
let inner_span = match qpath_generic_tys(qpath).next() {
Some(ty) => ty.span,
None => return false,
};
- let mut applicability = Applicability::MachineApplicable;
+ let mut applicability = app;
span_lint_and_sugg(
cx,
RC_BUFFER,
@@ -84,7 +79,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
"Arc<[{}]>",
snippet_with_applicability(cx, inner_span, "..", &mut applicability)
),
- Applicability::MachineApplicable,
+ app,
);
return true;
}
diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
index a1312fcda..2b964b64a 100644
--- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
+++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
@@ -3,13 +3,19 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::{path_def_id, qpath_generic_tys};
use rustc_errors::Applicability;
use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind};
+use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::LateContext;
use rustc_span::symbol::sym;
-use rustc_typeck::hir_ty_to_ty;
use super::{utils, REDUNDANT_ALLOCATION};
-pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ hir_ty: &hir::Ty<'_>,
+ qpath: &QPath<'_>,
+ def_id: DefId,
+) -> bool {
+ let mut applicability = Applicability::MaybeIncorrect;
let outer_sym = if Some(def_id) == cx.tcx.lang_items().owned_box() {
"Box"
} else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
@@ -21,19 +27,21 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
};
if let Some(span) = utils::match_borrows_parameter(cx, qpath) {
- let mut applicability = Applicability::MaybeIncorrect;
let generic_snippet = snippet_with_applicability(cx, span, "..", &mut applicability);
span_lint_and_then(
cx,
REDUNDANT_ALLOCATION,
hir_ty.span,
- &format!("usage of `{}<{}>`", outer_sym, generic_snippet),
+ &format!("usage of `{outer_sym}<{generic_snippet}>`"),
|diag| {
- diag.span_suggestion(hir_ty.span, "try", format!("{}", generic_snippet), applicability);
+ diag.span_suggestion(
+ hir_ty.span,
+ "try",
+ format!("{generic_snippet}"),
+ applicability,
+ );
diag.note(&format!(
- "`{generic}` is already a pointer, `{outer}<{generic}>` allocates a pointer on the heap",
- outer = outer_sym,
- generic = generic_snippet
+ "`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap"
));
},
);
@@ -49,42 +57,37 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
_ => return false,
};
- let inner_qpath = match &ty.kind {
- TyKind::Path(inner_qpath) => inner_qpath,
- _ => return false,
+ let TyKind::Path(inner_qpath) = &ty.kind else {
+ return false
};
let inner_span = match qpath_generic_tys(inner_qpath).next() {
Some(ty) => {
// Reallocation of a fat pointer causes it to become thin. `hir_ty_to_ty` is safe to use
// here because `mod.rs` guarantees this lint is only run on types outside of bodies and
// is not run on locals.
- if !hir_ty_to_ty(cx.tcx, ty).is_sized(cx.tcx.at(ty.span), cx.param_env) {
+ if !hir_ty_to_ty(cx.tcx, ty).is_sized(cx.tcx, cx.param_env) {
return false;
}
ty.span
- },
+ }
None => return false,
};
if inner_sym == outer_sym {
- let mut applicability = Applicability::MaybeIncorrect;
let generic_snippet = snippet_with_applicability(cx, inner_span, "..", &mut applicability);
span_lint_and_then(
cx,
REDUNDANT_ALLOCATION,
hir_ty.span,
- &format!("usage of `{}<{}<{}>>`", outer_sym, inner_sym, generic_snippet),
+ &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
|diag| {
diag.span_suggestion(
hir_ty.span,
"try",
- format!("{}<{}>", outer_sym, generic_snippet),
+ format!("{outer_sym}<{generic_snippet}>"),
applicability,
);
diag.note(&format!(
- "`{inner}<{generic}>` is already on the heap, `{outer}<{inner}<{generic}>>` makes an extra allocation",
- outer = outer_sym,
- inner = inner_sym,
- generic = generic_snippet
+ "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
));
},
);
@@ -94,19 +97,13 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
cx,
REDUNDANT_ALLOCATION,
hir_ty.span,
- &format!("usage of `{}<{}<{}>>`", outer_sym, inner_sym, generic_snippet),
+ &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
|diag| {
diag.note(&format!(
- "`{inner}<{generic}>` is already on the heap, `{outer}<{inner}<{generic}>>` makes an extra allocation",
- outer = outer_sym,
- inner = inner_sym,
- generic = generic_snippet
+ "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
));
diag.help(&format!(
- "consider using just `{outer}<{generic}>` or `{inner}<{generic}>`",
- outer = outer_sym,
- inner = inner_sym,
- generic = generic_snippet
+ "consider using just `{outer_sym}<{generic_snippet}>` or `{inner_sym}<{generic_snippet}>`"
));
},
);
diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
index b2f536ca7..9ad2cb853 100644
--- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
@@ -4,11 +4,11 @@ use clippy_utils::source::snippet;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{self as hir, def_id::DefId, GenericArg, QPath, TyKind};
+use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::LateContext;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::TypeVisitable;
use rustc_span::symbol::sym;
-use rustc_typeck::hir_ty_to_ty;
use super::VEC_BOX;
@@ -40,7 +40,7 @@ pub(super) fn check(
});
let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty);
if !ty_ty.has_escaping_bound_vars();
- if ty_ty.is_sized(cx.tcx.at(ty.span), cx.param_env);
+ if ty_ty.is_sized(cx.tcx, cx.param_env);
if let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes());
if ty_ty_size <= box_size_threshold;
then {
diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs
index cc64d17be..8980283e5 100644
--- a/src/tools/clippy/clippy_lints/src/unicode.rs
+++ b/src/tools/clippy/clippy_lints/src/unicode.rs
@@ -1,5 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_lint_allowed;
+use clippy_utils::macros::span_is_local;
use clippy_utils::source::snippet;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
@@ -98,6 +99,10 @@ fn escape<T: Iterator<Item = char>>(s: T) -> String {
}
fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
+ if !span_is_local(span) {
+ return;
+ }
+
let string = snippet(cx, span, "");
if string.chars().any(|c| ['\u{200B}', '\u{ad}', '\u{2060}'].contains(&c)) {
span_lint_and_sugg(
@@ -113,6 +118,7 @@ fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
Applicability::MachineApplicable,
);
}
+
if string.chars().any(|c| c as u32 > 0x7F) {
span_lint_and_sugg(
cx,
@@ -128,6 +134,7 @@ fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
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,
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index 9f4c5555f..1ab0162a8 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty};
-use clippy_utils::{is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq};
+use clippy_utils::{is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq};
use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
@@ -45,7 +45,7 @@ declare_clippy_lint! {
/// let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000);
/// vec.set_len(1000); // `MaybeUninit` can be uninitialized
/// ```
- /// 3. If you are on nightly, `Vec::spare_capacity_mut()` is available:
+ /// 3. If you are on 1.60.0 or later, `Vec::spare_capacity_mut()` is available:
/// ```rust,ignore
/// let mut vec: Vec<u8> = Vec::with_capacity(1000);
/// let remaining = vec.spare_capacity_mut(); // `&mut [MaybeUninit<u8>]`
@@ -177,7 +177,7 @@ fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt
});
}
},
- ExprKind::MethodCall(path, [self_expr, _], _) if is_reserve(cx, path, self_expr) => {
+ ExprKind::MethodCall(path, self_expr, [_], _) if is_reserve(cx, path, self_expr) => {
return Some(TargetVec {
location: VecLocation::Expr(self_expr),
init_kind: None,
@@ -211,9 +211,12 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt
}
});
match expr.kind {
- ExprKind::MethodCall(path, [self_expr, _], _) => {
+ ExprKind::MethodCall(path, self_expr, [arg], _) => {
let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs();
- if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" {
+ if is_type_diagnostic_item(cx, self_type, sym::Vec)
+ && path.ident.name.as_str() == "set_len"
+ && !is_integer_literal(arg, 0)
+ {
Some((self_expr, expr.span))
} else {
None
diff --git a/src/tools/clippy/clippy_lints/src/unit_hash.rs b/src/tools/clippy/clippy_lints/src/unit_hash.rs
deleted file mode 100644
index 88ca0cb20..000000000
--- a/src/tools/clippy/clippy_lints/src/unit_hash.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-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),
- /// }
- /// ```
- #[clippy::version = "1.58.0"]
- pub UNIT_HASH,
- correctness,
- "hashing a unit value, which does nothing"
-}
-declare_lint_pass!(UnitHash => [UNIT_HASH]);
-
-impl<'tcx> 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");
- }
- );
- }
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index b0fce91ab..130728862 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use clippy_utils::{get_trait_def_id, paths};
use if_chain::if_chain;
use rustc_hir::def_id::DefId;
use rustc_hir::{Closure, Expr, ExprKind, StmtKind};
@@ -7,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::{GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{BytePos, Span};
+use rustc_span::{sym, BytePos, Span};
declare_clippy_lint! {
/// ### What it does
@@ -80,7 +79,7 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
let fn_sig = cx.tcx.fn_sig(def_id);
let generics = cx.tcx.predicates_of(def_id);
let fn_mut_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().fn_mut_trait());
- let ord_preds = get_trait_predicates_for_trait_id(cx, generics, get_trait_def_id(cx, &paths::ORD));
+ let ord_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.get_diagnostic_item(sym::Ord));
let partial_ord_preds =
get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().partial_ord_trait());
// Trying to call erase_late_bound_regions on fn_sig.inputs() gives the following error
@@ -99,11 +98,15 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
if trait_pred.self_ty() == inp;
if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
then {
- if ord_preds.iter().any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty()) {
+ if ord_preds
+ .iter()
+ .any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty())
+ {
args_to_check.push((i, "Ord".to_string()));
- } else if partial_ord_preds.iter().any(|pord| {
- pord.self_ty() == return_ty_pred.term.ty().unwrap()
- }) {
+ } else if partial_ord_preds
+ .iter()
+ .any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap())
+ {
args_to_check.push((i, "PartialOrd".to_string()));
}
}
@@ -144,11 +147,12 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa
impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if let ExprKind::MethodCall(_, args, _) = expr.kind {
+ if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind {
let arg_indices = get_args_to_check(cx, expr);
+ let args = std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>();
for (i, trait_name) in arg_indices {
if i < args.len() {
- match check_arg(cx, &args[i]) {
+ match check_arg(cx, args[i]) {
Some((span, None)) => {
span_lint(
cx,
@@ -156,8 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
span,
&format!(
"this closure returns \
- the unit type which also implements {}",
- trait_name
+ the unit type which also implements {trait_name}"
),
);
},
@@ -168,8 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
span,
&format!(
"this closure returns \
- the unit type which also implements {}",
- trait_name
+ the unit type which also implements {trait_name}"
),
Some(last_semi),
"probably caused by this trailing semicolon",
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index aec028d5c..ce9ebad8c 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -19,10 +19,12 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
&& cx.typeck_results().pat_ty(local.pat).is_unit()
{
if (local.ty.map_or(false, |ty| !matches!(ty.kind, TyKind::Infer))
- || matches!(local.pat.kind, PatKind::Tuple([], None)))
+ || matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()))
&& expr_needs_inferred_result(cx, init)
{
- if !matches!(local.pat.kind, PatKind::Wild | PatKind::Tuple([], None)) {
+ if !matches!(local.pat.kind, PatKind::Wild)
+ && !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none())
+ {
span_lint_and_then(
cx,
LET_UNIT_VALUE,
@@ -128,7 +130,7 @@ fn needs_inferred_result_ty(
locals_to_check: &mut Vec<HirId>,
seen_locals: &mut HirIdSet,
) -> bool {
- let (id, args) = match e.kind {
+ let (id, receiver, args) = match e.kind {
ExprKind::Call(
Expr {
kind: ExprKind::Path(ref path),
@@ -137,11 +139,11 @@ fn needs_inferred_result_ty(
},
args,
) => match cx.qpath_res(path, *hir_id) {
- Res::Def(DefKind::AssocFn | DefKind::Fn, id) => (id, args),
+ Res::Def(DefKind::AssocFn | DefKind::Fn, id) => (id, None, args),
_ => return false,
},
- ExprKind::MethodCall(_, args, _) => match cx.typeck_results().type_dependent_def_id(e.hir_id) {
- Some(id) => (id, args),
+ ExprKind::MethodCall(_, receiver, args, _) => match cx.typeck_results().type_dependent_def_id(e.hir_id) {
+ Some(id) => (id, Some(receiver), args),
None => return false,
},
ExprKind::Path(QPath::Resolved(None, path)) => {
@@ -156,6 +158,11 @@ fn needs_inferred_result_ty(
};
let sig = cx.tcx.fn_sig(id).skip_binder();
if let ty::Param(output_ty) = *sig.output().kind() {
+ let args: Vec<&Expr<'_>> = if let Some(receiver) = receiver {
+ std::iter::once(receiver).chain(args.iter()).collect()
+ } else {
+ args.iter().collect()
+ };
sig.inputs().iter().zip(args).all(|(&ty, arg)| {
!ty.is_param(output_ty.index) || each_value_source_needs_inference(cx, arg, locals_to_check, seen_locals)
})
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
index 6aa86a57c..546242ebd 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
@@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitTypes {
let_unit_value::check(cx, local);
}
- fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
unit_cmp::check(cx, expr);
unit_arg::check(cx, expr);
}
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
index 97d92f10e..f6d3fb00f 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
@@ -1,4 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_from_proc_macro;
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
use if_chain::if_chain;
use rustc_errors::Applicability;
@@ -7,7 +8,7 @@ use rustc_lint::LateContext;
use super::{utils, UNIT_ARG};
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if expr.span.from_expansion() {
return;
}
@@ -29,26 +30,27 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
}
}
- match expr.kind {
- ExprKind::Call(_, args) | ExprKind::MethodCall(_, args, _) => {
- let args_to_recover = args
- .iter()
- .filter(|arg| {
- if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) {
- !matches!(
- &arg.kind,
- ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..)
- )
- } else {
- false
- }
- })
- .collect::<Vec<_>>();
- if !args_to_recover.is_empty() {
- lint_unit_args(cx, expr, &args_to_recover);
+ let args: Vec<_> = match expr.kind {
+ ExprKind::Call(_, args) => args.iter().collect(),
+ ExprKind::MethodCall(_, receiver, args, _) => std::iter::once(receiver).chain(args.iter()).collect(),
+ _ => return,
+ };
+
+ let args_to_recover = args
+ .into_iter()
+ .filter(|arg| {
+ if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) {
+ !matches!(
+ &arg.kind,
+ ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..)
+ )
+ } else {
+ false
}
- },
- _ => (),
+ })
+ .collect::<Vec<_>>();
+ if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
+ lint_unit_args(cx, expr, args_to_recover.as_slice());
}
}
@@ -72,7 +74,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
cx,
UNIT_ARG,
expr.span,
- &format!("passing {}unit value{} to a function", singular, plural),
+ &format!("passing {singular}unit value{plural} to a function"),
|db| {
let mut or = "";
args_to_recover
@@ -127,7 +129,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
if arg_snippets_without_empty_blocks.is_empty() {
db.multipart_suggestion(
- &format!("use {}unit literal{} instead", singular, plural),
+ &format!("use {singular}unit literal{plural} instead"),
args_to_recover
.iter()
.map(|arg| (arg.span, "()".to_string()))
@@ -141,8 +143,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
db.span_suggestion(
expr.span,
&format!(
- "{}move the expression{} in front of the call and replace {} with the unit literal `()`",
- or, empty_or_s, it_or_them
+ "{or}move the expression{empty_or_s} in front of the call and replace {it_or_them} with the unit literal `()`"
),
sugg,
applicability,
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
index 1dd8895eb..226495dcb 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
@@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
cx,
UNIT_CMP,
macro_call.span,
- &format!("`{}` of unit values detected. This will always {}", macro_name, result),
+ &format!("`{macro_name}` of unit values detected. This will always {result}"),
);
}
return;
@@ -40,9 +40,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
UNIT_CMP,
expr.span,
&format!(
- "{}-comparison of unit values detected. This will always be {}",
- op.as_str(),
- result
+ "{}-comparison of unit values detected. This will always be {result}",
+ op.as_str()
),
);
}
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
index 8a4f4c0ad..016aacbf9 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
@@ -3,7 +3,7 @@ use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
+use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings {
);
} else {
if_chain! {
- if match_def_path(cx, fun_def_id, &paths::FROM_FROM);
+ if cx.tcx.lang_items().require(LangItem::FromFrom).ok() == Some(fun_def_id);
if let [.., last_arg] = args;
if let ExprKind::Lit(spanned) = &last_arg.kind;
if let LitKind::Str(symbol, _) = spanned.node;
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
index 839a4bdab..bc0dd263d 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
@@ -57,7 +57,7 @@ impl EarlyLintPass for UnnecessarySelfImports {
format!(
"{}{};",
last_segment.ident,
- if let UseTreeKind::Simple(Some(alias), ..) = self_tree.kind { format!(" as {}", alias) } else { String::new() },
+ if let UseTreeKind::Simple(Some(alias), ..) = self_tree.kind { format!(" as {alias}") } else { String::new() },
),
Applicability::MaybeIncorrect,
);
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index f4f5a4336..60b46854b 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
-use clippy_utils::{contains_return, is_lang_ctor, return_ty, visitors::find_all_ret_expressions};
+use clippy_utils::{contains_return, is_res_lang_ctor, path_res, return_ty, visitors::find_all_ret_expressions};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
@@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
match fn_kind {
FnKind::ItemFn(..) | FnKind::Method(..) => {
let def_id = cx.tcx.hir().local_def_id(hir_id);
- if self.avoid_breaking_exported_api && cx.access_levels.is_exported(def_id) {
+ if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
return;
}
},
@@ -115,14 +115,12 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
// Check if all return expression respect the following condition and collect them.
let mut suggs = Vec::new();
- let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
+ let can_sugg = find_all_ret_expressions(cx, body.value, |ret_expr| {
if_chain! {
if !ret_expr.span.from_expansion();
// Check if a function call.
if let ExprKind::Call(func, [arg]) = ret_expr.kind;
- // Check if OPTION_SOME or RESULT_OK, depending on return type.
- if let ExprKind::Path(qpath) = &func.kind;
- if is_lang_ctor(cx, qpath, lang_item);
+ if is_res_lang_ctor(cx, path_res(cx, func), lang_item);
// Make sure the function argument does not contain a return expression.
if !contains_return(arg);
then {
@@ -130,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
(
ret_expr.span,
if inner_type.is_unit() {
- "".to_string()
+ String::new()
} else {
snippet(cx, arg.span.source_callsite(), "..").to_string()
}
@@ -153,11 +151,8 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
)
} else {
(
- format!(
- "this function's return value is unnecessarily wrapped by `{}`",
- return_type_label
- ),
- format!("remove `{}` from the return type...", return_type_label),
+ format!("this function's return value is unnecessarily wrapped by `{return_type_label}`"),
+ format!("remove `{return_type_label}` from the return type..."),
inner_type.to_string(),
"...and then change returning expressions",
)
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 04e2f301b..b305dae76 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -137,12 +137,12 @@ fn insert_necessary_parens(pat: &mut P<Pat>) {
struct Visitor;
impl MutVisitor for Visitor {
fn visit_pat(&mut self, pat: &mut P<Pat>) {
- use ast::{BindingMode::*, Mutability::*};
+ use ast::BindingAnnotation;
noop_visit_pat(pat, self);
let target = match &mut pat.kind {
// `i @ a | b`, `box a | b`, and `& mut? a | b`.
Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p,
- Ref(p, Not) if matches!(p.kind, Ident(ByValue(Mut), ..)) => p, // `&(mut x)`
+ Ref(p, Mutability::Not) if matches!(p.kind, Ident(BindingAnnotation::MUT, ..)) => p, // `&(mut x)`
_ => return,
};
target.kind = Paren(P(take_pat(target)));
@@ -163,9 +163,8 @@ fn unnest_or_patterns(pat: &mut P<Pat>) -> bool {
noop_visit_pat(p, self);
// Don't have an or-pattern? Just quit early on.
- let alternatives = match &mut p.kind {
- Or(ps) => ps,
- _ => return,
+ let Or(alternatives) = &mut p.kind else {
+ return
};
// Collapse or-patterns directly nested in or-patterns.
diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
index 64f7a055c..32cd46812 100644
--- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
+++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
@@ -65,10 +65,7 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>,
cx,
UNSAFE_REMOVED_FROM_NAME,
span,
- &format!(
- "removed `unsafe` from the name of `{}` in use as `{}`",
- old_str, new_str
- ),
+ &format!("removed `unsafe` from the name of `{old_str}` in use as `{new_str}`"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index a832dfccc..bf487c7ca 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
) {
if !span.from_expansion() && fn_kind.asyncness() == IsAsync::Async {
let mut visitor = AsyncFnVisitor { cx, found_await: false };
- walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), span, hir_id);
+ walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), hir_id);
if !visitor.found_await {
span_lint_and_help(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index 323cf83ff..92053cec5 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -1,8 +1,9 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use clippy_utils::{is_try, match_trait_method, paths};
+use clippy_utils::{is_trait_method, is_try, match_trait_method, paths};
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -46,9 +47,8 @@ declare_lint_pass!(UnusedIoAmount => [UNUSED_IO_AMOUNT]);
impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
- let expr = match s.kind {
- hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
- _ => return,
+ let (hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr)) = s.kind else {
+ return
};
match expr.kind {
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
check_map_error(cx, res, expr);
}
},
- hir::ExprKind::MethodCall(path, [ref arg_0, ..], _) => match path.ident.as_str() {
+ hir::ExprKind::MethodCall(path, arg_0, ..) => match path.ident.as_str() {
"expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => {
check_map_error(cx, arg_0, expr);
},
@@ -94,9 +94,9 @@ fn try_remove_await<'a>(expr: &'a hir::Expr<'a>) -> Option<&hir::Expr<'a>> {
fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
let mut call = call;
- while let hir::ExprKind::MethodCall(path, args, _) = call.kind {
+ while let hir::ExprKind::MethodCall(path, receiver, ..) = call.kind {
if matches!(path.ident.as_str(), "or" | "or_else" | "ok") {
- call = &args[0];
+ call = receiver;
} else {
break;
}
@@ -110,19 +110,19 @@ fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<
}
fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>, is_await: bool) {
- if let hir::ExprKind::MethodCall(path, _, _) = call.kind {
+ if let hir::ExprKind::MethodCall(path, ..) = call.kind {
let symbol = path.ident.as_str();
let read_trait = if is_await {
match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT)
|| match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCREADEXT)
} else {
- match_trait_method(cx, call, &paths::IO_READ)
+ is_trait_method(cx, call, sym::IoRead)
};
let write_trait = if is_await {
match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCWRITEEXT)
|| match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCWRITEEXT)
} else {
- match_trait_method(cx, call, &paths::IO_WRITE)
+ is_trait_method(cx, call, sym::IoWrite)
};
match (read_trait, write_trait, symbol, is_await) {
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
new file mode 100644
index 000000000..f1cebf0f9
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
@@ -0,0 +1,232 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::{match_type, peel_mid_ty_refs_is_mutable};
+use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, paths, peel_ref_operators};
+use rustc_ast::Mutability;
+use rustc_hir::intravisit::{walk_expr, Visitor};
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::nested_filter::OnlyBodies;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for the creation of a `peekable` iterator that is never `.peek()`ed
+ ///
+ /// ### Why is this bad?
+ /// Creating a peekable iterator without using any of its methods is likely a mistake,
+ /// or just a leftover after a refactor.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let collection = vec![1, 2, 3];
+ /// let iter = collection.iter().peekable();
+ ///
+ /// for item in iter {
+ /// // ...
+ /// }
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust
+ /// let collection = vec![1, 2, 3];
+ /// let iter = collection.iter();
+ ///
+ /// for item in iter {
+ /// // ...
+ /// }
+ /// ```
+ #[clippy::version = "1.64.0"]
+ pub UNUSED_PEEKABLE,
+ nursery,
+ "creating a peekable iterator without using any of its methods"
+}
+
+declare_lint_pass!(UnusedPeekable => [UNUSED_PEEKABLE]);
+
+impl<'tcx> LateLintPass<'tcx> for UnusedPeekable {
+ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
+ // Don't lint `Peekable`s returned from a block
+ if let Some(expr) = block.expr
+ && let Some(ty) = cx.typeck_results().expr_ty_opt(peel_ref_operators(cx, expr))
+ && match_type(cx, ty, &paths::PEEKABLE)
+ {
+ return;
+ }
+
+ for (idx, stmt) in block.stmts.iter().enumerate() {
+ if !stmt.span.from_expansion()
+ && let StmtKind::Local(local) = stmt.kind
+ && let PatKind::Binding(_, binding, ident, _) = local.pat.kind
+ && let Some(init) = local.init
+ && !init.span.from_expansion()
+ && let Some(ty) = cx.typeck_results().expr_ty_opt(init)
+ && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty)
+ && match_type(cx, ty, &paths::PEEKABLE)
+ {
+ let mut vis = PeekableVisitor::new(cx, binding);
+
+ if idx + 1 == block.stmts.len() && block.expr.is_none() {
+ return;
+ }
+
+ for stmt in &block.stmts[idx..] {
+ vis.visit_stmt(stmt);
+ }
+
+ if let Some(expr) = block.expr {
+ vis.visit_expr(expr);
+ }
+
+ if !vis.found_peek_call {
+ span_lint_and_help(
+ cx,
+ UNUSED_PEEKABLE,
+ ident.span,
+ "`peek` never called on `Peekable` iterator",
+ None,
+ "consider removing the call to `peekable`"
+ );
+ }
+ }
+ }
+ }
+}
+
+struct PeekableVisitor<'a, 'tcx> {
+ cx: &'a LateContext<'tcx>,
+ expected_hir_id: HirId,
+ found_peek_call: bool,
+}
+
+impl<'a, 'tcx> PeekableVisitor<'a, 'tcx> {
+ fn new(cx: &'a LateContext<'tcx>, expected_hir_id: HirId) -> Self {
+ Self {
+ cx,
+ expected_hir_id,
+ found_peek_call: false,
+ }
+ }
+}
+
+impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
+ type NestedFilter = OnlyBodies;
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.cx.tcx.hir()
+ }
+
+ fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
+ if self.found_peek_call {
+ return;
+ }
+
+ if path_to_local_id(ex, self.expected_hir_id) {
+ for (_, node) in self.cx.tcx.hir().parent_iter(ex.hir_id) {
+ match node {
+ Node::Expr(expr) => {
+ match expr.kind {
+ // some_function(peekable)
+ //
+ // If the Peekable is passed to a function, stop
+ ExprKind::Call(_, args) => {
+ if let Some(func_did) = fn_def_id(self.cx, expr)
+ && let Ok(into_iter_did) = self
+ .cx
+ .tcx
+ .lang_items()
+ .require(LangItem::IntoIterIntoIter)
+ && func_did == into_iter_did
+ {
+ // Probably a for loop desugar, stop searching
+ return;
+ }
+
+ if args.iter().any(|arg| arg_is_mut_peekable(self.cx, arg)) {
+ self.found_peek_call = true;
+ }
+
+ return;
+ },
+ // Catch anything taking a Peekable mutably
+ ExprKind::MethodCall(
+ PathSegment {
+ ident: method_name_ident,
+ ..
+ },
+ self_arg,
+ remaining_args,
+ _,
+ ) => {
+ let method_name = method_name_ident.name.as_str();
+
+ // `Peekable` methods
+ if matches!(method_name, "peek" | "peek_mut" | "next_if" | "next_if_eq")
+ && arg_is_mut_peekable(self.cx, self_arg)
+ {
+ self.found_peek_call = true;
+ return;
+ }
+
+ // foo.some_method() excluding Iterator methods
+ if remaining_args.iter().any(|arg| arg_is_mut_peekable(self.cx, arg))
+ && !is_trait_method(self.cx, expr, sym::Iterator)
+ {
+ self.found_peek_call = true;
+ return;
+ }
+
+ // foo.by_ref(), keep checking for `peek`
+ if method_name == "by_ref" {
+ continue;
+ }
+
+ return;
+ },
+ ExprKind::AddrOf(_, Mutability::Mut, _) | ExprKind::Unary(..) | ExprKind::DropTemps(_) => {
+ },
+ ExprKind::AddrOf(_, Mutability::Not, _) => return,
+ _ => {
+ self.found_peek_call = true;
+ return;
+ },
+ }
+ },
+ Node::Local(Local { init: Some(init), .. }) => {
+ if arg_is_mut_peekable(self.cx, init) {
+ self.found_peek_call = true;
+ }
+
+ return;
+ },
+ Node::Stmt(stmt) => {
+ match stmt.kind {
+ StmtKind::Local(_) | StmtKind::Item(_) => self.found_peek_call = true,
+ StmtKind::Expr(_) | StmtKind::Semi(_) => {},
+ }
+
+ return;
+ },
+ Node::Block(_) | Node::ExprField(_) => {},
+ _ => {
+ return;
+ },
+ }
+ }
+ }
+
+ walk_expr(self, ex);
+ }
+}
+
+fn arg_is_mut_peekable(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
+ if let Some(ty) = cx.typeck_results().expr_ty_opt(arg)
+ && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty)
+ && match_type(cx, ty, &paths::PEEKABLE)
+ {
+ true
+ } else {
+ false
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/unused_rounding.rs b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
index 306afe441..316493729 100644
--- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
@@ -22,7 +22,7 @@ declare_clippy_lint! {
/// ```rust
/// let x = 1f32;
/// ```
- #[clippy::version = "1.62.0"]
+ #[clippy::version = "1.63.0"]
pub UNUSED_ROUNDING,
nursery,
"Uselessly rounding a whole number floating-point literal"
@@ -30,11 +30,10 @@ declare_clippy_lint! {
declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);
fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> {
- if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind
+ if let ExprKind::MethodCall(name_ident, receiver, _, _) = &expr.kind
&& let method_name = name_ident.ident.name.as_str()
&& (method_name == "ceil" || method_name == "round" || method_name == "floor")
- && !args.is_empty()
- && let ExprKind::Lit(spanned) = &args[0].kind
+ && let ExprKind::Lit(spanned) = &receiver.kind
&& let LitKind::Float(symbol, ty) = spanned.kind {
let f = symbol.as_str().parse::<f64>().unwrap();
let f_str = symbol.to_string() + if let LitFloatType::Suffixed(ty) = ty {
@@ -59,8 +58,8 @@ impl EarlyLintPass for UnusedRounding {
cx,
UNUSED_ROUNDING,
expr.span,
- &format!("used the `{}` method with a whole number float", method_name),
- &format!("remove the `{}` method call", method_name),
+ &format!("used the `{method_name}` method with a whole number float"),
+ &format!("remove the `{method_name}` method call"),
float,
Applicability::MachineApplicable,
);
diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs
index 51c65d898..42bccc721 100644
--- a/src/tools/clippy/clippy_lints/src/unused_self.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_self.rs
@@ -54,14 +54,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
if impl_item.span.from_expansion() {
return;
}
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
let parent_item = cx.tcx.hir().expect_item(parent);
- let assoc_item = cx.tcx.associated_item(impl_item.def_id);
+ let assoc_item = cx.tcx.associated_item(impl_item.owner_id);
if_chain! {
if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind;
if assoc_item.fn_has_self_parameter;
if let ImplItemKind::Fn(.., body_id) = &impl_item.kind;
- if !cx.access_levels.is_exported(impl_item.def_id) || !self.avoid_breaking_exported_api;
+ if !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api;
let body = cx.tcx.hir().body(*body_id);
if let [self_param, ..] = body.params;
if !is_local_used(cx, body, self_param.pat.hir_id);
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs
index 52585e595..cd1d90e86 100644
--- a/src/tools/clippy/clippy_lints/src/unused_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -89,7 +89,7 @@ impl EarlyLintPass for UnusedUnit {
}
}
- fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef, _: &ast::TraitBoundModifier) {
+ fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef) {
let segments = &poly.trait_ref.path.segments;
if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index d3f9e5abf..ea878043c 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -154,13 +154,13 @@ fn collect_unwrap_info<'tcx>(
return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false);
} else {
if_chain! {
- if let ExprKind::MethodCall(method_name, args, _) = &expr.kind;
- if let Some(local_id) = path_to_local(&args[0]);
- let ty = cx.typeck_results().expr_ty(&args[0]);
+ if let ExprKind::MethodCall(method_name, receiver, args, _) = &expr.kind;
+ if let Some(local_id) = path_to_local(receiver);
+ let ty = cx.typeck_results().expr_ty(receiver);
let name = method_name.ident.as_str();
if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name);
then {
- assert!(args.len() == 1);
+ assert!(args.is_empty());
let unwrappable = match name {
"is_some" | "is_ok" => true,
"is_err" | "is_none" => false,
@@ -231,7 +231,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
} else {
// find `unwrap[_err]()` calls:
if_chain! {
- if let ExprKind::MethodCall(method_name, [self_arg, ..], _) = expr.kind;
+ if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind;
if let Some(id) = path_to_local(self_arg);
if [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name);
let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name);
@@ -257,9 +257,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
expr.hir_id,
expr.span,
&format!(
- "called `{}` on `{}` after checking its variant with `{}`",
+ "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`",
method_name.ident.name,
- unwrappable_variable_name,
unwrappable.check_name.ident.as_str(),
),
|diag| {
@@ -268,9 +267,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
unwrappable.check.span.with_lo(unwrappable.if_expr.span.lo()),
"try",
format!(
- "if let {} = {}",
- suggested_pattern,
- unwrappable_variable_name,
+ "if let {suggested_pattern} = {unwrappable_variable_name}",
),
// We don't track how the unwrapped value is used inside the
// block or suggest deleting the unwrap, so we can't offer a
@@ -326,6 +323,6 @@ impl<'tcx> LateLintPass<'tcx> for Unwrap {
unwrappables: Vec::new(),
};
- walk_fn(&mut v, kind, decl, body.id(), span, fn_id);
+ walk_fn(&mut v, kind, decl, body.id(), fn_id);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index b32be238c..f3611d174 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -1,12 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::for_each_expr;
use clippy_utils::{method_chain_args, return_ty};
+use core::ops::ControlFlow;
use if_chain::if_chain;
use rustc_hir as hir;
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Expr, ImplItemKind};
+use rustc_hir::ImplItemKind;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span};
@@ -73,51 +73,37 @@ impl<'tcx> LateLintPass<'tcx> for UnwrapInResult {
}
}
-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> {
- fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
- // check for `expect`
- if let Some(arglists) = method_chain_args(expr, &["expect"]) {
- let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
- if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
- || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
- {
- self.result.push(expr.span);
+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 typeck = cx.tcx.typeck(impl_item.owner_id.def_id);
+ let mut result = Vec::new();
+ let _: Option<!> = for_each_expr(body.value, |e| {
+ // check for `expect`
+ if let Some(arglists) = method_chain_args(e, &["expect"]) {
+ let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs();
+ if is_type_diagnostic_item(cx, receiver_ty, sym::Option)
+ || is_type_diagnostic_item(cx, receiver_ty, sym::Result)
+ {
+ result.push(e.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.lcx, receiver_ty, sym::Option)
- || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
- {
- self.result.push(expr.span);
+ // check for `unwrap`
+ if let Some(arglists) = method_chain_args(e, &["unwrap"]) {
+ let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs();
+ if is_type_diagnostic_item(cx, receiver_ty, sym::Option)
+ || is_type_diagnostic_item(cx, receiver_ty, sym::Result)
+ {
+ result.push(e.span);
+ }
}
- }
- // and check sub-expressions
- intravisit::walk_expr(self, expr);
- }
-}
-
-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);
+ ControlFlow::Continue(())
+ });
// if we've found one, lint
- if !fpu.result.is_empty() {
+ if !result.is_empty() {
span_lint_and_then(
cx,
UNWRAP_IN_RESULT,
@@ -125,7 +111,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc
"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)");
+ diag.span_note(result, "potential non-recoverable error(s)");
},
);
}
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
index 02bf09ed5..1d2d3eb12 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -93,7 +93,7 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) {
cx,
UPPER_CASE_ACRONYMS,
span,
- &format!("name `{}` contains a capitalized acronym", ident),
+ &format!("name `{ident}` contains a capitalized acronym"),
"consider making the acronym lowercase, except the initial letter",
corrected,
Applicability::MaybeIncorrect,
@@ -105,7 +105,7 @@ impl LateLintPass<'_> for UpperCaseAcronyms {
fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) {
// do not lint public items or in macros
if in_external_macro(cx.sess(), it.span)
- || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.def_id))
+ || (self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(it.owner_id.def_id))
{
return;
}
@@ -114,6 +114,7 @@ impl LateLintPass<'_> for UpperCaseAcronyms {
check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive);
},
ItemKind::Enum(ref enumdef, _) => {
+ check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive);
// check enum variants separately because again we only want to lint on private enums and
// the fn check_variant does not know about the vis of the enum of its variants
enumdef
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 486ea5e5c..c6cdf3f85 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::same_type_and_consts;
-use clippy_utils::{meets_msrv, msrvs};
+use clippy_utils::{is_from_proc_macro, meets_msrv, msrvs};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@@ -12,11 +12,11 @@ use rustc_hir::{
Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath,
TyKind,
};
+use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
-use rustc_typeck::hir_ty_to_ty;
declare_clippy_lint! {
/// ### What it does
@@ -87,7 +87,7 @@ impl_lint_pass!(UseSelf => [USE_SELF]);
const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";
impl<'tcx> LateLintPass<'tcx> for UseSelf {
- fn check_item(&mut self, _cx: &LateContext<'_>, item: &Item<'_>) {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
if matches!(item.kind, ItemKind::OpaqueTy(_)) {
// skip over `ItemKind::OpaqueTy` in order to lint `foo() -> impl <..>`
return;
@@ -103,9 +103,10 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
if parameters.as_ref().map_or(true, |params| {
!params.parenthesized && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
});
+ if !is_from_proc_macro(cx, item); // expensive, should be last check
then {
StackItem::Check {
- impl_id: item.def_id,
+ impl_id: item.owner_id.def_id,
in_body: 0,
types_to_skip: std::iter::once(self_ty.hir_id).collect(),
}
@@ -142,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
// trait, not in the impl of the trait.
let trait_method = cx
.tcx
- .associated_item(impl_item.def_id)
+ .associated_item(impl_item.owner_id)
.trait_item_def_id
.expect("impl method matches a trait method");
let trait_method_sig = cx.tcx.fn_sig(trait_method);
@@ -205,7 +206,12 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
ref types_to_skip,
}) = self.stack.last();
if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
- if !matches!(path.res, Res::SelfTy { .. } | Res::Def(DefKind::TyParam, _));
+ if !matches!(
+ path.res,
+ Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. }
+ | Res::Def(DefKind::TyParam, _)
+ );
if !types_to_skip.contains(&hir_ty.hir_id);
let ty = if in_body > 0 {
cx.typeck_results().node_type(hir_ty.hir_id)
@@ -213,9 +219,6 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
hir_ty_to_ty(cx.tcx, hir_ty)
};
if same_type_and_consts(ty, cx.tcx.type_of(impl_id));
- let hir = cx.tcx.hir();
- // prevents false positive on `#[derive(serde::Deserialize)]`
- if !hir.span(hir.get_parent_node(hir_ty.hir_id)).in_derive_expansion();
then {
span_lint(cx, hir_ty.span);
}
@@ -232,7 +235,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
}
match expr.kind {
ExprKind::Struct(QPath::Resolved(_, path), ..) => match path.res {
- Res::SelfTy { .. } => (),
+ Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => (),
Res::Def(DefKind::Variant, _) => lint_path_to_variant(cx, path),
_ => span_lint(cx, path.span),
},
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index fe29bf29d..1f69db1cb 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -5,7 +5,7 @@ use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts};
use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
+use rustc_hir::{Expr, ExprKind, HirId, LangItem, MatchSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -55,26 +55,25 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
match e.kind {
ExprKind::Match(_, arms, MatchSource::TryDesugar) => {
- let e = match arms[0].body.kind {
- ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e)) => e,
- _ => return,
+ let (ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e))) = arms[0].body.kind else {
+ return
};
- if let ExprKind::Call(_, args) = e.kind {
- self.try_desugar_arm.push(args[0].hir_id);
+ if let ExprKind::Call(_, [arg, ..]) = e.kind {
+ self.try_desugar_arm.push(arg.hir_id);
}
},
- ExprKind::MethodCall(name, .., args, _) => {
+ ExprKind::MethodCall(name, recv, ..) => {
if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" {
let a = cx.typeck_results().expr_ty(e);
- let b = cx.typeck_results().expr_ty(&args[0]);
+ let b = cx.typeck_results().expr_ty(recv);
if same_type_and_consts(a, b) {
- let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
+ let sugg = snippet_with_macro_callsite(cx, recv.span, "<expr>").to_string();
span_lint_and_sugg(
cx,
USELESS_CONVERSION,
e.span,
- &format!("useless conversion to the same type: `{}`", b),
+ &format!("useless conversion to the same type: `{b}`"),
"consider removing `.into()`",
sugg,
Applicability::MachineApplicable, // snippet
@@ -90,14 +89,14 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
}
}
let a = cx.typeck_results().expr_ty(e);
- let b = cx.typeck_results().expr_ty(&args[0]);
+ let b = cx.typeck_results().expr_ty(recv);
if same_type_and_consts(a, b) {
- let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
+ let sugg = snippet(cx, recv.span, "<expr>").into_owned();
span_lint_and_sugg(
cx,
USELESS_CONVERSION,
e.span,
- &format!("useless conversion to the same type: `{}`", b),
+ &format!("useless conversion to the same type: `{b}`"),
"consider removing `.into_iter()`",
sugg,
Applicability::MachineApplicable, // snippet
@@ -107,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
if_chain! {
if is_trait_method(cx, e, sym::TryInto) && name.ident.name == sym::try_into;
let a = cx.typeck_results().expr_ty(e);
- let b = cx.typeck_results().expr_ty(&args[0]);
+ let b = cx.typeck_results().expr_ty(recv);
if is_type_diagnostic_item(cx, a, sym::Result);
if let ty::Adt(_, substs) = a.kind();
if let Some(a_type) = substs.types().next();
@@ -118,7 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
cx,
USELESS_CONVERSION,
e.span,
- &format!("useless conversion to the same type: `{}`", b),
+ &format!("useless conversion to the same type: `{b}`"),
None,
"consider removing `.try_into()`",
);
@@ -126,14 +125,13 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
}
},
- ExprKind::Call(path, args) => {
+ ExprKind::Call(path, [arg]) => {
if_chain! {
- if args.len() == 1;
if let ExprKind::Path(ref qpath) = path.kind;
if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
then {
let a = cx.typeck_results().expr_ty(e);
- let b = cx.typeck_results().expr_ty(&args[0]);
+ let b = cx.typeck_results().expr_ty(arg);
if_chain! {
if match_def_path(cx, def_id, &paths::TRY_FROM);
if is_type_diagnostic_item(cx, a, sym::Result);
@@ -147,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
cx,
USELESS_CONVERSION,
e.span,
- &format!("useless conversion to the same type: `{}`", b),
+ &format!("useless conversion to the same type: `{b}`"),
None,
&hint,
);
@@ -155,18 +153,18 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
}
if_chain! {
- if match_def_path(cx, def_id, &paths::FROM_FROM);
+ if cx.tcx.lang_items().require(LangItem::FromFrom).ok() == Some(def_id);
if same_type_and_consts(a, b);
then {
- let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "<expr>").maybe_par();
+ let sugg = Sugg::hir_with_macro_callsite(cx, arg, "<expr>").maybe_par();
let sugg_msg =
format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
span_lint_and_sugg(
cx,
USELESS_CONVERSION,
e.span,
- &format!("useless conversion to the same type: `{}`", b),
+ &format!("useless conversion to the same type: `{b}`"),
&sugg_msg,
sugg.to_string(),
Applicability::MachineApplicable, // snippet
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index c0726868f..0c052d86e 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -6,10 +6,13 @@ use rustc_ast::ast::{LitFloatType, LitKind};
use rustc_ast::LitIntType;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
-use rustc_hir::{ArrayLen, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
+use rustc_hir::{
+ ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind,
+};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::{Ident, Symbol};
+use std::cell::Cell;
use std::fmt::{Display, Formatter, Write as _};
declare_clippy_lint! {
@@ -35,15 +38,13 @@ declare_clippy_lint! {
///
/// ```rust,ignore
/// // ./tests/ui/new_lint.stdout
- /// if_chain! {
- /// if let ExprKind::If(ref cond, ref then, None) = item.kind,
- /// if let ExprKind::Binary(BinOp::Eq, ref left, ref right) = cond.kind,
- /// if let ExprKind::Path(ref path) = left.kind,
- /// if let ExprKind::Lit(ref lit) = right.kind,
- /// if let LitKind::Int(42, _) = lit.node,
- /// then {
- /// // report your lint here
- /// }
+ /// if ExprKind::If(ref cond, ref then, None) = item.kind
+ /// && let ExprKind::Binary(BinOp::Eq, ref left, ref right) = cond.kind
+ /// && let ExprKind::Path(ref path) = left.kind
+ /// && let ExprKind::Lit(ref lit) = right.kind
+ /// && let LitKind::Int(42, _) = lit.node
+ /// {
+ /// // report your lint here
/// }
/// ```
pub LINT_AUTHOR,
@@ -89,15 +90,16 @@ macro_rules! field {
};
}
-fn prelude() {
- println!("if_chain! {{");
-}
-
-fn done() {
- println!(" then {{");
- println!(" // report your lint here");
- println!(" }}");
- println!("}}");
+/// Print a condition of a let chain, `chain!(self, "let Some(x) = y")` will print
+/// `if let Some(x) = y` on the first call and ` && let Some(x) = y` thereafter
+macro_rules! chain {
+ ($self:ident, $($t:tt)*) => {
+ if $self.first.take() {
+ println!("if {}", format_args!($($t)*));
+ } else {
+ println!(" && {}", format_args!($($t)*));
+ }
+ }
}
impl<'tcx> LateLintPass<'tcx> for Author {
@@ -138,18 +140,19 @@ impl<'tcx> LateLintPass<'tcx> for Author {
fn check_item(cx: &LateContext<'_>, hir_id: HirId) {
let hir = cx.tcx.hir();
- if let Some(body_id) = hir.maybe_body_owned_by(hir_id.expect_owner()) {
+ if let Some(body_id) = hir.maybe_body_owned_by(hir_id.expect_owner().def_id) {
check_node(cx, hir_id, |v| {
- v.expr(&v.bind("expr", &hir.body(body_id).value));
+ v.expr(&v.bind("expr", hir.body(body_id).value));
});
}
}
fn check_node(cx: &LateContext<'_>, hir_id: HirId, f: impl Fn(&PrintVisitor<'_, '_>)) {
if has_attr(cx, hir_id) {
- prelude();
f(&PrintVisitor::new(cx));
- done();
+ println!("{{");
+ println!(" // report your lint here");
+ println!("}}");
}
}
@@ -193,7 +196,9 @@ struct PrintVisitor<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
/// Fields are the current index that needs to be appended to pattern
/// binding names
- ids: std::cell::Cell<FxHashMap<&'static str, u32>>,
+ ids: Cell<FxHashMap<&'static str, u32>>,
+ /// Currently at the first condition in the if chain
+ first: Cell<bool>,
}
#[allow(clippy::unused_self)]
@@ -201,7 +206,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
fn new(cx: &'a LateContext<'tcx>) -> Self {
Self {
cx,
- ids: std::cell::Cell::default(),
+ ids: Cell::default(),
+ first: Cell::new(true),
}
}
@@ -224,10 +230,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
fn option<T: Copy>(&self, option: &Binding<Option<T>>, name: &'static str, f: impl Fn(&Binding<T>)) {
match option.value {
- None => out!("if {option}.is_none();"),
+ None => chain!(self, "{option}.is_none()"),
Some(value) => {
let value = &self.bind(name, value);
- out!("if let Some({value}) = {option};");
+ chain!(self, "let Some({value}) = {option}");
f(value);
},
}
@@ -235,9 +241,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
fn slice<T>(&self, slice: &Binding<&[T]>, f: impl Fn(&Binding<&T>)) {
if slice.value.is_empty() {
- out!("if {slice}.is_empty();");
+ chain!(self, "{slice}.is_empty()");
} else {
- out!("if {slice}.len() == {};", slice.value.len());
+ chain!(self, "{slice}.len() == {}", slice.value.len());
for (i, value) in slice.value.iter().enumerate() {
let name = format!("{slice}[{i}]");
f(&Binding { name, value });
@@ -252,23 +258,23 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
}
fn ident(&self, ident: &Binding<Ident>) {
- out!("if {ident}.as_str() == {:?};", ident.value.as_str());
+ chain!(self, "{ident}.as_str() == {:?}", ident.value.as_str());
}
fn symbol(&self, symbol: &Binding<Symbol>) {
- out!("if {symbol}.as_str() == {:?};", symbol.value.as_str());
+ chain!(self, "{symbol}.as_str() == {:?}", symbol.value.as_str());
}
fn qpath(&self, qpath: &Binding<&QPath<'_>>) {
if let QPath::LangItem(lang_item, ..) = *qpath.value {
- out!("if matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _));");
+ chain!(self, "matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _))");
} else {
- out!("if match_qpath({qpath}, &[{}]);", path_to_string(qpath.value));
+ chain!(self, "match_qpath({qpath}, &[{}])", path_to_string(qpath.value));
}
}
fn lit(&self, lit: &Binding<&Lit>) {
- let kind = |kind| out!("if let LitKind::{kind} = {lit}.node;");
+ let kind = |kind| chain!(self, "let LitKind::{kind} = {lit}.node");
macro_rules! kind {
($($t:tt)*) => (kind(format_args!($($t)*)));
}
@@ -276,7 +282,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
match lit.value.node {
LitKind::Bool(val) => kind!("Bool({val:?})"),
LitKind::Char(c) => kind!("Char({c:?})"),
- LitKind::Err(val) => kind!("Err({val})"),
+ LitKind::Err => kind!("Err"),
LitKind::Byte(b) => kind!("Byte({b})"),
LitKind::Int(i, suffix) => {
let int_ty = match suffix {
@@ -296,7 +302,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
LitKind::ByteStr(ref vec) => {
bind!(self, vec);
kind!("ByteStr(ref {vec})");
- out!("if let [{:?}] = **{vec};", vec.value);
+ chain!(self, "let [{:?}] = **{vec}", vec.value);
},
LitKind::Str(s, _) => {
bind!(self, s);
@@ -309,15 +315,15 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
fn arm(&self, arm: &Binding<&hir::Arm<'_>>) {
self.pat(field!(arm.pat));
match arm.value.guard {
- None => out!("if {arm}.guard.is_none();"),
+ None => chain!(self, "{arm}.guard.is_none()"),
Some(hir::Guard::If(expr)) => {
bind!(self, expr);
- out!("if let Some(Guard::If({expr})) = {arm}.guard;");
+ chain!(self, "let Some(Guard::If({expr})) = {arm}.guard");
self.expr(expr);
},
Some(hir::Guard::IfLet(let_expr)) => {
bind!(self, let_expr);
- out!("if let Some(Guard::IfLet({let_expr}) = {arm}.guard;");
+ chain!(self, "let Some(Guard::IfLet({let_expr}) = {arm}.guard");
self.pat(field!(let_expr.pat));
self.expr(field!(let_expr.init));
},
@@ -329,9 +335,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
fn expr(&self, expr: &Binding<&hir::Expr<'_>>) {
if let Some(higher::While { condition, body }) = higher::While::hir(expr.value) {
bind!(self, condition, body);
- out!(
- "if let Some(higher::While {{ condition: {condition}, body: {body} }}) \
- = higher::While::hir({expr});"
+ chain!(
+ self,
+ "let Some(higher::While {{ condition: {condition}, body: {body} }}) \
+ = higher::While::hir({expr})"
);
self.expr(condition);
self.expr(body);
@@ -345,9 +352,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
}) = higher::WhileLet::hir(expr.value)
{
bind!(self, let_pat, let_expr, if_then);
- out!(
- "if let Some(higher::WhileLet {{ let_pat: {let_pat}, let_expr: {let_expr}, if_then: {if_then} }}) \
- = higher::WhileLet::hir({expr});"
+ chain!(
+ self,
+ "let Some(higher::WhileLet {{ let_pat: {let_pat}, let_expr: {let_expr}, if_then: {if_then} }}) \
+ = higher::WhileLet::hir({expr})"
);
self.pat(let_pat);
self.expr(let_expr);
@@ -357,9 +365,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
if let Some(higher::ForLoop { pat, arg, body, .. }) = higher::ForLoop::hir(expr.value) {
bind!(self, pat, arg, body);
- out!(
- "if let Some(higher::ForLoop {{ pat: {pat}, arg: {arg}, body: {body}, .. }}) \
- = higher::ForLoop::hir({expr});"
+ chain!(
+ self,
+ "let Some(higher::ForLoop {{ pat: {pat}, arg: {arg}, body: {body}, .. }}) \
+ = higher::ForLoop::hir({expr})"
);
self.pat(pat);
self.expr(arg);
@@ -367,7 +376,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
return;
}
- let kind = |kind| out!("if let ExprKind::{kind} = {expr}.kind;");
+ let kind = |kind| chain!(self, "let ExprKind::{kind} = {expr}.kind");
macro_rules! kind {
($($t:tt)*) => (kind(format_args!($($t)*)));
}
@@ -381,7 +390,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
// if it's a path
if let Some(TyKind::Path(ref qpath)) = let_expr.value.ty.as_ref().map(|ty| &ty.kind) {
bind!(self, qpath);
- out!("if let TyKind::Path(ref {qpath}) = {let_expr}.ty.kind;");
+ chain!(self, "let TyKind::Path(ref {qpath}) = {let_expr}.ty.kind");
self.qpath(qpath);
}
self.expr(field!(let_expr.init));
@@ -402,10 +411,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
self.expr(func);
self.slice(args, |e| self.expr(e));
},
- ExprKind::MethodCall(method_name, args, _) => {
- bind!(self, method_name, args);
- kind!("MethodCall({method_name}, {args}, _)");
+ ExprKind::MethodCall(method_name, receiver, args, _) => {
+ bind!(self, method_name, receiver, args);
+ kind!("MethodCall({method_name}, {receiver}, {args}, _)");
self.ident(field!(method_name.ident));
+ self.expr(receiver);
self.slice(args, |e| self.expr(e));
},
ExprKind::Tup(elements) => {
@@ -416,7 +426,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
ExprKind::Binary(op, left, right) => {
bind!(self, op, left, right);
kind!("Binary({op}, {left}, {right})");
- out!("if BinOpKind::{:?} == {op}.node;", op.value.node);
+ chain!(self, "BinOpKind::{:?} == {op}.node", op.value.node);
self.expr(left);
self.expr(right);
},
@@ -435,7 +445,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
kind!("Cast({expr}, {cast_ty})");
if let TyKind::Path(ref qpath) = cast_ty.value.kind {
bind!(self, qpath);
- out!("if let TyKind::Path(ref {qpath}) = {cast_ty}.kind;");
+ chain!(self, "let TyKind::Path(ref {qpath}) = {cast_ty}.kind");
self.qpath(qpath);
}
self.expr(expr);
@@ -482,7 +492,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
bind!(self, fn_decl, body_id);
kind!("Closure(CaptureBy::{capture_clause:?}, {fn_decl}, {body_id}, _, {movability})");
- out!("if let {ret_ty} = {fn_decl}.output;");
+ chain!(self, "let {ret_ty} = {fn_decl}.output");
self.body(body_id);
},
ExprKind::Yield(sub, source) => {
@@ -506,7 +516,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
ExprKind::AssignOp(op, target, value) => {
bind!(self, op, target, value);
kind!("AssignOp({op}, {target}, {value})");
- out!("if BinOpKind::{:?} == {op}.node;", op.value.node);
+ chain!(self, "BinOpKind::{:?} == {op}.node", op.value.node);
self.expr(target);
self.expr(value);
},
@@ -570,10 +580,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
kind!("Repeat({value}, {length})");
self.expr(value);
match length.value {
- ArrayLen::Infer(..) => out!("if let ArrayLen::Infer(..) = length;"),
+ ArrayLen::Infer(..) => chain!(self, "let ArrayLen::Infer(..) = length"),
ArrayLen::Body(anon_const) => {
bind!(self, anon_const);
- out!("if let ArrayLen::Body({anon_const}) = {length};");
+ chain!(self, "let ArrayLen::Body({anon_const}) = {length}");
self.body(field!(anon_const.body));
},
}
@@ -595,24 +605,30 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
}
fn body(&self, body_id: &Binding<hir::BodyId>) {
- let expr = &self.cx.tcx.hir().body(body_id.value).value;
+ let expr = self.cx.tcx.hir().body(body_id.value).value;
bind!(self, expr);
- out!("let {expr} = &cx.tcx.hir().body({body_id}).value;");
+ chain!(self, "{expr} = &cx.tcx.hir().body({body_id}).value");
self.expr(expr);
}
fn pat(&self, pat: &Binding<&hir::Pat<'_>>) {
- let kind = |kind| out!("if let PatKind::{kind} = {pat}.kind;");
+ let kind = |kind| chain!(self, "let PatKind::{kind} = {pat}.kind");
macro_rules! kind {
($($t:tt)*) => (kind(format_args!($($t)*)));
}
match pat.value.kind {
PatKind::Wild => kind!("Wild"),
- PatKind::Binding(anno, .., name, sub) => {
+ PatKind::Binding(ann, _, name, sub) => {
bind!(self, name);
opt_bind!(self, sub);
- kind!("Binding(BindingAnnotation::{anno:?}, _, {name}, {sub})");
+ let ann = match ann {
+ BindingAnnotation::NONE => "NONE",
+ BindingAnnotation::REF => "REF",
+ BindingAnnotation::MUT => "MUT",
+ BindingAnnotation::REF_MUT => "REF_MUT",
+ };
+ kind!("Binding(BindingAnnotation::{ann}, _, {name}, {sub})");
self.ident(name);
sub.if_some(|p| self.pat(p));
},
@@ -679,7 +695,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
}
fn stmt(&self, stmt: &Binding<&hir::Stmt<'_>>) {
- let kind = |kind| out!("if let StmtKind::{kind} = {stmt}.kind;");
+ let kind = |kind| chain!(self, "let StmtKind::{kind} = {stmt}.kind");
macro_rules! kind {
($($t:tt)*) => (kind(format_args!($($t)*)));
}
@@ -730,7 +746,7 @@ fn path_to_string(path: &QPath<'_>) -> String {
*s += ", ";
write!(s, "{:?}", segment.ident.as_str()).unwrap();
},
- other => write!(s, "/* unimplemented: {:?}*/", other).unwrap(),
+ other => write!(s, "/* unimplemented: {other:?}*/").unwrap(),
},
QPath::LangItem(..) => panic!("path_to_string: called for lang item qpath"),
}
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 6e033b3be..668123e4d 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -30,7 +30,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
"MinGW",
"CamelCase",
];
-const DEFAULT_BLACKLISTED_NAMES: &[&str] = &["foo", "baz", "quux"];
+const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"];
/// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint.
#[derive(Clone, Debug, Deserialize)]
@@ -39,28 +39,28 @@ pub struct Rename {
pub rename: String,
}
-/// A single disallowed method, used by the `DISALLOWED_METHODS` lint.
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
-pub enum DisallowedMethod {
+pub enum DisallowedPath {
Simple(String),
WithReason { path: String, reason: Option<String> },
}
-impl DisallowedMethod {
+impl DisallowedPath {
pub fn path(&self) -> &str {
let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
path
}
-}
-/// A single disallowed type, used by the `DISALLOWED_TYPES` lint.
-#[derive(Clone, Debug, Deserialize)]
-#[serde(untagged)]
-pub enum DisallowedType {
- Simple(String),
- WithReason { path: String, reason: Option<String> },
+ pub fn reason(&self) -> Option<&str> {
+ match self {
+ Self::WithReason {
+ reason: Some(reason), ..
+ } => Some(reason),
+ _ => None,
+ }
+ }
}
/// Conf with parse errors
@@ -68,6 +68,7 @@ pub enum DisallowedType {
pub struct TryConf {
pub conf: Conf,
pub errors: Vec<Box<dyn Error>>,
+ pub warnings: Vec<Box<dyn Error>>,
}
impl TryConf {
@@ -75,6 +76,7 @@ impl TryConf {
Self {
conf: Conf::default(),
errors: vec![Box::new(error)],
+ warnings: vec![],
}
}
}
@@ -90,14 +92,14 @@ impl fmt::Display for ConfError {
impl Error for ConfError {}
-fn conf_error(s: String) -> Box<dyn Error> {
- Box::new(ConfError(s))
+fn conf_error(s: impl Into<String>) -> Box<dyn Error> {
+ Box::new(ConfError(s.into()))
}
macro_rules! define_Conf {
($(
$(#[doc = $doc:literal])+
- $(#[conf_deprecated($dep:literal)])?
+ $(#[conf_deprecated($dep:literal, $new_conf:ident)])?
($name:ident: $ty:ty = $default:expr),
)*) => {
/// Clippy lint configuration
@@ -137,17 +139,29 @@ macro_rules! define_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 warnings = 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(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)?
+ $(warnings.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)?
match map.next_value() {
Err(e) => errors.push(conf_error(e.to_string())),
Ok(value) => match $name {
Some(_) => errors.push(conf_error(format!("duplicate field `{}`", name))),
- None => $name = Some(value),
+ None => {
+ $name = Some(value);
+ // $new_conf is the same as one of the defined `$name`s, so
+ // this variable is defined in line 2 of this function.
+ $(match $new_conf {
+ Some(_) => errors.push(conf_error(concat!(
+ "duplicate field `", stringify!($new_conf),
+ "` (provided as `", stringify!($name), "`)"
+ ))),
+ None => $new_conf = $name.clone(),
+ })?
+ },
}
}
})*
@@ -156,7 +170,7 @@ macro_rules! define_Conf {
}
}
let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* };
- Ok(TryConf { conf, errors })
+ Ok(TryConf { conf, errors, warnings })
}
}
@@ -194,21 +208,20 @@ define_Conf! {
/// Lint: Arithmetic.
///
/// Suppress checking of the passed type names.
- (arithmetic_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
+ (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX.
///
/// Suppress lints whenever the suggested change would cause breakage for other crates.
(avoid_breaking_exported_api: bool = true),
- /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED.
+ /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP.
///
/// The minimum rust version that the project supports
(msrv: Option<String> = None),
- /// Lint: BLACKLISTED_NAME.
+ /// DEPRECATED LINT: BLACKLISTED_NAME.
///
- /// The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses. The value
- /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
- /// default configuration of Clippy. By default any configuraction will replace the default value.
- (blacklisted_names: Vec<String> = super::DEFAULT_BLACKLISTED_NAMES.iter().map(ToString::to_string).collect()),
+ /// Use the Disallowed Names lint instead
+ #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)]
+ (blacklisted_names: Vec<String> = Vec::new()),
/// Lint: COGNITIVE_COMPLEXITY.
///
/// The maximum cognitive complexity a function can have
@@ -216,8 +229,14 @@ define_Conf! {
/// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
///
/// Use the Cognitive Complexity lint instead.
- #[conf_deprecated("Please use `cognitive-complexity-threshold` instead")]
- (cyclomatic_complexity_threshold: Option<u64> = None),
+ #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)]
+ (cyclomatic_complexity_threshold: u64 = 25),
+ /// Lint: DISALLOWED_NAMES.
+ ///
+ /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
+ /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
+ /// default configuration of Clippy. By default any configuration will replace the default value.
+ (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
/// Lint: DOC_MARKDOWN.
///
/// The list of words this lint should not consider as identifiers needing ticks. The value
@@ -296,14 +315,18 @@ define_Conf! {
///
/// Whether to allow certain wildcard imports (prelude, super in tests).
(warn_on_all_wildcard_imports: bool = false),
+ /// Lint: DISALLOWED_MACROS.
+ ///
+ /// The list of disallowed macros, written as fully qualified paths.
+ (disallowed_macros: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
/// Lint: DISALLOWED_METHODS.
///
/// The list of disallowed methods, written as fully qualified paths.
- (disallowed_methods: Vec<crate::utils::conf::DisallowedMethod> = Vec::new()),
+ (disallowed_methods: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
/// Lint: DISALLOWED_TYPES.
///
/// The list of disallowed types, written as fully qualified paths.
- (disallowed_types: Vec<crate::utils::conf::DisallowedType> = Vec::new()),
+ (disallowed_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
/// Lint: UNREADABLE_LITERAL.
///
/// Should the fraction of a decimal be linted to include separators.
@@ -331,7 +354,7 @@ define_Conf! {
/// 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()),
+ (allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
/// Lint: NON_SEND_FIELDS_IN_SEND_TY.
///
/// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
@@ -343,7 +366,7 @@ define_Conf! {
/// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
(max_suggested_slice_pattern_length: u64 = 3),
/// Lint: AWAIT_HOLDING_INVALID_TYPE
- (await_holding_invalid_types: Vec<crate::utils::conf::DisallowedType> = Vec::new()),
+ (await_holding_invalid_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
/// Lint: LARGE_INCLUDE_FILE.
///
/// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
@@ -360,6 +383,10 @@ define_Conf! {
///
/// Whether `dbg!` should be allowed in test functions
(allow_dbg_in_tests: bool = false),
+ /// Lint: RESULT_LARGE_ERR
+ ///
+ /// The maximum size of the `Err`-variant in a `Result` returned from a function
+ (large_error_threshold: u64 = 128),
}
/// Search for the configuration file.
@@ -420,7 +447,7 @@ pub fn read(path: &Path) -> TryConf {
match toml::from_str::<TryConf>(&content) {
Ok(mut conf) => {
extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
- extend_vec_if_indicator_present(&mut conf.conf.blacklisted_names, DEFAULT_BLACKLISTED_NAMES);
+ extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
conf
},
@@ -453,22 +480,19 @@ pub fn format_error(error: Box<dyn Error>) -> String {
let mut msg = String::from(prefix);
for row in 0..rows {
- write!(msg, "\n").unwrap();
+ writeln!(msg).unwrap();
for (column, column_width) in column_widths.iter().copied().enumerate() {
let index = column * rows + row;
let field = fields.get(index).copied().unwrap_or_default();
write!(
msg,
- "{:separator_width$}{:field_width$}",
- " ",
- field,
- separator_width = SEPARATOR_WIDTH,
- field_width = column_width
+ "{:SEPARATOR_WIDTH$}{field:column_width$}",
+ " "
)
.unwrap();
}
}
- write!(msg, "\n{}", suffix).unwrap();
+ write!(msg, "\n{suffix}").unwrap();
msg
} else {
s
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index b30965329..71f6c9909 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -1,1436 +1,12 @@
-use crate::utils::internal_lints::metadata_collector::is_deprecated_lint;
-use clippy_utils::consts::{constant_simple, Constant};
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::macros::root_macro_call_first_node;
-use clippy_utils::source::snippet;
-use clippy_utils::ty::match_type;
-use clippy_utils::{
- def_path_res, higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path,
- method_calls, paths, peel_blocks_with_stmt, SpanlessEq,
-};
-use if_chain::if_chain;
-use rustc_ast as ast;
-use rustc_ast::ast::{Crate, ItemKind, LitKind, ModKind, NodeId};
-use rustc_ast::visit::FnKind;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
-use rustc_hir::hir_id::CRATE_HIR_ID;
-use rustc_hir::intravisit::Visitor;
-use rustc_hir::{
- BinOpKind, Block, Closure, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind, Ty,
- TyKind, UnOp,
-};
-use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::nested_filter;
-use rustc_middle::mir::interpret::ConstValue;
-use rustc_middle::ty::{self, fast_reject::SimplifiedTypeGen, subst::GenericArgKind, FloatTy};
-use rustc_semver::RustcVersion;
-use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::Spanned;
-use rustc_span::symbol::Symbol;
-use rustc_span::{sym, BytePos, Span};
-use rustc_typeck::hir_ty_to_ty;
-
-use std::borrow::{Borrow, Cow};
-
-#[cfg(feature = "internal")]
+pub mod clippy_lints_internal;
+pub mod collapsible_calls;
+pub mod compiler_lint_functions;
+pub mod if_chain_style;
+pub mod interning_defined_symbol;
+pub mod invalid_paths;
+pub mod lint_without_lint_pass;
pub mod metadata_collector;
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for various things we like to keep tidy in clippy.
- ///
- /// ### Why is this bad?
- /// We like to pretend we're an example of tidy code.
- ///
- /// ### Example
- /// Wrong ordering of the util::paths constants.
- pub CLIPPY_LINTS_INTERNAL,
- internal,
- "various things that will negatively affect your clippy experience"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Ensures every lint is associated to a `LintPass`.
- ///
- /// ### Why is this bad?
- /// The compiler only knows lints via a `LintPass`. Without
- /// putting a lint to a `LintPass::get_lints()`'s return, the compiler will not
- /// know the name of the lint.
- ///
- /// ### Known problems
- /// Only checks for lints associated using the
- /// `declare_lint_pass!`, `impl_lint_pass!`, and `lint_array!` macros.
- ///
- /// ### Example
- /// ```rust,ignore
- /// declare_lint! { pub LINT_1, ... }
- /// declare_lint! { pub LINT_2, ... }
- /// declare_lint! { pub FORGOTTEN_LINT, ... }
- /// // ...
- /// declare_lint_pass!(Pass => [LINT_1, LINT_2]);
- /// // missing FORGOTTEN_LINT
- /// ```
- pub LINT_WITHOUT_LINT_PASS,
- internal,
- "declaring a lint without associating it in a LintPass"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
- /// variant of the function.
- ///
- /// ### Why is this bad?
- /// The `utils::*` variants also add a link to the Clippy documentation to the
- /// warning/error messages.
- ///
- /// ### Example
- /// ```rust,ignore
- /// cx.span_lint(LINT_NAME, "message");
- /// ```
- ///
- /// Use instead:
- /// ```rust,ignore
- /// utils::span_lint(cx, LINT_NAME, "message");
- /// ```
- pub COMPILER_LINT_FUNCTIONS,
- internal,
- "usage of the lint functions of the compiler instead of the utils::* variant"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for calls to `cx.outer().expn_data()` and suggests to use
- /// the `cx.outer_expn_data()`
- ///
- /// ### Why is this bad?
- /// `cx.outer_expn_data()` is faster and more concise.
- ///
- /// ### Example
- /// ```rust,ignore
- /// expr.span.ctxt().outer().expn_data()
- /// ```
- ///
- /// Use instead:
- /// ```rust,ignore
- /// expr.span.ctxt().outer_expn_data()
- /// ```
- pub OUTER_EXPN_EXPN_DATA,
- internal,
- "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Not an actual lint. This lint is only meant for testing our customized internal compiler
- /// error message by calling `panic`.
- ///
- /// ### Why is this bad?
- /// ICE in large quantities can damage your teeth
- ///
- /// ### Example
- /// ```rust,ignore
- /// 🍦🍦🍦🍦🍦
- /// ```
- pub PRODUCE_ICE,
- internal,
- "this message should not appear anywhere as we ICE before and don't emit the lint"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for cases of an auto-generated lint without an updated description,
- /// i.e. `default lint description`.
- ///
- /// ### Why is this bad?
- /// Indicates that the lint is not finished.
- ///
- /// ### Example
- /// ```rust,ignore
- /// declare_lint! { pub COOL_LINT, nursery, "default lint description" }
- /// ```
- ///
- /// Use instead:
- /// ```rust,ignore
- /// declare_lint! { pub COOL_LINT, nursery, "a great new lint" }
- /// ```
- pub DEFAULT_LINT,
- internal,
- "found 'default lint description' in a lint declaration"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Lints `span_lint_and_then` function calls, where the
- /// closure argument has only one statement and that statement is a method
- /// call to `span_suggestion`, `span_help`, `span_note` (using the same
- /// span), `help` or `note`.
- ///
- /// These usages of `span_lint_and_then` should be replaced with one of the
- /// wrapper functions `span_lint_and_sugg`, span_lint_and_help`, or
- /// `span_lint_and_note`.
- ///
- /// ### Why is this bad?
- /// Using the wrapper `span_lint_and_*` functions, is more
- /// convenient, readable and less error prone.
- ///
- /// ### Example
- /// ```rust,ignore
- /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
- /// diag.span_suggestion(
- /// expr.span,
- /// help_msg,
- /// sugg.to_string(),
- /// Applicability::MachineApplicable,
- /// );
- /// });
- /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
- /// diag.span_help(expr.span, help_msg);
- /// });
- /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
- /// diag.help(help_msg);
- /// });
- /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
- /// diag.span_note(expr.span, note_msg);
- /// });
- /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
- /// diag.note(note_msg);
- /// });
- /// ```
- ///
- /// Use instead:
- /// ```rust,ignore
- /// span_lint_and_sugg(
- /// cx,
- /// TEST_LINT,
- /// expr.span,
- /// lint_msg,
- /// help_msg,
- /// sugg.to_string(),
- /// Applicability::MachineApplicable,
- /// );
- /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg);
- /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg);
- /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg);
- /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg);
- /// ```
- pub COLLAPSIBLE_SPAN_LINT_CALLS,
- internal,
- "found collapsible `span_lint_and_then` calls"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for calls to `utils::match_type()` on a type diagnostic item
- /// and suggests to use `utils::is_type_diagnostic_item()` instead.
- ///
- /// ### Why is this bad?
- /// `utils::is_type_diagnostic_item()` does not require hardcoded paths.
- ///
- /// ### Example
- /// ```rust,ignore
- /// utils::match_type(cx, ty, &paths::VEC)
- /// ```
- ///
- /// Use instead:
- /// ```rust,ignore
- /// utils::is_type_diagnostic_item(cx, ty, sym::Vec)
- /// ```
- pub MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
- internal,
- "using `utils::match_type()` instead of `utils::is_type_diagnostic_item()`"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks the paths module for invalid paths.
- ///
- /// ### Why is this bad?
- /// It indicates a bug in the code.
- ///
- /// ### Example
- /// None.
- pub INVALID_PATHS,
- internal,
- "invalid path"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for interning symbols that have already been pre-interned and defined as constants.
- ///
- /// ### Why is this bad?
- /// It's faster and easier to use the symbol constant.
- ///
- /// ### Example
- /// ```rust,ignore
- /// let _ = sym!(f32);
- /// ```
- ///
- /// Use instead:
- /// ```rust,ignore
- /// let _ = sym::f32;
- /// ```
- pub INTERNING_DEFINED_SYMBOL,
- internal,
- "interning a symbol that is pre-interned and defined as a constant"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for unnecessary conversion from Symbol to a string.
- ///
- /// ### Why is this bad?
- /// It's faster use symbols directly instead of strings.
- ///
- /// ### Example
- /// ```rust,ignore
- /// symbol.as_str() == "clippy";
- /// ```
- ///
- /// Use instead:
- /// ```rust,ignore
- /// symbol == sym::clippy;
- /// ```
- pub UNNECESSARY_SYMBOL_STR,
- internal,
- "unnecessary conversion between Symbol and string"
-}
-
-declare_clippy_lint! {
- /// Finds unidiomatic usage of `if_chain!`
- pub IF_CHAIN_STYLE,
- internal,
- "non-idiomatic `if_chain!` usage"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for invalid `clippy::version` attributes.
- ///
- /// Valid values are:
- /// * "pre 1.29.0"
- /// * any valid semantic version
- pub INVALID_CLIPPY_VERSION_ATTRIBUTE,
- internal,
- "found an invalid `clippy::version` attribute"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for declared clippy lints without the `clippy::version` attribute.
- ///
- pub MISSING_CLIPPY_VERSION_ATTRIBUTE,
- internal,
- "found clippy lint without `clippy::version` attribute"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Check that the `extract_msrv_attr!` macro is used, when a lint has a MSRV.
- ///
- pub MISSING_MSRV_ATTR_IMPL,
- internal,
- "checking if all necessary steps were taken when adding a MSRV to a lint"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for cases of an auto-generated deprecated lint without an updated reason,
- /// i.e. `"default deprecation note"`.
- ///
- /// ### Why is this bad?
- /// Indicates that the documentation is incomplete.
- ///
- /// ### Example
- /// ```rust,ignore
- /// declare_deprecated_lint! {
- /// /// ### What it does
- /// /// Nothing. This lint has been deprecated.
- /// ///
- /// /// ### Deprecation reason
- /// /// TODO
- /// #[clippy::version = "1.63.0"]
- /// pub COOL_LINT,
- /// "default deprecation note"
- /// }
- /// ```
- ///
- /// Use instead:
- /// ```rust,ignore
- /// declare_deprecated_lint! {
- /// /// ### What it does
- /// /// Nothing. This lint has been deprecated.
- /// ///
- /// /// ### Deprecation reason
- /// /// This lint has been replaced by `cooler_lint`
- /// #[clippy::version = "1.63.0"]
- /// pub COOL_LINT,
- /// "this lint has been replaced by `cooler_lint`"
- /// }
- /// ```
- pub DEFAULT_DEPRECATION_REASON,
- internal,
- "found 'default deprecation note' in a deprecated lint declaration"
-}
-
-declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
-
-impl EarlyLintPass for ClippyLintsInternal {
- fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
- if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") {
- if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind {
- if let Some(paths) = items.iter().find(|item| item.ident.name.as_str() == "paths") {
- if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = paths.kind {
- let mut last_name: Option<&str> = None;
- for item in items {
- let name = item.ident.as_str();
- if let Some(last_name) = last_name {
- if *last_name > *name {
- span_lint(
- cx,
- CLIPPY_LINTS_INTERNAL,
- item.span,
- "this constant should be before the previous constant due to lexical \
- ordering",
- );
- }
- }
- last_name = Some(name);
- }
- }
- }
- }
- }
- }
-}
-
-#[derive(Clone, Debug, Default)]
-pub struct LintWithoutLintPass {
- declared_lints: FxHashMap<Symbol, Span>,
- registered_lints: FxHashSet<Symbol>,
-}
-
-impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE, DEFAULT_DEPRECATION_REASON]);
-
-impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
- fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
- if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id())
- || is_lint_allowed(cx, DEFAULT_DEPRECATION_REASON, item.hir_id())
- {
- return;
- }
-
- if let hir::ItemKind::Static(ty, Mutability::Not, body_id) = item.kind {
- let is_lint_ref_ty = is_lint_ref_type(cx, ty);
- if is_deprecated_lint(cx, ty) || is_lint_ref_ty {
- check_invalid_clippy_version_attribute(cx, item);
-
- let expr = &cx.tcx.hir().body(body_id).value;
- let fields;
- if is_lint_ref_ty {
- if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind
- && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind {
- fields = struct_fields;
- } else {
- return;
- }
- } else if let ExprKind::Struct(_, struct_fields, _) = expr.kind {
- fields = struct_fields;
- } else {
- return;
- }
-
- let field = fields
- .iter()
- .find(|f| f.ident.as_str() == "desc")
- .expect("lints must have a description field");
-
- if let ExprKind::Lit(Spanned {
- node: LitKind::Str(ref sym, _),
- ..
- }) = field.expr.kind
- {
- let sym_str = sym.as_str();
- if is_lint_ref_ty {
- if sym_str == "default lint description" {
- span_lint(
- cx,
- DEFAULT_LINT,
- item.span,
- &format!("the lint `{}` has the default lint description", item.ident.name),
- );
- }
-
- self.declared_lints.insert(item.ident.name, item.span);
- } else if sym_str == "default deprecation note" {
- span_lint(
- cx,
- DEFAULT_DEPRECATION_REASON,
- item.span,
- &format!("the lint `{}` has the default deprecation reason", item.ident.name),
- );
- }
- }
- }
- } else if let Some(macro_call) = root_macro_call_first_node(cx, item) {
- if !matches!(
- cx.tcx.item_name(macro_call.def_id).as_str(),
- "impl_lint_pass" | "declare_lint_pass"
- ) {
- return;
- }
- if let hir::ItemKind::Impl(hir::Impl {
- of_trait: None,
- items: impl_item_refs,
- ..
- }) = item.kind
- {
- let mut collector = LintCollector {
- output: &mut self.registered_lints,
- cx,
- };
- let body_id = cx.tcx.hir().body_owned_by(
- impl_item_refs
- .iter()
- .find(|iiref| iiref.ident.as_str() == "get_lints")
- .expect("LintPass needs to implement get_lints")
- .id
- .hir_id(),
- );
- collector.visit_expr(&cx.tcx.hir().body(body_id).value);
- }
- }
- }
-
- fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
- if is_lint_allowed(cx, LINT_WITHOUT_LINT_PASS, CRATE_HIR_ID) {
- return;
- }
-
- for (lint_name, &lint_span) in &self.declared_lints {
- // When using the `declare_tool_lint!` macro, the original `lint_span`'s
- // file points to "<rustc macros>".
- // `compiletest-rs` thinks that's an error in a different file and
- // just ignores it. This causes the test in compile-fail/lint_pass
- // not able to capture the error.
- // Therefore, we need to climb the macro expansion tree and find the
- // actual span that invoked `declare_tool_lint!`:
- let lint_span = lint_span.ctxt().outer_expn_data().call_site;
-
- if !self.registered_lints.contains(lint_name) {
- span_lint(
- cx,
- LINT_WITHOUT_LINT_PASS,
- lint_span,
- &format!("the lint `{}` is not added to any `LintPass`", lint_name),
- );
- }
- }
- }
-}
-
-fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &Ty<'_>) -> bool {
- if let TyKind::Rptr(
- _,
- MutTy {
- ty: inner,
- mutbl: Mutability::Not,
- },
- ) = ty.kind
- {
- if let TyKind::Path(ref path) = inner.kind {
- if let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id) {
- return match_def_path(cx, def_id, &paths::LINT);
- }
- }
- }
-
- false
-}
-
-fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'_>) {
- if let Some(value) = extract_clippy_version_value(cx, item) {
- // The `sym!` macro doesn't work as it only expects a single token.
- // It's better to keep it this way and have a direct `Symbol::intern` call here.
- if value == Symbol::intern("pre 1.29.0") {
- return;
- }
-
- if RustcVersion::parse(value.as_str()).is_err() {
- span_lint_and_help(
- cx,
- INVALID_CLIPPY_VERSION_ATTRIBUTE,
- item.span,
- "this item has an invalid `clippy::version` attribute",
- None,
- "please use a valid sematic version, see `doc/adding_lints.md`",
- );
- }
- } else {
- span_lint_and_help(
- cx,
- MISSING_CLIPPY_VERSION_ATTRIBUTE,
- item.span,
- "this lint is missing the `clippy::version` attribute or version value",
- None,
- "please use a `clippy::version` attribute, see `doc/adding_lints.md`",
- );
- }
-}
-
-/// This function extracts the version value of a `clippy::version` attribute if the given value has
-/// one
-fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Option<Symbol> {
- let attrs = cx.tcx.hir().attrs(item.hir_id());
- attrs.iter().find_map(|attr| {
- if_chain! {
- // Identify attribute
- if let ast::AttrKind::Normal(ref attr_kind, _) = &attr.kind;
- if let [tool_name, attr_name] = &attr_kind.path.segments[..];
- if tool_name.ident.name == sym::clippy;
- if attr_name.ident.name == sym::version;
- if let Some(version) = attr.value_str();
- then {
- Some(version)
- } else {
- None
- }
- }
- })
-}
-
-struct LintCollector<'a, 'tcx> {
- output: &'a mut FxHashSet<Symbol>,
- cx: &'a LateContext<'tcx>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
- type NestedFilter = nested_filter::All;
-
- fn visit_path(&mut self, path: &'tcx Path<'_>, _: HirId) {
- if path.segments.len() == 1 {
- self.output.insert(path.segments[0].ident.name);
- }
- }
-
- fn nested_visit_map(&mut self) -> Self::Map {
- self.cx.tcx.hir()
- }
-}
-
-#[derive(Clone, Default)]
-pub struct CompilerLintFunctions {
- map: FxHashMap<&'static str, &'static str>,
-}
-
-impl CompilerLintFunctions {
- #[must_use]
- pub fn new() -> Self {
- let mut map = FxHashMap::default();
- map.insert("span_lint", "utils::span_lint");
- map.insert("struct_span_lint", "utils::span_lint");
- map.insert("lint", "utils::span_lint");
- map.insert("span_lint_note", "utils::span_lint_and_note");
- map.insert("span_lint_help", "utils::span_lint_and_help");
- Self { map }
- }
-}
-
-impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]);
-
-impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if is_lint_allowed(cx, COMPILER_LINT_FUNCTIONS, expr.hir_id) {
- return;
- }
-
- if_chain! {
- if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
- let fn_name = path.ident;
- if let Some(sugg) = self.map.get(fn_name.as_str());
- let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
- if match_type(cx, ty, &paths::EARLY_CONTEXT)
- || match_type(cx, ty, &paths::LATE_CONTEXT);
- then {
- span_lint_and_help(
- cx,
- COMPILER_LINT_FUNCTIONS,
- path.ident.span,
- "usage of a compiler lint function",
- None,
- &format!("please use the Clippy variant of this function: `{}`", sugg),
- );
- }
- }
- }
-}
-
-declare_lint_pass!(OuterExpnDataPass => [OUTER_EXPN_EXPN_DATA]);
-
-impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if is_lint_allowed(cx, OUTER_EXPN_EXPN_DATA, expr.hir_id) {
- return;
- }
-
- let (method_names, arg_lists, spans) = method_calls(expr, 2);
- let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect();
- if_chain! {
- if let ["expn_data", "outer_expn"] = method_names.as_slice();
- let args = arg_lists[1];
- if args.len() == 1;
- let self_arg = &args[0];
- let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
- if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
- then {
- span_lint_and_sugg(
- cx,
- OUTER_EXPN_EXPN_DATA,
- spans[1].with_hi(expr.span.hi()),
- "usage of `outer_expn().expn_data()`",
- "try",
- "outer_expn_data()".to_string(),
- Applicability::MachineApplicable,
- );
- }
- }
- }
-}
-
-declare_lint_pass!(ProduceIce => [PRODUCE_ICE]);
-
-impl EarlyLintPass for ProduceIce {
- fn check_fn(&mut self, _: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
- assert!(!is_trigger_fn(fn_kind), "Would you like some help with that?");
- }
-}
-
-fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool {
- match fn_kind {
- FnKind::Fn(_, ident, ..) => ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy",
- FnKind::Closure(..) => false,
- }
-}
-
-declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]);
-
-impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if is_lint_allowed(cx, COLLAPSIBLE_SPAN_LINT_CALLS, expr.hir_id) {
- return;
- }
-
- if_chain! {
- if let ExprKind::Call(func, and_then_args) = expr.kind;
- if is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]);
- if and_then_args.len() == 5;
- if let ExprKind::Closure(&Closure { body, .. }) = &and_then_args[4].kind;
- let body = cx.tcx.hir().body(body);
- let only_expr = peel_blocks_with_stmt(&body.value);
- if let ExprKind::MethodCall(ps, span_call_args, _) = &only_expr.kind;
- if let ExprKind::Path(..) = span_call_args[0].kind;
- then {
- let and_then_snippets = get_and_then_snippets(cx, and_then_args);
- let mut sle = SpanlessEq::new(cx).deny_side_effects();
- match ps.ident.as_str() {
- "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
- suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args));
- },
- "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
- let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
- suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true);
- },
- "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
- let note_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
- suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true);
- },
- "help" => {
- let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
- suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false);
- }
- "note" => {
- let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
- suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false);
- }
- _ => (),
- }
- }
- }
- }
-}
-
-struct AndThenSnippets<'a> {
- cx: Cow<'a, str>,
- lint: Cow<'a, str>,
- span: Cow<'a, str>,
- msg: Cow<'a, str>,
-}
-
-fn get_and_then_snippets<'a, 'hir>(cx: &LateContext<'_>, and_then_snippets: &'hir [Expr<'hir>]) -> AndThenSnippets<'a> {
- let cx_snippet = snippet(cx, and_then_snippets[0].span, "cx");
- let lint_snippet = snippet(cx, and_then_snippets[1].span, "..");
- let span_snippet = snippet(cx, and_then_snippets[2].span, "span");
- let msg_snippet = snippet(cx, and_then_snippets[3].span, r#""...""#);
-
- AndThenSnippets {
- cx: cx_snippet,
- lint: lint_snippet,
- span: span_snippet,
- msg: msg_snippet,
- }
-}
-
-struct SpanSuggestionSnippets<'a> {
- help: Cow<'a, str>,
- sugg: Cow<'a, str>,
- applicability: Cow<'a, str>,
-}
-
-fn span_suggestion_snippets<'a, 'hir>(
- cx: &LateContext<'_>,
- span_call_args: &'hir [Expr<'hir>],
-) -> SpanSuggestionSnippets<'a> {
- let help_snippet = snippet(cx, span_call_args[2].span, r#""...""#);
- let sugg_snippet = snippet(cx, span_call_args[3].span, "..");
- let applicability_snippet = snippet(cx, span_call_args[4].span, "Applicability::MachineApplicable");
-
- SpanSuggestionSnippets {
- help: help_snippet,
- sugg: sugg_snippet,
- applicability: applicability_snippet,
- }
-}
-
-fn suggest_suggestion(
- cx: &LateContext<'_>,
- expr: &Expr<'_>,
- and_then_snippets: &AndThenSnippets<'_>,
- span_suggestion_snippets: &SpanSuggestionSnippets<'_>,
-) {
- span_lint_and_sugg(
- cx,
- COLLAPSIBLE_SPAN_LINT_CALLS,
- expr.span,
- "this call is collapsible",
- "collapse into",
- format!(
- "span_lint_and_sugg({}, {}, {}, {}, {}, {}, {})",
- and_then_snippets.cx,
- and_then_snippets.lint,
- and_then_snippets.span,
- and_then_snippets.msg,
- span_suggestion_snippets.help,
- span_suggestion_snippets.sugg,
- span_suggestion_snippets.applicability
- ),
- Applicability::MachineApplicable,
- );
-}
-
-fn suggest_help(
- cx: &LateContext<'_>,
- expr: &Expr<'_>,
- and_then_snippets: &AndThenSnippets<'_>,
- help: &str,
- with_span: bool,
-) {
- let option_span = if with_span {
- format!("Some({})", and_then_snippets.span)
- } else {
- "None".to_string()
- };
-
- span_lint_and_sugg(
- cx,
- COLLAPSIBLE_SPAN_LINT_CALLS,
- expr.span,
- "this call is collapsible",
- "collapse into",
- format!(
- "span_lint_and_help({}, {}, {}, {}, {}, {})",
- and_then_snippets.cx,
- and_then_snippets.lint,
- and_then_snippets.span,
- and_then_snippets.msg,
- &option_span,
- help
- ),
- Applicability::MachineApplicable,
- );
-}
-
-fn suggest_note(
- cx: &LateContext<'_>,
- expr: &Expr<'_>,
- and_then_snippets: &AndThenSnippets<'_>,
- note: &str,
- with_span: bool,
-) {
- let note_span = if with_span {
- format!("Some({})", and_then_snippets.span)
- } else {
- "None".to_string()
- };
-
- span_lint_and_sugg(
- cx,
- COLLAPSIBLE_SPAN_LINT_CALLS,
- expr.span,
- "this call is collapsible",
- "collapse into",
- format!(
- "span_lint_and_note({}, {}, {}, {}, {}, {})",
- and_then_snippets.cx,
- and_then_snippets.lint,
- and_then_snippets.span,
- and_then_snippets.msg,
- note_span,
- note
- ),
- Applicability::MachineApplicable,
- );
-}
-
-declare_lint_pass!(MatchTypeOnDiagItem => [MATCH_TYPE_ON_DIAGNOSTIC_ITEM]);
-
-impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if is_lint_allowed(cx, MATCH_TYPE_ON_DIAGNOSTIC_ITEM, expr.hir_id) {
- return;
- }
-
- if_chain! {
- // Check if this is a call to utils::match_type()
- if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind;
- if is_expr_path_def_path(cx, fn_path, &["clippy_utils", "ty", "match_type"]);
- // Extract the path to the matched type
- if let Some(segments) = path_to_matched_type(cx, ty_path);
- let segments: Vec<&str> = segments.iter().map(Symbol::as_str).collect();
- if let Some(ty_did) = def_path_res(cx, &segments[..]).opt_def_id();
- // Check if the matched type is a diagnostic item
- if let Some(item_name) = cx.tcx.get_diagnostic_name(ty_did);
- then {
- // TODO: check paths constants from external crates.
- let cx_snippet = snippet(cx, context.span, "_");
- let ty_snippet = snippet(cx, ty.span, "_");
-
- span_lint_and_sugg(
- cx,
- MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
- expr.span,
- "usage of `clippy_utils::ty::match_type()` on a type diagnostic item",
- "try",
- format!("clippy_utils::ty::is_type_diagnostic_item({}, {}, sym::{})", cx_snippet, ty_snippet, item_name),
- Applicability::MaybeIncorrect,
- );
- }
- }
- }
-}
-
-fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<Symbol>> {
- use rustc_hir::ItemKind;
-
- match &expr.kind {
- ExprKind::AddrOf(.., expr) => return path_to_matched_type(cx, expr),
- ExprKind::Path(qpath) => match cx.qpath_res(qpath, expr.hir_id) {
- Res::Local(hir_id) => {
- let parent_id = cx.tcx.hir().get_parent_node(hir_id);
- if let Some(Node::Local(local)) = cx.tcx.hir().find(parent_id) {
- if let Some(init) = local.init {
- return path_to_matched_type(cx, init);
- }
- }
- },
- Res::Def(DefKind::Const | DefKind::Static(..), def_id) => {
- if let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(def_id) {
- if let ItemKind::Const(.., body_id) | ItemKind::Static(.., body_id) = item.kind {
- let body = cx.tcx.hir().body(body_id);
- return path_to_matched_type(cx, &body.value);
- }
- }
- },
- _ => {},
- },
- ExprKind::Array(exprs) => {
- let segments: Vec<Symbol> = exprs
- .iter()
- .filter_map(|expr| {
- if let ExprKind::Lit(lit) = &expr.kind {
- if let LitKind::Str(sym, _) = lit.node {
- return Some(sym);
- }
- }
-
- None
- })
- .collect();
-
- if segments.len() == exprs.len() {
- return Some(segments);
- }
- },
- _ => {},
- }
-
- None
-}
-
-// This is not a complete resolver for paths. It works on all the paths currently used in the paths
-// module. That's all it does and all it needs to do.
-pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
- if def_path_res(cx, path) != Res::Err {
- return true;
- }
-
- // Some implementations can't be found by `path_to_res`, particularly inherent
- // implementations of native types. Check lang items.
- let path_syms: Vec<_> = path.iter().map(|p| Symbol::intern(p)).collect();
- let lang_items = cx.tcx.lang_items();
- // This list isn't complete, but good enough for our current list of paths.
- let incoherent_impls = [
- SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F32),
- SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F64),
- SimplifiedTypeGen::SliceSimplifiedType,
- SimplifiedTypeGen::StrSimplifiedType,
- ]
- .iter()
- .flat_map(|&ty| cx.tcx.incoherent_impls(ty));
- for item_def_id in lang_items.items().iter().flatten().chain(incoherent_impls) {
- let lang_item_path = cx.get_def_path(*item_def_id);
- if path_syms.starts_with(&lang_item_path) {
- if let [item] = &path_syms[lang_item_path.len()..] {
- if matches!(
- cx.tcx.def_kind(*item_def_id),
- DefKind::Mod | DefKind::Enum | DefKind::Trait
- ) {
- for child in cx.tcx.module_children(*item_def_id) {
- if child.ident.name == *item {
- return true;
- }
- }
- } else {
- for child in cx.tcx.associated_item_def_ids(*item_def_id) {
- if cx.tcx.item_name(*child) == *item {
- return true;
- }
- }
- }
- }
- }
- }
-
- false
-}
-
-declare_lint_pass!(InvalidPaths => [INVALID_PATHS]);
-
-impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
- fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
- let local_def_id = &cx.tcx.parent_module(item.hir_id());
- let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
- if_chain! {
- if mod_name.as_str() == "paths";
- if let hir::ItemKind::Const(ty, body_id) = item.kind;
- let ty = hir_ty_to_ty(cx.tcx, ty);
- if let ty::Array(el_ty, _) = &ty.kind();
- if let ty::Ref(_, el_ty, _) = &el_ty.kind();
- if el_ty.is_str();
- let body = cx.tcx.hir().body(body_id);
- let typeck_results = cx.tcx.typeck_body(body_id);
- if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, &body.value);
- let path: Vec<&str> = path.iter().map(|x| {
- if let Constant::Str(s) = x {
- s.as_str()
- } else {
- // We checked the type of the constant above
- unreachable!()
- }
- }).collect();
- if !check_path(cx, &path[..]);
- then {
- span_lint(cx, INVALID_PATHS, item.span, "invalid path");
- }
- }
- }
-}
-
-#[derive(Default)]
-pub struct InterningDefinedSymbol {
- // Maps the symbol value to the constant DefId.
- symbol_map: FxHashMap<u32, DefId>,
-}
-
-impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL, UNNECESSARY_SYMBOL_STR]);
-
-impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
- fn check_crate(&mut self, cx: &LateContext<'_>) {
- if !self.symbol_map.is_empty() {
- return;
- }
-
- for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
- if let Some(def_id) = def_path_res(cx, module).opt_def_id() {
- for item in cx.tcx.module_children(def_id).iter() {
- if_chain! {
- if let Res::Def(DefKind::Const, item_def_id) = item.res;
- let ty = cx.tcx.type_of(item_def_id);
- if match_type(cx, ty, &paths::SYMBOL);
- if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id);
- if let Ok(value) = value.to_u32();
- then {
- self.symbol_map.insert(value, item_def_id);
- }
- }
- }
- }
- }
- }
-
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if_chain! {
- if let ExprKind::Call(func, [arg]) = &expr.kind;
- if let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind();
- if match_def_path(cx, *def_id, &paths::SYMBOL_INTERN);
- if let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg);
- let value = Symbol::intern(&arg).as_u32();
- if let Some(&def_id) = self.symbol_map.get(&value);
- then {
- span_lint_and_sugg(
- cx,
- INTERNING_DEFINED_SYMBOL,
- is_expn_of(expr.span, "sym").unwrap_or(expr.span),
- "interning a defined symbol",
- "try",
- cx.tcx.def_path_str(def_id),
- Applicability::MachineApplicable,
- );
- }
- }
- if let ExprKind::Binary(op, left, right) = expr.kind {
- if matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) {
- let data = [
- (left, self.symbol_str_expr(left, cx)),
- (right, self.symbol_str_expr(right, cx)),
- ];
- match data {
- // both operands are a symbol string
- [(_, Some(left)), (_, Some(right))] => {
- span_lint_and_sugg(
- cx,
- UNNECESSARY_SYMBOL_STR,
- expr.span,
- "unnecessary `Symbol` to string conversion",
- "try",
- format!(
- "{} {} {}",
- left.as_symbol_snippet(cx),
- op.node.as_str(),
- right.as_symbol_snippet(cx),
- ),
- Applicability::MachineApplicable,
- );
- },
- // one of the operands is a symbol string
- [(expr, Some(symbol)), _] | [_, (expr, Some(symbol))] => {
- // creating an owned string for comparison
- if matches!(symbol, SymbolStrExpr::Expr { is_to_owned: true, .. }) {
- span_lint_and_sugg(
- cx,
- UNNECESSARY_SYMBOL_STR,
- expr.span,
- "unnecessary string allocation",
- "try",
- format!("{}.as_str()", symbol.as_symbol_snippet(cx)),
- Applicability::MachineApplicable,
- );
- }
- },
- // nothing found
- [(_, None), (_, None)] => {},
- }
- }
- }
- }
-}
-
-impl InterningDefinedSymbol {
- fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> {
- static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR, &paths::TO_STRING_METHOD];
- static SYMBOL_STR_PATHS: &[&[&str]] = &[
- &paths::SYMBOL_AS_STR,
- &paths::SYMBOL_TO_IDENT_STRING,
- &paths::TO_STRING_METHOD,
- ];
- let call = if_chain! {
- if let ExprKind::AddrOf(_, _, e) = expr.kind;
- if let ExprKind::Unary(UnOp::Deref, e) = e.kind;
- then { e } else { expr }
- };
- if_chain! {
- // is a method call
- if let ExprKind::MethodCall(_, [item], _) = call.kind;
- if let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id);
- let ty = cx.typeck_results().expr_ty(item);
- // ...on either an Ident or a Symbol
- if let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) {
- Some(false)
- } else if match_type(cx, ty, &paths::IDENT) {
- Some(true)
- } else {
- None
- };
- // ...which converts it to a string
- let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS };
- if let Some(path) = paths.iter().find(|path| match_def_path(cx, did, path));
- then {
- let is_to_owned = path.last().unwrap().ends_with("string");
- return Some(SymbolStrExpr::Expr {
- item,
- is_ident,
- is_to_owned,
- });
- }
- }
- // is a string constant
- if let Some(Constant::Str(s)) = constant_simple(cx, cx.typeck_results(), expr) {
- let value = Symbol::intern(&s).as_u32();
- // ...which matches a symbol constant
- if let Some(&def_id) = self.symbol_map.get(&value) {
- return Some(SymbolStrExpr::Const(def_id));
- }
- }
- None
- }
-}
-
-enum SymbolStrExpr<'tcx> {
- /// a string constant with a corresponding symbol constant
- Const(DefId),
- /// a "symbol to string" expression like `symbol.as_str()`
- Expr {
- /// part that evaluates to `Symbol` or `Ident`
- item: &'tcx Expr<'tcx>,
- is_ident: bool,
- /// whether an owned `String` is created like `to_ident_string()`
- is_to_owned: bool,
- },
-}
-
-impl<'tcx> SymbolStrExpr<'tcx> {
- /// Returns a snippet that evaluates to a `Symbol` and is const if possible
- fn as_symbol_snippet(&self, cx: &LateContext<'_>) -> Cow<'tcx, str> {
- match *self {
- Self::Const(def_id) => cx.tcx.def_path_str(def_id).into(),
- Self::Expr { item, is_ident, .. } => {
- let mut snip = snippet(cx, item.span.source_callsite(), "..");
- if is_ident {
- // get `Ident.name`
- snip.to_mut().push_str(".name");
- }
- snip
- },
- }
- }
-}
-
-declare_lint_pass!(IfChainStyle => [IF_CHAIN_STYLE]);
-
-impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
- fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
- let (local, after, if_chain_span) = if_chain! {
- if let [Stmt { kind: StmtKind::Local(local), .. }, after @ ..] = block.stmts;
- if let Some(if_chain_span) = is_expn_of(block.span, "if_chain");
- then { (local, after, if_chain_span) } else { return }
- };
- if is_first_if_chain_expr(cx, block.hir_id, if_chain_span) {
- span_lint(
- cx,
- IF_CHAIN_STYLE,
- if_chain_local_span(cx, local, if_chain_span),
- "`let` expression should be above the `if_chain!`",
- );
- } else if local.span.ctxt() == block.span.ctxt() && is_if_chain_then(after, block.expr, if_chain_span) {
- span_lint(
- cx,
- IF_CHAIN_STYLE,
- if_chain_local_span(cx, local, if_chain_span),
- "`let` expression should be inside `then { .. }`",
- );
- }
- }
-
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- let (cond, then, els) = if let Some(higher::IfOrIfLet { cond, r#else, then }) = higher::IfOrIfLet::hir(expr) {
- (cond, then, r#else.is_some())
- } else {
- return;
- };
- let then_block = match then.kind {
- ExprKind::Block(block, _) => block,
- _ => return,
- };
- let if_chain_span = is_expn_of(expr.span, "if_chain");
- if !els {
- check_nested_if_chains(cx, expr, then_block, if_chain_span);
- }
- let if_chain_span = match if_chain_span {
- None => return,
- Some(span) => span,
- };
- // check for `if a && b;`
- if_chain! {
- if let ExprKind::Binary(op, _, _) = cond.kind;
- if op.node == BinOpKind::And;
- if cx.sess().source_map().is_multiline(cond.span);
- then {
- span_lint(cx, IF_CHAIN_STYLE, cond.span, "`if a && b;` should be `if a; if b;`");
- }
- }
- if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span)
- && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span)
- {
- span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`");
- }
- }
-}
-
-fn check_nested_if_chains(
- cx: &LateContext<'_>,
- if_expr: &Expr<'_>,
- then_block: &Block<'_>,
- if_chain_span: Option<Span>,
-) {
- #[rustfmt::skip]
- let (head, tail) = match *then_block {
- Block { stmts, expr: Some(tail), .. } => (stmts, tail),
- Block {
- stmts: &[
- ref head @ ..,
- Stmt { kind: StmtKind::Expr(tail) | StmtKind::Semi(tail), .. }
- ],
- ..
- } => (head, tail),
- _ => return,
- };
- if_chain! {
- if let Some(higher::IfOrIfLet { r#else: None, .. }) = higher::IfOrIfLet::hir(tail);
- let sm = cx.sess().source_map();
- if head
- .iter()
- .all(|stmt| matches!(stmt.kind, StmtKind::Local(..)) && !sm.is_multiline(stmt.span));
- if if_chain_span.is_some() || !is_else_clause(cx.tcx, if_expr);
- then {} else { return }
- }
- let (span, msg) = match (if_chain_span, is_expn_of(tail.span, "if_chain")) {
- (None, Some(_)) => (if_expr.span, "this `if` can be part of the inner `if_chain!`"),
- (Some(_), None) => (tail.span, "this `if` can be part of the outer `if_chain!`"),
- (Some(a), Some(b)) if a != b => (b, "this `if_chain!` can be merged with the outer `if_chain!`"),
- _ => return,
- };
- span_lint_and_then(cx, IF_CHAIN_STYLE, span, msg, |diag| {
- let (span, msg) = match head {
- [] => return,
- [stmt] => (stmt.span, "this `let` statement can also be in the `if_chain!`"),
- [a, .., b] => (
- a.span.to(b.span),
- "these `let` statements can also be in the `if_chain!`",
- ),
- };
- diag.span_help(span, msg);
- });
-}
-
-fn is_first_if_chain_expr(cx: &LateContext<'_>, hir_id: HirId, if_chain_span: Span) -> bool {
- cx.tcx
- .hir()
- .parent_iter(hir_id)
- .find(|(_, node)| {
- #[rustfmt::skip]
- !matches!(node, Node::Expr(Expr { kind: ExprKind::Block(..), .. }) | Node::Stmt(_))
- })
- .map_or(false, |(id, _)| {
- is_expn_of(cx.tcx.hir().span(id), "if_chain") != Some(if_chain_span)
- })
-}
-
-/// Checks a trailing slice of statements and expression of a `Block` to see if they are part
-/// of the `then {..}` portion of an `if_chain!`
-fn is_if_chain_then(stmts: &[Stmt<'_>], expr: Option<&Expr<'_>>, if_chain_span: Span) -> bool {
- let span = if let [stmt, ..] = stmts {
- stmt.span
- } else if let Some(expr) = expr {
- expr.span
- } else {
- // empty `then {}`
- return true;
- };
- is_expn_of(span, "if_chain").map_or(true, |span| span != if_chain_span)
-}
-
-/// Creates a `Span` for `let x = ..;` in an `if_chain!` call.
-fn if_chain_local_span(cx: &LateContext<'_>, local: &Local<'_>, if_chain_span: Span) -> Span {
- let mut span = local.pat.span;
- if let Some(init) = local.init {
- span = span.to(init.span);
- }
- span.adjust(if_chain_span.ctxt().outer_expn());
- let sm = cx.sess().source_map();
- let span = sm.span_extend_to_prev_str(span, "let", false, true).unwrap_or(span);
- let span = sm.span_extend_to_next_char(span, ';', false);
- Span::new(
- span.lo() - BytePos(3),
- span.hi() + BytePos(1),
- span.ctxt(),
- span.parent(),
- )
-}
-
-declare_lint_pass!(MsrvAttrImpl => [MISSING_MSRV_ATTR_IMPL]);
-
-impl LateLintPass<'_> for MsrvAttrImpl {
- fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if_chain! {
- if let hir::ItemKind::Impl(hir::Impl {
- of_trait: Some(lint_pass_trait_ref),
- self_ty,
- items,
- ..
- }) = &item.kind;
- if let Some(lint_pass_trait_def_id) = lint_pass_trait_ref.trait_def_id();
- let is_late_pass = match_def_path(cx, lint_pass_trait_def_id, &paths::LATE_LINT_PASS);
- if is_late_pass || match_def_path(cx, lint_pass_trait_def_id, &paths::EARLY_LINT_PASS);
- let self_ty = hir_ty_to_ty(cx.tcx, self_ty);
- if let ty::Adt(self_ty_def, _) = self_ty.kind();
- if self_ty_def.is_struct();
- if self_ty_def.all_fields().any(|f| {
- cx.tcx
- .type_of(f.did)
- .walk()
- .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
- .any(|t| match_type(cx, t.expect_ty(), &paths::RUSTC_VERSION))
- });
- if !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs));
- then {
- let context = if is_late_pass { "LateContext" } else { "EarlyContext" };
- let lint_pass = if is_late_pass { "LateLintPass" } else { "EarlyLintPass" };
- let span = cx.sess().source_map().span_through_char(item.span, '{');
- span_lint_and_sugg(
- cx,
- MISSING_MSRV_ATTR_IMPL,
- span,
- &format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"),
- &format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"),
- format!("{}\n extract_msrv_attr!({context});", snippet(cx, span, "..")),
- Applicability::MachineApplicable,
- );
- }
- }
- }
-}
+pub mod msrv_attr_impl;
+pub mod outer_expn_data_pass;
+pub mod produce_ice;
+pub mod unnecessary_def_path;
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs
new file mode 100644
index 000000000..da9514dd1
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs
@@ -0,0 +1,49 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_ast::ast::{Crate, ItemKind, ModKind};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for various things we like to keep tidy in clippy.
+ ///
+ /// ### Why is this bad?
+ /// We like to pretend we're an example of tidy code.
+ ///
+ /// ### Example
+ /// Wrong ordering of the util::paths constants.
+ pub CLIPPY_LINTS_INTERNAL,
+ internal,
+ "various things that will negatively affect your clippy experience"
+}
+
+declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
+
+impl EarlyLintPass for ClippyLintsInternal {
+ fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
+ if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") {
+ if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind {
+ if let Some(paths) = items.iter().find(|item| item.ident.name.as_str() == "paths") {
+ if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = paths.kind {
+ let mut last_name: Option<&str> = None;
+ for item in items {
+ let name = item.ident.as_str();
+ if let Some(last_name) = last_name {
+ if *last_name > *name {
+ span_lint(
+ cx,
+ CLIPPY_LINTS_INTERNAL,
+ item.span,
+ "this constant should be before the previous constant due to lexical \
+ ordering",
+ );
+ }
+ }
+ last_name = Some(name);
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
new file mode 100644
index 000000000..d7666b77f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
@@ -0,0 +1,245 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::{is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt, SpanlessEq};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::{Closure, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+use std::borrow::{Borrow, Cow};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Lints `span_lint_and_then` function calls, where the
+ /// closure argument has only one statement and that statement is a method
+ /// call to `span_suggestion`, `span_help`, `span_note` (using the same
+ /// span), `help` or `note`.
+ ///
+ /// These usages of `span_lint_and_then` should be replaced with one of the
+ /// wrapper functions `span_lint_and_sugg`, span_lint_and_help`, or
+ /// `span_lint_and_note`.
+ ///
+ /// ### Why is this bad?
+ /// Using the wrapper `span_lint_and_*` functions, is more
+ /// convenient, readable and less error prone.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
+ /// diag.span_suggestion(
+ /// expr.span,
+ /// help_msg,
+ /// sugg.to_string(),
+ /// Applicability::MachineApplicable,
+ /// );
+ /// });
+ /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
+ /// diag.span_help(expr.span, help_msg);
+ /// });
+ /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
+ /// diag.help(help_msg);
+ /// });
+ /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
+ /// diag.span_note(expr.span, note_msg);
+ /// });
+ /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
+ /// diag.note(note_msg);
+ /// });
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust,ignore
+ /// span_lint_and_sugg(
+ /// cx,
+ /// TEST_LINT,
+ /// expr.span,
+ /// lint_msg,
+ /// help_msg,
+ /// sugg.to_string(),
+ /// Applicability::MachineApplicable,
+ /// );
+ /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg);
+ /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg);
+ /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg);
+ /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg);
+ /// ```
+ pub COLLAPSIBLE_SPAN_LINT_CALLS,
+ internal,
+ "found collapsible `span_lint_and_then` calls"
+}
+
+declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]);
+
+impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+ if is_lint_allowed(cx, COLLAPSIBLE_SPAN_LINT_CALLS, expr.hir_id) {
+ return;
+ }
+
+ if_chain! {
+ if let ExprKind::Call(func, and_then_args) = expr.kind;
+ if is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]);
+ if and_then_args.len() == 5;
+ if let ExprKind::Closure(&Closure { body, .. }) = &and_then_args[4].kind;
+ let body = cx.tcx.hir().body(body);
+ let only_expr = peel_blocks_with_stmt(body.value);
+ if let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind;
+ if let ExprKind::Path(..) = recv.kind;
+ then {
+ let and_then_snippets = get_and_then_snippets(cx, and_then_args);
+ let mut sle = SpanlessEq::new(cx).deny_side_effects();
+ match ps.ident.as_str() {
+ "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
+ suggest_suggestion(
+ cx,
+ expr,
+ &and_then_snippets,
+ &span_suggestion_snippets(cx, span_call_args),
+ );
+ },
+ "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
+ let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
+ suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true);
+ },
+ "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
+ let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
+ suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true);
+ },
+ "help" => {
+ let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#);
+ suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false);
+ },
+ "note" => {
+ let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#);
+ suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false);
+ },
+ _ => (),
+ }
+ }
+ }
+ }
+}
+
+struct AndThenSnippets<'a> {
+ cx: Cow<'a, str>,
+ lint: Cow<'a, str>,
+ span: Cow<'a, str>,
+ msg: Cow<'a, str>,
+}
+
+fn get_and_then_snippets<'a, 'hir>(cx: &LateContext<'_>, and_then_snippets: &'hir [Expr<'hir>]) -> AndThenSnippets<'a> {
+ let cx_snippet = snippet(cx, and_then_snippets[0].span, "cx");
+ let lint_snippet = snippet(cx, and_then_snippets[1].span, "..");
+ let span_snippet = snippet(cx, and_then_snippets[2].span, "span");
+ let msg_snippet = snippet(cx, and_then_snippets[3].span, r#""...""#);
+
+ AndThenSnippets {
+ cx: cx_snippet,
+ lint: lint_snippet,
+ span: span_snippet,
+ msg: msg_snippet,
+ }
+}
+
+struct SpanSuggestionSnippets<'a> {
+ help: Cow<'a, str>,
+ sugg: Cow<'a, str>,
+ applicability: Cow<'a, str>,
+}
+
+fn span_suggestion_snippets<'a, 'hir>(
+ cx: &LateContext<'_>,
+ span_call_args: &'hir [Expr<'hir>],
+) -> SpanSuggestionSnippets<'a> {
+ let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
+ let sugg_snippet = snippet(cx, span_call_args[2].span, "..");
+ let applicability_snippet = snippet(cx, span_call_args[3].span, "Applicability::MachineApplicable");
+
+ SpanSuggestionSnippets {
+ help: help_snippet,
+ sugg: sugg_snippet,
+ applicability: applicability_snippet,
+ }
+}
+
+fn suggest_suggestion(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ and_then_snippets: &AndThenSnippets<'_>,
+ span_suggestion_snippets: &SpanSuggestionSnippets<'_>,
+) {
+ span_lint_and_sugg(
+ cx,
+ COLLAPSIBLE_SPAN_LINT_CALLS,
+ expr.span,
+ "this call is collapsible",
+ "collapse into",
+ format!(
+ "span_lint_and_sugg({}, {}, {}, {}, {}, {}, {})",
+ and_then_snippets.cx,
+ and_then_snippets.lint,
+ and_then_snippets.span,
+ and_then_snippets.msg,
+ span_suggestion_snippets.help,
+ span_suggestion_snippets.sugg,
+ span_suggestion_snippets.applicability
+ ),
+ Applicability::MachineApplicable,
+ );
+}
+
+fn suggest_help(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ and_then_snippets: &AndThenSnippets<'_>,
+ help: &str,
+ with_span: bool,
+) {
+ let option_span = if with_span {
+ format!("Some({})", and_then_snippets.span)
+ } else {
+ "None".to_string()
+ };
+
+ span_lint_and_sugg(
+ cx,
+ COLLAPSIBLE_SPAN_LINT_CALLS,
+ expr.span,
+ "this call is collapsible",
+ "collapse into",
+ format!(
+ "span_lint_and_help({}, {}, {}, {}, {}, {help})",
+ and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg, &option_span,
+ ),
+ Applicability::MachineApplicable,
+ );
+}
+
+fn suggest_note(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ and_then_snippets: &AndThenSnippets<'_>,
+ note: &str,
+ with_span: bool,
+) {
+ let note_span = if with_span {
+ format!("Some({})", and_then_snippets.span)
+ } else {
+ "None".to_string()
+ };
+
+ span_lint_and_sugg(
+ cx,
+ COLLAPSIBLE_SPAN_LINT_CALLS,
+ expr.span,
+ "this call is collapsible",
+ "collapse into",
+ format!(
+ "span_lint_and_note({}, {}, {}, {}, {note_span}, {note})",
+ and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg,
+ ),
+ Applicability::MachineApplicable,
+ );
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
new file mode 100644
index 000000000..cacd05262
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
@@ -0,0 +1,77 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::match_type;
+use clippy_utils::{is_lint_allowed, paths};
+use if_chain::if_chain;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
+ /// variant of the function.
+ ///
+ /// ### Why is this bad?
+ /// The `utils::*` variants also add a link to the Clippy documentation to the
+ /// warning/error messages.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// cx.span_lint(LINT_NAME, "message");
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust,ignore
+ /// utils::span_lint(cx, LINT_NAME, "message");
+ /// ```
+ pub COMPILER_LINT_FUNCTIONS,
+ internal,
+ "usage of the lint functions of the compiler instead of the utils::* variant"
+}
+
+impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]);
+
+#[derive(Clone, Default)]
+pub struct CompilerLintFunctions {
+ map: FxHashMap<&'static str, &'static str>,
+}
+
+impl CompilerLintFunctions {
+ #[must_use]
+ pub fn new() -> Self {
+ let mut map = FxHashMap::default();
+ map.insert("span_lint", "utils::span_lint");
+ map.insert("struct_span_lint", "utils::span_lint");
+ map.insert("lint", "utils::span_lint");
+ map.insert("span_lint_note", "utils::span_lint_and_note");
+ map.insert("span_lint_help", "utils::span_lint_and_help");
+ Self { map }
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ if is_lint_allowed(cx, COMPILER_LINT_FUNCTIONS, expr.hir_id) {
+ return;
+ }
+
+ if_chain! {
+ if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind;
+ let fn_name = path.ident;
+ if let Some(sugg) = self.map.get(fn_name.as_str());
+ let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
+ if match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT);
+ then {
+ span_lint_and_help(
+ cx,
+ COMPILER_LINT_FUNCTIONS,
+ path.ident.span,
+ "usage of a compiler lint function",
+ None,
+ &format!("please use the Clippy variant of this function: `{sugg}`"),
+ );
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
new file mode 100644
index 000000000..883a5c08e
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
@@ -0,0 +1,164 @@
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::{higher, is_else_clause, is_expn_of};
+use if_chain::if_chain;
+use rustc_hir as hir;
+use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Local, Node, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{BytePos, Span};
+
+declare_clippy_lint! {
+ /// Finds unidiomatic usage of `if_chain!`
+ pub IF_CHAIN_STYLE,
+ internal,
+ "non-idiomatic `if_chain!` usage"
+}
+
+declare_lint_pass!(IfChainStyle => [IF_CHAIN_STYLE]);
+
+impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
+ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
+ let (local, after, if_chain_span) = if_chain! {
+ if let [Stmt { kind: StmtKind::Local(local), .. }, after @ ..] = block.stmts;
+ if let Some(if_chain_span) = is_expn_of(block.span, "if_chain");
+ then { (local, after, if_chain_span) } else { return }
+ };
+ if is_first_if_chain_expr(cx, block.hir_id, if_chain_span) {
+ span_lint(
+ cx,
+ IF_CHAIN_STYLE,
+ if_chain_local_span(cx, local, if_chain_span),
+ "`let` expression should be above the `if_chain!`",
+ );
+ } else if local.span.ctxt() == block.span.ctxt() && is_if_chain_then(after, block.expr, if_chain_span) {
+ span_lint(
+ cx,
+ IF_CHAIN_STYLE,
+ if_chain_local_span(cx, local, if_chain_span),
+ "`let` expression should be inside `then { .. }`",
+ );
+ }
+ }
+
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+ let (cond, then, els) = if let Some(higher::IfOrIfLet { cond, r#else, then }) = higher::IfOrIfLet::hir(expr) {
+ (cond, then, r#else.is_some())
+ } else {
+ return;
+ };
+ let ExprKind::Block(then_block, _) = then.kind else { return };
+ let if_chain_span = is_expn_of(expr.span, "if_chain");
+ if !els {
+ check_nested_if_chains(cx, expr, then_block, if_chain_span);
+ }
+ let Some(if_chain_span) = if_chain_span else { return };
+ // check for `if a && b;`
+ if_chain! {
+ if let ExprKind::Binary(op, _, _) = cond.kind;
+ if op.node == BinOpKind::And;
+ if cx.sess().source_map().is_multiline(cond.span);
+ then {
+ span_lint(cx, IF_CHAIN_STYLE, cond.span, "`if a && b;` should be `if a; if b;`");
+ }
+ }
+ if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span)
+ && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span)
+ {
+ span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`");
+ }
+ }
+}
+
+fn check_nested_if_chains(
+ cx: &LateContext<'_>,
+ if_expr: &Expr<'_>,
+ then_block: &Block<'_>,
+ if_chain_span: Option<Span>,
+) {
+ #[rustfmt::skip]
+ let (head, tail) = match *then_block {
+ Block { stmts, expr: Some(tail), .. } => (stmts, tail),
+ Block {
+ stmts: &[
+ ref head @ ..,
+ Stmt { kind: StmtKind::Expr(tail) | StmtKind::Semi(tail), .. }
+ ],
+ ..
+ } => (head, tail),
+ _ => return,
+ };
+ if_chain! {
+ if let Some(higher::IfOrIfLet { r#else: None, .. }) = higher::IfOrIfLet::hir(tail);
+ let sm = cx.sess().source_map();
+ if head
+ .iter()
+ .all(|stmt| matches!(stmt.kind, StmtKind::Local(..)) && !sm.is_multiline(stmt.span));
+ if if_chain_span.is_some() || !is_else_clause(cx.tcx, if_expr);
+ then {
+ } else {
+ return;
+ }
+ }
+ let (span, msg) = match (if_chain_span, is_expn_of(tail.span, "if_chain")) {
+ (None, Some(_)) => (if_expr.span, "this `if` can be part of the inner `if_chain!`"),
+ (Some(_), None) => (tail.span, "this `if` can be part of the outer `if_chain!`"),
+ (Some(a), Some(b)) if a != b => (b, "this `if_chain!` can be merged with the outer `if_chain!`"),
+ _ => return,
+ };
+ span_lint_and_then(cx, IF_CHAIN_STYLE, span, msg, |diag| {
+ let (span, msg) = match head {
+ [] => return,
+ [stmt] => (stmt.span, "this `let` statement can also be in the `if_chain!`"),
+ [a, .., b] => (
+ a.span.to(b.span),
+ "these `let` statements can also be in the `if_chain!`",
+ ),
+ };
+ diag.span_help(span, msg);
+ });
+}
+
+fn is_first_if_chain_expr(cx: &LateContext<'_>, hir_id: HirId, if_chain_span: Span) -> bool {
+ cx.tcx
+ .hir()
+ .parent_iter(hir_id)
+ .find(|(_, node)| {
+ #[rustfmt::skip]
+ !matches!(node, Node::Expr(Expr { kind: ExprKind::Block(..), .. }) | Node::Stmt(_))
+ })
+ .map_or(false, |(id, _)| {
+ is_expn_of(cx.tcx.hir().span(id), "if_chain") != Some(if_chain_span)
+ })
+}
+
+/// Checks a trailing slice of statements and expression of a `Block` to see if they are part
+/// of the `then {..}` portion of an `if_chain!`
+fn is_if_chain_then(stmts: &[Stmt<'_>], expr: Option<&Expr<'_>>, if_chain_span: Span) -> bool {
+ let span = if let [stmt, ..] = stmts {
+ stmt.span
+ } else if let Some(expr) = expr {
+ expr.span
+ } else {
+ // empty `then {}`
+ return true;
+ };
+ is_expn_of(span, "if_chain").map_or(true, |span| span != if_chain_span)
+}
+
+/// Creates a `Span` for `let x = ..;` in an `if_chain!` call.
+fn if_chain_local_span(cx: &LateContext<'_>, local: &Local<'_>, if_chain_span: Span) -> Span {
+ let mut span = local.pat.span;
+ if let Some(init) = local.init {
+ span = span.to(init.span);
+ }
+ span.adjust(if_chain_span.ctxt().outer_expn());
+ let sm = cx.sess().source_map();
+ let span = sm.span_extend_to_prev_str(span, "let", false, true).unwrap_or(span);
+ let span = sm.span_extend_to_next_char(span, ';', false);
+ Span::new(
+ span.lo() - BytePos(3),
+ span.hi() + BytePos(1),
+ span.ctxt(),
+ span.parent(),
+ )
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
new file mode 100644
index 000000000..096b60157
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -0,0 +1,239 @@
+use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::match_type;
+use clippy_utils::{def_path_res, is_expn_of, match_def_path, paths};
+use if_chain::if_chain;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::Applicability;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::mir::interpret::ConstValue;
+use rustc_middle::ty::{self};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::Symbol;
+
+use std::borrow::Cow;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for interning symbols that have already been pre-interned and defined as constants.
+ ///
+ /// ### Why is this bad?
+ /// It's faster and easier to use the symbol constant.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// let _ = sym!(f32);
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust,ignore
+ /// let _ = sym::f32;
+ /// ```
+ pub INTERNING_DEFINED_SYMBOL,
+ internal,
+ "interning a symbol that is pre-interned and defined as a constant"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for unnecessary conversion from Symbol to a string.
+ ///
+ /// ### Why is this bad?
+ /// It's faster use symbols directly instead of strings.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// symbol.as_str() == "clippy";
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust,ignore
+ /// symbol == sym::clippy;
+ /// ```
+ pub UNNECESSARY_SYMBOL_STR,
+ internal,
+ "unnecessary conversion between Symbol and string"
+}
+
+#[derive(Default)]
+pub struct InterningDefinedSymbol {
+ // Maps the symbol value to the constant DefId.
+ symbol_map: FxHashMap<u32, DefId>,
+}
+
+impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL, UNNECESSARY_SYMBOL_STR]);
+
+impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
+ fn check_crate(&mut self, cx: &LateContext<'_>) {
+ if !self.symbol_map.is_empty() {
+ return;
+ }
+
+ for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
+ if let Some(def_id) = def_path_res(cx, module, None).opt_def_id() {
+ for item in cx.tcx.module_children(def_id).iter() {
+ if_chain! {
+ if let Res::Def(DefKind::Const, item_def_id) = item.res;
+ let ty = cx.tcx.type_of(item_def_id);
+ if match_type(cx, ty, &paths::SYMBOL);
+ if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id);
+ if let Ok(value) = value.to_u32();
+ then {
+ self.symbol_map.insert(value, item_def_id);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ if_chain! {
+ if let ExprKind::Call(func, [arg]) = &expr.kind;
+ if let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind();
+ if match_def_path(cx, *def_id, &paths::SYMBOL_INTERN);
+ if let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg);
+ let value = Symbol::intern(&arg).as_u32();
+ if let Some(&def_id) = self.symbol_map.get(&value);
+ then {
+ span_lint_and_sugg(
+ cx,
+ INTERNING_DEFINED_SYMBOL,
+ is_expn_of(expr.span, "sym").unwrap_or(expr.span),
+ "interning a defined symbol",
+ "try",
+ cx.tcx.def_path_str(def_id),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ if let ExprKind::Binary(op, left, right) = expr.kind {
+ if matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) {
+ let data = [
+ (left, self.symbol_str_expr(left, cx)),
+ (right, self.symbol_str_expr(right, cx)),
+ ];
+ match data {
+ // both operands are a symbol string
+ [(_, Some(left)), (_, Some(right))] => {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_SYMBOL_STR,
+ expr.span,
+ "unnecessary `Symbol` to string conversion",
+ "try",
+ format!(
+ "{} {} {}",
+ left.as_symbol_snippet(cx),
+ op.node.as_str(),
+ right.as_symbol_snippet(cx),
+ ),
+ Applicability::MachineApplicable,
+ );
+ },
+ // one of the operands is a symbol string
+ [(expr, Some(symbol)), _] | [_, (expr, Some(symbol))] => {
+ // creating an owned string for comparison
+ if matches!(symbol, SymbolStrExpr::Expr { is_to_owned: true, .. }) {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_SYMBOL_STR,
+ expr.span,
+ "unnecessary string allocation",
+ "try",
+ format!("{}.as_str()", symbol.as_symbol_snippet(cx)),
+ Applicability::MachineApplicable,
+ );
+ }
+ },
+ // nothing found
+ [(_, None), (_, None)] => {},
+ }
+ }
+ }
+ }
+}
+
+impl InterningDefinedSymbol {
+ fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> {
+ static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR, &paths::TO_STRING_METHOD];
+ static SYMBOL_STR_PATHS: &[&[&str]] = &[
+ &paths::SYMBOL_AS_STR,
+ &paths::SYMBOL_TO_IDENT_STRING,
+ &paths::TO_STRING_METHOD,
+ ];
+ let call = if_chain! {
+ if let ExprKind::AddrOf(_, _, e) = expr.kind;
+ if let ExprKind::Unary(UnOp::Deref, e) = e.kind;
+ then { e } else { expr }
+ };
+ if_chain! {
+ // is a method call
+ if let ExprKind::MethodCall(_, item, [], _) = call.kind;
+ if let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id);
+ let ty = cx.typeck_results().expr_ty(item);
+ // ...on either an Ident or a Symbol
+ if let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) {
+ Some(false)
+ } else if match_type(cx, ty, &paths::IDENT) {
+ Some(true)
+ } else {
+ None
+ };
+ // ...which converts it to a string
+ let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS };
+ if let Some(path) = paths.iter().find(|path| match_def_path(cx, did, path));
+ then {
+ let is_to_owned = path.last().unwrap().ends_with("string");
+ return Some(SymbolStrExpr::Expr {
+ item,
+ is_ident,
+ is_to_owned,
+ });
+ }
+ }
+ // is a string constant
+ if let Some(Constant::Str(s)) = constant_simple(cx, cx.typeck_results(), expr) {
+ let value = Symbol::intern(&s).as_u32();
+ // ...which matches a symbol constant
+ if let Some(&def_id) = self.symbol_map.get(&value) {
+ return Some(SymbolStrExpr::Const(def_id));
+ }
+ }
+ None
+ }
+}
+
+enum SymbolStrExpr<'tcx> {
+ /// a string constant with a corresponding symbol constant
+ Const(DefId),
+ /// a "symbol to string" expression like `symbol.as_str()`
+ Expr {
+ /// part that evaluates to `Symbol` or `Ident`
+ item: &'tcx Expr<'tcx>,
+ is_ident: bool,
+ /// whether an owned `String` is created like `to_ident_string()`
+ is_to_owned: bool,
+ },
+}
+
+impl<'tcx> SymbolStrExpr<'tcx> {
+ /// Returns a snippet that evaluates to a `Symbol` and is const if possible
+ fn as_symbol_snippet(&self, cx: &LateContext<'_>) -> Cow<'tcx, str> {
+ match *self {
+ Self::Const(def_id) => cx.tcx.def_path_str(def_id).into(),
+ Self::Expr { item, is_ident, .. } => {
+ let mut snip = snippet(cx, item.span.source_callsite(), "..");
+ if is_ident {
+ // get `Ident.name`
+ snip.to_mut().push_str(".name");
+ }
+ snip
+ },
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
new file mode 100644
index 000000000..25532dd4e
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -0,0 +1,108 @@
+use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::def_path_res;
+use clippy_utils::diagnostics::span_lint;
+use if_chain::if_chain;
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::Item;
+use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self, fast_reject::SimplifiedTypeGen, FloatTy};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::Symbol;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks the paths module for invalid paths.
+ ///
+ /// ### Why is this bad?
+ /// It indicates a bug in the code.
+ ///
+ /// ### Example
+ /// None.
+ pub INVALID_PATHS,
+ internal,
+ "invalid path"
+}
+
+declare_lint_pass!(InvalidPaths => [INVALID_PATHS]);
+
+impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+ let local_def_id = &cx.tcx.parent_module(item.hir_id());
+ let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
+ if_chain! {
+ if mod_name.as_str() == "paths";
+ if let hir::ItemKind::Const(ty, body_id) = item.kind;
+ let ty = hir_ty_to_ty(cx.tcx, ty);
+ if let ty::Array(el_ty, _) = &ty.kind();
+ if let ty::Ref(_, el_ty, _) = &el_ty.kind();
+ if el_ty.is_str();
+ let body = cx.tcx.hir().body(body_id);
+ let typeck_results = cx.tcx.typeck_body(body_id);
+ if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value);
+ let path: Vec<&str> = path
+ .iter()
+ .map(|x| {
+ if let Constant::Str(s) = x {
+ s.as_str()
+ } else {
+ // We checked the type of the constant above
+ unreachable!()
+ }
+ })
+ .collect();
+ if !check_path(cx, &path[..]);
+ then {
+ span_lint(cx, INVALID_PATHS, item.span, "invalid path");
+ }
+ }
+ }
+}
+
+// This is not a complete resolver for paths. It works on all the paths currently used in the paths
+// module. That's all it does and all it needs to do.
+pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
+ if def_path_res(cx, path, None) != Res::Err {
+ return true;
+ }
+
+ // Some implementations can't be found by `path_to_res`, particularly inherent
+ // implementations of native types. Check lang items.
+ let path_syms: Vec<_> = path.iter().map(|p| Symbol::intern(p)).collect();
+ let lang_items = cx.tcx.lang_items();
+ // This list isn't complete, but good enough for our current list of paths.
+ let incoherent_impls = [
+ SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F32),
+ SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F64),
+ SimplifiedTypeGen::SliceSimplifiedType,
+ SimplifiedTypeGen::StrSimplifiedType,
+ ]
+ .iter()
+ .flat_map(|&ty| cx.tcx.incoherent_impls(ty));
+ for item_def_id in lang_items.items().iter().flatten().chain(incoherent_impls) {
+ let lang_item_path = cx.get_def_path(*item_def_id);
+ if path_syms.starts_with(&lang_item_path) {
+ if let [item] = &path_syms[lang_item_path.len()..] {
+ if matches!(
+ cx.tcx.def_kind(*item_def_id),
+ DefKind::Mod | DefKind::Enum | DefKind::Trait
+ ) {
+ for child in cx.tcx.module_children(*item_def_id) {
+ if child.ident.name == *item {
+ return true;
+ }
+ }
+ } else {
+ for child in cx.tcx.associated_item_def_ids(*item_def_id) {
+ if cx.tcx.item_name(*child) == *item {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ false
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
new file mode 100644
index 000000000..0dac64376
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
@@ -0,0 +1,342 @@
+use crate::utils::internal_lints::metadata_collector::is_deprecated_lint;
+use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::macros::root_macro_call_first_node;
+use clippy_utils::{is_lint_allowed, match_def_path, paths};
+use if_chain::if_chain;
+use rustc_ast as ast;
+use rustc_ast::ast::LitKind;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::hir_id::CRATE_HIR_ID;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::nested_filter;
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::source_map::Spanned;
+use rustc_span::symbol::Symbol;
+use rustc_span::{sym, Span};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Ensures every lint is associated to a `LintPass`.
+ ///
+ /// ### Why is this bad?
+ /// The compiler only knows lints via a `LintPass`. Without
+ /// putting a lint to a `LintPass::get_lints()`'s return, the compiler will not
+ /// know the name of the lint.
+ ///
+ /// ### Known problems
+ /// Only checks for lints associated using the
+ /// `declare_lint_pass!`, `impl_lint_pass!`, and `lint_array!` macros.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// declare_lint! { pub LINT_1, ... }
+ /// declare_lint! { pub LINT_2, ... }
+ /// declare_lint! { pub FORGOTTEN_LINT, ... }
+ /// // ...
+ /// declare_lint_pass!(Pass => [LINT_1, LINT_2]);
+ /// // missing FORGOTTEN_LINT
+ /// ```
+ pub LINT_WITHOUT_LINT_PASS,
+ internal,
+ "declaring a lint without associating it in a LintPass"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for cases of an auto-generated lint without an updated description,
+ /// i.e. `default lint description`.
+ ///
+ /// ### Why is this bad?
+ /// Indicates that the lint is not finished.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// declare_lint! { pub COOL_LINT, nursery, "default lint description" }
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust,ignore
+ /// declare_lint! { pub COOL_LINT, nursery, "a great new lint" }
+ /// ```
+ pub DEFAULT_LINT,
+ internal,
+ "found 'default lint description' in a lint declaration"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for invalid `clippy::version` attributes.
+ ///
+ /// Valid values are:
+ /// * "pre 1.29.0"
+ /// * any valid semantic version
+ pub INVALID_CLIPPY_VERSION_ATTRIBUTE,
+ internal,
+ "found an invalid `clippy::version` attribute"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for declared clippy lints without the `clippy::version` attribute.
+ ///
+ pub MISSING_CLIPPY_VERSION_ATTRIBUTE,
+ internal,
+ "found clippy lint without `clippy::version` attribute"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for cases of an auto-generated deprecated lint without an updated reason,
+ /// i.e. `"default deprecation note"`.
+ ///
+ /// ### Why is this bad?
+ /// Indicates that the documentation is incomplete.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// declare_deprecated_lint! {
+ /// /// ### What it does
+ /// /// Nothing. This lint has been deprecated.
+ /// ///
+ /// /// ### Deprecation reason
+ /// /// TODO
+ /// #[clippy::version = "1.63.0"]
+ /// pub COOL_LINT,
+ /// "default deprecation note"
+ /// }
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust,ignore
+ /// declare_deprecated_lint! {
+ /// /// ### What it does
+ /// /// Nothing. This lint has been deprecated.
+ /// ///
+ /// /// ### Deprecation reason
+ /// /// This lint has been replaced by `cooler_lint`
+ /// #[clippy::version = "1.63.0"]
+ /// pub COOL_LINT,
+ /// "this lint has been replaced by `cooler_lint`"
+ /// }
+ /// ```
+ pub DEFAULT_DEPRECATION_REASON,
+ internal,
+ "found 'default deprecation note' in a deprecated lint declaration"
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct LintWithoutLintPass {
+ declared_lints: FxHashMap<Symbol, Span>,
+ registered_lints: FxHashSet<Symbol>,
+}
+
+impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE, DEFAULT_DEPRECATION_REASON]);
+
+impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+ if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id())
+ || is_lint_allowed(cx, DEFAULT_DEPRECATION_REASON, item.hir_id())
+ {
+ return;
+ }
+
+ if let hir::ItemKind::Static(ty, Mutability::Not, body_id) = item.kind {
+ let is_lint_ref_ty = is_lint_ref_type(cx, ty);
+ if is_deprecated_lint(cx, ty) || is_lint_ref_ty {
+ check_invalid_clippy_version_attribute(cx, item);
+
+ let expr = &cx.tcx.hir().body(body_id).value;
+ let fields;
+ if is_lint_ref_ty {
+ if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind
+ && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind {
+ fields = struct_fields;
+ } else {
+ return;
+ }
+ } else if let ExprKind::Struct(_, struct_fields, _) = expr.kind {
+ fields = struct_fields;
+ } else {
+ return;
+ }
+
+ let field = fields
+ .iter()
+ .find(|f| f.ident.as_str() == "desc")
+ .expect("lints must have a description field");
+
+ if let ExprKind::Lit(Spanned {
+ node: LitKind::Str(ref sym, _),
+ ..
+ }) = field.expr.kind
+ {
+ let sym_str = sym.as_str();
+ if is_lint_ref_ty {
+ if sym_str == "default lint description" {
+ span_lint(
+ cx,
+ DEFAULT_LINT,
+ item.span,
+ &format!("the lint `{}` has the default lint description", item.ident.name),
+ );
+ }
+
+ self.declared_lints.insert(item.ident.name, item.span);
+ } else if sym_str == "default deprecation note" {
+ span_lint(
+ cx,
+ DEFAULT_DEPRECATION_REASON,
+ item.span,
+ &format!("the lint `{}` has the default deprecation reason", item.ident.name),
+ );
+ }
+ }
+ }
+ } else if let Some(macro_call) = root_macro_call_first_node(cx, item) {
+ if !matches!(
+ cx.tcx.item_name(macro_call.def_id).as_str(),
+ "impl_lint_pass" | "declare_lint_pass"
+ ) {
+ return;
+ }
+ if let hir::ItemKind::Impl(hir::Impl {
+ of_trait: None,
+ items: impl_item_refs,
+ ..
+ }) = item.kind
+ {
+ let mut collector = LintCollector {
+ output: &mut self.registered_lints,
+ cx,
+ };
+ let body_id = cx.tcx.hir().body_owned_by(
+ cx.tcx.hir().local_def_id(
+ impl_item_refs
+ .iter()
+ .find(|iiref| iiref.ident.as_str() == "get_lints")
+ .expect("LintPass needs to implement get_lints")
+ .id
+ .hir_id(),
+ ),
+ );
+ collector.visit_expr(cx.tcx.hir().body(body_id).value);
+ }
+ }
+ }
+
+ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+ if is_lint_allowed(cx, LINT_WITHOUT_LINT_PASS, CRATE_HIR_ID) {
+ return;
+ }
+
+ for (lint_name, &lint_span) in &self.declared_lints {
+ // When using the `declare_tool_lint!` macro, the original `lint_span`'s
+ // file points to "<rustc macros>".
+ // `compiletest-rs` thinks that's an error in a different file and
+ // just ignores it. This causes the test in compile-fail/lint_pass
+ // not able to capture the error.
+ // Therefore, we need to climb the macro expansion tree and find the
+ // actual span that invoked `declare_tool_lint!`:
+ let lint_span = lint_span.ctxt().outer_expn_data().call_site;
+
+ if !self.registered_lints.contains(lint_name) {
+ span_lint(
+ cx,
+ LINT_WITHOUT_LINT_PASS,
+ lint_span,
+ &format!("the lint `{lint_name}` is not added to any `LintPass`"),
+ );
+ }
+ }
+ }
+}
+
+pub(super) fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &hir::Ty<'_>) -> bool {
+ if let TyKind::Rptr(
+ _,
+ MutTy {
+ ty: inner,
+ mutbl: Mutability::Not,
+ },
+ ) = ty.kind
+ {
+ if let TyKind::Path(ref path) = inner.kind {
+ if let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id) {
+ return match_def_path(cx, def_id, &paths::LINT);
+ }
+ }
+ }
+
+ false
+}
+
+fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'_>) {
+ if let Some(value) = extract_clippy_version_value(cx, item) {
+ // The `sym!` macro doesn't work as it only expects a single token.
+ // It's better to keep it this way and have a direct `Symbol::intern` call here.
+ if value == Symbol::intern("pre 1.29.0") {
+ return;
+ }
+
+ if RustcVersion::parse(value.as_str()).is_err() {
+ span_lint_and_help(
+ cx,
+ INVALID_CLIPPY_VERSION_ATTRIBUTE,
+ item.span,
+ "this item has an invalid `clippy::version` attribute",
+ None,
+ "please use a valid semantic version, see `doc/adding_lints.md`",
+ );
+ }
+ } else {
+ span_lint_and_help(
+ cx,
+ MISSING_CLIPPY_VERSION_ATTRIBUTE,
+ item.span,
+ "this lint is missing the `clippy::version` attribute or version value",
+ None,
+ "please use a `clippy::version` attribute, see `doc/adding_lints.md`",
+ );
+ }
+}
+
+/// This function extracts the version value of a `clippy::version` attribute if the given value has
+/// one
+pub(super) fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Option<Symbol> {
+ let attrs = cx.tcx.hir().attrs(item.hir_id());
+ attrs.iter().find_map(|attr| {
+ if_chain! {
+ // Identify attribute
+ if let ast::AttrKind::Normal(ref attr_kind) = &attr.kind;
+ if let [tool_name, attr_name] = &attr_kind.item.path.segments[..];
+ if tool_name.ident.name == sym::clippy;
+ if attr_name.ident.name == sym::version;
+ if let Some(version) = attr.value_str();
+ then { Some(version) } else { None }
+ }
+ })
+}
+
+struct LintCollector<'a, 'tcx> {
+ output: &'a mut FxHashSet<Symbol>,
+ cx: &'a LateContext<'tcx>,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
+ type NestedFilter = nested_filter::All;
+
+ fn visit_path(&mut self, path: &'tcx Path<'_>, _: HirId) {
+ if path.segments.len() == 1 {
+ self.output.insert(path.segments[0].ident.name);
+ }
+ }
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.cx.tcx.hir()
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 92934c16d..d06a616e4 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -8,7 +8,7 @@
//! a simple mistake)
use crate::renamed_lints::RENAMED_LINTS;
-use crate::utils::internal_lints::{extract_clippy_version_value, is_lint_ref_type};
+use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
@@ -64,46 +64,6 @@ const DEFAULT_LINT_LEVELS: &[(&str, &str)] = &[
/// 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"
- };
-}
-
-macro_rules! RENAMES_SECTION_TEMPLATE {
- () => {
- r#"
-### Past names
-
-{names}
-"#
- };
-}
-macro_rules! RENAME_VALUE_TEMPLATE {
- () => {
- "* `{name}`\n"
- };
-}
-
const LINT_EMISSION_FUNCTIONS: [&[&str]; 7] = [
&["clippy_utils", "diagnostics", "span_lint"],
&["clippy_utils", "diagnostics", "span_lint_and_help"],
@@ -205,7 +165,16 @@ impl MetadataCollector {
.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))
+ .map(|configurations| {
+ format!(
+ r#"
+### Configuration
+This lint has the following configuration variables:
+
+{configurations}
+"#
+ )
+ })
}
}
@@ -291,16 +260,13 @@ fn replace_produces(lint_name: &str, docs: &mut String, clippy_project_root: &Pa
continue;
}
- panic!("lint `{}` has an unterminated code block", lint_name)
+ panic!("lint `{lint_name}` has an unterminated code block")
}
break;
},
Some(line) if line.trim_start() == "{{produces}}" => {
- panic!(
- "lint `{}` has marker {{{{produces}}}} with an ignored or missing code block",
- lint_name
- )
+ panic!("lint `{lint_name}` has marker {{{{produces}}}} with an ignored or missing code block")
},
Some(line) => {
let line = line.trim();
@@ -319,7 +285,7 @@ fn replace_produces(lint_name: &str, docs: &mut String, clippy_project_root: &Pa
match lines.next() {
Some(line) if line.trim_start() == "```" => break,
Some(line) => example.push(line),
- None => panic!("lint `{}` has an unterminated code block", lint_name),
+ None => panic!("lint `{lint_name}` has an unterminated code block"),
}
}
@@ -336,10 +302,9 @@ fn replace_produces(lint_name: &str, docs: &mut String, clippy_project_root: &Pa
<summary>Produces</summary>\n\
\n\
```text\n\
- {}\n\
+ {output}\n\
```\n\
- </details>",
- output
+ </details>"
),
);
@@ -394,7 +359,7 @@ fn get_lint_output(lint_name: &str, example: &[&mut String], clippy_project_root
panic!("failed to write to `{}`: {e}", file.as_path().to_string_lossy());
}
- let prefixed_name = format!("{}{lint_name}", CLIPPY_LINT_GROUP_PREFIX);
+ let prefixed_name = format!("{CLIPPY_LINT_GROUP_PREFIX}{lint_name}");
let mut cmd = Command::new("cargo");
@@ -417,7 +382,7 @@ fn get_lint_output(lint_name: &str, example: &[&mut String], clippy_project_root
let output = cmd
.arg(file.as_path())
.output()
- .unwrap_or_else(|e| panic!("failed to run `{:?}`: {e}", cmd));
+ .unwrap_or_else(|e| panic!("failed to run `{cmd:?}`: {e}"));
let tmp_file_path = file.to_string_lossy();
let stderr = std::str::from_utf8(&output.stderr).unwrap();
@@ -441,8 +406,7 @@ fn get_lint_output(lint_name: &str, example: &[&mut String], clippy_project_root
let rendered: Vec<&str> = msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
let non_json: Vec<&str> = stderr.lines().filter(|line| !line.starts_with('{')).collect();
panic!(
- "did not find lint `{}` in output of example, got:\n{}\n{}",
- lint_name,
+ "did not find lint `{lint_name}` in output of example, got:\n{}\n{}",
non_json.join("\n"),
rendered.join("\n")
);
@@ -568,7 +532,11 @@ fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
// Extract lints
doc_comment.make_ascii_lowercase();
- let lints: Vec<String> = doc_comment.split_off(DOC_START.len()).split(", ").map(str::to_string).collect();
+ 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
@@ -588,13 +556,10 @@ fn to_kebab(config_name: &str) -> String {
impl fmt::Display for ClippyConfiguration {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
- write!(
+ writeln!(
f,
- CONFIGURATION_VALUE_TEMPLATE!(),
- name = self.name,
- ty = self.config_type,
- doc = self.doc,
- default = self.default
+ "* `{}`: `{}`: {} (defaults to `{}`)",
+ self.name, self.config_type, self.doc, self.default
)
}
}
@@ -619,7 +584,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
if_chain! {
// item validation
if is_lint_ref_type(cx, ty);
- // blacklist check
+ // disallow check
let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
// metadata extraction
@@ -644,7 +609,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
if_chain! {
if is_deprecated_lint(cx, ty);
- // blacklist check
+ // disallow 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
@@ -797,7 +762,7 @@ fn get_lint_group_and_level_or_lint(
let result = cx.lint_store.check_lint_name(
lint_name,
Some(sym::clippy),
- &[Ident::with_dummy_span(sym::clippy)].into_iter().collect(),
+ &std::iter::once(Ident::with_dummy_span(sym::clippy)).collect(),
);
if let CheckLintNameResult::Tool(Ok(lint_lst)) = result {
if let Some(group) = get_lint_group(cx, lint_lst[0]) {
@@ -811,7 +776,7 @@ fn get_lint_group_and_level_or_lint(
lint_collection_error_item(
cx,
item,
- &format!("Unable to determine lint level for found group `{}`", group),
+ &format!("Unable to determine lint level for found group `{group}`"),
);
None
}
@@ -869,7 +834,7 @@ fn collect_renames(lints: &mut Vec<LintMetadata>) {
if name == lint_name;
if let Some(past_name) = k.strip_prefix(CLIPPY_LINT_GROUP_PREFIX);
then {
- write!(collected, RENAME_VALUE_TEMPLATE!(), name = past_name).unwrap();
+ writeln!(collected, "* `{past_name}`").unwrap();
names.push(past_name.to_string());
}
}
@@ -882,7 +847,15 @@ fn collect_renames(lints: &mut Vec<LintMetadata>) {
}
if !collected.is_empty() {
- write!(&mut lint.docs, RENAMES_SECTION_TEMPLATE!(), names = collected).unwrap();
+ write!(
+ &mut lint.docs,
+ r#"
+### Past names
+
+{collected}
+"#
+ )
+ .unwrap();
}
}
}
@@ -895,7 +868,7 @@ fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &s
cx,
INTERNAL_METADATA_COLLECTOR,
item.ident.span,
- &format!("metadata collection error for `{}`: {}", item.ident.name, message),
+ &format!("metadata collection error for `{}`: {message}", item.ident.name),
);
}
@@ -1145,8 +1118,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> {
self.add_single_span_suggestion();
}
},
- ExprKind::MethodCall(path, arg, _arg_span) => {
- let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&arg[0]));
+ ExprKind::MethodCall(path, recv, _, _arg_span) => {
+ let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(recv));
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 {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
new file mode 100644
index 000000000..1e994e3f2
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
@@ -0,0 +1,63 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::match_type;
+use clippy_utils::{match_def_path, paths};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::ty::{self, subst::GenericArgKind};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Check that the `extract_msrv_attr!` macro is used, when a lint has a MSRV.
+ ///
+ pub MISSING_MSRV_ATTR_IMPL,
+ internal,
+ "checking if all necessary steps were taken when adding a MSRV to a lint"
+}
+
+declare_lint_pass!(MsrvAttrImpl => [MISSING_MSRV_ATTR_IMPL]);
+
+impl LateLintPass<'_> for MsrvAttrImpl {
+ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
+ if_chain! {
+ if let hir::ItemKind::Impl(hir::Impl {
+ of_trait: Some(lint_pass_trait_ref),
+ self_ty,
+ items,
+ ..
+ }) = &item.kind;
+ if let Some(lint_pass_trait_def_id) = lint_pass_trait_ref.trait_def_id();
+ let is_late_pass = match_def_path(cx, lint_pass_trait_def_id, &paths::LATE_LINT_PASS);
+ if is_late_pass || match_def_path(cx, lint_pass_trait_def_id, &paths::EARLY_LINT_PASS);
+ let self_ty = hir_ty_to_ty(cx.tcx, self_ty);
+ if let ty::Adt(self_ty_def, _) = self_ty.kind();
+ if self_ty_def.is_struct();
+ if self_ty_def.all_fields().any(|f| {
+ cx.tcx
+ .type_of(f.did)
+ .walk()
+ .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
+ .any(|t| match_type(cx, t.expect_ty(), &paths::RUSTC_VERSION))
+ });
+ if !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs));
+ then {
+ let context = if is_late_pass { "LateContext" } else { "EarlyContext" };
+ let lint_pass = if is_late_pass { "LateLintPass" } else { "EarlyLintPass" };
+ let span = cx.sess().source_map().span_through_char(item.span, '{');
+ span_lint_and_sugg(
+ cx,
+ MISSING_MSRV_ATTR_IMPL,
+ span,
+ &format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"),
+ &format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"),
+ format!("{}\n extract_msrv_attr!({context});", snippet(cx, span, "..")),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs
new file mode 100644
index 000000000..2b13fad80
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs
@@ -0,0 +1,62 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::match_type;
+use clippy_utils::{is_lint_allowed, method_calls, paths};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::Symbol;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for calls to `cx.outer().expn_data()` and suggests to use
+ /// the `cx.outer_expn_data()`
+ ///
+ /// ### Why is this bad?
+ /// `cx.outer_expn_data()` is faster and more concise.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// expr.span.ctxt().outer().expn_data()
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust,ignore
+ /// expr.span.ctxt().outer_expn_data()
+ /// ```
+ pub OUTER_EXPN_EXPN_DATA,
+ internal,
+ "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`"
+}
+
+declare_lint_pass!(OuterExpnDataPass => [OUTER_EXPN_EXPN_DATA]);
+
+impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+ if is_lint_allowed(cx, OUTER_EXPN_EXPN_DATA, expr.hir_id) {
+ return;
+ }
+
+ let (method_names, arg_lists, spans) = method_calls(expr, 2);
+ let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect();
+ if_chain! {
+ if let ["expn_data", "outer_expn"] = method_names.as_slice();
+ let (self_arg, args) = arg_lists[1];
+ if args.is_empty();
+ let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
+ if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
+ then {
+ span_lint_and_sugg(
+ cx,
+ OUTER_EXPN_EXPN_DATA,
+ spans[1].with_hi(expr.span.hi()),
+ "usage of `outer_expn().expn_data()`",
+ "try",
+ "outer_expn_data()".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs
new file mode 100644
index 000000000..5899b94e1
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs
@@ -0,0 +1,37 @@
+use rustc_ast::ast::NodeId;
+use rustc_ast::visit::FnKind;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Not an actual lint. This lint is only meant for testing our customized internal compiler
+ /// error message by calling `panic`.
+ ///
+ /// ### Why is this bad?
+ /// ICE in large quantities can damage your teeth
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// 🍦🍦🍦🍦🍦
+ /// ```
+ pub PRODUCE_ICE,
+ internal,
+ "this message should not appear anywhere as we ICE before and don't emit the lint"
+}
+
+declare_lint_pass!(ProduceIce => [PRODUCE_ICE]);
+
+impl EarlyLintPass for ProduceIce {
+ fn check_fn(&mut self, _: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
+ assert!(!is_trigger_fn(fn_kind), "Would you like some help with that?");
+ }
+}
+
+fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool {
+ match fn_kind {
+ FnKind::Fn(_, ident, ..) => ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy",
+ FnKind::Closure(..) => false,
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
new file mode 100644
index 000000000..4cf76f536
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -0,0 +1,343 @@
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{def_path_res, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs};
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Namespace, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{Expr, ExprKind, Local, Mutability, Node};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::mir::interpret::{Allocation, ConstValue, GlobalAlloc};
+use rustc_middle::ty::{self, AssocKind, DefIdTree, Ty};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::Span;
+
+use std::str;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usages of def paths when a diagnostic item or a `LangItem` could be used.
+ ///
+ /// ### Why is this bad?
+ /// The path for an item is subject to change and is less efficient to look up than a
+ /// diagnostic item or a `LangItem`.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// utils::match_type(cx, ty, &paths::VEC)
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust,ignore
+ /// utils::is_type_diagnostic_item(cx, ty, sym::Vec)
+ /// ```
+ pub UNNECESSARY_DEF_PATH,
+ internal,
+ "using a def path when a diagnostic item or a `LangItem` is available"
+}
+
+impl_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]);
+
+#[derive(Default)]
+pub struct UnnecessaryDefPath {
+ array_def_ids: FxHashSet<(DefId, Span)>,
+ linted_def_ids: FxHashSet<DefId>,
+}
+
+impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+ if is_lint_allowed(cx, UNNECESSARY_DEF_PATH, expr.hir_id) {
+ return;
+ }
+
+ match expr.kind {
+ ExprKind::Call(func, args) => self.check_call(cx, func, args, expr.span),
+ ExprKind::Array(elements) => self.check_array(cx, elements, expr.span),
+ _ => {},
+ }
+ }
+
+ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+ for &(def_id, span) in &self.array_def_ids {
+ if self.linted_def_ids.contains(&def_id) {
+ continue;
+ }
+
+ let (msg, sugg) = if let Some(sym) = cx.tcx.get_diagnostic_name(def_id) {
+ ("diagnostic item", format!("sym::{sym}"))
+ } else if let Some(sym) = get_lang_item_name(cx, def_id) {
+ ("language item", format!("LangItem::{sym}"))
+ } else {
+ continue;
+ };
+
+ span_lint_and_help(
+ cx,
+ UNNECESSARY_DEF_PATH,
+ span,
+ &format!("hardcoded path to a {msg}"),
+ None,
+ &format!("convert all references to use `{sugg}`"),
+ );
+ }
+ }
+}
+
+impl UnnecessaryDefPath {
+ #[allow(clippy::too_many_lines)]
+ fn check_call(&mut self, cx: &LateContext<'_>, func: &Expr<'_>, args: &[Expr<'_>], span: Span) {
+ enum Item {
+ LangItem(Symbol),
+ DiagnosticItem(Symbol),
+ }
+ static PATHS: &[&[&str]] = &[
+ &["clippy_utils", "match_def_path"],
+ &["clippy_utils", "match_trait_method"],
+ &["clippy_utils", "ty", "match_type"],
+ &["clippy_utils", "is_expr_path_def_path"],
+ ];
+
+ if_chain! {
+ if let [cx_arg, def_arg, args @ ..] = args;
+ if let ExprKind::Path(path) = &func.kind;
+ if let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id();
+ if let Some(which_path) = match_any_def_paths(cx, id, PATHS);
+ let item_arg = if which_path == 4 { &args[1] } else { &args[0] };
+ // Extract the path to the matched type
+ if let Some(segments) = path_to_matched_type(cx, item_arg);
+ let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
+ if let Some(def_id) = inherent_def_path_res(cx, &segments[..]);
+ then {
+ // Check if the target item is a diagnostic item or LangItem.
+ #[rustfmt::skip]
+ let (msg, item) = if let Some(item_name)
+ = cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id)
+ {
+ (
+ "use of a def path to a diagnostic item",
+ Item::DiagnosticItem(*item_name),
+ )
+ } else if let Some(item_name) = get_lang_item_name(cx, def_id) {
+ (
+ "use of a def path to a `LangItem`",
+ Item::LangItem(item_name),
+ )
+ } else {
+ return;
+ };
+
+ let has_ctor = match cx.tcx.def_kind(def_id) {
+ DefKind::Struct => {
+ let variant = cx.tcx.adt_def(def_id).non_enum_variant();
+ variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
+ },
+ DefKind::Variant => {
+ let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id);
+ variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
+ },
+ _ => false,
+ };
+
+ let mut app = Applicability::MachineApplicable;
+ let cx_snip = snippet_with_applicability(cx, cx_arg.span, "..", &mut app);
+ let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app);
+ let (sugg, with_note) = match (which_path, item) {
+ // match_def_path
+ (0, Item::DiagnosticItem(item)) => (
+ format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"),
+ has_ctor,
+ ),
+ (0, Item::LangItem(item)) => (
+ format!("{cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some({def_snip})"),
+ has_ctor,
+ ),
+ // match_trait_method
+ (1, Item::DiagnosticItem(item)) => {
+ (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false)
+ },
+ // match_type
+ (2, Item::DiagnosticItem(item)) => (
+ format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"),
+ false,
+ ),
+ (2, Item::LangItem(item)) => (
+ format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"),
+ false,
+ ),
+ // is_expr_path_def_path
+ (3, Item::DiagnosticItem(item)) if has_ctor => (
+ format!("is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})",),
+ false,
+ ),
+ (3, Item::LangItem(item)) if has_ctor => (
+ format!("is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})",),
+ false,
+ ),
+ (3, Item::DiagnosticItem(item)) => (
+ format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"),
+ false,
+ ),
+ (3, Item::LangItem(item)) => (
+ format!(
+ "path_res({cx_snip}, {def_snip}).opt_def_id()\
+ .map_or(false, |id| {cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some(id))",
+ ),
+ false,
+ ),
+ _ => return,
+ };
+
+ span_lint_and_then(cx, UNNECESSARY_DEF_PATH, span, msg, |diag| {
+ diag.span_suggestion(span, "try", sugg, app);
+ if with_note {
+ diag.help(
+ "if this `DefId` came from a constructor expression or pattern then the \
+ parent `DefId` should be used instead",
+ );
+ }
+ });
+
+ self.linted_def_ids.insert(def_id);
+ }
+ }
+ }
+
+ fn check_array(&mut self, cx: &LateContext<'_>, elements: &[Expr<'_>], span: Span) {
+ let Some(path) = path_from_array(elements) else { return };
+
+ if let Some(def_id) = inherent_def_path_res(cx, &path.iter().map(AsRef::as_ref).collect::<Vec<_>>()) {
+ self.array_def_ids.insert((def_id, span));
+ }
+ }
+}
+
+fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<String>> {
+ match peel_hir_expr_refs(expr).0.kind {
+ ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) {
+ Res::Local(hir_id) => {
+ let parent_id = cx.tcx.hir().get_parent_node(hir_id);
+ if let Some(Node::Local(Local { init: Some(init), .. })) = cx.tcx.hir().find(parent_id) {
+ path_to_matched_type(cx, init)
+ } else {
+ None
+ }
+ },
+ Res::Def(DefKind::Static(_), def_id) => read_mir_alloc_def_path(
+ cx,
+ cx.tcx.eval_static_initializer(def_id).ok()?.inner(),
+ cx.tcx.type_of(def_id),
+ ),
+ Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? {
+ ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => {
+ read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id))
+ },
+ _ => None,
+ },
+ _ => None,
+ },
+ ExprKind::Array(exprs) => path_from_array(exprs),
+ _ => None,
+ }
+}
+
+fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option<Vec<String>> {
+ let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() {
+ let &alloc = alloc.provenance().values().next()?;
+ if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) {
+ (alloc.inner(), ty)
+ } else {
+ return None;
+ }
+ } else {
+ (alloc, ty)
+ };
+
+ if let ty::Array(ty, _) | ty::Slice(ty) = *ty.kind()
+ && let ty::Ref(_, ty, Mutability::Not) = *ty.kind()
+ && ty.is_str()
+ {
+ alloc
+ .provenance()
+ .values()
+ .map(|&alloc| {
+ if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) {
+ let alloc = alloc.inner();
+ str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()))
+ .ok().map(ToOwned::to_owned)
+ } else {
+ None
+ }
+ })
+ .collect()
+ } else {
+ None
+ }
+}
+
+fn path_from_array(exprs: &[Expr<'_>]) -> Option<Vec<String>> {
+ exprs
+ .iter()
+ .map(|expr| {
+ if let ExprKind::Lit(lit) = &expr.kind {
+ if let LitKind::Str(sym, _) = lit.node {
+ return Some((*sym.as_str()).to_owned());
+ }
+ }
+
+ None
+ })
+ .collect()
+}
+
+// def_path_res will match field names before anything else, but for this we want to match
+// inherent functions first.
+fn inherent_def_path_res(cx: &LateContext<'_>, segments: &[&str]) -> Option<DefId> {
+ def_path_res(cx, segments, None).opt_def_id().map(|def_id| {
+ if cx.tcx.def_kind(def_id) == DefKind::Field {
+ let method_name = *segments.last().unwrap();
+ cx.tcx
+ .def_key(def_id)
+ .parent
+ .and_then(|parent_idx| {
+ cx.tcx
+ .inherent_impls(DefId {
+ index: parent_idx,
+ krate: def_id.krate,
+ })
+ .iter()
+ .find_map(|impl_id| {
+ cx.tcx.associated_items(*impl_id).find_by_name_and_kind(
+ cx.tcx,
+ Ident::from_str(method_name),
+ AssocKind::Fn,
+ *impl_id,
+ )
+ })
+ })
+ .map_or(def_id, |item| item.def_id)
+ } else {
+ def_id
+ }
+ })
+}
+
+fn get_lang_item_name(cx: &LateContext<'_>, def_id: DefId) -> Option<Symbol> {
+ if let Some(lang_item) = cx.tcx.lang_items().items().iter().position(|id| *id == Some(def_id)) {
+ let lang_items = def_path_res(cx, &["rustc_hir", "lang_items", "LangItem"], Some(Namespace::TypeNS)).def_id();
+ let item_name = cx
+ .tcx
+ .adt_def(lang_items)
+ .variants()
+ .iter()
+ .nth(lang_item)
+ .unwrap()
+ .name;
+ Some(item_name)
+ } else {
+ None
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index d77a21d66..bd5be0c9d 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -100,7 +100,7 @@ impl VecPushSearcher {
|| get_parent_expr(cx, last_place)
.map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _)));
},
- ExprKind::MethodCall(_, [recv, ..], _)
+ ExprKind::MethodCall(_, recv, ..)
if recv.hir_id == e.hir_id
&& adjusted_mut == Mutability::Mut
&& !adjusted_ty.peel_refs().is_slice() =>
@@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
if let Some(init_expr) = local.init
- && let PatKind::Binding(BindingAnnotation::Mutable, id, name, None) = local.pat.kind
+ && let PatKind::Binding(BindingAnnotation::MUT, id, name, None) = local.pat.kind
&& !in_external_macro(cx.sess(), local.span)
&& let Some(init) = get_vec_init_kind(cx, init_expr)
&& !matches!(init, VecInitKind::WithExprCapacity(_))
@@ -201,7 +201,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
if let Some(searcher) = self.searcher.take() {
if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
- && let ExprKind::MethodCall(name, [self_arg, _], _) = expr.kind
+ && let ExprKind::MethodCall(name, self_arg, [_], _) = expr.kind
&& path_to_local_id(self_arg, searcher.local_id)
&& name.ident.as_str() == "push"
{
diff --git a/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs
deleted file mode 100644
index 0fee3e812..000000000
--- a/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{match_def_path, paths};
-use if_chain::if_chain;
-use rustc_ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Spanned;
-
-declare_clippy_lint! {
- /// ### What it does
- /// Finds occurrences of `Vec::resize(0, an_int)`
- ///
- /// ### Why is this bad?
- /// This is probably an argument inversion mistake.
- ///
- /// ### Example
- /// ```rust
- /// vec!(1, 2, 3, 4, 5).resize(0, 5)
- /// ```
- ///
- /// Use instead:
- /// ```rust
- /// vec!(1, 2, 3, 4, 5).clear()
- /// ```
- #[clippy::version = "1.46.0"]
- pub VEC_RESIZE_TO_ZERO,
- correctness,
- "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake"
-}
-
-declare_lint_pass!(VecResizeToZero => [VEC_RESIZE_TO_ZERO]);
-
-impl<'tcx> LateLintPass<'tcx> for VecResizeToZero {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if_chain! {
- if let hir::ExprKind::MethodCall(path_segment, args, _) = expr.kind;
- if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if match_def_path(cx, method_def_id, &paths::VEC_RESIZE) && args.len() == 3;
- if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = args[1].kind;
- if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = args[2].kind;
- then {
- let method_call_span = expr.span.with_lo(path_segment.ident.span.lo());
- span_lint_and_then(
- cx,
- VEC_RESIZE_TO_ZERO,
- expr.span,
- "emptying a vector with `resize`",
- |db| {
- db.help("the arguments may be inverted...");
- db.span_suggestion(
- method_call_span,
- "...or you can empty the vector with",
- "clear()".to_string(),
- Applicability::MaybeIncorrect,
- );
- },
- );
- }
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
deleted file mode 100644
index 8e2ddd225..000000000
--- a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
+++ /dev/null
@@ -1,88 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::paths;
-use clippy_utils::ty::match_type;
-use if_chain::if_chain;
-use rustc_hir::{Expr, ExprKind, QPath};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for use of File::read_to_end and File::read_to_string.
- ///
- /// ### Why is this bad?
- /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values.
- /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html)
- ///
- /// ### Example
- /// ```rust,no_run
- /// # use std::io::Read;
- /// # use std::fs::File;
- /// let mut f = File::open("foo.txt").unwrap();
- /// let mut bytes = Vec::new();
- /// f.read_to_end(&mut bytes).unwrap();
- /// ```
- /// Can be written more concisely as
- /// ```rust,no_run
- /// # use std::fs;
- /// let mut bytes = fs::read("foo.txt").unwrap();
- /// ```
- #[clippy::version = "1.44.0"]
- pub VERBOSE_FILE_READS,
- restriction,
- "use of `File::read_to_end` or `File::read_to_string`"
-}
-
-declare_lint_pass!(VerboseFileReads => [VERBOSE_FILE_READS]);
-
-impl<'tcx> LateLintPass<'tcx> for VerboseFileReads {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if is_file_read_to_end(cx, expr) {
- span_lint_and_help(
- cx,
- VERBOSE_FILE_READS,
- expr.span,
- "use of `File::read_to_end`",
- None,
- "consider using `fs::read` instead",
- );
- } else if is_file_read_to_string(cx, expr) {
- span_lint_and_help(
- cx,
- VERBOSE_FILE_READS,
- expr.span,
- "use of `File::read_to_string`",
- None,
- "consider using `fs::read_to_string` instead",
- );
- }
- }
-}
-
-fn is_file_read_to_end<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
- if_chain! {
- if let ExprKind::MethodCall(method_name, exprs, _) = expr.kind;
- if method_name.ident.as_str() == "read_to_end";
- if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind;
- let ty = cx.typeck_results().expr_ty(&exprs[0]);
- if match_type(cx, ty, &paths::FILE);
- then {
- return true
- }
- }
- false
-}
-
-fn is_file_read_to_string<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
- if_chain! {
- if let ExprKind::MethodCall(method_name, exprs, _) = expr.kind;
- if method_name.ident.as_str() == "read_to_string";
- if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind;
- let ty = cx.typeck_results().expr_ty(&exprs[0]);
- if match_type(cx, ty, &paths::FILE);
- then {
- return true
- }
- }
- false
-}
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 5418eca38..be9834447 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -120,14 +120,14 @@ impl LateLintPass<'_> for WildcardImports {
if is_test_module_or_function(cx.tcx, item) {
self.test_modules_deep = self.test_modules_deep.saturating_add(1);
}
- let module = cx.tcx.parent_module_from_def_id(item.def_id);
- if cx.tcx.visibility(item.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
+ let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id);
+ if cx.tcx.visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
return;
}
if_chain! {
if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind;
if self.warn_on_all || !self.check_exceptions(item, use_path.segments);
- let used_imports = cx.tcx.names_imported_by_glob_use(item.def_id);
+ let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id);
if !used_imports.is_empty(); // Already handled by `unused_imports`
then {
let mut applicability = Applicability::MachineApplicable;
@@ -173,7 +173,7 @@ impl LateLintPass<'_> for WildcardImports {
let sugg = if braced_glob {
imports_string
} else {
- format!("{}::{}", import_source_snippet, imports_string)
+ format!("{import_source_snippet}::{imports_string}")
};
let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res {
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 32718200c..36574198f 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -1,19 +1,12 @@
-use std::borrow::Cow;
-use std::iter;
-use std::ops::{Deref, Range};
-
-use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::{snippet_opt, snippet_with_applicability};
-use rustc_ast::ast::{Expr, ExprKind, Impl, Item, ItemKind, MacCall, Path, StrLit, StrStyle};
-use rustc_ast::token::{self, LitKind};
-use rustc_ast::tokenstream::TokenStream;
-use rustc_errors::{Applicability, DiagnosticBuilder};
-use rustc_lexer::unescape::{self, EscapeError};
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_parse::parser;
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn, MacroCall};
+use clippy_utils::source::{expand_past_previous_comma, snippet_opt};
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, HirIdMap, Impl, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::symbol::{kw, Symbol};
-use rustc_span::{sym, BytePos, InnerSpan, Span, DUMMY_SP};
+use rustc_span::{sym, BytePos};
declare_clippy_lint! {
/// ### What it does
@@ -73,13 +66,7 @@ declare_clippy_lint! {
/// application and might forget to remove those prints afterward.
///
/// ### Known problems
- /// * Only catches `print!` and `println!` calls.
- /// * The lint level is unaffected by crate attributes. The level can still
- /// be set for functions, modules and other items. To change the level for
- /// the entire crate, please use command line flags. More information and a
- /// configuration example can be found in [clippy#6610].
- ///
- /// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
+ /// Only catches `print!` and `println!` calls.
///
/// ### Example
/// ```rust
@@ -101,13 +88,7 @@ declare_clippy_lint! {
/// application and might forget to remove those prints afterward.
///
/// ### Known problems
- /// * Only catches `eprint!` and `eprintln!` calls.
- /// * The lint level is unaffected by crate attributes. The level can still
- /// be set for functions, modules and other items. To change the level for
- /// the entire crate, please use command line flags. More information and a
- /// configuration example can be found in [clippy#6610].
- ///
- /// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
+ /// Only catches `eprint!` and `eprintln!` calls.
///
/// ### Example
/// ```rust
@@ -148,10 +129,6 @@ declare_clippy_lint! {
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
- /// ### Known problems
- /// Will also warn with macro calls as arguments that expand to literals
- /// -- e.g., `println!("{}", env!("FOO"))`.
- ///
/// ### Example
/// ```rust
/// println!("{}", "foo");
@@ -233,10 +210,6 @@ declare_clippy_lint! {
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
- /// ### Known problems
- /// Will also warn with macro calls as arguments that expand to literals
- /// -- e.g., `writeln!(buf, "{}", env!("FOO"))`.
- ///
/// ### Example
/// ```rust
/// # use std::fmt::Write;
@@ -270,440 +243,302 @@ impl_lint_pass!(Write => [
PRINT_LITERAL,
WRITE_WITH_NEWLINE,
WRITELN_EMPTY_STRING,
- WRITE_LITERAL
+ WRITE_LITERAL,
]);
-impl EarlyLintPass for Write {
- fn check_item(&mut self, _: &EarlyContext<'_>, item: &Item) {
- if let ItemKind::Impl(box Impl {
- of_trait: Some(trait_ref),
- ..
- }) = &item.kind
- {
- let trait_name = trait_ref
- .path
- .segments
- .iter()
- .last()
- .expect("path has at least one segment")
- .ident
- .name;
- if trait_name == sym::Debug {
- self.in_debug_impl = true;
- }
+impl<'tcx> LateLintPass<'tcx> for Write {
+ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+ if is_debug_impl(cx, item) {
+ self.in_debug_impl = true;
}
}
- fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &Item) {
- self.in_debug_impl = false;
+ fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+ if is_debug_impl(cx, item) {
+ self.in_debug_impl = false;
+ }
}
- fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) {
- fn is_build_script(cx: &EarlyContext<'_>) -> bool {
- // Cargo sets the crate name for build scripts to `build_script_build`
- cx.sess()
- .opts
- .crate_name
- .as_ref()
- .map_or(false, |crate_name| crate_name == "build_script_build")
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
+ let Some(diag_name) = cx.tcx.get_diagnostic_name(macro_call.def_id) else { return };
+ let Some(name) = diag_name.as_str().strip_suffix("_macro") else { return };
+
+ let is_build_script = cx
+ .sess()
+ .opts
+ .crate_name
+ .as_ref()
+ .map_or(false, |crate_name| crate_name == "build_script_build");
+
+ match diag_name {
+ sym::print_macro | sym::println_macro => {
+ if !is_build_script {
+ span_lint(cx, PRINT_STDOUT, macro_call.span, &format!("use of `{name}!`"));
+ }
+ },
+ sym::eprint_macro | sym::eprintln_macro => {
+ span_lint(cx, PRINT_STDERR, macro_call.span, &format!("use of `{name}!`"));
+ },
+ sym::write_macro | sym::writeln_macro => {},
+ _ => return,
}
- if mac.path == sym!(print) {
- if !is_build_script(cx) {
- span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`");
- }
- self.lint_print_with_newline(cx, mac);
- } else if mac.path == sym!(println) {
- if !is_build_script(cx) {
- span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
- }
- self.lint_println_empty_string(cx, mac);
- } else if mac.path == sym!(eprint) {
- span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprint!`");
- self.lint_print_with_newline(cx, mac);
- } else if mac.path == sym!(eprintln) {
- span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`");
- self.lint_println_empty_string(cx, mac);
- } else if mac.path == sym!(write) {
- if let (Some(fmt_str), dest) = self.check_tts(cx, mac.args.inner_tokens(), true) {
- if check_newlines(&fmt_str) {
- let (nl_span, only_nl) = newline_span(&fmt_str);
- let nl_span = match (dest, only_nl) {
- // Special case of `write!(buf, "\n")`: Mark everything from the end of
- // `buf` for removal so no trailing comma [`writeln!(buf, )`] remains.
- (Some(dest_expr), true) => nl_span.with_lo(dest_expr.span.hi()),
- _ => nl_span,
- };
- span_lint_and_then(
- cx,
- WRITE_WITH_NEWLINE,
- mac.span(),
- "using `write!()` with a format string that ends in a single newline",
- |err| {
- err.multipart_suggestion(
- "use `writeln!()` instead",
- vec![(mac.path.span, String::from("writeln")), (nl_span, String::new())],
- Applicability::MachineApplicable,
- );
- },
- );
- }
- }
- } else if mac.path == sym!(writeln) {
- if let (Some(fmt_str), expr) = self.check_tts(cx, mac.args.inner_tokens(), true) {
- if fmt_str.symbol == kw::Empty {
- let mut applicability = Applicability::MachineApplicable;
- let suggestion = if let Some(e) = expr {
- snippet_with_applicability(cx, e.span, "v", &mut applicability)
- } else {
- applicability = Applicability::HasPlaceholders;
- Cow::Borrowed("v")
- };
-
- span_lint_and_sugg(
- cx,
- WRITELN_EMPTY_STRING,
- mac.span(),
- format!("using `writeln!({}, \"\")`", suggestion).as_str(),
- "replace it with",
- format!("writeln!({})", suggestion),
- applicability,
- );
+ let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn) else { return };
+
+ // ignore `writeln!(w)` and `write!(v, some_macro!())`
+ if format_args.format_string.span.from_expansion() {
+ return;
+ }
+
+ match diag_name {
+ sym::print_macro | sym::eprint_macro | sym::write_macro => {
+ check_newline(cx, &format_args, &macro_call, name);
+ },
+ sym::println_macro | sym::eprintln_macro | sym::writeln_macro => {
+ check_empty_string(cx, &format_args, &macro_call, name);
+ },
+ _ => {},
+ }
+
+ check_literal(cx, &format_args, name);
+
+ if !self.in_debug_impl {
+ for arg in &format_args.args {
+ if arg.format.r#trait == sym::Debug {
+ span_lint(cx, USE_DEBUG, arg.span, "use of `Debug`-based formatting");
}
}
}
}
}
-
-/// Given a format string that ends in a newline and its span, calculates the span of the
-/// newline, or the format string itself if the format string consists solely of a newline.
-/// Return this and a boolean indicating whether it only consisted of a newline.
-fn newline_span(fmtstr: &StrLit) -> (Span, bool) {
- let sp = fmtstr.span;
- let contents = fmtstr.symbol.as_str();
-
- if contents == r"\n" {
- return (sp, true);
+fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
+ if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), .. }) = &item.kind
+ && let Some(trait_id) = trait_ref.trait_def_id()
+ {
+ cx.tcx.is_diagnostic_item(sym::Debug, trait_id)
+ } else {
+ false
}
+}
- let newline_sp_hi = sp.hi()
- - match fmtstr.style {
- StrStyle::Cooked => BytePos(1),
- StrStyle::Raw(hashes) => BytePos((1 + hashes).into()),
- };
+fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_call: &MacroCall, name: &str) {
+ let format_string_parts = &format_args.format_string.parts;
+ let mut format_string_span = format_args.format_string.span;
- let newline_sp_len = if contents.ends_with('\n') {
- BytePos(1)
- } else if contents.ends_with(r"\n") {
- BytePos(2)
- } else {
- panic!("expected format string to contain a newline");
+ let Some(last) = format_string_parts.last() else { return };
+
+ let count_vertical_whitespace = || {
+ format_string_parts
+ .iter()
+ .flat_map(|part| part.as_str().chars())
+ .filter(|ch| matches!(ch, '\r' | '\n'))
+ .count()
};
- (sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi), false)
-}
+ if last.as_str().ends_with('\n')
+ // ignore format strings with other internal vertical whitespace
+ && count_vertical_whitespace() == 1
-/// Stores a list of replacement spans for each argument, but only if all the replacements used an
-/// empty format string.
-#[derive(Default)]
-struct SimpleFormatArgs {
- unnamed: Vec<Vec<Span>>,
- named: Vec<(Symbol, Vec<Span>)>,
-}
-impl SimpleFormatArgs {
- fn get_unnamed(&self) -> impl Iterator<Item = &[Span]> {
- self.unnamed.iter().map(|x| match x.as_slice() {
- // Ignore the dummy span added from out of order format arguments.
- [DUMMY_SP] => &[],
- x => x,
- })
- }
+ // ignore trailing arguments: `print!("Issue\n{}", 1265);`
+ && format_string_parts.len() > format_args.args.len()
+ {
+ let lint = if name == "write" {
+ format_string_span = expand_past_previous_comma(cx, format_string_span);
- fn get_named(&self, n: &Path) -> &[Span] {
- self.named.iter().find(|x| *n == x.0).map_or(&[], |x| x.1.as_slice())
- }
-
- fn push(&mut self, arg: rustc_parse_format::Argument<'_>, span: Span) {
- use rustc_parse_format::{
- AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec,
+ WRITE_WITH_NEWLINE
+ } else {
+ PRINT_WITH_NEWLINE
};
- const SIMPLE: FormatSpec<'_> = FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountImplied,
- precision_span: None,
- width: CountImplied,
- width_span: None,
- ty: "",
- ty_span: None,
- };
+ span_lint_and_then(
+ cx,
+ lint,
+ macro_call.span,
+ &format!("using `{name}!()` with a format string that ends in a single newline"),
+ |diag| {
+ let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!');
+ let Some(format_snippet) = snippet_opt(cx, format_string_span) else { return };
+
+ if format_string_parts.len() == 1 && last.as_str() == "\n" {
+ // print!("\n"), write!(f, "\n")
+
+ diag.multipart_suggestion(
+ &format!("use `{name}ln!` instead"),
+ vec![(name_span, format!("{name}ln")), (format_string_span, String::new())],
+ Applicability::MachineApplicable,
+ );
+ } else if format_snippet.ends_with("\\n\"") {
+ // print!("...\n"), write!(f, "...\n")
- match arg.position {
- ArgumentIs(n) | ArgumentImplicitlyIs(n) => {
- if self.unnamed.len() <= n {
- // Use a dummy span to mark all unseen arguments.
- self.unnamed.resize_with(n, || vec![DUMMY_SP]);
- if arg.format == SIMPLE {
- self.unnamed.push(vec![span]);
- } else {
- self.unnamed.push(Vec::new());
- }
- } else {
- let args = &mut self.unnamed[n];
- match (args.as_mut_slice(), arg.format == SIMPLE) {
- // A non-empty format string has been seen already.
- ([], _) => (),
- // Replace the dummy span, if it exists.
- ([dummy @ DUMMY_SP], true) => *dummy = span,
- ([_, ..], true) => args.push(span),
- ([_, ..], false) => *args = Vec::new(),
- }
- }
- },
- ArgumentNamed(n) => {
- let n = Symbol::intern(n);
- if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) {
- match x.1.as_slice() {
- // A non-empty format string has been seen already.
- [] => (),
- [_, ..] if arg.format == SIMPLE => x.1.push(span),
- [_, ..] => x.1 = Vec::new(),
- }
- } else if arg.format == SIMPLE {
- self.named.push((n, vec![span]));
- } else {
- self.named.push((n, Vec::new()));
+ let hi = format_string_span.hi();
+ let newline_span = format_string_span.with_lo(hi - BytePos(3)).with_hi(hi - BytePos(1));
+
+ diag.multipart_suggestion(
+ &format!("use `{name}ln!` instead"),
+ vec![(name_span, format!("{name}ln")), (newline_span, String::new())],
+ Applicability::MachineApplicable,
+ );
}
},
- };
+ );
}
}
-impl Write {
- /// Parses a format string into a collection of spans for each argument. This only keeps track
- /// of empty format arguments. Will also lint usages of debug format strings outside of debug
- /// impls.
- fn parse_fmt_string(&self, cx: &EarlyContext<'_>, str_lit: &StrLit) -> Option<SimpleFormatArgs> {
- use rustc_parse_format::{ParseMode, Parser, Piece};
-
- let str_sym = str_lit.symbol_unescaped.as_str();
- let style = match str_lit.style {
- StrStyle::Cooked => None,
- StrStyle::Raw(n) => Some(n as usize),
- };
-
- let mut parser = Parser::new(str_sym, style, snippet_opt(cx, str_lit.span), false, ParseMode::Format);
- let mut args = SimpleFormatArgs::default();
-
- while let Some(arg) = parser.next() {
- let arg = match arg {
- Piece::String(_) => continue,
- Piece::NextArgument(arg) => arg,
- };
- let span = parser
- .arg_places
- .last()
- .map_or(DUMMY_SP, |&x| str_lit.span.from_inner(InnerSpan::new(x.start, x.end)));
-
- if !self.in_debug_impl && arg.format.ty == "?" {
- // FIXME: modify rustc's fmt string parser to give us the current span
- span_lint(cx, USE_DEBUG, span, "use of `Debug`-based formatting");
- }
-
- args.push(arg, span);
- }
-
- parser.errors.is_empty().then_some(args)
- }
+fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_call: &MacroCall, name: &str) {
+ if let [part] = &format_args.format_string.parts[..]
+ && let mut span = format_args.format_string.span
+ && part.as_str() == "\n"
+ {
+ let lint = if name == "writeln" {
+ span = expand_past_previous_comma(cx, span);
- /// Checks the arguments of `print[ln]!` and `write[ln]!` calls. It will return a tuple of two
- /// `Option`s. The first `Option` of the tuple is the macro's format string. It includes
- /// the contents of the string, whether it's a raw string, and the span of the literal in the
- /// source. The second `Option` in the tuple is, in the `write[ln]!` case, the expression the
- /// `format_str` should be written to.
- ///
- /// Example:
- ///
- /// Calling this function on
- /// ```rust
- /// # use std::fmt::Write;
- /// # let mut buf = String::new();
- /// # let something = "something";
- /// writeln!(buf, "string to write: {}", something);
- /// ```
- /// will return
- /// ```rust,ignore
- /// (Some("string to write: {}"), Some(buf))
- /// ```
- fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option<StrLit>, Option<Expr>) {
- let mut parser = parser::Parser::new(&cx.sess().parse_sess, tts, false, None);
- let expr = if is_write {
- match parser
- .parse_expr()
- .map(rustc_ast::ptr::P::into_inner)
- .map_err(DiagnosticBuilder::cancel)
- {
- // write!(e, ...)
- Ok(p) if parser.eat(&token::Comma) => Some(p),
- // write!(e) or error
- e => return (None, e.ok()),
- }
+ WRITELN_EMPTY_STRING
} else {
- None
+ PRINTLN_EMPTY_STRING
};
- let fmtstr = match parser.parse_str_lit() {
- Ok(fmtstr) => fmtstr,
- Err(_) => return (None, expr),
- };
+ span_lint_and_then(
+ cx,
+ lint,
+ macro_call.span,
+ &format!("empty string literal in `{name}!`"),
+ |diag| {
+ diag.span_suggestion(
+ span,
+ "remove the empty string",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ },
+ );
+ }
+}
- let args = match self.parse_fmt_string(cx, &fmtstr) {
- Some(args) => args,
- None => return (Some(fmtstr), expr),
- };
+fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, name: &str) {
+ let mut counts = HirIdMap::<usize>::default();
+ for param in format_args.params() {
+ *counts.entry(param.value.hir_id).or_default() += 1;
+ }
- let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL };
- let mut unnamed_args = args.get_unnamed();
- loop {
- if !parser.eat(&token::Comma) {
- return (Some(fmtstr), expr);
- }
+ for arg in &format_args.args {
+ let value = arg.param.value;
- let comma_span = parser.prev_token.span;
- let token_expr = if let Ok(expr) = parser.parse_expr().map_err(DiagnosticBuilder::cancel) {
- expr
- } else {
- return (Some(fmtstr), None);
+ if counts[&value.hir_id] == 1
+ && arg.format.is_default()
+ && let ExprKind::Lit(lit) = &value.kind
+ && !value.span.from_expansion()
+ && let Some(value_string) = snippet_opt(cx, value.span)
+ {
+ let (replacement, replace_raw) = match lit.node {
+ LitKind::Str(..) => extract_str_literal(&value_string),
+ LitKind::Char(ch) => (
+ match ch {
+ '"' => "\\\"",
+ '\'' => "'",
+ _ => &value_string[1..value_string.len() - 1],
+ }
+ .to_string(),
+ false,
+ ),
+ LitKind::Bool(b) => (b.to_string(), false),
+ _ => continue,
};
- let (fmt_spans, lit) = match &token_expr.kind {
- ExprKind::Lit(lit) => (unnamed_args.next().unwrap_or(&[]), lit),
- ExprKind::Assign(lhs, rhs, _) => match (&lhs.kind, &rhs.kind) {
- (ExprKind::Path(_, p), ExprKind::Lit(lit)) => (args.get_named(p), lit),
- _ => continue,
- },
- _ => {
- unnamed_args.next();
- continue;
- },
+
+ let lint = if name.starts_with("write") {
+ WRITE_LITERAL
+ } else {
+ PRINT_LITERAL
};
- let replacement: String = match lit.token.kind {
- LitKind::StrRaw(_) | LitKind::ByteStrRaw(_) if matches!(fmtstr.style, StrStyle::Raw(_)) => {
- lit.token.symbol.as_str().replace('{', "{{").replace('}', "}}")
+ let format_string_is_raw = format_args.format_string.style.is_some();
+ let replacement = match (format_string_is_raw, replace_raw) {
+ (false, false) => Some(replacement),
+ (false, true) => Some(replacement.replace('"', "\\\"").replace('\\', "\\\\")),
+ (true, false) => match conservative_unescape(&replacement) {
+ Ok(unescaped) => Some(unescaped),
+ Err(UnescapeErr::Lint) => None,
+ Err(UnescapeErr::Ignore) => continue,
},
- LitKind::Str | LitKind::ByteStr if matches!(fmtstr.style, StrStyle::Cooked) => {
- lit.token.symbol.as_str().replace('{', "{{").replace('}', "}}")
+ (true, true) => {
+ if replacement.contains(['#', '"']) {
+ None
+ } else {
+ Some(replacement)
+ }
},
- LitKind::StrRaw(_)
- | LitKind::Str
- | LitKind::ByteStrRaw(_)
- | LitKind::ByteStr
- | LitKind::Integer
- | LitKind::Float
- | LitKind::Err => continue,
- LitKind::Byte | LitKind::Char => match lit.token.symbol.as_str() {
- "\"" if matches!(fmtstr.style, StrStyle::Cooked) => "\\\"",
- "\"" if matches!(fmtstr.style, StrStyle::Raw(0)) => continue,
- "\\\\" if matches!(fmtstr.style, StrStyle::Raw(_)) => "\\",
- "\\'" => "'",
- "{" => "{{",
- "}" => "}}",
- x if matches!(fmtstr.style, StrStyle::Raw(_)) && x.starts_with('\\') => continue,
- x => x,
- }
- .into(),
- LitKind::Bool => lit.token.symbol.as_str().deref().into(),
};
- if !fmt_spans.is_empty() {
- span_lint_and_then(
- cx,
- lint,
- token_expr.span,
- "literal with an empty format string",
- |diag| {
+ span_lint_and_then(
+ cx,
+ lint,
+ value.span,
+ "literal with an empty format string",
+ |diag| {
+ if let Some(replacement) = replacement
+ // `format!("{}", "a")`, `format!("{named}", named = "b")
+ // ~~~~~ ~~~~~~~~~~~~~
+ && let Some(value_span) = format_args.value_with_prev_comma_span(value.hir_id)
+ {
+ let replacement = replacement.replace('{', "{{").replace('}', "}}");
diag.multipart_suggestion(
"try this",
- iter::once((comma_span.to(token_expr.span), String::new()))
- .chain(fmt_spans.iter().copied().zip(iter::repeat(replacement)))
- .collect(),
+ vec![(arg.span, replacement), (value_span, String::new())],
Applicability::MachineApplicable,
);
- },
- );
- }
- }
- }
-
- fn lint_println_empty_string(&self, cx: &EarlyContext<'_>, mac: &MacCall) {
- if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
- if fmt_str.symbol == kw::Empty {
- let name = mac.path.segments[0].ident.name;
- span_lint_and_sugg(
- cx,
- PRINTLN_EMPTY_STRING,
- mac.span(),
- &format!("using `{}!(\"\")`", name),
- "replace it with",
- format!("{}!()", name),
- Applicability::MachineApplicable,
- );
- }
- }
- }
-
- fn lint_print_with_newline(&self, cx: &EarlyContext<'_>, mac: &MacCall) {
- if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
- if check_newlines(&fmt_str) {
- let name = mac.path.segments[0].ident.name;
- let suggested = format!("{}ln", name);
- span_lint_and_then(
- cx,
- PRINT_WITH_NEWLINE,
- mac.span(),
- &format!("using `{}!()` with a format string that ends in a single newline", name),
- |err| {
- err.multipart_suggestion(
- &format!("use `{}!` instead", suggested),
- vec![(mac.path.span, suggested), (newline_span(&fmt_str).0, String::new())],
- Applicability::MachineApplicable,
- );
- },
- );
- }
+ }
+ },
+ );
}
}
}
-/// Checks if the format string contains a single newline that terminates it.
+/// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw
+///
+/// `r#"a"#` -> (`a`, true)
///
-/// Literal and escaped newlines are both checked (only literal for raw strings).
-fn check_newlines(fmtstr: &StrLit) -> bool {
- let mut has_internal_newline = false;
- let mut last_was_cr = false;
- let mut should_lint = false;
+/// `"b"` -> (`b`, false)
+fn extract_str_literal(literal: &str) -> (String, bool) {
+ let (literal, raw) = match literal.strip_prefix('r') {
+ Some(stripped) => (stripped.trim_matches('#'), true),
+ None => (literal, false),
+ };
- let contents = fmtstr.symbol.as_str();
+ (literal[1..literal.len() - 1].to_string(), raw)
+}
- let mut cb = |r: Range<usize>, c: Result<char, EscapeError>| {
- let c = c.unwrap();
+enum UnescapeErr {
+ /// Should still be linted, can be manually resolved by author, e.g.
+ ///
+ /// ```ignore
+ /// print!(r"{}", '"');
+ /// ```
+ Lint,
+ /// Should not be linted, e.g.
+ ///
+ /// ```ignore
+ /// print!(r"{}", '\r');
+ /// ```
+ Ignore,
+}
- if r.end == contents.len() && c == '\n' && !last_was_cr && !has_internal_newline {
- should_lint = true;
- } else {
- last_was_cr = c == '\r';
- if c == '\n' {
- has_internal_newline = true;
- }
+/// Unescape a normal string into a raw string
+fn conservative_unescape(literal: &str) -> Result<String, UnescapeErr> {
+ let mut unescaped = String::with_capacity(literal.len());
+ let mut chars = literal.chars();
+ let mut err = false;
+
+ while let Some(ch) = chars.next() {
+ match ch {
+ '#' => err = true,
+ '\\' => match chars.next() {
+ Some('\\') => unescaped.push('\\'),
+ Some('"') => err = true,
+ _ => return Err(UnescapeErr::Ignore),
+ },
+ _ => unescaped.push(ch),
}
- };
-
- match fmtstr.style {
- StrStyle::Cooked => unescape::unescape_literal(contents, unescape::Mode::Str, &mut cb),
- StrStyle::Raw(_) => unescape::unescape_literal(contents, unescape::Mode::RawStr, &mut cb),
}
- should_lint
+ if err { Err(UnescapeErr::Lint) } else { Ok(unescaped) }
}
diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
index 50d3c079f..9b3de35db 100644
--- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
@@ -57,8 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv {
"constant division of `0.0` with `0.0` will always result in NaN",
None,
&format!(
- "consider using `{}::NAN` if you would like a constant representing NaN",
- float_type,
+ "consider using `{float_type}::NAN` if you would like a constant representing NaN",
),
);
}
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index 8dc43c0e2..6cf2a955f 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -2,12 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item};
use if_chain::if_chain;
use rustc_hir::{self as hir, HirId, ItemKind, Node};
+use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf as _;
use rustc_middle::ty::{Adt, Ty, TypeVisitable};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
-use rustc_typeck::hir_ty_to_ty;
declare_clippy_lint! {
/// ### What it does
@@ -69,10 +69,7 @@ impl LateLintPass<'_> for ZeroSizedMapValues {
fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool {
let parent_id = cx.tcx.hir().get_parent_item(hir_id);
- let second_parent_id = cx
- .tcx
- .hir()
- .get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(parent_id));
+ let second_parent_id = cx.tcx.hir().get_parent_item(parent_id.into()).def_id;
if let Some(Node::Item(item)) = cx.tcx.hir().find_by_def_id(second_parent_id) {
if let ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind {
return true;
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index bb443bdc1..83fee7bb3 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,12 +1,13 @@
[package]
name = "clippy_utils"
-version = "0.1.64"
+version = "0.1.66"
edition = "2021"
publish = false
[dependencies]
arrayvec = { version = "0.7", default-features = false }
if_chain = "1.0"
+itertools = "0.10.1"
rustc-semver = "1.1"
[features]
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index b22602632..013399756 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -147,7 +147,9 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
(Array(l), Array(r)) | (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)),
(Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value),
(Call(lc, la), Call(rc, ra)) => eq_expr(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
- (MethodCall(lc, la, _), MethodCall(rc, ra, _)) => eq_path_seg(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
+ (MethodCall(lc, ls, la, _), MethodCall(rc, rs, ra, _)) => {
+ eq_path_seg(lc, rc) && eq_expr(ls, rs) && over(la, ra, |l, r| eq_expr(l, r))
+ },
(Binary(lo, ll, lr), Binary(ro, rl, rr)) => lo.node == ro.node && eq_expr(ll, rl) && eq_expr(lr, rr),
(Unary(lo, l), Unary(ro, r)) => mem::discriminant(lo) == mem::discriminant(ro) && eq_expr(l, r),
(Lit(l), Lit(r)) => l.kind == r.kind,
@@ -436,14 +438,14 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
},
(
- TyAlias(box ast::TyAlias {
+ Type(box ast::TyAlias {
defaultness: ld,
generics: lg,
bounds: lb,
ty: lt,
..
}),
- TyAlias(box ast::TyAlias {
+ Type(box ast::TyAlias {
defaultness: rd,
generics: rg,
bounds: rb,
@@ -693,7 +695,7 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool {
l.style == r.style
&& match (&l.kind, &r.kind) {
(DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2,
- (Normal(l, _), Normal(r, _)) => eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args),
+ (Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_mac_args(&l.item.args, &r.item.args),
_ => false,
}
}
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index 186bba09d..cd8575c90 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -59,8 +59,8 @@ pub fn get_attr<'a>(
name: &'static str,
) -> impl Iterator<Item = &'a ast::Attribute> {
attrs.iter().filter(move |attr| {
- let attr = if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
- attr
+ let attr = if let ast::AttrKind::Normal(ref normal) = attr.kind {
+ &normal.item
} else {
return false;
};
@@ -131,12 +131,12 @@ pub fn get_unique_inner_attr(sess: &Session, attrs: &[ast::Attribute], name: &'s
match attr.style {
ast::AttrStyle::Inner if unique_attr.is_none() => unique_attr = Some(attr.clone()),
ast::AttrStyle::Inner => {
- sess.struct_span_err(attr.span, &format!("`{}` is defined multiple times", name))
+ sess.struct_span_err(attr.span, &format!("`{name}` is defined multiple times"))
.span_note(unique_attr.as_ref().unwrap().span, "first definition found here")
.emit();
},
ast::AttrStyle::Outer => {
- sess.span_err(attr.span, &format!("`{}` cannot be an outer attribute", name));
+ sess.span_err(attr.span, format!("`{name}` cannot be an outer attribute"));
},
}
}
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
new file mode 100644
index 000000000..c6bf98b7b
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -0,0 +1,329 @@
+//! This module handles checking if the span given is from a proc-macro or not.
+//!
+//! Proc-macros are capable of setting the span of every token they output to a few possible spans.
+//! This includes spans we can detect easily as coming from a proc-macro (e.g. the call site
+//! or the def site), and spans we can't easily detect as such (e.g. the span of any token
+//! passed into the proc macro). This capability means proc-macros are capable of generating code
+//! with a span that looks like it was written by the user, but which should not be linted by clippy
+//! as it was generated by an external macro.
+//!
+//! That brings us to this module. The current approach is to determine a small bit of text which
+//! must exist at both the start and the end of an item (e.g. an expression or a path) assuming the
+//! code was written, and check if the span contains that text. Note this will only work correctly
+//! if the span is not from a `macro_rules` based macro.
+
+use rustc_ast::ast::{IntTy, LitIntType, LitKind, StrStyle, UintTy};
+use rustc_hir::{
+ intravisit::FnKind, Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId,
+ Impl, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, Node, QPath, TraitItem,
+ TraitItemKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource,
+};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::ty::TyCtxt;
+use rustc_session::Session;
+use rustc_span::{Span, Symbol};
+use rustc_target::spec::abi::Abi;
+
+/// The search pattern to look for. Used by `span_matches_pat`
+#[derive(Clone, Copy)]
+pub enum Pat {
+ /// A single string.
+ Str(&'static str),
+ /// Any of the given strings.
+ MultiStr(&'static [&'static str]),
+ /// The string representation of the symbol.
+ Sym(Symbol),
+ /// Any decimal or hexadecimal digit depending on the location.
+ Num,
+}
+
+/// Checks if the start and the end of the span's text matches the patterns. This will return false
+/// if the span crosses multiple files or if source is not available.
+fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) -> bool {
+ let pos = sess.source_map().lookup_byte_offset(span.lo());
+ let Some(ref src) = pos.sf.src else {
+ return false;
+ };
+ let end = span.hi() - pos.sf.start_pos;
+ src.get(pos.pos.0 as usize..end.0 as usize).map_or(false, |s| {
+ // Spans can be wrapped in a mixture or parenthesis, whitespace, and trailing commas.
+ let start_str = s.trim_start_matches(|c: char| c.is_whitespace() || c == '(');
+ let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ',');
+ (match start_pat {
+ Pat::Str(text) => start_str.starts_with(text),
+ Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
+ Pat::Sym(sym) => start_str.starts_with(sym.as_str()),
+ Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit),
+ } && match end_pat {
+ Pat::Str(text) => end_str.ends_with(text),
+ Pat::MultiStr(texts) => texts.iter().any(|s| start_str.ends_with(s)),
+ Pat::Sym(sym) => end_str.ends_with(sym.as_str()),
+ Pat::Num => end_str.as_bytes().last().map_or(false, u8::is_ascii_hexdigit),
+ })
+ })
+}
+
+/// Get the search patterns to use for the given literal
+fn lit_search_pat(lit: &LitKind) -> (Pat, Pat) {
+ match lit {
+ LitKind::Str(_, StrStyle::Cooked) => (Pat::Str("\""), Pat::Str("\"")),
+ LitKind::Str(_, StrStyle::Raw(0)) => (Pat::Str("r"), Pat::Str("\"")),
+ LitKind::Str(_, StrStyle::Raw(_)) => (Pat::Str("r#"), Pat::Str("#")),
+ LitKind::ByteStr(_) => (Pat::Str("b\""), Pat::Str("\"")),
+ LitKind::Byte(_) => (Pat::Str("b'"), Pat::Str("'")),
+ LitKind::Char(_) => (Pat::Str("'"), Pat::Str("'")),
+ LitKind::Int(_, LitIntType::Signed(IntTy::Isize)) => (Pat::Num, Pat::Str("isize")),
+ LitKind::Int(_, LitIntType::Unsigned(UintTy::Usize)) => (Pat::Num, Pat::Str("usize")),
+ LitKind::Int(..) => (Pat::Num, Pat::Num),
+ LitKind::Float(..) => (Pat::Num, Pat::Str("")),
+ LitKind::Bool(true) => (Pat::Str("true"), Pat::Str("true")),
+ LitKind::Bool(false) => (Pat::Str("false"), Pat::Str("false")),
+ _ => (Pat::Str(""), Pat::Str("")),
+ }
+}
+
+/// Get the search patterns to use for the given path
+fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) {
+ match path {
+ QPath::Resolved(ty, path) => {
+ let start = if ty.is_some() {
+ Pat::Str("<")
+ } else {
+ path.segments
+ .first()
+ .map_or(Pat::Str(""), |seg| Pat::Sym(seg.ident.name))
+ };
+ let end = path.segments.last().map_or(Pat::Str(""), |seg| {
+ if seg.args.is_some() {
+ Pat::Str(">")
+ } else {
+ Pat::Sym(seg.ident.name)
+ }
+ });
+ (start, end)
+ },
+ QPath::TypeRelative(_, name) => (Pat::Str(""), Pat::Sym(name.ident.name)),
+ QPath::LangItem(..) => (Pat::Str(""), Pat::Str("")),
+ }
+}
+
+/// Get the search patterns to use for the given expression
+fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
+ match e.kind {
+ ExprKind::Box(e) => (Pat::Str("box"), expr_search_pat(tcx, e).1),
+ ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")),
+ ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")),
+ ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1),
+ ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1),
+ ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1),
+ ExprKind::Lit(ref lit) => lit_search_pat(&lit.node),
+ ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")),
+ ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
+ ExprKind::Call(first, [.., last])
+ | ExprKind::MethodCall(_, first, [.., last], _)
+ | ExprKind::Binary(_, first, last)
+ | ExprKind::Tup([first, .., last])
+ | ExprKind::Assign(first, last, _)
+ | ExprKind::AssignOp(_, first, last) => (expr_search_pat(tcx, first).0, expr_search_pat(tcx, last).1),
+ ExprKind::Tup([e]) | ExprKind::DropTemps(e) => expr_search_pat(tcx, e),
+ ExprKind::Cast(e, _) | ExprKind::Type(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("")),
+ ExprKind::Let(let_expr) => (Pat::Str("let"), expr_search_pat(tcx, let_expr.init).1),
+ ExprKind::If(..) => (Pat::Str("if"), Pat::Str("}")),
+ ExprKind::Loop(_, Some(_), _, _) | ExprKind::Block(_, Some(_)) => (Pat::Str("'"), Pat::Str("}")),
+ ExprKind::Loop(_, None, LoopSource::Loop, _) => (Pat::Str("loop"), Pat::Str("}")),
+ ExprKind::Loop(_, None, LoopSource::While, _) => (Pat::Str("while"), Pat::Str("}")),
+ ExprKind::Loop(_, None, LoopSource::ForLoop, _) | ExprKind::Match(_, _, MatchSource::ForLoopDesugar) => {
+ (Pat::Str("for"), Pat::Str("}"))
+ },
+ ExprKind::Match(_, _, MatchSource::Normal) => (Pat::Str("match"), Pat::Str("}")),
+ ExprKind::Match(e, _, MatchSource::TryDesugar) => (expr_search_pat(tcx, e).0, Pat::Str("?")),
+ ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => {
+ (expr_search_pat(tcx, e).0, Pat::Str("await"))
+ },
+ ExprKind::Closure(&Closure { body, .. }) => (Pat::Str(""), expr_search_pat(tcx, tcx.hir().body(body).value).1),
+ ExprKind::Block(
+ Block {
+ rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
+ ..
+ },
+ None,
+ ) => (Pat::Str("unsafe"), Pat::Str("}")),
+ ExprKind::Block(_, None) => (Pat::Str("{"), Pat::Str("}")),
+ ExprKind::Field(e, name) => (expr_search_pat(tcx, e).0, Pat::Sym(name.name)),
+ ExprKind::Index(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")),
+ ExprKind::Path(ref path) => qpath_search_pat(path),
+ ExprKind::AddrOf(_, _, e) => (Pat::Str("&"), expr_search_pat(tcx, e).1),
+ ExprKind::Break(Destination { label: None, .. }, None) => (Pat::Str("break"), Pat::Str("break")),
+ ExprKind::Break(Destination { label: Some(name), .. }, None) => (Pat::Str("break"), Pat::Sym(name.ident.name)),
+ ExprKind::Break(_, Some(e)) => (Pat::Str("break"), expr_search_pat(tcx, e).1),
+ ExprKind::Continue(Destination { label: None, .. }) => (Pat::Str("continue"), Pat::Str("continue")),
+ ExprKind::Continue(Destination { label: Some(name), .. }) => (Pat::Str("continue"), Pat::Sym(name.ident.name)),
+ ExprKind::Ret(None) => (Pat::Str("return"), Pat::Str("return")),
+ ExprKind::Ret(Some(e)) => (Pat::Str("return"), expr_search_pat(tcx, e).1),
+ ExprKind::Struct(path, _, _) => (qpath_search_pat(path).0, Pat::Str("}")),
+ ExprKind::Yield(e, YieldSource::Yield) => (Pat::Str("yield"), expr_search_pat(tcx, e).1),
+ _ => (Pat::Str(""), Pat::Str("")),
+ }
+}
+
+fn fn_header_search_pat(header: FnHeader) -> Pat {
+ if header.is_async() {
+ Pat::Str("async")
+ } else if header.is_const() {
+ Pat::Str("const")
+ } else if header.is_unsafe() {
+ Pat::Str("unsafe")
+ } else if header.abi != Abi::Rust {
+ Pat::Str("extern")
+ } else {
+ Pat::MultiStr(&["fn", "extern"])
+ }
+}
+
+fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) {
+ let (start_pat, end_pat) = match &item.kind {
+ ItemKind::ExternCrate(_) => (Pat::Str("extern"), Pat::Str(";")),
+ ItemKind::Static(..) => (Pat::Str("static"), Pat::Str(";")),
+ ItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+ ItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+ ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")),
+ ItemKind::TyAlias(..) | ItemKind::OpaqueTy(_) => (Pat::Str("type"), Pat::Str(";")),
+ ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")),
+ ItemKind::Struct(VariantData::Struct(..), _) => (Pat::Str("struct"), Pat::Str("}")),
+ ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")),
+ ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")),
+ ItemKind::Trait(_, Unsafety::Unsafe, ..)
+ | ItemKind::Impl(Impl {
+ unsafety: Unsafety::Unsafe,
+ ..
+ }) => (Pat::Str("unsafe"), Pat::Str("}")),
+ ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")),
+ ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")),
+ ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")),
+ _ => return (Pat::Str(""), Pat::Str("")),
+ };
+ if item.vis_span.is_empty() {
+ (start_pat, end_pat)
+ } else {
+ (Pat::Str("pub"), end_pat)
+ }
+}
+
+fn trait_item_search_pat(item: &TraitItem<'_>) -> (Pat, Pat) {
+ match &item.kind {
+ TraitItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+ TraitItemKind::Type(..) => (Pat::Str("type"), Pat::Str(";")),
+ TraitItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+ }
+}
+
+fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) {
+ let (start_pat, end_pat) = match &item.kind {
+ ImplItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+ ImplItemKind::Type(..) => (Pat::Str("type"), Pat::Str(";")),
+ ImplItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+ };
+ if item.vis_span.is_empty() {
+ (start_pat, end_pat)
+ } else {
+ (Pat::Str("pub"), end_pat)
+ }
+}
+
+fn field_def_search_pat(def: &FieldDef<'_>) -> (Pat, Pat) {
+ if def.vis_span.is_empty() {
+ if def.is_positional() {
+ (Pat::Str(""), Pat::Str(""))
+ } else {
+ (Pat::Sym(def.ident.name), Pat::Str(""))
+ }
+ } else {
+ (Pat::Str("pub"), Pat::Str(""))
+ }
+}
+
+fn variant_search_pat(v: &Variant<'_>) -> (Pat, Pat) {
+ match v.data {
+ VariantData::Struct(..) => (Pat::Sym(v.ident.name), Pat::Str("}")),
+ VariantData::Tuple(..) => (Pat::Sym(v.ident.name), Pat::Str("")),
+ VariantData::Unit(..) => (Pat::Sym(v.ident.name), Pat::Sym(v.ident.name)),
+ }
+}
+
+fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirId) -> (Pat, Pat) {
+ let (start_pat, end_pat) = match kind {
+ FnKind::ItemFn(.., header) => (fn_header_search_pat(*header), Pat::Str("")),
+ FnKind::Method(.., sig) => (fn_header_search_pat(sig.header), Pat::Str("")),
+ FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, body.value).1),
+ };
+ let start_pat = match tcx.hir().get(hir_id) {
+ Node::Item(Item { vis_span, .. }) | Node::ImplItem(ImplItem { vis_span, .. }) => {
+ if vis_span.is_empty() {
+ start_pat
+ } else {
+ Pat::Str("pub")
+ }
+ },
+ Node::TraitItem(_) => start_pat,
+ _ => Pat::Str(""),
+ };
+ (start_pat, end_pat)
+}
+
+pub trait WithSearchPat {
+ type Context: LintContext;
+ fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat);
+ fn span(&self) -> Span;
+}
+macro_rules! impl_with_search_pat {
+ ($cx:ident: $ty:ident with $fn:ident $(($tcx:ident))?) => {
+ impl<'cx> WithSearchPat for $ty<'cx> {
+ type Context = $cx<'cx>;
+ #[allow(unused_variables)]
+ fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) {
+ $(let $tcx = cx.tcx;)?
+ $fn($($tcx,)? self)
+ }
+ fn span(&self) -> Span {
+ self.span
+ }
+ }
+ };
+}
+impl_with_search_pat!(LateContext: Expr with expr_search_pat(tcx));
+impl_with_search_pat!(LateContext: Item with item_search_pat);
+impl_with_search_pat!(LateContext: TraitItem with trait_item_search_pat);
+impl_with_search_pat!(LateContext: ImplItem with impl_item_search_pat);
+impl_with_search_pat!(LateContext: FieldDef with field_def_search_pat);
+impl_with_search_pat!(LateContext: Variant with variant_search_pat);
+
+impl<'cx> WithSearchPat for (&FnKind<'cx>, &Body<'cx>, HirId, Span) {
+ type Context = LateContext<'cx>;
+
+ fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) {
+ fn_kind_pat(cx.tcx, self.0, self.1, self.2)
+ }
+
+ fn span(&self) -> Span {
+ self.3
+ }
+}
+
+/// Checks if the item likely came from a proc-macro.
+///
+/// This should be called after `in_external_macro` and the initial pattern matching of the ast as
+/// it is significantly slower than both of those.
+pub fn is_from_proc_macro<T: WithSearchPat>(cx: &T::Context, item: &T) -> bool {
+ let (start_pat, end_pat) = item.search_pat(cx);
+ !span_matches_pat(cx.sess(), item.span(), start_pat, end_pat)
+}
+
+/// Checks if the span actually refers to a match expression
+pub fn is_span_match(cx: &impl LintContext, span: Span) -> bool {
+ span_matches_pat(cx.sess(), span, Pat::Str("match"), Pat::Str("}"))
+}
+
+/// Checks if the span actually refers to an if expression
+pub fn is_span_if(cx: &impl LintContext, span: Span) -> bool {
+ span_matches_pat(cx.sess(), span, Pat::Str("if"), Pat::Str("}"))
+}
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 351a3f4ae..07e4ef6a2 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -9,7 +9,7 @@ use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind,
use rustc_lint::LateContext;
use rustc_middle::mir;
use rustc_middle::mir::interpret::Scalar;
-use rustc_middle::ty::subst::{Subst, SubstsRef};
+use rustc_middle::ty::SubstsRef;
use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::symbol::Symbol;
@@ -45,7 +45,7 @@ pub enum Constant {
/// A reference
Ref(Box<Constant>),
/// A literal with syntax error.
- Err(Symbol),
+ Err,
}
impl PartialEq for Constant {
@@ -118,9 +118,7 @@ impl Hash for Constant {
Self::Ref(ref r) => {
r.hash(state);
},
- Self::Err(ref s) => {
- s.hash(state);
- },
+ Self::Err => {},
}
}
}
@@ -138,17 +136,49 @@ impl Constant {
(&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::Tuple(ref l), &Self::Tuple(ref r)) if l.len() == r.len() => match *cmp_type.kind() {
+ ty::Tuple(tys) if tys.len() == l.len() => l
+ .iter()
+ .zip(r)
+ .zip(tys)
+ .map(|((li, ri), cmp_type)| 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()))),
+ _ => None,
+ },
+ (&Self::Vec(ref l), &Self::Vec(ref r)) => {
+ let cmp_type = match *cmp_type.kind() {
+ ty::Array(ty, _) | ty::Slice(ty) => ty,
+ _ => return None,
+ };
+ 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) {
+ match Self::partial_cmp(
+ tcx,
+ match *cmp_type.kind() {
+ ty::Array(ty, _) => ty,
+ _ => return None,
+ },
+ 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),
+ (&Self::Ref(ref lb), &Self::Ref(ref rb)) => Self::partial_cmp(
+ tcx,
+ match *cmp_type.kind() {
+ ty::Ref(_, ty, _) => ty,
+ _ => return None,
+ },
+ lb,
+ rb,
+ ),
// TODO: are there any useful inter-type orderings?
_ => None,
}
@@ -194,7 +224,7 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
_ => bug!(),
},
LitKind::Bool(b) => Constant::Bool(b),
- LitKind::Err(s) => Constant::Err(s),
+ LitKind::Err => Constant::Err,
}
}
@@ -426,7 +456,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
.tcx
.const_eval_resolve(
self.param_env,
- ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs),
+ mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs),
None,
)
.ok()
@@ -503,8 +533,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
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::Shr => l.checked_shr(r.try_into().ok()?).map(zext),
+ BinOpKind::Shl => l.checked_shl(r.try_into().ok()?).map(zext),
BinOpKind::BitXor => Some(zext(l ^ r)),
BinOpKind::BitOr => Some(zext(l | r)),
BinOpKind::BitAnd => Some(zext(l & r)),
@@ -523,8 +553,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
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::Shr => l.checked_shr(r.try_into().ok()?).map(Constant::Int),
+ BinOpKind::Shl => l.checked_shl(r.try_into().ok()?).map(Constant::Int),
BinOpKind::BitXor => Some(Constant::Int(l ^ r)),
BinOpKind::BitOr => Some(Constant::Int(l | r)),
BinOpKind::BitAnd => Some(Constant::Int(l & r)),
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index 7f55db3b3..78f93755b 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -18,12 +18,11 @@ fn docs_link(diag: &mut Diagnostic, 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#{}",
+ "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}",
&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
+ })
));
}
}
@@ -47,10 +46,9 @@ fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) {
/// | ^^^^^^^^^^^^^^^^^^^^^^^
/// ```
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();
+ cx.struct_span_lint(lint, sp, msg, |diag| {
+ docs_link(diag, lint);
+ diag
});
}
@@ -82,15 +80,14 @@ pub fn span_lint_and_help<'a, T: LintContext>(
help_span: Option<Span>,
help: &str,
) {
- cx.struct_span_lint(lint, span, |diag| {
- let mut diag = diag.build(msg);
+ cx.struct_span_lint(lint, span, msg, |diag| {
if let Some(help_span) = help_span {
diag.span_help(help_span, help);
} else {
diag.help(help);
}
- docs_link(&mut diag, lint);
- diag.emit();
+ docs_link(diag, lint);
+ diag
});
}
@@ -125,15 +122,14 @@ pub fn span_lint_and_note<'a, T: LintContext>(
note_span: Option<Span>,
note: &str,
) {
- cx.struct_span_lint(lint, span, |diag| {
- let mut diag = diag.build(msg);
+ cx.struct_span_lint(lint, span, msg, |diag| {
if let Some(note_span) = note_span {
diag.span_note(note_span, note);
} else {
diag.note(note);
}
- docs_link(&mut diag, lint);
- diag.emit();
+ docs_link(diag, lint);
+ diag
});
}
@@ -147,25 +143,17 @@ where
S: Into<MultiSpan>,
F: FnOnce(&mut Diagnostic),
{
- cx.struct_span_lint(lint, sp, |diag| {
- let mut diag = diag.build(msg);
- f(&mut diag);
- docs_link(&mut diag, lint);
- diag.emit();
+ cx.struct_span_lint(lint, sp, msg, |diag| {
+ f(diag);
+ docs_link(diag, lint);
+ diag
});
}
-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(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
+ cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg, |diag| {
+ docs_link(diag, lint);
+ diag
});
}
@@ -177,11 +165,10 @@ pub fn span_lint_hir_and_then(
msg: &str,
f: impl FnOnce(&mut Diagnostic),
) {
- 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();
+ cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg, |diag| {
+ f(diag);
+ docs_link(diag, lint);
+ diag
});
}
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 730724b95..95b3e651e 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -45,12 +45,7 @@ impl ops::BitOrAssign for EagernessSuggestion {
}
/// Determine the eagerness of the given function call.
-fn fn_eagerness<'tcx>(
- cx: &LateContext<'tcx>,
- fn_id: DefId,
- name: Symbol,
- args: &'tcx [Expr<'_>],
-) -> EagernessSuggestion {
+fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion {
use EagernessSuggestion::{Eager, Lazy, NoChange};
let name = name.as_str();
@@ -59,7 +54,7 @@ fn fn_eagerness<'tcx>(
None => return Lazy,
};
- if (name.starts_with("as_") || name == "len" || name == "is_empty") && args.len() == 1 {
+ if (name.starts_with("as_") || name == "len" || name == "is_empty") && have_one_arg {
if matches!(
cx.tcx.crate_name(fn_id.krate),
sym::std | sym::core | sym::alloc | sym::proc_macro
@@ -118,7 +113,17 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
},
args,
) => match self.cx.qpath_res(path, hir_id) {
- Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_) => (),
+ Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_) => {
+ if self
+ .cx
+ .typeck_results()
+ .expr_ty(e)
+ .has_significant_drop(self.cx.tcx, self.cx.param_env)
+ {
+ self.eagerness = ForceNoChange;
+ return;
+ }
+ },
Res::Def(_, id) if self.cx.tcx.is_promotable_const_fn(id) => (),
// No need to walk the arguments here, `is_const_evaluatable` already did
Res::Def(..) if is_const_evaluatable(self.cx, e) => {
@@ -127,10 +132,11 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
},
Res::Def(_, id) => match path {
QPath::Resolved(_, p) => {
- self.eagerness |= fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, args);
+ self.eagerness |=
+ fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, !args.is_empty());
},
QPath::TypeRelative(_, name) => {
- self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, args);
+ self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, !args.is_empty());
},
QPath::LangItem(..) => self.eagerness = Lazy,
},
@@ -141,12 +147,12 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
self.eagerness |= NoChange;
return;
},
- ExprKind::MethodCall(name, args, _) => {
+ ExprKind::MethodCall(name, ..) => {
self.eagerness |= self
.cx
.typeck_results()
.type_dependent_def_id(e.hir_id)
- .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, args));
+ .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, true));
},
ExprKind::Index(_, e) => {
let ty = self.cx.typeck_results().expr_ty_adjusted(e);
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 1834e2a2d..cf24ec8b6 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -6,9 +6,9 @@ use rustc_data_structures::fx::FxHasher;
use rustc_hir::def::Res;
use rustc_hir::HirIdMap;
use rustc_hir::{
- ArrayLen, BinOpKind, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard,
- HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath,
- Stmt, StmtKind, Ty, TyKind, TypeBinding,
+ ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
+ GenericArgs, Guard, HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path,
+ PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::LateContext;
@@ -201,8 +201,8 @@ impl HirEqInterExpr<'_, '_, '_> {
self.inner.cx.tcx.typeck_body(right),
));
let res = self.eq_expr(
- &self.inner.cx.tcx.hir().body(left).value,
- &self.inner.cx.tcx.hir().body(right).value,
+ self.inner.cx.tcx.hir().body(left).value,
+ self.inner.cx.tcx.hir().body(right).value,
);
self.inner.maybe_typeck_results = old_maybe_typeck_results;
res
@@ -282,8 +282,14 @@ impl HirEqInterExpr<'_, '_, '_> {
&& self.eq_expr(l.body, r.body)
})
},
- (&ExprKind::MethodCall(l_path, l_args, _), &ExprKind::MethodCall(r_path, r_args, _)) => {
- self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
+ (
+ &ExprKind::MethodCall(l_path, l_receiver, l_args, _),
+ &ExprKind::MethodCall(r_path, r_receiver, r_args, _),
+ ) => {
+ self.inner.allow_side_effects
+ && self.eq_path_segment(l_path, r_path)
+ && self.eq_expr(l_receiver, r_receiver)
+ && self.eq_exprs(l_args, r_args)
},
(&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => {
self.eq_expr(le, re) && self.eq_array_length(ll, rl)
@@ -643,7 +649,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
}) => {
std::mem::discriminant(&capture_clause).hash(&mut self.s);
// closures inherit TypeckResults
- self.hash_expr(&self.cx.tcx.hir().body(body).value);
+ self.hash_expr(self.cx.tcx.hir().body(body).value);
},
ExprKind::Field(e, ref f) => {
self.hash_expr(e);
@@ -743,8 +749,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
s.hash(&mut self.s);
},
- ExprKind::MethodCall(path, args, ref _fn_span) => {
+ ExprKind::MethodCall(path, receiver, args, ref _fn_span) => {
self.hash_name(path.ident.name);
+ self.hash_expr(receiver);
self.hash_exprs(args);
},
ExprKind::ConstBlock(ref l_id) => {
@@ -815,8 +822,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
pub fn hash_pat(&mut self, pat: &Pat<'_>) {
std::mem::discriminant(&pat.kind).hash(&mut self.s);
match pat.kind {
- PatKind::Binding(ann, _, _, pat) => {
- std::mem::discriminant(&ann).hash(&mut self.s);
+ PatKind::Binding(BindingAnnotation(by_ref, mutability), _, _, pat) => {
+ std::mem::discriminant(&by_ref).hash(&mut self.s);
+ std::mem::discriminant(&mutability).hash(&mut self.s);
if let Some(pat) = pat {
self.hash_pat(pat);
}
@@ -921,7 +929,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
}
}
- pub fn hash_lifetime(&mut self, lifetime: Lifetime) {
+ pub fn hash_lifetime(&mut self, lifetime: &Lifetime) {
std::mem::discriminant(&lifetime.name).hash(&mut self.s);
if let LifetimeName::Param(param_id, ref name) = lifetime.name {
std::mem::discriminant(name).hash(&mut self.s);
@@ -954,7 +962,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
mut_ty.mutbl.hash(&mut self.s);
},
TyKind::Rptr(lifetime, ref mut_ty) => {
- self.hash_lifetime(*lifetime);
+ self.hash_lifetime(lifetime);
self.hash_ty(mut_ty.ty);
mut_ty.mutbl.hash(&mut self.s);
},
@@ -979,11 +987,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
}
},
TyKind::Path(ref qpath) => self.hash_qpath(qpath),
- TyKind::OpaqueDef(_, arg_list) => {
+ TyKind::OpaqueDef(_, arg_list, in_trait) => {
self.hash_generic_args(arg_list);
+ in_trait.hash(&mut self.s);
},
TyKind::TraitObject(_, lifetime, _) => {
- self.hash_lifetime(*lifetime);
+ self.hash_lifetime(lifetime);
},
TyKind::Typeof(anon_const) => {
self.hash_body(anon_const.body);
@@ -1002,7 +1011,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
pub fn hash_body(&mut self, body_id: BodyId) {
// swap out TypeckResults when hashing a body
let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body_id));
- self.hash_expr(&self.cx.tcx.hir().body(body_id).value);
+ self.hash_expr(self.cx.tcx.hir().body(body_id).value);
self.maybe_typeck_results = old_maybe_typeck_results;
}
@@ -1010,7 +1019,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
for arg in arg_list {
match *arg {
GenericArg::Lifetime(l) => self.hash_lifetime(l),
- GenericArg::Type(ref ty) => self.hash_ty(ty),
+ GenericArg::Type(ty) => self.hash_ty(ty),
GenericArg::Const(ref ca) => self.hash_body(ca.value.body),
GenericArg::Infer(ref inf) => self.hash_ty(&inf.to_ty()),
}
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 8322df862..3ebfc5e00 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1,9 +1,9 @@
#![feature(array_chunks)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
-#![feature(let_else)]
#![feature(let_chains)]
#![feature(lint_reasons)]
+#![feature(never_type)]
#![feature(once_cell)]
#![feature(rustc_private)]
#![recursion_limit = "512"]
@@ -24,21 +24,25 @@ extern crate rustc_attr;
extern crate rustc_data_structures;
extern crate rustc_errors;
extern crate rustc_hir;
+extern crate rustc_hir_typeck;
+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_format;
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;
pub mod ast_utils;
pub mod attrs;
+mod check_proc_macro;
pub mod comparisons;
pub mod consts;
pub mod diagnostics;
@@ -46,6 +50,7 @@ pub mod eager_or_lazy;
pub mod higher;
mod hir_utils;
pub mod macros;
+pub mod mir;
pub mod msrvs;
pub mod numeric_literal;
pub mod paths;
@@ -59,10 +64,12 @@ pub mod usage;
pub mod visitors;
pub use self::attrs::*;
+pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match};
pub use self::hir_utils::{
both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash,
};
+use core::ops::ControlFlow;
use std::collections::hash_map::Entry;
use std::hash::BuildHasherDefault;
use std::sync::OnceLock;
@@ -74,8 +81,8 @@ use rustc_ast::Attribute;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unhash::UnhashMap;
use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_hir::def::{DefKind, Namespace, Res};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
use rustc_hir::hir_id::{HirIdMap, HirIdSet};
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
@@ -85,6 +92,7 @@ use rustc_hir::{
Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
TraitRef, TyKind, UnOp,
};
+use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, Level, Lint, LintContext};
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::ty as rustc_ty;
@@ -102,6 +110,7 @@ use rustc_semver::RustcVersion;
use rustc_session::Session;
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::source_map::original_sp;
+use rustc_span::source_map::SourceMap;
use rustc_span::sym;
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{Span, DUMMY_SP};
@@ -109,14 +118,14 @@ use rustc_target::abi::Integer;
use crate::consts::{constant, Constant};
use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param};
-use crate::visitors::expr_visitor_no_bodies;
+use crate::visitors::for_each_expr;
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));
+ sess.span_err(span, format!("`{msrv}` is not a valid Rust version"));
}
}
None
@@ -187,7 +196,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<
let hir = cx.tcx.hir();
if_chain! {
if let Some(Node::Pat(pat)) = hir.find(hir_id);
- if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..));
+ if matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..));
let parent = hir.get_parent_node(hir_id);
if let Some(Node::Local(local)) = hir.find(parent);
then {
@@ -207,7 +216,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<
/// }
/// ```
pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
- let parent_id = cx.tcx.hir().get_parent_item(id);
+ let parent_id = cx.tcx.hir().get_parent_item(id).def_id;
match cx.tcx.hir().get_by_def_id(parent_id) {
Node::Item(&Item {
kind: ItemKind::Const(..) | ItemKind::Static(..),
@@ -234,19 +243,69 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
}
}
-/// Checks if a `QPath` resolves to a constructor of a `LangItem`.
+/// Checks if a `Res` refers 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 {
+pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> bool {
+ if let Res::Def(DefKind::Ctor(..), id) = res
+ && let Ok(lang_id) = cx.tcx.lang_items().require(lang_item)
+ && let Some(id) = cx.tcx.opt_parent(id)
+ {
+ id == lang_id
+ } else {
+ false
+ }
+}
+
+pub fn is_res_diagnostic_ctor(cx: &LateContext<'_>, res: Res, diag_item: Symbol) -> bool {
+ if let Res::Def(DefKind::Ctor(..), id) = res
+ && let Some(id) = cx.tcx.opt_parent(id)
+ {
+ cx.tcx.is_diagnostic_item(diag_item, id)
+ } else {
+ false
+ }
+}
+
+/// Checks if a `QPath` resolves to a constructor of a diagnostic item.
+pub fn is_diagnostic_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, diagnostic_item: Symbol) -> 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) == item_id;
- }
+ return cx.tcx.is_diagnostic_item(diagnostic_item, cx.tcx.parent(ctor_id));
}
}
false
}
+/// Checks if the `DefId` matches the given diagnostic item or it's constructor.
+pub fn is_diagnostic_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: Symbol) -> bool {
+ let did = match cx.tcx.def_kind(did) {
+ DefKind::Ctor(..) => cx.tcx.parent(did),
+ // Constructors for types in external crates seem to have `DefKind::Variant`
+ DefKind::Variant => match cx.tcx.opt_parent(did) {
+ Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did,
+ _ => did,
+ },
+ _ => did,
+ };
+
+ cx.tcx.is_diagnostic_item(item, did)
+}
+
+/// Checks if the `DefId` matches the given `LangItem` or it's constructor.
+pub fn is_lang_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: LangItem) -> bool {
+ let did = match cx.tcx.def_kind(did) {
+ DefKind::Ctor(..) => cx.tcx.parent(did),
+ // Constructors for types in external crates seem to have `DefKind::Variant`
+ DefKind::Variant => match cx.tcx.opt_parent(did) {
+ Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did,
+ _ => did,
+ },
+ _ => did,
+ };
+
+ cx.tcx.lang_items().require(item).map_or(false, |id| id == did)
+}
+
pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
matches!(
expr.kind,
@@ -332,7 +391,7 @@ pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tc
.map_or(&[][..], |a| a.args)
.iter()
.filter_map(|a| match a {
- hir::GenericArg::Type(ty) => Some(ty),
+ hir::GenericArg::Type(ty) => Some(*ty),
_ => None,
})
}
@@ -370,15 +429,19 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
/// 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.
+/// Please use `is_path_diagnostic_item` if the target is a diagnostic item.
pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments))
}
-/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given
-/// diagnostic item.
-pub fn is_expr_diagnostic_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
- path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
+/// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
+/// it matches the given diagnostic item.
+pub fn is_path_diagnostic_item<'tcx>(
+ cx: &LateContext<'_>,
+ maybe_path: &impl MaybePath<'tcx>,
+ diag_item: Symbol,
+) -> bool {
+ path_def_id(cx, maybe_path).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
@@ -462,15 +525,49 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
path_res(cx, maybe_path).opt_def_id()
}
-/// Resolves a def path like `std::vec::Vec`.
+fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
+ let single = |ty| tcx.incoherent_impls(ty).iter().copied();
+ let empty = || [].iter().copied();
+ match name {
+ "bool" => single(BoolSimplifiedType),
+ "char" => single(CharSimplifiedType),
+ "str" => single(StrSimplifiedType),
+ "array" => single(ArraySimplifiedType),
+ "slice" => single(SliceSimplifiedType),
+ // FIXME: rustdoc documents these two using just `pointer`.
+ //
+ // Maybe this is something we should do here too.
+ "const_ptr" => single(PtrSimplifiedType(Mutability::Not)),
+ "mut_ptr" => single(PtrSimplifiedType(Mutability::Mut)),
+ "isize" => single(IntSimplifiedType(IntTy::Isize)),
+ "i8" => single(IntSimplifiedType(IntTy::I8)),
+ "i16" => single(IntSimplifiedType(IntTy::I16)),
+ "i32" => single(IntSimplifiedType(IntTy::I32)),
+ "i64" => single(IntSimplifiedType(IntTy::I64)),
+ "i128" => single(IntSimplifiedType(IntTy::I128)),
+ "usize" => single(UintSimplifiedType(UintTy::Usize)),
+ "u8" => single(UintSimplifiedType(UintTy::U8)),
+ "u16" => single(UintSimplifiedType(UintTy::U16)),
+ "u32" => single(UintSimplifiedType(UintTy::U32)),
+ "u64" => single(UintSimplifiedType(UintTy::U64)),
+ "u128" => single(UintSimplifiedType(UintTy::U128)),
+ "f32" => single(FloatSimplifiedType(FloatTy::F32)),
+ "f64" => single(FloatSimplifiedType(FloatTy::F64)),
+ _ => empty(),
+ }
+}
+
+/// Resolves a def path like `std::vec::Vec`. `namespace_hint` can be supplied to disambiguate
+/// between `std::vec` the module and `std::vec` the macro
+///
/// This function is expensive and should be used sparingly.
-pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
- fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str) -> Option<Res> {
+pub fn def_path_res(cx: &LateContext<'_>, path: &[&str], namespace_hint: Option<Namespace>) -> Res {
+ fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str, matches_ns: impl Fn(Res) -> bool) -> Option<Res> {
match tcx.def_kind(def_id) {
DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx
.module_children(def_id)
.iter()
- .find(|item| item.ident.name.as_str() == name)
+ .find(|item| item.ident.name.as_str() == name && matches_ns(item.res.expect_non_local()))
.map(|child| child.res.expect_non_local()),
DefKind::Impl => tcx
.associated_item_def_ids(def_id)
@@ -478,40 +575,17 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
.copied()
.find(|assoc_def_id| tcx.item_name(*assoc_def_id).as_str() == name)
.map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id)),
+ DefKind::Struct | DefKind::Union => tcx
+ .adt_def(def_id)
+ .non_enum_variant()
+ .fields
+ .iter()
+ .find(|f| f.name.as_str() == name)
+ .map(|f| Res::Def(DefKind::Field, f.did)),
_ => None,
}
}
- fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
- let single = |ty| tcx.incoherent_impls(ty).iter().copied();
- let empty = || [].iter().copied();
- match name {
- "bool" => single(BoolSimplifiedType),
- "char" => single(CharSimplifiedType),
- "str" => single(StrSimplifiedType),
- "array" => single(ArraySimplifiedType),
- "slice" => single(SliceSimplifiedType),
- // FIXME: rustdoc documents these two using just `pointer`.
- //
- // Maybe this is something we should do here too.
- "const_ptr" => single(PtrSimplifiedType(Mutability::Not)),
- "mut_ptr" => single(PtrSimplifiedType(Mutability::Mut)),
- "isize" => single(IntSimplifiedType(IntTy::Isize)),
- "i8" => single(IntSimplifiedType(IntTy::I8)),
- "i16" => single(IntSimplifiedType(IntTy::I16)),
- "i32" => single(IntSimplifiedType(IntTy::I32)),
- "i64" => single(IntSimplifiedType(IntTy::I64)),
- "i128" => single(IntSimplifiedType(IntTy::I128)),
- "usize" => single(UintSimplifiedType(UintTy::Usize)),
- "u8" => single(UintSimplifiedType(UintTy::U8)),
- "u16" => single(UintSimplifiedType(UintTy::U16)),
- "u32" => single(UintSimplifiedType(UintTy::U32)),
- "u64" => single(UintSimplifiedType(UintTy::U64)),
- "u128" => single(UintSimplifiedType(UintTy::U128)),
- "f32" => single(FloatSimplifiedType(FloatTy::F32)),
- "f64" => single(FloatSimplifiedType(FloatTy::F64)),
- _ => empty(),
- }
- }
+
fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> {
tcx.crates(())
.iter()
@@ -520,32 +594,45 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
.map(CrateNum::as_def_id)
}
- let (base, first, path) = match *path {
- [base, first, ref path @ ..] => (base, first, path),
+ let (base, path) = match *path {
[primitive] => {
return PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy);
},
+ [base, ref path @ ..] => (base, path),
_ => return Res::Err,
};
let tcx = cx.tcx;
let starts = find_primitive(tcx, base)
.chain(find_crate(tcx, base))
- .filter_map(|id| item_child_by_name(tcx, id, first));
+ .map(|id| Res::Def(tcx.def_kind(id), id));
for first in starts {
let last = path
.iter()
.copied()
+ .enumerate()
// for each segment, find the child item
- .try_fold(first, |res, segment| {
+ .try_fold(first, |res, (idx, segment)| {
+ let matches_ns = |res: Res| {
+ // If at the last segment in the path, respect the namespace hint
+ if idx == path.len() - 1 {
+ match namespace_hint {
+ Some(ns) => res.matches_ns(ns),
+ None => true,
+ }
+ } else {
+ res.matches_ns(Namespace::TypeNS)
+ }
+ };
+
let def_id = res.def_id();
- if let Some(item) = item_child_by_name(tcx, def_id, segment) {
+ if let Some(item) = item_child_by_name(tcx, def_id, segment, matches_ns) {
Some(item)
} else if matches!(res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
// it is not a child item so check inherent impl items
tcx.inherent_impls(def_id)
.iter()
- .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment))
+ .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment, matches_ns))
} else {
None
}
@@ -561,8 +648,10 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
/// Convenience function to get the `DefId` of a trait by path.
/// It could be a trait or trait alias.
+///
+/// This function is expensive and should be used sparingly.
pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
- match def_path_res(cx, path) {
+ match def_path_res(cx, path, Some(Namespace::TypeNS)) {
Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
_ => None,
}
@@ -588,8 +677,8 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) ->
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
let parent_impl = cx.tcx.hir().get_parent_item(hir_id);
if_chain! {
- if parent_impl != CRATE_DEF_ID;
- if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent_impl);
+ if parent_impl != hir::CRATE_OWNER_ID;
+ if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent_impl.def_id);
if let hir::ItemKind::Impl(impl_) = &item.kind;
then {
return impl_.of_trait.as_ref();
@@ -729,13 +818,37 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
false
}
},
- ExprKind::Call(repl_func, _) => is_default_equivalent_call(cx, repl_func),
- ExprKind::Path(qpath) => is_lang_ctor(cx, qpath, OptionNone),
+ ExprKind::Call(repl_func, []) => is_default_equivalent_call(cx, repl_func),
+ ExprKind::Call(from_func, [ref arg]) => is_default_equivalent_from(cx, from_func, arg),
+ ExprKind::Path(qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, e.hir_id), OptionNone),
ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])),
_ => false,
}
}
+fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &Expr<'_>) -> bool {
+ if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = from_func.kind &&
+ seg.ident.name == sym::from
+ {
+ match arg.kind {
+ ExprKind::Lit(hir::Lit {
+ node: LitKind::Str(ref sym, _),
+ ..
+ }) => return sym.is_empty() && is_path_diagnostic_item(cx, ty, sym::String),
+ ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
+ ExprKind::Repeat(_, ArrayLen::Body(len)) => {
+ if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind &&
+ let LitKind::Int(v, _) = const_lit.node
+ {
+ return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);
+ }
+ }
+ _ => (),
+ }
+ }
+ 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.
@@ -1022,26 +1135,26 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'
v.allow_closure.then_some(v.captures)
}
+/// Arguments of a method: the receiver and all the additional arguments.
+pub type MethodArguments<'tcx> = Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>;
+
/// 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>) {
+pub fn method_calls<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> (Vec<Symbol>, MethodArguments<'tcx>, Vec<Span>) {
let mut method_names = Vec::with_capacity(max_depth);
let mut arg_lists = Vec::with_capacity(max_depth);
let mut spans = Vec::with_capacity(max_depth);
let mut current = expr;
for _ in 0..max_depth {
- if let ExprKind::MethodCall(path, args, _) = &current.kind {
- if args.iter().any(|e| e.span.from_expansion()) {
+ if let ExprKind::MethodCall(path, receiver, args, _) = &current.kind {
+ if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
break;
}
method_names.push(path.ident.name);
- arg_lists.push(&**args);
+ arg_lists.push((*receiver, &**args));
spans.push(path.ident.span);
- current = &args[0];
+ current = receiver;
} else {
break;
}
@@ -1056,18 +1169,18 @@ pub fn method_calls<'tcx>(
/// `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>]>> {
+pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<(&'a Expr<'a>, &'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 let ExprKind::MethodCall(path, receiver, args, _) = current.kind {
if path.ident.name.as_str() == *method_name {
- if args.iter().any(|e| e.span.from_expansion()) {
+ if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
return None;
}
- matched.push(args); // build up `matched` backwards
- current = &args[0]; // go to parent expression
+ matched.push((receiver, args)); // build up `matched` backwards
+ current = receiver; // go to parent expression
} else {
return None;
}
@@ -1095,7 +1208,7 @@ pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
/// 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);
+ let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id).def_id;
match cx.tcx.hir().find_by_def_id(parent_id) {
Some(
Node::Item(Item { ident, .. })
@@ -1112,7 +1225,7 @@ pub struct ContainsName {
}
impl<'tcx> Visitor<'tcx> for ContainsName {
- fn visit_name(&mut self, _: Span, name: Symbol) {
+ fn visit_name(&mut self, name: Symbol) {
if self.name == name {
self.result = true;
}
@@ -1128,17 +1241,14 @@ pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool {
/// Returns `true` if `expr` contains a return expression
pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
- let mut found = false;
- expr_visitor_no_bodies(|expr| {
- if !found {
- if let hir::ExprKind::Ret(..) = &expr.kind {
- found = true;
- }
+ for_each_expr(expr, |e| {
+ if matches!(e.kind, hir::ExprKind::Ret(..)) {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(())
}
- !found
})
- .visit_expr(expr);
- found
+ .is_some()
}
/// Extends the span to the beginning of the spans line, incl. whitespaces.
@@ -1230,8 +1340,10 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
ty_is_fn_once_param(cx.tcx, ty.skip_binder(), predicates).then_some(())
})
},
- ExprKind::MethodCall(_, args, _) => {
- let i = args.iter().position(|arg| arg.hir_id == id)?;
+ ExprKind::MethodCall(_, receiver, args, _) => {
+ let i = std::iter::once(receiver)
+ .chain(args.iter())
+ .position(|arg| arg.hir_id == id)?;
let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
@@ -1376,8 +1488,8 @@ pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
/// 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.
+/// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_hir_analysis::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()
}
@@ -1525,7 +1637,7 @@ pub fn is_self(slf: &Param<'_>) -> bool {
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 {
+ if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path.res {
return true;
}
}
@@ -1541,8 +1653,9 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It
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::TupleStruct(ref path, pat, ddpos) = arm.pat.kind;
+ if ddpos.as_opt_usize().is_none();
+ if is_res_lang_ctor(cx, cx.qpath_res(path, arm.pat.hir_id), ResultOk);
if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
if path_to_local_id(arm.body, hir_id);
then {
@@ -1554,7 +1667,7 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc
fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind {
- is_lang_ctor(cx, path, ResultErr)
+ is_res_lang_ctor(cx, cx.qpath_res(path, arm.pat.hir_id), ResultErr)
} else {
false
}
@@ -1636,7 +1749,7 @@ pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool
return true;
}
prev_enclosing_node = Some(enclosing_node);
- enclosing_node = map.local_def_id_to_hir_id(map.get_parent_item(enclosing_node));
+ enclosing_node = map.get_parent_item(enclosing_node).into();
}
false
@@ -1653,6 +1766,7 @@ pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool
/// ```rust,ignore
/// if let Some(args) = match_function_call(cx, cmp_max_call, &paths::CMP_MAX);
/// ```
+/// This function is deprecated. Use [`match_function_call_with_def_id`].
pub fn match_function_call<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>,
@@ -1670,6 +1784,22 @@ pub fn match_function_call<'tcx>(
None
}
+pub fn match_function_call_with_def_id<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ fun_def_id: DefId,
+) -> Option<&'tcx [Expr<'tcx>]> {
+ if_chain! {
+ if let ExprKind::Call(fun, args) = expr.kind;
+ if let ExprKind::Path(ref qpath) = fun.kind;
+ if cx.qpath_res(qpath, fun.hir_id).opt_def_id() == Some(fun_def_id);
+ then {
+ return Some(args);
+ }
+ };
+ None
+}
+
/// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if
/// any.
///
@@ -1803,7 +1933,7 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool
}
};
- let mut expr = &func.value;
+ let mut expr = func.value;
loop {
match expr.kind {
#[rustfmt::skip]
@@ -1892,8 +2022,8 @@ pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> {
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
+ if let ast::AttrKind::Normal(ref normal) = attr.kind {
+ normal.item.path == sym::no_std
} else {
false
}
@@ -1902,8 +2032,8 @@ pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
- if let ast::AttrKind::Normal(ref attr, _) = attr.kind {
- attr.path == sym::no_core
+ if let ast::AttrKind::Normal(ref normal) = attr.kind {
+ normal.item.path == sym::no_core
} else {
false
}
@@ -1978,9 +2108,9 @@ pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
}
}
-/// 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.
+/// 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();
@@ -2151,7 +2281,7 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalDefId, f: impl Fn(&[Symbol
Entry::Vacant(entry) => {
let mut names = Vec::new();
for id in tcx.hir().module_items(module) {
- if matches!(tcx.def_kind(id.def_id), DefKind::Const)
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Const)
&& let item = tcx.hir().item(id)
&& let ItemKind::Const(ty, _body) = item.kind {
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
@@ -2272,6 +2402,41 @@ pub fn walk_to_expr_usage<'tcx, T>(
None
}
+/// Checks whether a given span has any comment token
+/// This checks for all types of comment: line "//", block "/**", doc "///" "//!"
+pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
+ let Ok(snippet) = sm.span_to_snippet(span) else { return false };
+ return tokenize(&snippet).any(|token| {
+ matches!(
+ token.kind,
+ TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }
+ )
+ });
+}
+
+/// Return all the comments a given span contains
+/// Comments are returned wrapped with their relevant delimiters
+pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String {
+ let snippet = sm.span_to_snippet(span).unwrap_or_default();
+ let mut comments_buf: Vec<String> = Vec::new();
+ let mut index: usize = 0;
+
+ for token in tokenize(&snippet) {
+ let token_range = index..(index + token.len as usize);
+ index += token.len as usize;
+ match token.kind {
+ TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => {
+ if let Some(comment) = snippet.get(token_range) {
+ comments_buf.push(comment.to_string());
+ }
+ },
+ _ => (),
+ }
+ }
+
+ comments_buf.join("\n")
+}
+
macro_rules! op_utils {
($($name:ident $assign:ident)*) => {
/// Binary operation traits like `LangItem::Add`
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index a268e339b..9a682fbe6 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -1,16 +1,22 @@
#![allow(clippy::similar_names)] // `expr` and `expn`
-use crate::visitors::expr_visitor_no_bodies;
+use crate::is_path_diagnostic_item;
+use crate::source::snippet_opt;
+use crate::visitors::{for_each_expr, Descend};
use arrayvec::ArrayVec;
-use if_chain::if_chain;
+use itertools::{izip, Either, Itertools};
use rustc_ast::ast::LitKind;
-use rustc_hir::intravisit::Visitor;
-use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath};
+use rustc_hir::intravisit::{walk_expr, Visitor};
+use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, Node, QPath};
+use rustc_lexer::unescape::unescape_literal;
+use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
use rustc_lint::LateContext;
+use rustc_parse_format::{self as rpf, Alignment};
use rustc_span::def_id::DefId;
use rustc_span::hygiene::{self, MacroKind, SyntaxContext};
-use rustc_span::{sym, ExpnData, ExpnId, ExpnKind, Span, Symbol};
+use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Pos, Span, SpanData, Symbol};
+use std::iter::{once, zip};
use std::ops::ControlFlow;
const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[
@@ -265,20 +271,19 @@ fn find_assert_args_inner<'a, const N: usize>(
};
let mut args = ArrayVec::new();
let mut panic_expn = None;
- expr_visitor_no_bodies(|e| {
+ let _: Option<!> = for_each_expr(expr, |e| {
if args.is_full() {
if panic_expn.is_none() && e.span.ctxt() != expr.span.ctxt() {
panic_expn = PanicExpn::parse(cx, e);
}
- panic_expn.is_none()
+ ControlFlow::Continue(Descend::from(panic_expn.is_none()))
} else if is_assert_arg(cx, e, expn) {
args.push(e);
- false
+ ControlFlow::Continue(Descend::No)
} else {
- true
+ ControlFlow::Continue(Descend::Yes)
}
- })
- .visit_expr(expr);
+ });
let args = args.into_inner().ok()?;
// if no `panic!(..)` is found, use `PanicExpn::Empty`
// to indicate that the default assertion message is used
@@ -292,22 +297,19 @@ fn find_assert_within_debug_assert<'a>(
expn: ExpnId,
assert_name: Symbol,
) -> Option<(&'a Expr<'a>, ExpnId)> {
- let mut found = None;
- expr_visitor_no_bodies(|e| {
- if found.is_some() || !e.span.from_expansion() {
- return false;
+ for_each_expr(expr, |e| {
+ if !e.span.from_expansion() {
+ return ControlFlow::Continue(Descend::No);
}
let e_expn = e.span.ctxt().outer_expn();
if e_expn == expn {
- return true;
- }
- if e_expn.expn_data().macro_def_id.map(|id| cx.tcx.item_name(id)) == Some(assert_name) {
- found = Some((e, e_expn));
+ ControlFlow::Continue(Descend::Yes)
+ } else if e_expn.expn_data().macro_def_id.map(|id| cx.tcx.item_name(id)) == Some(assert_name) {
+ ControlFlow::Break((e, e_expn))
+ } else {
+ ControlFlow::Continue(Descend::No)
}
- false
})
- .visit_expr(expr);
- found
}
fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) -> bool {
@@ -332,222 +334,692 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) ->
}
}
-/// A parsed `format_args!` expansion
+/// The format string doesn't exist in the HIR, so we reassemble it from source code
#[derive(Debug)]
-pub struct FormatArgsExpn<'tcx> {
- /// Span of the first argument, the format string
- pub format_string_span: Span,
- /// The format string split by formatted args like `{..}`
- pub format_string_parts: Vec<Symbol>,
- /// Values passed after the format string
- pub value_args: Vec<&'tcx Expr<'tcx>>,
- /// Each element is a `value_args` index and a formatting trait (e.g. `sym::Debug`)
- pub formatters: Vec<(usize, Symbol)>,
- /// List of `fmt::v1::Argument { .. }` expressions. If this is empty,
- /// then `formatters` represents the format args (`{..}`).
- /// If this is non-empty, it represents the format args, and the `position`
- /// parameters within the struct expressions are indexes of `formatters`.
- pub specs: Vec<&'tcx Expr<'tcx>>,
+pub struct FormatString {
+ /// Span of the whole format string literal, including `[r#]"`.
+ pub span: Span,
+ /// Snippet of the whole format string literal, including `[r#]"`.
+ pub snippet: String,
+ /// If the string is raw `r"..."`/`r#""#`, how many `#`s does it have on each side.
+ pub style: Option<usize>,
+ /// The unescaped value of the format string, e.g. `"val – {}"` for the literal
+ /// `"val \u{2013} {}"`.
+ pub unescaped: String,
+ /// The format string split by format args like `{..}`.
+ pub parts: Vec<Symbol>,
}
-impl<'tcx> FormatArgsExpn<'tcx> {
- /// Parses an expanded `format_args!` or `format_args_nl!` invocation
- pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<Self> {
- macro_backtrace(expr.span).find(|macro_call| {
- matches!(
- cx.tcx.item_name(macro_call.def_id),
- sym::const_format_args | sym::format_args | sym::format_args_nl
- )
- })?;
- let mut format_string_span: Option<Span> = None;
- let mut format_string_parts: Vec<Symbol> = Vec::new();
- let mut value_args: Vec<&Expr<'_>> = Vec::new();
- let mut formatters: Vec<(usize, Symbol)> = Vec::new();
- let mut specs: Vec<&Expr<'_>> = Vec::new();
- expr_visitor_no_bodies(|e| {
- // if we're still inside of the macro definition...
- if e.span.ctxt() == expr.span.ctxt() {
- // ArgumentV1::new_<format_trait>(<value>)
- if_chain! {
- if let ExprKind::Call(callee, [val]) = e.kind;
- if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind;
- if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
- if path.segments.last().unwrap().ident.name == sym::ArgumentV1;
- if seg.ident.name.as_str().starts_with("new_");
- then {
- let val_idx = if_chain! {
- if val.span.ctxt() == expr.span.ctxt();
- if let ExprKind::Field(_, field) = val.kind;
- if let Ok(idx) = field.name.as_str().parse();
- then {
- // tuple index
- idx
- } else {
- // assume the value expression is passed directly
- formatters.len()
- }
- };
- let fmt_trait = match seg.ident.name.as_str() {
- "new_display" => "Display",
- "new_debug" => "Debug",
- "new_lower_exp" => "LowerExp",
- "new_upper_exp" => "UpperExp",
- "new_octal" => "Octal",
- "new_pointer" => "Pointer",
- "new_binary" => "Binary",
- "new_lower_hex" => "LowerHex",
- "new_upper_hex" => "UpperHex",
- _ => unreachable!(),
- };
- formatters.push((val_idx, Symbol::intern(fmt_trait)));
- }
- }
- if let ExprKind::Struct(QPath::Resolved(_, path), ..) = e.kind {
- if path.segments.last().unwrap().ident.name == sym::Argument {
- specs.push(e);
- }
+impl FormatString {
+ fn new(cx: &LateContext<'_>, pieces: &Expr<'_>) -> Option<Self> {
+ // format_args!(r"a {} b \", 1);
+ //
+ // expands to
+ //
+ // ::core::fmt::Arguments::new_v1(&["a ", " b \\"],
+ // &[::core::fmt::ArgumentV1::new_display(&1)]);
+ //
+ // where `pieces` is the expression `&["a ", " b \\"]`. It has the span of `r"a {} b \"`
+ let span = pieces.span;
+ let snippet = snippet_opt(cx, span)?;
+
+ let (inner, style) = match tokenize(&snippet).next()?.kind {
+ TokenKind::Literal { kind, .. } => {
+ let style = match kind {
+ LiteralKind::Str { .. } => None,
+ LiteralKind::RawStr { n_hashes: Some(n), .. } => Some(n.into()),
+ _ => return None,
+ };
+
+ let start = style.map_or(1, |n| 2 + n);
+ let end = snippet.len() - style.map_or(1, |n| 1 + n);
+
+ (&snippet[start..end], style)
+ },
+ _ => return None,
+ };
+
+ let mode = if style.is_some() {
+ unescape::Mode::RawStr
+ } else {
+ unescape::Mode::Str
+ };
+
+ let mut unescaped = String::with_capacity(inner.len());
+ unescape_literal(inner, mode, &mut |_, ch| match ch {
+ Ok(ch) => unescaped.push(ch),
+ Err(e) if !e.is_fatal() => (),
+ Err(e) => panic!("{e:?}"),
+ });
+
+ let mut parts = Vec::new();
+ let _: Option<!> = for_each_expr(pieces, |expr| {
+ if let ExprKind::Lit(lit) = &expr.kind
+ && let LitKind::Str(symbol, _) = lit.node
+ {
+ parts.push(symbol);
+ }
+ ControlFlow::Continue(())
+ });
+
+ Some(Self {
+ span,
+ snippet,
+ style,
+ unescaped,
+ parts,
+ })
+ }
+}
+
+struct FormatArgsValues<'tcx> {
+ /// Values passed after the format string and implicit captures. `[1, z + 2, x]` for
+ /// `format!("{x} {} {}", 1, z + 2)`.
+ value_args: Vec<&'tcx Expr<'tcx>>,
+ /// Maps an `rt::v1::Argument::position` or an `rt::v1::Count::Param` to its index in
+ /// `value_args`
+ pos_to_value_index: Vec<usize>,
+ /// Used to check if a value is declared inline & to resolve `InnerSpan`s.
+ format_string_span: SpanData,
+}
+
+impl<'tcx> FormatArgsValues<'tcx> {
+ fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self {
+ let mut pos_to_value_index = Vec::new();
+ let mut value_args = Vec::new();
+ let _: Option<!> = for_each_expr(args, |expr| {
+ if expr.span.ctxt() == args.span.ctxt() {
+ // ArgumentV1::new_<format_trait>(<val>)
+ // ArgumentV1::from_usize(<val>)
+ if let ExprKind::Call(callee, [val]) = expr.kind
+ && let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind
+ && let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind
+ && path.segments.last().unwrap().ident.name == sym::ArgumentV1
+ {
+ let val_idx = if val.span.ctxt() == expr.span.ctxt()
+ && let ExprKind::Field(_, field) = val.kind
+ && let Ok(idx) = field.name.as_str().parse()
+ {
+ // tuple index
+ idx
+ } else {
+ // assume the value expression is passed directly
+ pos_to_value_index.len()
+ };
+
+ pos_to_value_index.push(val_idx);
}
- // walk through the macro expansion
- return true;
+ ControlFlow::Continue(Descend::Yes)
+ } else {
+ // assume that any expr with a differing span is a value
+ value_args.push(expr);
+ ControlFlow::Continue(Descend::No)
}
- // assume that the first expr with a differing context represents
- // (and has the span of) the format string
- if format_string_span.is_none() {
- format_string_span = Some(e.span);
- let span = e.span;
- // walk the expr and collect string literals which are format string parts
- expr_visitor_no_bodies(|e| {
- if e.span.ctxt() != span.ctxt() {
- // defensive check, probably doesn't happen
- return false;
- }
- if let ExprKind::Lit(lit) = &e.kind {
- if let LitKind::Str(symbol, _s) = lit.node {
- format_string_parts.push(symbol);
- }
- }
- true
- })
- .visit_expr(e);
+ });
+
+ Self {
+ value_args,
+ pos_to_value_index,
+ format_string_span,
+ }
+ }
+}
+
+/// The positions of a format argument's value, precision and width
+///
+/// A position is an index into the second argument of `Arguments::new_v1[_formatted]`
+#[derive(Debug, Default, Copy, Clone)]
+struct ParamPosition {
+ /// The position stored in `rt::v1::Argument::position`.
+ value: usize,
+ /// The position stored in `rt::v1::FormatSpec::width` if it is a `Count::Param`.
+ width: Option<usize>,
+ /// The position stored in `rt::v1::FormatSpec::precision` if it is a `Count::Param`.
+ precision: Option<usize>,
+}
+
+impl<'tcx> Visitor<'tcx> for ParamPosition {
+ fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) {
+ fn parse_count(expr: &Expr<'_>) -> Option<usize> {
+ // ::core::fmt::rt::v1::Count::Param(1usize),
+ if let ExprKind::Call(ctor, [val]) = expr.kind
+ && let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind
+ && path.segments.last()?.ident.name == sym::Param
+ && let ExprKind::Lit(lit) = &val.kind
+ && let LitKind::Int(pos, _) = lit.node
+ {
+ Some(pos as usize)
} else {
- // assume that any further exprs with a differing context are value args
- value_args.push(e);
+ None
}
- // don't walk anything not from the macro expansion (e.a. inputs)
- false
+ }
+
+ match field.ident.name {
+ sym::position => {
+ if let ExprKind::Lit(lit) = &field.expr.kind
+ && let LitKind::Int(pos, _) = lit.node
+ {
+ self.value = pos as usize;
+ }
+ },
+ sym::precision => {
+ self.precision = parse_count(field.expr);
+ },
+ sym::width => {
+ self.width = parse_count(field.expr);
+ },
+ _ => walk_expr(self, field.expr),
+ }
+ }
+}
+
+/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)`
+fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option<impl Iterator<Item = ParamPosition> + 'tcx> {
+ if let ExprKind::AddrOf(.., array) = fmt_arg.kind
+ && let ExprKind::Array(specs) = array.kind
+ {
+ Some(specs.iter().map(|spec| {
+ let mut position = ParamPosition::default();
+ position.visit_expr(spec);
+ position
+ }))
+ } else {
+ None
+ }
+}
+
+/// `Span::from_inner`, but for `rustc_parse_format`'s `InnerSpan`
+fn span_from_inner(base: SpanData, inner: rpf::InnerSpan) -> Span {
+ Span::new(
+ base.lo + BytePos::from_usize(inner.start),
+ base.lo + BytePos::from_usize(inner.end),
+ base.ctxt,
+ base.parent,
+ )
+}
+
+/// How a format parameter is used in the format string
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum FormatParamKind {
+ /// An implicit parameter , such as `{}` or `{:?}`.
+ Implicit,
+ /// A parameter with an explicit number, e.g. `{1}`, `{0:?}`, or `{:.0$}`
+ Numbered,
+ /// A parameter with an asterisk precision. e.g. `{:.*}`.
+ Starred,
+ /// A named parameter with a named `value_arg`, such as the `x` in `format!("{x}", x = 1)`.
+ Named(Symbol),
+ /// An implicit named parameter, such as the `y` in `format!("{y}")`.
+ NamedInline(Symbol),
+}
+
+/// Where a format parameter is being used in the format string
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum FormatParamUsage {
+ /// Appears as an argument, e.g. `format!("{}", foo)`
+ Argument,
+ /// Appears as a width, e.g. `format!("{:width$}", foo, width = 1)`
+ Width,
+ /// Appears as a precision, e.g. `format!("{:.precision$}", foo, precision = 1)`
+ Precision,
+}
+
+/// A `FormatParam` is any place in a `FormatArgument` that refers to a supplied value, e.g.
+///
+/// ```
+/// let precision = 2;
+/// format!("{:.precision$}", 0.1234);
+/// ```
+///
+/// has two `FormatParam`s, a [`FormatParamKind::Implicit`] `.kind` with a `.value` of `0.1234`
+/// and a [`FormatParamKind::NamedInline("precision")`] `.kind` with a `.value` of `2`
+#[derive(Debug, Copy, Clone)]
+pub struct FormatParam<'tcx> {
+ /// The expression this parameter refers to.
+ pub value: &'tcx Expr<'tcx>,
+ /// How this parameter refers to its `value`.
+ pub kind: FormatParamKind,
+ /// Where this format param is being used - argument/width/precision
+ pub usage: FormatParamUsage,
+ /// Span of the parameter, may be zero width. Includes the whitespace of implicit parameters.
+ ///
+ /// ```text
+ /// format!("{}, { }, {0}, {name}", ...);
+ /// ^ ~~ ~ ~~~~
+ /// ```
+ pub span: Span,
+}
+
+impl<'tcx> FormatParam<'tcx> {
+ fn new(
+ mut kind: FormatParamKind,
+ usage: FormatParamUsage,
+ position: usize,
+ inner: rpf::InnerSpan,
+ values: &FormatArgsValues<'tcx>,
+ ) -> Option<Self> {
+ let value_index = *values.pos_to_value_index.get(position)?;
+ let value = *values.value_args.get(value_index)?;
+ let span = span_from_inner(values.format_string_span, inner);
+
+ // if a param is declared inline, e.g. `format!("{x}")`, the generated expr's span points
+ // into the format string
+ if let FormatParamKind::Named(name) = kind && values.format_string_span.contains(value.span.data()) {
+ kind = FormatParamKind::NamedInline(name);
+ }
+
+ Some(Self {
+ value,
+ kind,
+ usage,
+ span,
})
- .visit_expr(expr);
- Some(FormatArgsExpn {
- format_string_span: format_string_span?,
- format_string_parts,
- value_args,
- formatters,
- specs,
+ }
+}
+
+/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and
+/// [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
+#[derive(Debug, Copy, Clone)]
+pub enum Count<'tcx> {
+ /// Specified with a literal number, stores the value.
+ Is(usize, Span),
+ /// Specified using `$` and `*` syntaxes. The `*` format is still considered to be
+ /// `FormatParamKind::Numbered`.
+ Param(FormatParam<'tcx>),
+ /// Not specified.
+ Implied(Option<Span>),
+}
+
+impl<'tcx> Count<'tcx> {
+ fn new(
+ usage: FormatParamUsage,
+ count: rpf::Count<'_>,
+ position: Option<usize>,
+ inner: Option<rpf::InnerSpan>,
+ values: &FormatArgsValues<'tcx>,
+ ) -> Option<Self> {
+ let span = inner.map(|inner| span_from_inner(values.format_string_span, inner));
+
+ Some(match count {
+ rpf::Count::CountIs(val) => Self::Is(val, span?),
+ rpf::Count::CountIsName(name, _) => Self::Param(FormatParam::new(
+ FormatParamKind::Named(Symbol::intern(name)),
+ usage,
+ position?,
+ inner?,
+ values,
+ )?),
+ rpf::Count::CountIsParam(_) => Self::Param(FormatParam::new(
+ FormatParamKind::Numbered,
+ usage,
+ position?,
+ inner?,
+ values,
+ )?),
+ rpf::Count::CountIsStar(_) => Self::Param(FormatParam::new(
+ FormatParamKind::Starred,
+ usage,
+ position?,
+ inner?,
+ values,
+ )?),
+ rpf::Count::CountImplied => Self::Implied(span),
})
}
- /// Finds a nested call to `format_args!` within a `format!`-like macro call
- pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option<Self> {
- let mut format_args = None;
- expr_visitor_no_bodies(|e| {
- if format_args.is_some() {
- return false;
- }
- let e_ctxt = e.span.ctxt();
- if e_ctxt == expr.span.ctxt() {
- return true;
+ pub fn is_implied(self) -> bool {
+ matches!(self, Count::Implied(_))
+ }
+
+ pub fn param(self) -> Option<FormatParam<'tcx>> {
+ match self {
+ Count::Param(param) => Some(param),
+ _ => None,
+ }
+ }
+
+ pub fn span(self) -> Option<Span> {
+ match self {
+ Count::Is(_, span) => Some(span),
+ Count::Param(param) => Some(param.span),
+ Count::Implied(span) => span,
+ }
+ }
+}
+
+/// Specification for the formatting of an argument in the format string. See
+/// <https://doc.rust-lang.org/std/fmt/index.html#formatting-parameters> for the precise meanings.
+#[derive(Debug)]
+pub struct FormatSpec<'tcx> {
+ /// Optionally specified character to fill alignment with.
+ pub fill: Option<char>,
+ /// Optionally specified alignment.
+ pub align: Alignment,
+ /// Packed version of various flags provided, see [`rustc_parse_format::Flag`].
+ pub flags: u32,
+ /// Represents either the maximum width or the integer precision.
+ pub precision: Count<'tcx>,
+ /// The minimum width, will be padded according to `width`/`align`
+ pub width: Count<'tcx>,
+ /// The formatting trait used by the argument, e.g. `sym::Display` for `{}`, `sym::Debug` for
+ /// `{:?}`.
+ pub r#trait: Symbol,
+ pub trait_span: Option<Span>,
+}
+
+impl<'tcx> FormatSpec<'tcx> {
+ fn new(spec: rpf::FormatSpec<'_>, positions: ParamPosition, values: &FormatArgsValues<'tcx>) -> Option<Self> {
+ Some(Self {
+ fill: spec.fill,
+ align: spec.align,
+ flags: spec.flags,
+ precision: Count::new(
+ FormatParamUsage::Precision,
+ spec.precision,
+ positions.precision,
+ spec.precision_span,
+ values,
+ )?,
+ width: Count::new(
+ FormatParamUsage::Width,
+ spec.width,
+ positions.width,
+ spec.width_span,
+ values,
+ )?,
+ r#trait: match spec.ty {
+ "" => sym::Display,
+ "?" => sym::Debug,
+ "o" => sym!(Octal),
+ "x" => sym!(LowerHex),
+ "X" => sym!(UpperHex),
+ "p" => sym::Pointer,
+ "b" => sym!(Binary),
+ "e" => sym!(LowerExp),
+ "E" => sym!(UpperExp),
+ _ => return None,
+ },
+ trait_span: spec
+ .ty_span
+ .map(|span| span_from_inner(values.format_string_span, span)),
+ })
+ }
+
+ /// Returns true if this format spec is unchanged from the default. e.g. returns true for `{}`,
+ /// `{foo}` and `{2}`, but false for `{:?}`, `{foo:5}` and `{3:.5}`
+ pub fn is_default(&self) -> bool {
+ self.r#trait == sym::Display && self.is_default_for_trait()
+ }
+
+ /// Has no other formatting specifiers than setting the format trait. returns true for `{}`,
+ /// `{foo}`, `{:?}`, but false for `{foo:5}`, `{3:.5?}`
+ pub fn is_default_for_trait(&self) -> bool {
+ self.width.is_implied()
+ && self.precision.is_implied()
+ && self.align == Alignment::AlignUnknown
+ && self.flags == 0
+ }
+}
+
+/// A format argument, such as `{}`, `{foo:?}`.
+#[derive(Debug)]
+pub struct FormatArg<'tcx> {
+ /// The parameter the argument refers to.
+ pub param: FormatParam<'tcx>,
+ /// How to format `param`.
+ pub format: FormatSpec<'tcx>,
+ /// span of the whole argument, `{..}`.
+ pub span: Span,
+}
+
+impl<'tcx> FormatArg<'tcx> {
+ /// Span of the `:` and format specifiers
+ ///
+ /// ```ignore
+ /// format!("{:.}"), format!("{foo:.}")
+ /// ^^ ^^
+ /// ```
+ pub fn format_span(&self) -> Span {
+ let base = self.span.data();
+
+ // `base.hi` is `{...}|`, subtract 1 byte (the length of '}') so that it points before the closing
+ // brace `{...|}`
+ Span::new(self.param.span.hi(), base.hi - BytePos(1), base.ctxt, base.parent)
+ }
+}
+
+/// A parsed `format_args!` expansion.
+#[derive(Debug)]
+pub struct FormatArgsExpn<'tcx> {
+ /// The format string literal.
+ pub format_string: FormatString,
+ /// The format arguments, such as `{:?}`.
+ pub args: Vec<FormatArg<'tcx>>,
+ /// Has an added newline due to `println!()`/`writeln!()`/etc. The last format string part will
+ /// include this added newline.
+ pub newline: bool,
+ /// Spans of the commas between the format string and explicit values, excluding any trailing
+ /// comma
+ ///
+ /// ```ignore
+ /// format!("..", 1, 2, 3,)
+ /// // ^ ^ ^
+ /// ```
+ comma_spans: Vec<Span>,
+ /// Explicit values passed after the format string, ignoring implicit captures. `[1, z + 2]` for
+ /// `format!("{x} {} {y}", 1, z + 2)`.
+ explicit_values: Vec<&'tcx Expr<'tcx>>,
+}
+
+impl<'tcx> FormatArgsExpn<'tcx> {
+ /// Gets the spans of the commas inbetween the format string and explicit args, not including
+ /// any trailing comma
+ ///
+ /// ```ignore
+ /// format!("{} {}", a, b)
+ /// // ^ ^
+ /// ```
+ ///
+ /// Ensures that the format string and values aren't coming from a proc macro that sets the
+ /// output span to that of its input
+ fn comma_spans(cx: &LateContext<'_>, explicit_values: &[&Expr<'_>], fmt_span: Span) -> Option<Vec<Span>> {
+ // `format!("{} {} {c}", "one", "two", c = "three")`
+ // ^^^^^ ^^^^^ ^^^^^^^
+ let value_spans = explicit_values
+ .iter()
+ .map(|val| hygiene::walk_chain(val.span, fmt_span.ctxt()));
+
+ // `format!("{} {} {c}", "one", "two", c = "three")`
+ // ^^ ^^ ^^^^^^
+ let between_spans = once(fmt_span)
+ .chain(value_spans)
+ .tuple_windows()
+ .map(|(start, end)| start.between(end));
+
+ let mut comma_spans = Vec::new();
+ for between_span in between_spans {
+ let mut offset = 0;
+ let mut seen_comma = false;
+
+ for token in tokenize(&snippet_opt(cx, between_span)?) {
+ match token.kind {
+ TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {},
+ TokenKind::Comma if !seen_comma => {
+ seen_comma = true;
+
+ let base = between_span.data();
+ comma_spans.push(Span::new(
+ base.lo + BytePos(offset),
+ base.lo + BytePos(offset + 1),
+ base.ctxt,
+ base.parent,
+ ));
+ },
+ // named arguments, `start_val, name = end_val`
+ // ^^^^^^^^^ between_span
+ TokenKind::Ident | TokenKind::Eq if seen_comma => {},
+ // An unexpected token usually indicates the format string or a value came from a proc macro output
+ // that sets the span of its output to an input, e.g. `println!(some_proc_macro!("input"), ..)` that
+ // emits a string literal with the span set to that of `"input"`
+ _ => return None,
+ }
+ offset += token.len;
}
- if e_ctxt.outer_expn().is_descendant_of(expn_id) {
- format_args = FormatArgsExpn::parse(cx, e);
+
+ if !seen_comma {
+ return None;
}
- false
- })
- .visit_expr(expr);
- format_args
+ }
+
+ Some(comma_spans)
}
- /// Returns a vector of `FormatArgsArg`.
- pub fn args(&self) -> Option<Vec<FormatArgsArg<'tcx>>> {
- if self.specs.is_empty() {
- let args = std::iter::zip(&self.value_args, &self.formatters)
- .map(|(value, &(_, format_trait))| FormatArgsArg {
- value,
- format_trait,
- spec: None,
+ pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<Self> {
+ let macro_name = macro_backtrace(expr.span)
+ .map(|macro_call| cx.tcx.item_name(macro_call.def_id))
+ .find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?;
+ let newline = macro_name == sym::format_args_nl;
+
+ // ::core::fmt::Arguments::new_v1(pieces, args)
+ // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg)
+ if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind
+ && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind
+ && is_path_diagnostic_item(cx, ty, sym::Arguments)
+ && matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted")
+ {
+ let format_string = FormatString::new(cx, pieces)?;
+
+ let mut parser = rpf::Parser::new(
+ &format_string.unescaped,
+ format_string.style,
+ Some(format_string.snippet.clone()),
+ // `format_string.unescaped` does not contain the appended newline
+ false,
+ rpf::ParseMode::Format,
+ );
+
+ let parsed_args = parser
+ .by_ref()
+ .filter_map(|piece| match piece {
+ rpf::Piece::NextArgument(a) => Some(a),
+ rpf::Piece::String(_) => None,
})
- .collect();
- return Some(args);
+ .collect_vec();
+ if !parser.errors.is_empty() {
+ return None;
+ }
+
+ let positions = if let Some(fmt_arg) = rest.first() {
+ // If the argument contains format specs, `new_v1_formatted(_, _, fmt, _)`, parse
+ // them.
+
+ Either::Left(parse_rt_fmt(fmt_arg)?)
+ } else {
+ // If no format specs are given, the positions are in the given order and there are
+ // no `precision`/`width`s to consider.
+
+ Either::Right((0..).map(|n| ParamPosition {
+ value: n,
+ width: None,
+ precision: None,
+ }))
+ };
+
+ let values = FormatArgsValues::new(args, format_string.span.data());
+
+ let args = izip!(positions, parsed_args, parser.arg_places)
+ .map(|(position, parsed_arg, arg_span)| {
+ Some(FormatArg {
+ param: FormatParam::new(
+ match parsed_arg.position {
+ rpf::Position::ArgumentImplicitlyIs(_) => FormatParamKind::Implicit,
+ rpf::Position::ArgumentIs(_) => FormatParamKind::Numbered,
+ // NamedInline is handled by `FormatParam::new()`
+ rpf::Position::ArgumentNamed(name) => FormatParamKind::Named(Symbol::intern(name)),
+ },
+ FormatParamUsage::Argument,
+ position.value,
+ parsed_arg.position_span,
+ &values,
+ )?,
+ format: FormatSpec::new(parsed_arg.format, position, &values)?,
+ span: span_from_inner(values.format_string_span, arg_span),
+ })
+ })
+ .collect::<Option<Vec<_>>>()?;
+
+ let mut explicit_values = values.value_args;
+ // remove values generated for implicitly captured vars
+ let len = explicit_values
+ .iter()
+ .take_while(|val| !format_string.span.contains(val.span))
+ .count();
+ explicit_values.truncate(len);
+
+ let comma_spans = Self::comma_spans(cx, &explicit_values, format_string.span)?;
+
+ Some(Self {
+ format_string,
+ args,
+ newline,
+ comma_spans,
+ explicit_values,
+ })
+ } else {
+ None
}
- self.specs
- .iter()
- .map(|spec| {
- if_chain! {
- // struct `core::fmt::rt::v1::Argument`
- if let ExprKind::Struct(_, fields, _) = spec.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);
- if let Some(&(j, format_trait)) = self.formatters.get(i);
- then {
- Some(FormatArgsArg {
- value: self.value_args[j],
- format_trait,
- spec: Some(spec),
- })
- } else {
- None
- }
+ }
+
+ pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option<Self> {
+ for_each_expr(expr, |e| {
+ let e_ctxt = e.span.ctxt();
+ if e_ctxt == expr.span.ctxt() {
+ ControlFlow::Continue(Descend::Yes)
+ } else if e_ctxt.outer_expn().is_descendant_of(expn_id) {
+ if let Some(args) = FormatArgsExpn::parse(cx, e) {
+ ControlFlow::Break(args)
+ } else {
+ ControlFlow::Continue(Descend::No)
}
- })
- .collect()
+ } else {
+ ControlFlow::Continue(Descend::No)
+ }
+ })
}
/// Source callsite span of all inputs
pub fn inputs_span(&self) -> Span {
- match *self.value_args {
- [] => self.format_string_span,
+ match *self.explicit_values {
+ [] => self.format_string.span,
[.., last] => self
- .format_string_span
- .to(hygiene::walk_chain(last.span, self.format_string_span.ctxt())),
+ .format_string
+ .span
+ .to(hygiene::walk_chain(last.span, self.format_string.span.ctxt())),
}
}
-}
-/// 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 format_trait: Symbol,
- /// An element of `specs`
- pub spec: 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.spec.map_or(false, |spec| {
- // `!` because these conditions check that `self` is unformatted.
- !if_chain! {
- // struct `core::fmt::rt::v1::Argument`
- if let ExprKind::Struct(_, fields, _) = spec.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;
- if subfields.iter().all(|field| match field.ident.name {
- sym::precision | sym::width => match field.expr.kind {
- ExprKind::Path(QPath::Resolved(_, path)) => {
- path.segments.last().unwrap().ident.name == sym::Implied
- }
- _ => false,
- }
- _ => true,
- });
- then { true } else { false }
+ /// Get the span of a value expanded to the previous comma, e.g. for the value `10`
+ ///
+ /// ```ignore
+ /// format("{}.{}", 10, 11)
+ /// // ^^^^
+ /// ```
+ pub fn value_with_prev_comma_span(&self, value_id: HirId) -> Option<Span> {
+ for (comma_span, value) in zip(&self.comma_spans, &self.explicit_values) {
+ if value.hir_id == value_id {
+ return Some(comma_span.to(hygiene::walk_chain(value.span, comma_span.ctxt())));
}
- })
+ }
+
+ None
+ }
+
+ /// Iterator of all format params, both values and those referenced by `width`/`precision`s.
+ pub fn params(&'tcx self) -> impl Iterator<Item = FormatParam<'tcx>> {
+ self.args
+ .iter()
+ .flat_map(|arg| [Some(arg.param), arg.format.precision.param(), arg.format.width.param()])
+ .flatten()
}
}
diff --git a/src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs b/src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs
new file mode 100644
index 000000000..d262b335d
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs
@@ -0,0 +1,52 @@
+use rustc_index::bit_set::BitSet;
+use rustc_middle::mir;
+use rustc_mir_dataflow::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis};
+
+/// Determines liveness of each local purely based on `StorageLive`/`Dead`.
+#[derive(Copy, Clone)]
+pub(super) struct MaybeStorageLive;
+
+impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
+ type Domain = BitSet<mir::Local>;
+ const NAME: &'static str = "maybe_storage_live";
+
+ fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+ // bottom = dead
+ BitSet::new_empty(body.local_decls.len())
+ }
+
+ fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
+ for arg in body.args_iter() {
+ state.insert(arg);
+ }
+ }
+}
+
+impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
+ type Idx = mir::Local;
+
+ fn statement_effect(&self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, _: mir::Location) {
+ match stmt.kind {
+ mir::StatementKind::StorageLive(l) => trans.gen(l),
+ mir::StatementKind::StorageDead(l) => trans.kill(l),
+ _ => (),
+ }
+ }
+
+ fn terminator_effect(
+ &self,
+ _trans: &mut impl GenKill<Self::Idx>,
+ _terminator: &mir::Terminator<'tcx>,
+ _loc: mir::Location,
+ ) {
+ }
+
+ fn call_return_effect(
+ &self,
+ _trans: &mut impl GenKill<Self::Idx>,
+ _block: mir::BasicBlock,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
+ ) {
+ // Nothing to do when a call returns successfully
+ }
+}
diff --git a/src/tools/clippy/clippy_utils/src/mir/mod.rs b/src/tools/clippy/clippy_utils/src/mir/mod.rs
new file mode 100644
index 000000000..818e603f6
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/mir/mod.rs
@@ -0,0 +1,164 @@
+use rustc_hir::{Expr, HirId};
+use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
+use rustc_middle::mir::{
+ traversal, Body, InlineAsmOperand, Local, Location, Place, StatementKind, TerminatorKind, START_BLOCK,
+};
+use rustc_middle::ty::TyCtxt;
+
+mod maybe_storage_live;
+
+mod possible_borrower;
+pub use possible_borrower::PossibleBorrowerMap;
+
+mod possible_origin;
+
+mod transitive_relation;
+
+#[derive(Clone, Debug, Default)]
+pub struct LocalUsage {
+ /// The locations where the local is used, if any.
+ pub local_use_locs: Vec<Location>,
+ /// The locations where the local is consumed or mutated, if any.
+ pub local_consume_or_mutate_locs: Vec<Location>,
+}
+
+pub fn visit_local_usage(locals: &[Local], mir: &Body<'_>, location: Location) -> Option<Vec<LocalUsage>> {
+ let init = vec![
+ LocalUsage {
+ local_use_locs: Vec::new(),
+ local_consume_or_mutate_locs: Vec::new(),
+ };
+ locals.len()
+ ];
+
+ traversal::ReversePostorder::new(mir, location.block).try_fold(init, |usage, (tbb, tdata)| {
+ // Give up on loops
+ if tdata.terminator().successors().any(|s| s == location.block) {
+ return None;
+ }
+
+ let mut v = V {
+ locals,
+ location,
+ results: usage,
+ };
+ v.visit_basic_block_data(tbb, tdata);
+ Some(v.results)
+ })
+}
+
+struct V<'a> {
+ locals: &'a [Local],
+ location: Location,
+ results: Vec<LocalUsage>,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for V<'a> {
+ fn visit_place(&mut self, place: &Place<'tcx>, ctx: PlaceContext, loc: Location) {
+ if loc.block == self.location.block && loc.statement_index <= self.location.statement_index {
+ return;
+ }
+
+ let local = place.local;
+
+ for (i, self_local) in self.locals.iter().enumerate() {
+ if local == *self_local {
+ if !matches!(
+ ctx,
+ PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(_)
+ ) {
+ self.results[i].local_use_locs.push(loc);
+ }
+ if matches!(
+ ctx,
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)
+ | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
+ ) {
+ self.results[i].local_consume_or_mutate_locs.push(loc);
+ }
+ }
+ }
+ }
+}
+
+/// Convenience wrapper around `visit_local_usage`.
+pub fn used_exactly_once(mir: &rustc_middle::mir::Body<'_>, local: rustc_middle::mir::Local) -> Option<bool> {
+ visit_local_usage(
+ &[local],
+ mir,
+ Location {
+ block: START_BLOCK,
+ statement_index: 0,
+ },
+ )
+ .map(|mut vec| {
+ let LocalUsage { local_use_locs, .. } = vec.remove(0);
+ local_use_locs
+ .into_iter()
+ .filter(|location| !is_local_assignment(mir, local, *location))
+ .count()
+ == 1
+ })
+}
+
+/// Returns the `mir::Body` containing the node associated with `hir_id`.
+#[allow(clippy::module_name_repetitions)]
+pub fn enclosing_mir(tcx: TyCtxt<'_>, hir_id: HirId) -> &Body<'_> {
+ let body_owner_local_def_id = tcx.hir().enclosing_body_owner(hir_id);
+ tcx.optimized_mir(body_owner_local_def_id.to_def_id())
+}
+
+/// Tries to determine the `Local` corresponding to `expr`, if any.
+/// This function is expensive and should be used sparingly.
+pub fn expr_local(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> Option<Local> {
+ let mir = enclosing_mir(tcx, expr.hir_id);
+ mir.local_decls.iter_enumerated().find_map(|(local, local_decl)| {
+ if local_decl.source_info.span == expr.span {
+ Some(local)
+ } else {
+ None
+ }
+ })
+}
+
+/// Returns a vector of `mir::Location` where `local` is assigned.
+pub fn local_assignments(mir: &Body<'_>, local: Local) -> Vec<Location> {
+ let mut locations = Vec::new();
+ for (block, data) in mir.basic_blocks.iter_enumerated() {
+ for statement_index in 0..=data.statements.len() {
+ let location = Location { block, statement_index };
+ if is_local_assignment(mir, local, location) {
+ locations.push(location);
+ }
+ }
+ }
+ locations
+}
+
+// `is_local_assignment` is based on `is_place_assignment`:
+// https://github.com/rust-lang/rust/blob/b7413511dc85ec01ef4b91785f86614589ac6103/compiler/rustc_middle/src/mir/visit.rs#L1350
+fn is_local_assignment(mir: &Body<'_>, local: Local, location: Location) -> bool {
+ let Location { block, statement_index } = location;
+ let basic_block = &mir.basic_blocks[block];
+ if statement_index < basic_block.statements.len() {
+ let statement = &basic_block.statements[statement_index];
+ if let StatementKind::Assign(box (place, _)) = statement.kind {
+ place.as_local() == Some(local)
+ } else {
+ false
+ }
+ } else {
+ let terminator = basic_block.terminator();
+ match &terminator.kind {
+ TerminatorKind::Call { destination, .. } => destination.as_local() == Some(local),
+ TerminatorKind::InlineAsm { operands, .. } => operands.iter().any(|operand| {
+ if let InlineAsmOperand::Out { place: Some(place), .. } = operand {
+ place.as_local() == Some(local)
+ } else {
+ false
+ }
+ }),
+ _ => false,
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
new file mode 100644
index 000000000..25717bf3d
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -0,0 +1,241 @@
+use super::{
+ maybe_storage_live::MaybeStorageLive, possible_origin::PossibleOriginVisitor,
+ transitive_relation::TransitiveRelation,
+};
+use crate::ty::is_copy;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_index::bit_set::{BitSet, HybridBitSet};
+use rustc_lint::LateContext;
+use rustc_middle::mir::{self, visit::Visitor as _, Mutability};
+use rustc_middle::ty::{self, visit::TypeVisitor};
+use rustc_mir_dataflow::{Analysis, ResultsCursor};
+use std::ops::ControlFlow;
+
+/// Collects the possible borrowers of each local.
+/// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
+/// possible borrowers of `a`.
+#[allow(clippy::module_name_repetitions)]
+struct PossibleBorrowerVisitor<'a, 'b, 'tcx> {
+ possible_borrower: TransitiveRelation,
+ body: &'b mir::Body<'tcx>,
+ cx: &'a LateContext<'tcx>,
+ possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
+}
+
+impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
+ fn new(
+ cx: &'a LateContext<'tcx>,
+ body: &'b mir::Body<'tcx>,
+ possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
+ ) -> Self {
+ Self {
+ possible_borrower: TransitiveRelation::default(),
+ cx,
+ body,
+ possible_origin,
+ }
+ }
+
+ fn into_map(
+ self,
+ cx: &'a LateContext<'tcx>,
+ maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>,
+ ) -> PossibleBorrowerMap<'b, 'tcx> {
+ let mut map = FxHashMap::default();
+ for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
+ if is_copy(cx, self.body.local_decls[row].ty) {
+ continue;
+ }
+
+ let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len());
+ borrowers.remove(mir::Local::from_usize(0));
+ if !borrowers.is_empty() {
+ map.insert(row, borrowers);
+ }
+ }
+
+ let bs = BitSet::new_empty(self.body.local_decls.len());
+ PossibleBorrowerMap {
+ map,
+ maybe_live,
+ bitset: (bs.clone(), bs),
+ }
+ }
+}
+
+impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> {
+ fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
+ let lhs = place.local;
+ match rvalue {
+ mir::Rvalue::Ref(_, _, borrowed) => {
+ self.possible_borrower.add(borrowed.local, lhs);
+ },
+ other => {
+ if ContainsRegion
+ .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty)
+ .is_continue()
+ {
+ return;
+ }
+ rvalue_locals(other, |rhs| {
+ if lhs != rhs {
+ self.possible_borrower.add(rhs, lhs);
+ }
+ });
+ },
+ }
+ }
+
+ fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) {
+ if let mir::TerminatorKind::Call {
+ args,
+ destination: mir::Place { local: dest, .. },
+ ..
+ } = &terminator.kind
+ {
+ // TODO add doc
+ // If the call returns something with lifetimes,
+ // let's conservatively assume the returned value contains lifetime of all the arguments.
+ // For example, given `let y: Foo<'a> = foo(x)`, `y` is considered to be a possible borrower of `x`.
+
+ let mut immutable_borrowers = vec![];
+ let mut mutable_borrowers = vec![];
+
+ for op in args {
+ match op {
+ mir::Operand::Copy(p) | mir::Operand::Move(p) => {
+ if let ty::Ref(_, _, Mutability::Mut) = self.body.local_decls[p.local].ty.kind() {
+ mutable_borrowers.push(p.local);
+ } else {
+ immutable_borrowers.push(p.local);
+ }
+ },
+ mir::Operand::Constant(..) => (),
+ }
+ }
+
+ let mut mutable_variables: Vec<mir::Local> = mutable_borrowers
+ .iter()
+ .filter_map(|r| self.possible_origin.get(r))
+ .flat_map(HybridBitSet::iter)
+ .collect();
+
+ if ContainsRegion.visit_ty(self.body.local_decls[*dest].ty).is_break() {
+ mutable_variables.push(*dest);
+ }
+
+ for y in mutable_variables {
+ for x in &immutable_borrowers {
+ self.possible_borrower.add(*x, y);
+ }
+ for x in &mutable_borrowers {
+ self.possible_borrower.add(*x, y);
+ }
+ }
+ }
+ }
+}
+
+struct ContainsRegion;
+
+impl TypeVisitor<'_> for ContainsRegion {
+ type BreakTy = ();
+
+ fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow<Self::BreakTy> {
+ ControlFlow::BREAK
+ }
+}
+
+fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
+ use rustc_middle::mir::Rvalue::{Aggregate, BinaryOp, Cast, CheckedBinaryOp, Repeat, UnaryOp, Use};
+
+ let mut visit_op = |op: &mir::Operand<'_>| match op {
+ mir::Operand::Copy(p) | mir::Operand::Move(p) => visit(p.local),
+ mir::Operand::Constant(..) => (),
+ };
+
+ match rvalue {
+ Use(op) | Repeat(op, _) | Cast(_, op, _) | UnaryOp(_, op) => visit_op(op),
+ Aggregate(_, ops) => ops.iter().for_each(visit_op),
+ BinaryOp(_, box (lhs, rhs)) | CheckedBinaryOp(_, box (lhs, rhs)) => {
+ visit_op(lhs);
+ visit_op(rhs);
+ },
+ _ => (),
+ }
+}
+
+/// Result of `PossibleBorrowerVisitor`.
+#[allow(clippy::module_name_repetitions)]
+pub struct PossibleBorrowerMap<'b, 'tcx> {
+ /// Mapping `Local -> its possible borrowers`
+ pub map: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
+ maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>,
+ // Caches to avoid allocation of `BitSet` on every query
+ pub bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
+}
+
+impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
+ pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
+ let possible_origin = {
+ let mut vis = PossibleOriginVisitor::new(mir);
+ vis.visit_body(mir);
+ vis.into_map(cx)
+ };
+ let maybe_storage_live_result = MaybeStorageLive
+ .into_engine(cx.tcx, mir)
+ .pass_name("redundant_clone")
+ .iterate_to_fixpoint()
+ .into_results_cursor(mir);
+ let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
+ vis.visit_body(mir);
+ vis.into_map(cx, maybe_storage_live_result)
+ }
+
+ /// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`.
+ pub fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool {
+ self.bounded_borrowers(borrowers, borrowers, borrowed, at)
+ }
+
+ /// Returns true if the set of borrowers of `borrowed` living at `at` includes at least `below`
+ /// but no more than `above`.
+ pub fn bounded_borrowers(
+ &mut self,
+ below: &[mir::Local],
+ above: &[mir::Local],
+ borrowed: mir::Local,
+ at: mir::Location,
+ ) -> bool {
+ self.maybe_live.seek_after_primary_effect(at);
+
+ self.bitset.0.clear();
+ let maybe_live = &mut self.maybe_live;
+ if let Some(bitset) = self.map.get(&borrowed) {
+ for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) {
+ self.bitset.0.insert(b);
+ }
+ } else {
+ return false;
+ }
+
+ self.bitset.1.clear();
+ for b in below {
+ self.bitset.1.insert(*b);
+ }
+
+ if !self.bitset.0.superset(&self.bitset.1) {
+ return false;
+ }
+
+ for b in above {
+ self.bitset.0.remove(*b);
+ }
+
+ self.bitset.0.is_empty()
+ }
+
+ pub fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {
+ self.maybe_live.seek_after_primary_effect(at);
+ self.maybe_live.contains(local)
+ }
+}
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
new file mode 100644
index 000000000..8e7513d74
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
@@ -0,0 +1,59 @@
+use super::transitive_relation::TransitiveRelation;
+use crate::ty::is_copy;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_index::bit_set::HybridBitSet;
+use rustc_lint::LateContext;
+use rustc_middle::mir;
+
+/// Collect possible borrowed for every `&mut` local.
+/// For example, `_1 = &mut _2` generate _1: {_2,...}
+/// Known Problems: not sure all borrowed are tracked
+#[allow(clippy::module_name_repetitions)]
+pub(super) struct PossibleOriginVisitor<'a, 'tcx> {
+ possible_origin: TransitiveRelation,
+ body: &'a mir::Body<'tcx>,
+}
+
+impl<'a, 'tcx> PossibleOriginVisitor<'a, 'tcx> {
+ pub fn new(body: &'a mir::Body<'tcx>) -> Self {
+ Self {
+ possible_origin: TransitiveRelation::default(),
+ body,
+ }
+ }
+
+ pub fn into_map(self, cx: &LateContext<'tcx>) -> FxHashMap<mir::Local, HybridBitSet<mir::Local>> {
+ let mut map = FxHashMap::default();
+ for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
+ if is_copy(cx, self.body.local_decls[row].ty) {
+ continue;
+ }
+
+ let mut borrowers = self.possible_origin.reachable_from(row, self.body.local_decls.len());
+ borrowers.remove(mir::Local::from_usize(0));
+ if !borrowers.is_empty() {
+ map.insert(row, borrowers);
+ }
+ }
+ map
+ }
+}
+
+impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'a, 'tcx> {
+ fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
+ let lhs = place.local;
+ match rvalue {
+ // Only consider `&mut`, which can modify origin place
+ mir::Rvalue::Ref(_, rustc_middle::mir::BorrowKind::Mut { .. }, borrowed) |
+ // _2: &mut _;
+ // _3 = move _2
+ mir::Rvalue::Use(mir::Operand::Move(borrowed)) |
+ // _3 = move _2 as &mut _;
+ mir::Rvalue::Cast(_, mir::Operand::Move(borrowed), _)
+ => {
+ self.possible_origin.add(lhs, borrowed.local);
+ },
+ _ => {},
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_utils/src/mir/transitive_relation.rs b/src/tools/clippy/clippy_utils/src/mir/transitive_relation.rs
new file mode 100644
index 000000000..7fe296073
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/mir/transitive_relation.rs
@@ -0,0 +1,29 @@
+use rustc_data_structures::fx::FxHashMap;
+use rustc_index::bit_set::HybridBitSet;
+use rustc_middle::mir;
+
+#[derive(Default)]
+pub(super) struct TransitiveRelation {
+ relations: FxHashMap<mir::Local, Vec<mir::Local>>,
+}
+
+impl TransitiveRelation {
+ pub fn add(&mut self, a: mir::Local, b: mir::Local) {
+ self.relations.entry(a).or_default().push(b);
+ }
+
+ pub fn reachable_from(&self, a: mir::Local, domain_size: usize) -> HybridBitSet<mir::Local> {
+ let mut seen = HybridBitSet::new_empty(domain_size);
+ let mut stack = vec![a];
+ while let Some(u) = stack.pop() {
+ if let Some(edges) = self.relations.get(&u) {
+ for &v in edges {
+ if seen.insert(v) {
+ stack.push(v);
+ }
+ }
+ }
+ }
+ seen
+ }
+}
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 9e238c6f1..8b843732a 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -13,10 +13,11 @@ macro_rules! msrv_aliases {
// names may refer to stabilized feature flags or library items
msrv_aliases! {
1,62,0 { BOOL_THEN_SOME }
- 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN }
+ 1,58,0 { FORMAT_ARGS_CAPTURE }
+ 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST }
1,51,0 { BORROW_AS_PTR, UNSIGNED_ABS }
- 1,50,0 { BOOL_THEN }
+ 1,50,0 { BOOL_THEN, CLAMP }
1,47,0 { TAU }
1,46,0 { CONST_IF_MATCH }
1,45,0 { STR_STRIP_PREFIX }
@@ -32,8 +33,8 @@ msrv_aliases! {
1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
1,28,0 { FROM_BOOL }
1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN }
+ 1,24,0 { IS_ASCII_DIGIT }
1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN }
1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
1,16,0 { STR_REPEAT }
- 1,24,0 { IS_ASCII_DIGIT }
}
diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
index 3fb5415ce..c5dcd7b31 100644
--- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs
+++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
@@ -69,12 +69,13 @@ impl<'a> NumericLiteral<'a> {
#[must_use]
pub fn new(lit: &'a str, suffix: Option<&'a str>, float: bool) -> Self {
+ let unsigned_lit = lit.trim_start_matches('-');
// Determine delimiter for radix prefix, if present, and radix.
- let radix = if lit.starts_with("0x") {
+ let radix = if unsigned_lit.starts_with("0x") {
Radix::Hexadecimal
- } else if lit.starts_with("0b") {
+ } else if unsigned_lit.starts_with("0b") {
Radix::Binary
- } else if lit.starts_with("0o") {
+ } else if unsigned_lit.starts_with("0o") {
Radix::Octal
} else {
Radix::Decimal
@@ -223,10 +224,12 @@ impl<'a> NumericLiteral<'a> {
fn split_suffix<'a>(src: &'a str, lit_kind: &LitKind) -> (&'a str, Option<&'a str>) {
debug_assert!(lit_kind.is_numeric());
- lit_suffix_length(lit_kind).map_or((src, None), |suffix_length| {
- let (unsuffixed, suffix) = src.split_at(src.len() - suffix_length);
- (unsuffixed, Some(suffix))
- })
+ lit_suffix_length(lit_kind)
+ .and_then(|suffix_length| src.len().checked_sub(suffix_length))
+ .map_or((src, None), |split_pos| {
+ let (unsuffixed, suffix) = src.split_at(split_pos);
+ (unsuffixed, Some(suffix))
+ })
}
fn lit_suffix_length(lit_kind: &LitKind) -> Option<usize> {
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 05429d05d..bc8514734 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -16,26 +16,17 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [
#[cfg(feature = "internal")]
pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"];
pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
-pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
-pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"];
-pub const BTREEMAP_ENTRY: [&str; 6] = ["alloc", "collections", "btree", "map", "entry", "Entry"];
pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"];
pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"];
pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
-pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"];
pub const CORE_ITER_COLLECT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "collect"];
pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"];
pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"];
pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
-pub const CORE_ITER_INTO_ITER: [&str; 6] = ["core", "iter", "traits", "collect", "IntoIterator", "into_iter"];
pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"];
pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
-/// Preferably use the diagnostic item `sym::deref_method` where possible
-pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
-pub const DIR_BUILDER: [&str; 3] = ["std", "fs", "DirBuilder"];
-pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"];
#[cfg(feature = "internal")]
pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
#[cfg(feature = "internal")]
@@ -43,35 +34,22 @@ pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"]
pub const EXIT: [&str; 3] = ["std", "process", "exit"];
pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"];
pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"];
-pub const FILE: [&str; 3] = ["std", "fs", "File"];
-pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
-pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"];
pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"];
-pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"];
pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"];
-pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"];
pub const HASHSET_ITER: [&str; 6] = ["std", "collections", "hash", "set", "HashSet", "iter"];
#[cfg(feature = "internal")]
pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
#[cfg(feature = "internal")]
pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
-pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
-pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
-pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
-pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
-pub const IPADDR_V4: [&str; 5] = ["std", "net", "ip", "IpAddr", "V4"];
-pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"];
pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"];
pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"];
-pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
#[cfg(feature = "internal")]
pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
@@ -82,13 +60,7 @@ pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"];
#[cfg(feature = "internal")]
pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"];
-pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"];
pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
-/// Preferably use the diagnostic item `sym::Option` where possible
-pub const OPTION: [&str; 3] = ["core", "option", "Option"];
-pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"];
-pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"];
-pub const ORD: [&str; 3] = ["core", "cmp", "Ord"];
pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"];
@@ -96,12 +68,11 @@ pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwL
pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"];
pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
+pub const PEEKABLE: [&str; 5] = ["core", "iter", "adapters", "peekable", "Peekable"];
pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
#[cfg_attr(not(unix), allow(clippy::invalid_paths))]
pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"];
pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
-pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
-pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"];
pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"];
pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"];
pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
@@ -124,26 +95,14 @@ pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"];
pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
-/// Preferably use the diagnostic item `sym::Result` where possible
-pub const RESULT: [&str; 3] = ["core", "result", "Result"];
-pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"];
-pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"];
#[cfg(feature = "internal")]
pub const RUSTC_VERSION: [&str; 2] = ["rustc_semver", "RustcVersion"];
-pub const RWLOCK_READ_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockReadGuard"];
-pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWriteGuard"];
pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];
@@ -194,3 +153,5 @@ pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"];
+pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"];
+pub const INSTANT: [&str; 3] = ["std", "time", "Instant"];
diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs
index 649b7b994..88837d8a1 100644
--- a/src/tools/clippy/clippy_utils/src/ptr.rs
+++ b/src/tools/clippy/clippy_utils/src/ptr.rs
@@ -1,7 +1,7 @@
use crate::source::snippet;
-use crate::visitors::expr_visitor_no_bodies;
+use crate::visitors::{for_each_expr, Descend};
use crate::{path_to_local_id, strip_pat_refs};
-use rustc_hir::intravisit::Visitor;
+use core::ops::ControlFlow;
use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind};
use rustc_lint::LateContext;
use rustc_span::Span;
@@ -30,28 +30,23 @@ fn extract_clone_suggestions<'tcx>(
replace: &[(&'static str, &'static str)],
body: &'tcx Body<'_>,
) -> Option<Vec<(Span, Cow<'static, str>)>> {
- let mut abort = false;
let mut spans = Vec::new();
- expr_visitor_no_bodies(|expr| {
- if abort {
- return false;
- }
- if let ExprKind::MethodCall(seg, [recv], _) = expr.kind {
- if path_to_local_id(recv, id) {
- if seg.ident.name.as_str() == "capacity" {
- abort = true;
- return false;
- }
- for &(fn_name, suffix) in replace {
- if seg.ident.name.as_str() == fn_name {
- spans.push((expr.span, snippet(cx, recv.span, "_") + suffix));
- return false;
- }
+ for_each_expr(body, |e| {
+ if let ExprKind::MethodCall(seg, recv, [], _) = e.kind
+ && path_to_local_id(recv, id)
+ {
+ if seg.ident.as_str() == "capacity" {
+ return ControlFlow::Break(());
+ }
+ for &(fn_name, suffix) in replace {
+ if seg.ident.as_str() == fn_name {
+ spans.push((e.span, snippet(cx, recv.span, "_") + suffix));
+ return ControlFlow::Continue(Descend::No);
}
}
}
- !abort
+ ControlFlow::Continue(Descend::Yes)
})
- .visit_body(body);
- if abort { None } else { Some(spans) }
+ .is_none()
+ .then_some(spans)
}
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 3bf75bcbe..45b63a4aa 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -6,8 +6,8 @@
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::mir::{
- Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
- TerminatorKind,
+ Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind,
+ Terminator, TerminatorKind,
};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
@@ -33,10 +33,10 @@ pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv:
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Trait(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
- ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
- ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
- ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate),
- ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {:#?}", predicate),
+ ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"),
+ ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"),
+ ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"),
+ ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {predicate:#?}"),
}
}
match predicates.parent {
@@ -55,7 +55,7 @@ pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv:
body.local_decls.iter().next().unwrap().source_info.span,
)?;
- for bb in body.basic_blocks() {
+ for bb in body.basic_blocks.iter() {
check_terminator(tcx, body, bb.terminator(), msrv)?;
for stmt in &bb.statements {
check_statement(tcx, body, def_id, stmt)?;
@@ -82,7 +82,7 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult {
ty::FnPtr(..) => {
return Err((span, "function pointers in const fn are unstable".into()));
},
- ty::Dynamic(preds, _) => {
+ ty::Dynamic(preds, _, _) => {
for pred in preds.iter() {
match pred.skip_binder() {
ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => {
@@ -129,7 +129,12 @@ fn check_rvalue<'tcx>(
| Rvalue::Use(operand)
| Rvalue::Cast(
CastKind::PointerFromExposedAddress
- | CastKind::Misc
+ | CastKind::IntToInt
+ | CastKind::FloatToInt
+ | CastKind::IntToFloat
+ | CastKind::FloatToFloat
+ | CastKind::FnPtrToPtr
+ | CastKind::PtrToPtr
| CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
operand,
_,
@@ -161,6 +166,10 @@ fn check_rvalue<'tcx>(
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
Err((span, "casting pointers to ints is unstable in const fn".into()))
},
+ Rvalue::Cast(CastKind::DynStar, _, _) => {
+ // FIXME(dyn-star)
+ unimplemented!()
+ },
// binops are fine on integers
Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
check_operand(tcx, lhs, span, body)?;
@@ -212,7 +221,11 @@ fn check_statement<'tcx>(
check_place(tcx, **place, span, body)
},
- StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
+ StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body),
+
+ StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+ rustc_middle::mir::CopyNonOverlapping { dst, src, count },
+ )) => {
check_operand(tcx, dst, span, body)?;
check_operand(tcx, src, span, body)?;
check_operand(tcx, count, span, body)
@@ -252,6 +265,7 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B
}
},
ProjectionElem::ConstantIndex { .. }
+ | ProjectionElem::OpaqueCast(..)
| ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. }
| ProjectionElem::Deref
@@ -310,8 +324,7 @@ fn check_terminator<'a, 'tcx>(
span,
format!(
"can only call other `const fn` within a `const fn`, \
- but `{:?}` is not stable as `const fn`",
- func,
+ but `{func:?}` is not stable as `const fn`",
)
.into(),
));
@@ -358,10 +371,23 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<RustcVersion>) -> bo
// Checking MSRV is manually necessary because `rustc` has no such concept. This entire
// function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`.
// as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
+
+ // HACK(nilstrieb): CURRENT_RUSTC_VERSION can return versions like 1.66.0-dev. `rustc-semver`
+ // doesn't accept the `-dev` version number so we have to strip it
+ // off.
+ let short_version = since
+ .as_str()
+ .split('-')
+ .next()
+ .expect("rustc_attr::StabilityLevel::Stable::since` is empty");
+
+ let since = rustc_span::Symbol::intern(short_version);
+
crate::meets_msrv(
msrv,
- RustcVersion::parse(since.as_str())
- .expect("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted"),
+ RustcVersion::parse(since.as_str()).unwrap_or_else(|err| {
+ panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}")
+ }),
)
} else {
// Unstable const fn with the feature enabled.
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 1197fe914..d28bd92d7 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -11,24 +11,6 @@ use rustc_span::source_map::SourceMap;
use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext};
use std::borrow::Cow;
-/// Checks if the span starts with the given text. This will return false if the span crosses
-/// multiple files or if source is not available.
-///
-/// This is used to check for proc macros giving unhelpful spans to things.
-pub fn span_starts_with<T: LintContext>(cx: &T, span: Span, text: &str) -> bool {
- fn helper(sm: &SourceMap, span: Span, text: &str) -> bool {
- let pos = sm.lookup_byte_offset(span.lo());
- let Some(ref src) = pos.sf.src else {
- return false;
- };
- let end = span.hi() - pos.sf.start_pos;
- src.get(pos.pos.0 as usize..end.0 as usize)
- // Expression spans can include wrapping parenthesis. Remove them first.
- .map_or(false, |s| s.trim_start_matches('(').starts_with(text))
- }
- helper(cx.sess().source_map(), span, text)
-}
-
/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
/// Also takes an `Option<String>` which can be put inside the braces.
pub fn expr_block<'a, T: LintContext>(
@@ -43,11 +25,11 @@ pub fn expr_block<'a, T: LintContext>(
if expr.span.from_expansion() {
Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default)))
} else if let ExprKind::Block(_, _) = expr.kind {
- Cow::Owned(format!("{}{}", code, string))
+ Cow::Owned(format!("{code}{string}"))
} else if string.is_empty() {
- Cow::Owned(format!("{{ {} }}", code))
+ Cow::Owned(format!("{{ {code} }}"))
} else {
- Cow::Owned(format!("{{\n{};\n{}\n}}", code, string))
+ Cow::Owned(format!("{{\n{code};\n{string}\n}}"))
}
}
@@ -410,6 +392,16 @@ pub fn trim_span(sm: &SourceMap, span: Span) -> Span {
.span()
}
+/// Expand a span to include a preceding comma
+/// ```rust,ignore
+/// writeln!(o, "") -> writeln!(o, "")
+/// ^^ ^^^^
+/// ```
+pub fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span {
+ let extended = cx.sess().source_map().span_extend_to_prev_char(span, ',', true);
+ extended.with_lo(extended.lo() - BytePos(1))
+}
+
#[cfg(test)]
mod test {
use super::{reindent_multiline, without_block_comments};
@@ -484,7 +476,7 @@ mod test {
#[test]
fn test_without_block_comments_lines_without_block_comments() {
let result = without_block_comments(vec!["/*", "", "*/"]);
- println!("result: {:?}", result);
+ println!("result: {result:?}");
assert!(result.is_empty());
let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]);
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index bad291dfc..aad7da61a 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -1,7 +1,9 @@
//! Contains utility functions to generate suggestions.
#![deny(clippy::missing_docs_in_private_items)]
-use crate::source::{snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite};
+use crate::source::{
+ snippet, snippet_opt, snippet_with_applicability, snippet_with_context, snippet_with_macro_callsite,
+};
use crate::ty::expr_sig;
use crate::{get_parent_expr_for_hir, higher};
use rustc_ast::util::parser::AssocOp;
@@ -10,19 +12,19 @@ use rustc_ast_pretty::pprust::token_kind_to_string;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::{Closure, ExprKind, HirId, MutTy, TyKind};
+use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{EarlyContext, LateContext, LintContext};
use rustc_middle::hir::place::ProjectionKind;
use rustc_middle::mir::{FakeReadCause, Mutability};
use rustc_middle::ty;
use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext};
-use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use std::borrow::Cow;
use std::fmt::{Display, Write as _};
use std::ops::{Add, Neg, Not, Sub};
/// A helper type to build suggestion correctly handling parentheses.
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
pub enum Sugg<'a> {
/// An expression that never needs parentheses such as `1337` or `[0; 42]`.
NonParen(Cow<'a, str>),
@@ -110,7 +112,7 @@ impl<'a> Sugg<'a> {
if expr.span.ctxt() == ctxt {
Self::hir_from_snippet(expr, |span| snippet(cx, span, default))
} else {
- let snip = snippet_with_applicability(cx, expr.span, default, applicability);
+ let (snip, _) = snippet_with_context(cx, expr.span, ctxt, default, applicability);
Sugg::NonParen(snip)
}
}
@@ -155,8 +157,8 @@ impl<'a> Sugg<'a> {
| hir::ExprKind::Ret(..)
| hir::ExprKind::Struct(..)
| hir::ExprKind::Tup(..)
- | hir::ExprKind::DropTemps(_)
| hir::ExprKind::Err => Sugg::NonParen(get_snippet(expr.span)),
+ hir::ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
hir::ExprKind::Assign(lhs, rhs, _) => {
Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span))
},
@@ -177,11 +179,11 @@ impl<'a> Sugg<'a> {
pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
use rustc_ast::ast::RangeLimits;
- let get_whole_snippet = || {
- if expr.span.from_expansion() {
- snippet_with_macro_callsite(cx, expr.span, default)
+ let snippet_without_expansion = |cx, span: Span, default| {
+ if span.from_expansion() {
+ snippet_with_macro_callsite(cx, span, default)
} else {
- snippet(cx, expr.span, default)
+ snippet(cx, span, default)
}
};
@@ -192,7 +194,7 @@ impl<'a> Sugg<'a> {
| ast::ExprKind::If(..)
| ast::ExprKind::Let(..)
| ast::ExprKind::Unary(..)
- | ast::ExprKind::Match(..) => Sugg::MaybeParen(get_whole_snippet()),
+ | ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet_without_expansion(cx, expr.span, default)),
ast::ExprKind::Async(..)
| ast::ExprKind::Block(..)
| ast::ExprKind::Break(..)
@@ -221,41 +223,45 @@ impl<'a> Sugg<'a> {
| ast::ExprKind::Array(..)
| ast::ExprKind::While(..)
| ast::ExprKind::Await(..)
- | ast::ExprKind::Err => Sugg::NonParen(get_whole_snippet()),
+ | ast::ExprKind::Err => Sugg::NonParen(snippet_without_expansion(cx, expr.span, default)),
ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp(
AssocOp::DotDot,
- lhs.as_ref().map_or("".into(), |lhs| snippet(cx, lhs.span, default)),
- rhs.as_ref().map_or("".into(), |rhs| snippet(cx, rhs.span, default)),
+ lhs.as_ref()
+ .map_or("".into(), |lhs| snippet_without_expansion(cx, lhs.span, default)),
+ rhs.as_ref()
+ .map_or("".into(), |rhs| snippet_without_expansion(cx, rhs.span, default)),
),
ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp(
AssocOp::DotDotEq,
- lhs.as_ref().map_or("".into(), |lhs| snippet(cx, lhs.span, default)),
- rhs.as_ref().map_or("".into(), |rhs| snippet(cx, rhs.span, default)),
+ lhs.as_ref()
+ .map_or("".into(), |lhs| snippet_without_expansion(cx, lhs.span, default)),
+ rhs.as_ref()
+ .map_or("".into(), |rhs| snippet_without_expansion(cx, rhs.span, default)),
),
ast::ExprKind::Assign(ref lhs, ref rhs, _) => Sugg::BinOp(
AssocOp::Assign,
- snippet(cx, lhs.span, default),
- snippet(cx, rhs.span, default),
+ snippet_without_expansion(cx, lhs.span, default),
+ snippet_without_expansion(cx, rhs.span, default),
),
ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp(
astbinop2assignop(op),
- snippet(cx, lhs.span, default),
- snippet(cx, rhs.span, default),
+ snippet_without_expansion(cx, lhs.span, default),
+ snippet_without_expansion(cx, rhs.span, default),
),
ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp(
AssocOp::from_ast_binop(op.node),
- snippet(cx, lhs.span, default),
- snippet(cx, rhs.span, default),
+ snippet_without_expansion(cx, lhs.span, default),
+ snippet_without_expansion(cx, rhs.span, default),
),
ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp(
AssocOp::As,
- snippet(cx, lhs.span, default),
- snippet(cx, ty.span, default),
+ snippet_without_expansion(cx, lhs.span, default),
+ snippet_without_expansion(cx, ty.span, default),
),
ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp(
AssocOp::Colon,
- snippet(cx, lhs.span, default),
- snippet(cx, ty.span, default),
+ snippet_without_expansion(cx, lhs.span, default),
+ snippet_without_expansion(cx, ty.span, default),
),
}
}
@@ -306,13 +312,19 @@ impl<'a> Sugg<'a> {
/// Convenience method to transform suggestion into a return call
pub fn make_return(self) -> Sugg<'static> {
- Sugg::NonParen(Cow::Owned(format!("return {}", self)))
+ Sugg::NonParen(Cow::Owned(format!("return {self}")))
}
/// Convenience method to transform suggestion into a block
/// where the suggestion is a trailing expression
pub fn blockify(self) -> Sugg<'static> {
- Sugg::NonParen(Cow::Owned(format!("{{ {} }}", self)))
+ Sugg::NonParen(Cow::Owned(format!("{{ {self} }}")))
+ }
+
+ /// Convenience method to prefix the expression with the `async` keyword.
+ /// Can be used after `blockify` to create an async block.
+ pub fn asyncify(self) -> Sugg<'static> {
+ Sugg::NonParen(Cow::Owned(format!("async {self}")))
}
/// Convenience method to create the `<lhs>..<rhs>` or `<lhs>...<rhs>`
@@ -336,12 +348,12 @@ impl<'a> Sugg<'a> {
if has_enclosing_paren(&sugg) {
Sugg::MaybeParen(sugg)
} else {
- Sugg::NonParen(format!("({})", sugg).into())
+ Sugg::NonParen(format!("({sugg})").into())
}
},
Sugg::BinOp(op, lhs, rhs) => {
let sugg = binop_to_string(op, &lhs, &rhs);
- Sugg::NonParen(format!("({})", sugg).into())
+ Sugg::NonParen(format!("({sugg})").into())
},
}
}
@@ -367,20 +379,20 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
| AssocOp::LessEqual
| AssocOp::NotEqual
| AssocOp::Greater
- | AssocOp::GreaterEqual => format!(
- "{} {} {}",
- lhs,
- op.to_ast_binop().expect("Those are AST ops").to_string(),
- rhs
- ),
- AssocOp::Assign => format!("{} = {}", lhs, rhs),
+ | AssocOp::GreaterEqual => {
+ format!(
+ "{lhs} {} {rhs}",
+ op.to_ast_binop().expect("Those are AST ops").to_string()
+ )
+ },
+ AssocOp::Assign => format!("{lhs} = {rhs}"),
AssocOp::AssignOp(op) => {
- format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs)
+ format!("{lhs} {}= {rhs}", token_kind_to_string(&token::BinOp(op)))
},
- AssocOp::As => format!("{} as {}", lhs, rhs),
- AssocOp::DotDot => format!("{}..{}", lhs, rhs),
- AssocOp::DotDotEq => format!("{}..={}", lhs, rhs),
- AssocOp::Colon => format!("{}: {}", lhs, rhs),
+ AssocOp::As => format!("{lhs} as {rhs}"),
+ AssocOp::DotDot => format!("{lhs}..{rhs}"),
+ AssocOp::DotDotEq => format!("{lhs}..={rhs}"),
+ AssocOp::Colon => format!("{lhs}: {rhs}"),
}
}
@@ -511,7 +523,7 @@ impl<T: Display> Display for ParenHelper<T> {
/// operators have the same
/// precedence.
pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> {
- Sugg::MaybeParen(format!("{}{}", op, expr.maybe_par()).into())
+ Sugg::MaybeParen(format!("{op}{}", expr.maybe_par()).into())
}
/// Builds the string for `<lhs> <op> <rhs>` adding parenthesis when necessary.
@@ -732,7 +744,7 @@ impl<T: LintContext> DiagnosticExt<T> for rustc_errors::Diagnostic {
if let Some(indent) = indentation(cx, item) {
let span = item.with_hi(item.lo());
- self.span_suggestion(span, msg, format!("{}\n{}", attr, indent), applicability);
+ self.span_suggestion(span, msg, format!("{attr}\n{indent}"), applicability);
}
}
@@ -746,21 +758,20 @@ impl<T: LintContext> DiagnosticExt<T> for rustc_errors::Diagnostic {
.map(|l| {
if first {
first = false;
- format!("{}\n", l)
+ format!("{l}\n")
} else {
- format!("{}{}\n", indent, l)
+ format!("{indent}{l}\n")
}
})
.collect::<String>();
- self.span_suggestion(span, msg, format!("{}\n{}", new_item, indent), applicability);
+ self.span_suggestion(span, msg, format!("{new_item}\n{indent}"), applicability);
}
}
fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability: Applicability) {
let mut remove_span = item;
- let hi = cx.sess().source_map().next_point(remove_span).hi();
- let fmpos = cx.sess().source_map().lookup_byte_offset(hi);
+ let fmpos = cx.sess().source_map().lookup_byte_offset(remove_span.hi());
if let Some(ref src) = fmpos.sf.src {
let non_whitespace_offset = src[fmpos.pos.to_usize()..].find(|c| c != ' ' && c != '\t' && c != '\n');
@@ -811,10 +822,9 @@ pub fn deref_closure_args<'tcx>(cx: &LateContext<'_>, closure: &'tcx hir::Expr<'
};
let fn_def_id = cx.tcx.hir().local_def_id(closure.hir_id);
- cx.tcx.infer_ctxt().enter(|infcx| {
- ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results())
- .consume_body(closure_body);
- });
+ let infcx = cx.tcx.infer_ctxt().build();
+ ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results())
+ .consume_body(closure_body);
if !visitor.suggestion_start.is_empty() {
return Some(DerefClosure {
@@ -851,7 +861,7 @@ impl<'tcx> DerefDelegate<'_, 'tcx> {
pub fn finish(&mut self) -> String {
let end_span = Span::new(self.next_pos, self.closure_span.hi(), self.closure_span.ctxt(), None);
let end_snip = snippet_with_applicability(self.cx, end_span, "..", &mut self.applicability);
- let sugg = format!("{}{}", self.suggestion_start, end_snip);
+ let sugg = format!("{}{end_snip}", self.suggestion_start);
if self.closure_arg_is_type_annotated_double_ref {
sugg.replacen('&', "", 1)
} else {
@@ -862,15 +872,15 @@ impl<'tcx> DerefDelegate<'_, 'tcx> {
/// indicates whether the function from `parent_expr` takes its args by double reference
fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool {
let ty = match parent_expr.kind {
- ExprKind::MethodCall(_, call_args, _) => {
+ ExprKind::MethodCall(_, receiver, call_args, _) => {
if let Some(sig) = self
.cx
.typeck_results()
.type_dependent_def_id(parent_expr.hir_id)
.map(|did| self.cx.tcx.fn_sig(did).skip_binder())
{
- call_args
- .iter()
+ std::iter::once(receiver)
+ .chain(call_args.iter())
.position(|arg| arg.hir_id == cmt_hir_id)
.map(|i| sig.inputs()[i])
} else {
@@ -913,7 +923,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
if cmt.place.projections.is_empty() {
// handle item without any projection, that needs an explicit borrowing
// i.e.: suggest `&x` instead of `x`
- let _ = write!(self.suggestion_start, "{}&{}", start_snip, ident_str);
+ let _ = write!(self.suggestion_start, "{start_snip}&{ident_str}");
} else {
// cases where a parent `Call` or `MethodCall` is using the item
// i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()`
@@ -927,14 +937,14 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
match &parent_expr.kind {
// given expression is the self argument and will be handled completely by the compiler
// i.e.: `|x| x.is_something()`
- ExprKind::MethodCall(_, [self_expr, ..], _) if self_expr.hir_id == cmt.hir_id => {
- let _ = write!(self.suggestion_start, "{}{}", start_snip, ident_str_with_proj);
+ ExprKind::MethodCall(_, self_expr, ..) if self_expr.hir_id == cmt.hir_id => {
+ let _ = write!(self.suggestion_start, "{start_snip}{ident_str_with_proj}");
self.next_pos = span.hi();
return;
},
// item is used in a call
// i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)`
- ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, [_, call_args @ ..], _) => {
+ ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [call_args @ ..], _) => {
let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id);
let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind();
@@ -961,9 +971,9 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
} else {
ident_str
};
- format!("{}{}", start_snip, ident)
+ format!("{start_snip}{ident}")
} else {
- format!("{}&{}", start_snip, ident_str)
+ format!("{start_snip}&{ident_str}")
};
self.suggestion_start.push_str(&ident_sugg);
self.next_pos = span.hi();
@@ -1030,13 +1040,13 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
for item in projections {
if item.kind == ProjectionKind::Deref {
- replacement_str = format!("*{}", replacement_str);
+ replacement_str = format!("*{replacement_str}");
}
}
}
}
- let _ = write!(self.suggestion_start, "{}{}", start_snip, replacement_str);
+ let _ = write!(self.suggestion_start, "{start_snip}{replacement_str}");
}
self.next_pos = span.hi();
}
@@ -1044,7 +1054,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
- fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+ fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
}
#[cfg(test)]
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index a05d633d9..4e024ce40 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -12,13 +12,13 @@ use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
use rustc_middle::mir::interpret::{ConstValue, Scalar};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
use rustc_middle::ty::{
self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, ProjectionTy,
Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, VariantDef, VariantDiscr,
};
+use rustc_middle::ty::{GenericArg, GenericArgKind};
use rustc_span::symbol::Ident;
-use rustc_span::{sym, Span, Symbol, DUMMY_SP};
+use rustc_span::{sym, Span, Symbol};
use rustc_target::abi::{Size, VariantIdx};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::query::normalize::AtExt;
@@ -28,7 +28,14 @@ use crate::{match_def_path, path_res, paths};
// Checks if the given type implements copy.
pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
- ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env)
+ ty.is_copy_modulo_regions(cx.tcx, cx.param_env)
+}
+
+/// This checks whether a given type is known to implement Debug.
+pub fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+ cx.tcx
+ .get_diagnostic_item(sym::Debug)
+ .map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
}
/// Checks whether a type can be partially moved.
@@ -43,14 +50,6 @@ pub fn can_partially_move_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool
}
}
-/// Walks into `ty` and returns `true` if any inner type is the same as `other_ty`
-pub fn contains_ty<'tcx>(ty: Ty<'tcx>, other_ty: Ty<'tcx>) -> bool {
- ty.walk().any(|inner| match inner.unpack() {
- GenericArgKind::Type(inner_ty) => other_ty == inner_ty,
- GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
- })
-}
-
/// Walks into `ty` and returns `true` if any inner type is an instance of the given adt
/// constructor.
pub fn contains_adt_constructor<'tcx>(ty: Ty<'tcx>, adt: AdtDef<'tcx>) -> bool {
@@ -173,11 +172,10 @@ pub fn implements_trait_with_env<'tcx>(
return false;
}
let ty_params = tcx.mk_substs(ty_params.iter());
- tcx.infer_ctxt().enter(|infcx| {
- infcx
- .type_implements_trait(trait_id, ty, ty_params, param_env)
- .must_apply_modulo_regions()
- })
+ let infcx = tcx.infer_ctxt().build();
+ infcx
+ .type_implements_trait(trait_id, ty, ty_params, param_env)
+ .must_apply_modulo_regions()
}
/// Checks whether this type implements `Drop`.
@@ -209,7 +207,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
}
false
},
- ty::Dynamic(binder, _) => {
+ ty::Dynamic(binder, _, _) => {
for predicate in binder.iter() {
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
if cx.tcx.has_attr(trait_ref.def_id, sym::must_use) {
@@ -243,27 +241,26 @@ fn is_normalizable_helper<'tcx>(
}
// prevent recursive loops, false-negative is better than endless loop leading to stack overflow
cache.insert(ty, false);
- let result = cx.tcx.infer_ctxt().enter(|infcx| {
- let cause = rustc_middle::traits::ObligationCause::dummy();
- if infcx.at(&cause, param_env).normalize(ty).is_ok() {
- match ty.kind() {
- ty::Adt(def, substs) => def.variants().iter().all(|variant| {
- variant
- .fields
- .iter()
- .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache))
- }),
- _ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
- GenericArgKind::Type(inner_ty) if inner_ty != ty => {
- is_normalizable_helper(cx, param_env, inner_ty, cache)
- },
- _ => true, // if inner_ty == ty, we've already checked it
- }),
- }
- } else {
- false
+ let infcx = cx.tcx.infer_ctxt().build();
+ let cause = rustc_middle::traits::ObligationCause::dummy();
+ let result = if infcx.at(&cause, param_env).normalize(ty).is_ok() {
+ match ty.kind() {
+ ty::Adt(def, substs) => def.variants().iter().all(|variant| {
+ variant
+ .fields
+ .iter()
+ .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache))
+ }),
+ _ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
+ GenericArgKind::Type(inner_ty) if inner_ty != ty => {
+ is_normalizable_helper(cx, param_env, inner_ty, cache)
+ },
+ _ => true, // if inner_ty == ty, we've already checked it
+ }),
}
- });
+ } else {
+ false
+ };
cache.insert(ty, result);
result
}
@@ -410,7 +407,7 @@ pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
peel(ty, 0)
}
-/// Peels off all references on the type.Returns the underlying type, the number of references
+/// Peels off all references on the type. Returns the underlying type, the number of references
/// removed, and whether the pointer is ultimately mutable or not.
pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) {
fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) {
@@ -503,7 +500,7 @@ pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(P
pub enum ExprFnSig<'tcx> {
Sig(Binder<'tcx, FnSig<'tcx>>, Option<DefId>),
Closure(Option<&'tcx FnDecl<'tcx>>, Binder<'tcx, FnSig<'tcx>>),
- Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>),
+ Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>, Option<DefId>),
}
impl<'tcx> ExprFnSig<'tcx> {
/// Gets the argument type at the given offset. This will return `None` when the index is out of
@@ -518,7 +515,7 @@ impl<'tcx> ExprFnSig<'tcx> {
}
},
Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])),
- Self::Trait(inputs, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])),
+ Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])),
}
}
@@ -541,7 +538,7 @@ impl<'tcx> ExprFnSig<'tcx> {
decl.and_then(|decl| decl.inputs.get(i)),
sig.input(0).map_bound(|ty| ty.tuple_fields()[i]),
)),
- Self::Trait(inputs, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))),
+ Self::Trait(inputs, _, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))),
}
}
@@ -550,12 +547,16 @@ impl<'tcx> ExprFnSig<'tcx> {
pub fn output(self) -> Option<Binder<'tcx, Ty<'tcx>>> {
match self {
Self::Sig(sig, _) | Self::Closure(_, sig) => Some(sig.output()),
- Self::Trait(_, output) => output,
+ Self::Trait(_, output, _) => output,
}
}
pub fn predicates_id(&self) -> Option<DefId> {
- if let ExprFnSig::Sig(_, id) = *self { id } else { None }
+ if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self {
+ id
+ } else {
+ None
+ }
}
}
@@ -568,7 +569,8 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS
}
}
-fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
+/// If the type is function like, get the signature for it.
+pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
if ty.is_box() {
return ty_sig(cx, ty.boxed_ty());
}
@@ -580,9 +582,9 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>>
Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
},
ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
- ty::Opaque(id, _) => ty_sig(cx, cx.tcx.type_of(id)),
+ ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)),
ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
- ty::Dynamic(bounds, _) => {
+ ty::Dynamic(bounds, _, _) => {
let lang_items = cx.tcx.lang_items();
match bounds.principal() {
Some(bound)
@@ -594,26 +596,31 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>>
.projection_bounds()
.find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id()))
.map(|p| p.map_bound(|p| p.term.ty().unwrap()));
- Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output))
+ Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output, None))
},
_ => None,
}
},
ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) {
Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty),
- _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty)),
+ _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)),
},
- ty::Param(_) => sig_from_bounds(cx, ty),
+ ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None),
_ => None,
}
}
-fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
+fn sig_from_bounds<'tcx>(
+ cx: &LateContext<'tcx>,
+ ty: Ty<'tcx>,
+ predicates: &'tcx [Predicate<'tcx>],
+ predicates_id: Option<DefId>,
+) -> Option<ExprFnSig<'tcx>> {
let mut inputs = None;
let mut output = None;
let lang_items = cx.tcx.lang_items();
- for (pred, _) in all_predicates_of(cx.tcx, cx.typeck_results().hir_owner.to_def_id()) {
+ for pred in predicates {
match pred.kind().skip_binder() {
PredicateKind::Trait(p)
if (lang_items.fn_trait() == Some(p.def_id())
@@ -621,11 +628,12 @@ fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnS
|| lang_items.fn_once_trait() == Some(p.def_id()))
&& p.self_ty() == ty =>
{
- if inputs.is_some() {
+ let i = pred.kind().rebind(p.trait_ref.substs.type_at(1));
+ if inputs.map_or(false, |inputs| i != inputs) {
// Multiple different fn trait impls. Is this even allowed?
return None;
}
- inputs = Some(pred.kind().rebind(p.trait_ref.substs.type_at(1)));
+ inputs = Some(i);
},
PredicateKind::Projection(p)
if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output()
@@ -641,7 +649,7 @@ fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnS
}
}
- inputs.map(|ty| ExprFnSig::Trait(ty, output))
+ inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id))
}
fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option<ExprFnSig<'tcx>> {
@@ -649,42 +657,37 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
let mut output = None;
let lang_items = cx.tcx.lang_items();
- for pred in cx
+ for (pred, _) in cx
.tcx
.bound_explicit_item_bounds(ty.item_def_id)
- .transpose_iter()
- .map(|x| x.map_bound(|(p, _)| p))
+ .subst_iter_copied(cx.tcx, ty.substs)
{
- match pred.0.kind().skip_binder() {
+ match pred.kind().skip_binder() {
PredicateKind::Trait(p)
if (lang_items.fn_trait() == Some(p.def_id())
|| lang_items.fn_mut_trait() == Some(p.def_id())
|| lang_items.fn_once_trait() == Some(p.def_id())) =>
{
- if inputs.is_some() {
+ let i = pred.kind().rebind(p.trait_ref.substs.type_at(1));
+
+ if inputs.map_or(false, |inputs| inputs != i) {
// Multiple different fn trait impls. Is this even allowed?
return None;
}
- inputs = Some(
- pred.map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1)))
- .subst(cx.tcx, ty.substs),
- );
+ inputs = Some(i);
},
PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => {
if output.is_some() {
// Multiple different fn trait impls. Is this even allowed?
return None;
}
- output = Some(
- pred.map_bound(|pred| pred.kind().rebind(p.term.ty().unwrap()))
- .subst(cx.tcx, ty.substs),
- );
+ output = pred.kind().rebind(p.term.ty()).transpose();
},
_ => (),
}
}
- inputs.map(|ty| ExprFnSig::Trait(ty, output))
+ inputs.map(|ty| ExprFnSig::Trait(ty, output, None))
}
#[derive(Clone, Copy)]
@@ -827,3 +830,53 @@ pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tc
})
.unwrap_or(false)
}
+
+/// Comes up with an "at least" guesstimate for the type's size, not taking into
+/// account the layout of type parameters.
+pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
+ use rustc_middle::ty::layout::LayoutOf;
+ if !is_normalizable(cx, cx.param_env, ty) {
+ return 0;
+ }
+ match (cx.layout_of(ty).map(|layout| layout.size.bytes()), ty.kind()) {
+ (Ok(size), _) => size,
+ (Err(_), ty::Tuple(list)) => list.as_substs().types().map(|t| approx_ty_size(cx, t)).sum(),
+ (Err(_), ty::Array(t, n)) => {
+ n.try_eval_usize(cx.tcx, cx.param_env).unwrap_or_default() * approx_ty_size(cx, *t)
+ },
+ (Err(_), ty::Adt(def, subst)) if def.is_struct() => def
+ .variants()
+ .iter()
+ .map(|v| {
+ v.fields
+ .iter()
+ .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst)))
+ .sum::<u64>()
+ })
+ .sum(),
+ (Err(_), ty::Adt(def, subst)) if def.is_enum() => def
+ .variants()
+ .iter()
+ .map(|v| {
+ v.fields
+ .iter()
+ .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst)))
+ .sum::<u64>()
+ })
+ .max()
+ .unwrap_or_default(),
+ (Err(_), ty::Adt(def, subst)) if def.is_union() => def
+ .variants()
+ .iter()
+ .map(|v| {
+ v.fields
+ .iter()
+ .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst)))
+ .max()
+ .unwrap_or_default()
+ })
+ .max()
+ .unwrap_or_default(),
+ (Err(_), _) => 0,
+ }
+}
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 3af5dfb62..000fb51c0 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -1,15 +1,16 @@
use crate as utils;
-use crate::visitors::{expr_visitor, expr_visitor_no_bodies};
+use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend};
+use core::ops::ControlFlow;
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::HirIdSet;
use rustc_hir::{Expr, ExprKind, HirId, Node};
+use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter;
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty;
-use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
/// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option<HirIdSet> {
@@ -17,16 +18,15 @@ pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) ->
used_mutably: HirIdSet::default(),
skip: false,
};
- cx.tcx.infer_ctxt().enter(|infcx| {
- ExprUseVisitor::new(
- &mut delegate,
- &infcx,
- expr.hir_id.owner,
- cx.param_env,
- cx.typeck_results(),
- )
- .walk_expr(expr);
- });
+ let infcx = cx.tcx.infer_ctxt().build();
+ ExprUseVisitor::new(
+ &mut delegate,
+ &infcx,
+ expr.hir_id.owner.def_id,
+ cx.param_env,
+ cx.typeck_results(),
+ )
+ .walk_expr(expr);
if delegate.skip {
return None;
@@ -73,7 +73,12 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
self.update(cmt);
}
- fn fake_read(&mut self, _: &rustc_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+ fn fake_read(
+ &mut self,
+ _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
+ _: FakeReadCause,
+ _: HirId,
+ ) {}
}
pub struct ParamBindingIdCollector {
@@ -142,28 +147,17 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
}
pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
- let mut seen_return_break_continue = false;
- expr_visitor_no_bodies(|ex| {
- if seen_return_break_continue {
- return false;
- }
- match &ex.kind {
- ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => {
- seen_return_break_continue = true;
- },
+ for_each_expr(expression, |e| {
+ match e.kind {
+ ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => ControlFlow::Break(()),
// Something special could be done here to handle while or for loop
// desugaring, as this will detect a break if there's a while loop
// or a for loop inside the expression.
- _ => {
- if ex.span.from_expansion() {
- seen_return_break_continue = true;
- }
- },
+ _ if e.span.from_expansion() => ControlFlow::Break(()),
+ _ => ControlFlow::Continue(()),
}
- !seen_return_break_continue
})
- .visit_expr(expression);
- seen_return_break_continue
+ .is_some()
}
pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr<'_>) -> bool {
@@ -194,23 +188,16 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr
return true;
}
- let mut used_after_expr = false;
let mut past_expr = false;
- expr_visitor(cx, |expr| {
- if used_after_expr {
- return false;
- }
-
- if expr.hir_id == after.hir_id {
+ for_each_expr_with_closures(cx, block, |e| {
+ if e.hir_id == after.hir_id {
past_expr = true;
- return false;
- }
-
- if past_expr && utils::path_to_local_id(expr, local_id) {
- used_after_expr = true;
+ ControlFlow::Continue(Descend::No)
+ } else if past_expr && utils::path_to_local_id(e, local_id) {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(Descend::Yes)
}
- !used_after_expr
})
- .visit_block(block);
- used_after_expr
+ .is_some()
}
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index bae8ad9f5..d4294f18f 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -5,14 +5,13 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor};
use rustc_hir::{
- Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, Let, Pat, QPath, Stmt, UnOp,
- UnsafeSource, Unsafety,
+ AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, Let, Pat, QPath,
+ Stmt, UnOp, UnsafeSource, Unsafety,
};
use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::adjustment::Adjust;
-use rustc_middle::ty::{self, Ty, TypeckResults};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeckResults};
use rustc_span::Span;
mod internal {
@@ -48,6 +47,26 @@ impl Continue for Descend {
}
}
+/// A type which can be visited.
+pub trait Visitable<'tcx> {
+ /// Calls the corresponding `visit_*` function on the visitor.
+ fn visit<V: Visitor<'tcx>>(self, visitor: &mut V);
+}
+macro_rules! visitable_ref {
+ ($t:ident, $f:ident) => {
+ impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> {
+ fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+ visitor.$f(self);
+ }
+ }
+ };
+}
+visitable_ref!(Arm, visit_arm);
+visitable_ref!(Block, visit_block);
+visitable_ref!(Body, visit_body);
+visitable_ref!(Expr, visit_expr);
+visitable_ref!(Stmt, visit_stmt);
+
/// Calls the given function once for each expression contained. This does not enter any bodies or
/// nested items.
pub fn for_each_expr<'tcx, B, C: Continue>(
@@ -82,57 +101,63 @@ pub fn for_each_expr<'tcx, B, C: Continue>(
v.res
}
-/// Convenience method for creating a `Visitor` with just `visit_expr` overridden and nested
-/// bodies (i.e. closures) are visited.
-/// If the callback returns `true`, the expr just provided to the callback is walked.
-#[must_use]
-pub fn expr_visitor<'tcx>(cx: &LateContext<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> bool) -> impl Visitor<'tcx> {
- struct V<'tcx, F> {
- hir: Map<'tcx>,
+/// Calls the given function once for each expression contained. This will enter bodies, but not
+/// nested items.
+pub fn for_each_expr_with_closures<'tcx, B, C: Continue>(
+ cx: &LateContext<'tcx>,
+ node: impl Visitable<'tcx>,
+ f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>,
+) -> Option<B> {
+ struct V<'tcx, B, F> {
+ tcx: TyCtxt<'tcx>,
f: F,
+ res: Option<B>,
}
- impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> bool> Visitor<'tcx> for V<'tcx, F> {
+ impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>> Visitor<'tcx> for V<'tcx, B, F> {
type NestedFilter = nested_filter::OnlyBodies;
fn nested_visit_map(&mut self) -> Self::Map {
- self.hir
+ self.tcx.hir()
}
- fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
- if (self.f)(expr) {
- walk_expr(self, expr);
+ fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
+ if self.res.is_some() {
+ return;
}
- }
- }
- V { hir: cx.tcx.hir(), f }
-}
-
-/// Convenience method for creating a `Visitor` with just `visit_expr` overridden and nested
-/// bodies (i.e. closures) are not visited.
-/// If the callback returns `true`, the expr just provided to the callback is walked.
-#[must_use]
-pub fn expr_visitor_no_bodies<'tcx>(f: impl FnMut(&'tcx Expr<'tcx>) -> bool) -> impl Visitor<'tcx> {
- struct V<F>(F);
- impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> bool> Visitor<'tcx> for V<F> {
- fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
- if (self.0)(e) {
- walk_expr(self, e);
+ match (self.f)(e) {
+ ControlFlow::Continue(c) if c.descend() => walk_expr(self, e),
+ ControlFlow::Break(b) => self.res = Some(b),
+ ControlFlow::Continue(_) => (),
}
}
+
+ // Only walk closures
+ fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
+ // Avoid unnecessary `walk_*` calls.
+ fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) {}
+ fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {}
+ fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {}
+ // Avoid monomorphising all `visit_*` functions.
+ fn visit_nested_item(&mut self, _: ItemId) {}
}
- V(f)
+ let mut v = V {
+ tcx: cx.tcx,
+ f,
+ res: None,
+ };
+ node.visit(&mut v);
+ v.res
}
/// returns `true` if expr contains match expr desugared from try
fn contains_try(expr: &hir::Expr<'_>) -> bool {
- let mut found = false;
- expr_visitor_no_bodies(|e| {
- if !found {
- found = matches!(e.kind, hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar));
+ for_each_expr(expr, |e| {
+ if matches!(e.kind, hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar)) {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(())
}
- !found
})
- .visit_expr(expr);
- found
+ .is_some()
}
pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool
@@ -228,68 +253,29 @@ where
}
}
-/// A type which can be visited.
-pub trait Visitable<'tcx> {
- /// Calls the corresponding `visit_*` function on the visitor.
- fn visit<V: Visitor<'tcx>>(self, visitor: &mut V);
-}
-macro_rules! visitable_ref {
- ($t:ident, $f:ident) => {
- impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> {
- fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
- visitor.$f(self);
- }
- }
- };
-}
-visitable_ref!(Arm, visit_arm);
-visitable_ref!(Block, visit_block);
-visitable_ref!(Body, visit_body);
-visitable_ref!(Expr, visit_expr);
-visitable_ref!(Stmt, visit_stmt);
-
-// impl<'tcx, I: IntoIterator> Visitable<'tcx> for I
-// where
-// I::Item: Visitable<'tcx>,
-// {
-// fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
-// for x in self {
-// x.visit(visitor);
-// }
-// }
-// }
-
/// Checks if the given resolved path is used in the given body.
pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
- let mut found = false;
- expr_visitor(cx, |e| {
- if found {
- return false;
- }
-
+ for_each_expr_with_closures(cx, cx.tcx.hir().body(body).value, |e| {
if let ExprKind::Path(p) = &e.kind {
if cx.qpath_res(p, e.hir_id) == res {
- found = true;
+ return ControlFlow::Break(());
}
}
- !found
+ ControlFlow::Continue(())
})
- .visit_expr(&cx.tcx.hir().body(body).value);
- found
+ .is_some()
}
/// Checks if the given local is used.
pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool {
- let mut is_used = false;
- let mut visitor = expr_visitor(cx, |expr| {
- if !is_used {
- is_used = path_to_local_id(expr, id);
+ for_each_expr_with_closures(cx, visitable, |e| {
+ if path_to_local_id(e, id) {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(())
}
- !is_used
- });
- visitable.visit(&mut visitor);
- drop(visitor);
- is_used
+ })
+ .is_some()
}
/// Checks if the given expression is a constant.
@@ -568,6 +554,7 @@ pub fn for_each_local_use_after_expr<'tcx, B>(
// Calls the given function for every unconsumed temporary created by the expression. Note the
// function is only guaranteed to be called for types which need to be dropped, but it may be called
// for other types.
+#[allow(clippy::too_many_lines)]
pub fn for_each_unconsumed_temporary<'tcx, B>(
cx: &LateContext<'tcx>,
e: &'tcx Expr<'tcx>,
@@ -620,7 +607,13 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
helper(typeck, true, arg, f)?;
}
},
- ExprKind::MethodCall(_, args, _) | ExprKind::Tup(args) | ExprKind::Array(args) => {
+ ExprKind::MethodCall(_, receiver, args, _) => {
+ helper(typeck, true, receiver, f)?;
+ for arg in args {
+ helper(typeck, true, arg, f)?;
+ }
+ },
+ ExprKind::Tup(args) | ExprKind::Array(args) => {
for arg in args {
helper(typeck, true, arg, f)?;
}
diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml
index 737c845c0..de31c16b8 100644
--- a/src/tools/clippy/lintcheck/Cargo.toml
+++ b/src/tools/clippy/lintcheck/Cargo.toml
@@ -12,9 +12,11 @@ publish = false
[dependencies]
cargo_metadata = "0.14"
clap = "3.2"
+crossbeam-channel = "0.5.6"
flate2 = "1.0"
rayon = "1.5.1"
serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0.85"
tar = "0.4"
toml = "0.5"
ureq = "2.2"
diff --git a/src/tools/clippy/lintcheck/README.md b/src/tools/clippy/lintcheck/README.md
index 6f3d23382..6142de5e3 100644
--- a/src/tools/clippy/lintcheck/README.md
+++ b/src/tools/clippy/lintcheck/README.md
@@ -69,9 +69,27 @@ is checked.
is explicitly specified in the options.
### Fix mode
-You can run `./lintcheck/target/debug/lintcheck --fix` which will run Clippy with `--fix` and
+You can run `cargo lintcheck --fix` which will run Clippy with `--fix` and
print a warning if Clippy's suggestions fail to apply (if the resulting code does not build).
This lets us spot bad suggestions or false positives automatically in some cases.
Please note that the target dir should be cleaned afterwards since clippy will modify
the downloaded sources which can lead to unexpected results when running lintcheck again afterwards.
+
+### Recursive mode
+You can run `cargo lintcheck --recursive` to also run Clippy on the dependencies
+of the crates listed in the crates source `.toml`. e.g. adding `rand 0.8.5`
+would also lint `rand_core`, `rand_chacha`, etc.
+
+Particularly slow crates in the dependency graph can be ignored using
+`recursive.ignore`:
+
+```toml
+[crates]
+cargo = {name = "cargo", versions = ['0.64.0']}
+
+[recursive]
+ignore = [
+ "unicode-normalization",
+]
+```
diff --git a/src/tools/clippy/lintcheck/lintcheck_crates.toml b/src/tools/clippy/lintcheck/lintcheck_crates.toml
index 4fbae8614..52f7fee47 100644
--- a/src/tools/clippy/lintcheck/lintcheck_crates.toml
+++ b/src/tools/clippy/lintcheck/lintcheck_crates.toml
@@ -1,6 +1,6 @@
[crates]
# some of these are from cargotest
-cargo = {name = "cargo", versions = ['0.49.0']}
+cargo = {name = "cargo", versions = ['0.64.0']}
iron = {name = "iron", versions = ['0.6.1']}
ripgrep = {name = "ripgrep", versions = ['12.1.1']}
xsv = {name = "xsv", versions = ['0.13.0']}
@@ -33,3 +33,11 @@ cfg-expr = {name = "cfg-expr", versions = ['0.7.1']}
puffin = {name = "puffin", git_url = "https://github.com/EmbarkStudios/puffin", git_hash = "02dd4a3"}
rpmalloc = {name = "rpmalloc", versions = ['0.2.0']}
tame-oidc = {name = "tame-oidc", versions = ['0.1.0']}
+
+[recursive]
+ignore = [
+ # Takes ~30s to lint
+ "combine",
+ # Has 1.2 million `clippy::match_same_arms`s
+ "unicode-normalization",
+]
diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs
index 1742cf677..b8824024e 100644
--- a/src/tools/clippy/lintcheck/src/config.rs
+++ b/src/tools/clippy/lintcheck/src/config.rs
@@ -34,11 +34,16 @@ fn get_clap_config() -> ArgMatches {
Arg::new("markdown")
.long("markdown")
.help("Change the reports table to use markdown links"),
+ Arg::new("recursive")
+ .long("--recursive")
+ .help("Run clippy on the dependencies of crates specified in crates-toml")
+ .conflicts_with("threads")
+ .conflicts_with("fix"),
])
.get_matches()
}
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub(crate) struct LintcheckConfig {
/// max number of jobs to spawn (default 1)
pub max_jobs: usize,
@@ -54,6 +59,8 @@ pub(crate) struct LintcheckConfig {
pub lint_filter: Vec<String>,
/// Indicate if the output should support markdown syntax
pub markdown: bool,
+ /// Run clippy on the dependencies of crates
+ pub recursive: bool,
}
impl LintcheckConfig {
@@ -66,8 +73,7 @@ impl LintcheckConfig {
let sources_toml = env::var("LINTCHECK_TOML").unwrap_or_else(|_| {
clap_config
.get_one::<String>("crates-toml")
- .map(|s| &**s)
- .unwrap_or("lintcheck/lintcheck_crates.toml")
+ .map_or("lintcheck/lintcheck_crates.toml", |s| &**s)
.into()
});
@@ -90,7 +96,7 @@ impl LintcheckConfig {
Some(&0) => {
// automatic choice
// Rayon seems to return thread count so half that for core count
- (rayon::current_num_threads() / 2) as usize
+ rayon::current_num_threads() / 2
},
Some(&threads) => threads,
// no -j passed, use a single thread
@@ -119,6 +125,7 @@ impl LintcheckConfig {
fix: clap_config.contains_id("fix"),
lint_filter,
markdown,
+ recursive: clap_config.contains_id("recursive"),
}
}
}
diff --git a/src/tools/clippy/lintcheck/src/driver.rs b/src/tools/clippy/lintcheck/src/driver.rs
new file mode 100644
index 000000000..47724a2fe
--- /dev/null
+++ b/src/tools/clippy/lintcheck/src/driver.rs
@@ -0,0 +1,67 @@
+use crate::recursive::{deserialize_line, serialize_line, DriverInfo};
+
+use std::io::{self, BufReader, Write};
+use std::net::TcpStream;
+use std::process::{self, Command, Stdio};
+use std::{env, mem};
+
+/// 1. Sends [`DriverInfo`] to the [`crate::recursive::LintcheckServer`] running on `addr`
+/// 2. Receives [bool] from the server, if `false` returns `None`
+/// 3. Otherwise sends the stderr of running `clippy-driver` to the server
+fn run_clippy(addr: &str) -> Option<i32> {
+ let driver_info = DriverInfo {
+ package_name: env::var("CARGO_PKG_NAME").ok()?,
+ crate_name: env::var("CARGO_CRATE_NAME").ok()?,
+ version: env::var("CARGO_PKG_VERSION").ok()?,
+ };
+
+ let mut stream = BufReader::new(TcpStream::connect(addr).unwrap());
+
+ serialize_line(&driver_info, stream.get_mut());
+
+ let should_run = deserialize_line::<bool, _>(&mut stream);
+ if !should_run {
+ return None;
+ }
+
+ // Remove --cap-lints allow so that clippy runs and lints are emitted
+ let mut include_next = true;
+ let args = env::args().skip(1).filter(|arg| match arg.as_str() {
+ "--cap-lints=allow" => false,
+ "--cap-lints" => {
+ include_next = false;
+ false
+ },
+ _ => mem::replace(&mut include_next, true),
+ });
+
+ let output = Command::new(env::var("CLIPPY_DRIVER").expect("missing env CLIPPY_DRIVER"))
+ .args(args)
+ .stdout(Stdio::inherit())
+ .output()
+ .expect("failed to run clippy-driver");
+
+ stream
+ .get_mut()
+ .write_all(&output.stderr)
+ .unwrap_or_else(|e| panic!("{e:?} in {driver_info:?}"));
+
+ match output.status.code() {
+ Some(0) => Some(0),
+ code => {
+ io::stderr().write_all(&output.stderr).unwrap();
+ Some(code.expect("killed by signal"))
+ },
+ }
+}
+
+pub fn drive(addr: &str) {
+ process::exit(run_clippy(addr).unwrap_or_else(|| {
+ Command::new("rustc")
+ .args(env::args_os().skip(2))
+ .status()
+ .unwrap()
+ .code()
+ .unwrap()
+ }))
+}
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index 9ee25280f..54c1b80c4 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -8,13 +8,17 @@
#![allow(clippy::collapsible_else_if)]
mod config;
+mod driver;
+mod recursive;
-use config::LintcheckConfig;
+use crate::config::LintcheckConfig;
+use crate::recursive::LintcheckServer;
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
use std::env;
+use std::env::consts::EXE_SUFFIX;
use std::fmt::Write as _;
-use std::fs::write;
+use std::fs;
use std::io::ErrorKind;
use std::path::{Path, PathBuf};
use std::process::Command;
@@ -22,22 +26,12 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;
-use cargo_metadata::diagnostic::DiagnosticLevel;
+use cargo_metadata::diagnostic::{Diagnostic, DiagnosticLevel};
use cargo_metadata::Message;
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use walkdir::{DirEntry, WalkDir};
-#[cfg(not(windows))]
-const CLIPPY_DRIVER_PATH: &str = "target/debug/clippy-driver";
-#[cfg(not(windows))]
-const CARGO_CLIPPY_PATH: &str = "target/debug/cargo-clippy";
-
-#[cfg(windows)]
-const CLIPPY_DRIVER_PATH: &str = "target/debug/clippy-driver.exe";
-#[cfg(windows)]
-const CARGO_CLIPPY_PATH: &str = "target/debug/cargo-clippy.exe";
-
const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads";
const LINTCHECK_SOURCES: &str = "target/lintcheck/sources";
@@ -45,6 +39,13 @@ const LINTCHECK_SOURCES: &str = "target/lintcheck/sources";
#[derive(Debug, Serialize, Deserialize)]
struct SourceList {
crates: HashMap<String, TomlCrate>,
+ #[serde(default)]
+ recursive: RecursiveOptions,
+}
+
+#[derive(Debug, Serialize, Deserialize, Default)]
+struct RecursiveOptions {
+ ignore: HashSet<String>,
}
/// A crate source stored inside the .toml
@@ -105,12 +106,7 @@ struct ClippyWarning {
#[allow(unused)]
impl ClippyWarning {
- fn new(cargo_message: Message, krate: &Crate) -> Option<Self> {
- let diag = match cargo_message {
- Message::CompilerMessage(message) => message.message,
- _ => return None,
- };
-
+ fn new(diag: Diagnostic, crate_name: &str, crate_version: &str) -> Option<Self> {
let lint_type = diag.code?.code;
if !(lint_type.contains("clippy") || diag.message.contains("clippy"))
|| diag.message.contains("could not read cargo metadata")
@@ -120,16 +116,17 @@ impl ClippyWarning {
let span = diag.spans.into_iter().find(|span| span.is_primary)?;
- let file = match Path::new(&span.file_name).strip_prefix(env!("CARGO_HOME")) {
- Ok(stripped) => format!("$CARGO_HOME/{}", stripped.display()),
- Err(_) => format!(
+ let file = if let Ok(stripped) = Path::new(&span.file_name).strip_prefix(env!("CARGO_HOME")) {
+ format!("$CARGO_HOME/{}", stripped.display())
+ } else {
+ format!(
"target/lintcheck/sources/{}-{}/{}",
- krate.name, krate.version, span.file_name
- ),
+ crate_name, crate_version, span.file_name
+ )
};
Some(Self {
- crate_name: krate.name.clone(),
+ crate_name: crate_name.to_owned(),
file,
line: span.line_start,
column: span.column_start,
@@ -142,24 +139,23 @@ impl ClippyWarning {
fn to_output(&self, markdown: bool) -> String {
let file_with_pos = format!("{}:{}:{}", &self.file, &self.line, &self.column);
if markdown {
- let lint = format!("`{}`", self.lint_type);
-
let mut file = self.file.clone();
if !file.starts_with('$') {
file.insert_str(0, "../");
}
let mut output = String::from("| ");
- let _ = write!(output, "[`{}`]({}#L{})", file_with_pos, file, self.line);
- let _ = write!(output, r#" | {:<50} | "{}" |"#, lint, self.message);
+ let _ = write!(output, "[`{file_with_pos}`]({file}#L{})", self.line);
+ let _ = write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.message);
output.push('\n');
output
} else {
- format!("{} {} \"{}\"\n", file_with_pos, self.lint_type, self.message)
+ format!("{file_with_pos} {} \"{}\"\n", self.lint_type, self.message)
}
}
}
+#[allow(clippy::result_large_err)]
fn get(path: &str) -> Result<ureq::Response, ureq::Error> {
const MAX_RETRIES: u8 = 4;
let mut retries = 0;
@@ -167,11 +163,11 @@ fn get(path: &str) -> Result<ureq::Response, ureq::Error> {
match ureq::get(path).call() {
Ok(res) => return Ok(res),
Err(e) if retries >= MAX_RETRIES => return Err(e),
- Err(ureq::Error::Transport(e)) => eprintln!("Error: {}", e),
+ Err(ureq::Error::Transport(e)) => eprintln!("Error: {e}"),
Err(e) => return Err(e),
}
- eprintln!("retrying in {} seconds...", retries);
- thread::sleep(Duration::from_secs(retries as u64));
+ eprintln!("retrying in {retries} seconds...");
+ thread::sleep(Duration::from_secs(u64::from(retries)));
retries += 1;
}
}
@@ -187,11 +183,11 @@ impl CrateSource {
let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS);
// url to download the crate from crates.io
- let url = format!("https://crates.io/api/v1/crates/{}/{}/download", name, version);
- println!("Downloading and extracting {} {} from {}", name, version, url);
+ let url = format!("https://crates.io/api/v1/crates/{name}/{version}/download");
+ println!("Downloading and extracting {name} {version} from {url}");
create_dirs(&krate_download_dir, &extract_dir);
- let krate_file_path = krate_download_dir.join(format!("{}-{}.crate.tar.gz", name, version));
+ let krate_file_path = krate_download_dir.join(format!("{name}-{version}.crate.tar.gz"));
// don't download/extract if we already have done so
if !krate_file_path.is_file() {
// create a file path to download and write the crate data into
@@ -211,7 +207,7 @@ impl CrateSource {
Crate {
version: version.clone(),
name: name.clone(),
- path: extract_dir.join(format!("{}-{}/", name, version)),
+ path: extract_dir.join(format!("{name}-{version}/")),
options: options.clone(),
}
},
@@ -224,12 +220,12 @@ impl CrateSource {
let repo_path = {
let mut repo_path = PathBuf::from(LINTCHECK_SOURCES);
// add a -git suffix in case we have the same crate from crates.io and a git repo
- repo_path.push(format!("{}-git", name));
+ repo_path.push(format!("{name}-git"));
repo_path
};
// clone the repo if we have not done so
if !repo_path.is_dir() {
- println!("Cloning {} and checking out {}", url, commit);
+ println!("Cloning {url} and checking out {commit}");
if !Command::new("git")
.arg("clone")
.arg(url)
@@ -238,11 +234,12 @@ impl CrateSource {
.expect("Failed to clone git repo!")
.success()
{
- eprintln!("Failed to clone {} into {}", url, repo_path.display())
+ eprintln!("Failed to clone {url} into {}", repo_path.display());
}
}
// check out the commit/branch/whatever
if !Command::new("git")
+ .args(["-c", "advice.detachedHead=false"])
.arg("checkout")
.arg(commit)
.current_dir(&repo_path)
@@ -250,7 +247,7 @@ impl CrateSource {
.expect("Failed to check out commit")
.success()
{
- eprintln!("Failed to checkout {} of repo at {}", commit, repo_path.display())
+ eprintln!("Failed to checkout {commit} of repo at {}", repo_path.display());
}
Crate {
@@ -261,22 +258,22 @@ impl CrateSource {
}
},
CrateSource::Path { name, path, options } => {
+ fn is_cache_dir(entry: &DirEntry) -> bool {
+ std::fs::read(entry.path().join("CACHEDIR.TAG"))
+ .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55"))
+ .unwrap_or(false)
+ }
+
// copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file.
// The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory
// as a result of this filter.
let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name);
if dest_crate_root.exists() {
- println!("Deleting existing directory at {:?}", dest_crate_root);
+ println!("Deleting existing directory at {dest_crate_root:?}");
std::fs::remove_dir_all(&dest_crate_root).unwrap();
}
- println!("Copying {:?} to {:?}", path, dest_crate_root);
-
- fn is_cache_dir(entry: &DirEntry) -> bool {
- std::fs::read(entry.path().join("CACHEDIR.TAG"))
- .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55"))
- .unwrap_or(false)
- }
+ println!("Copying {path:?} to {dest_crate_root:?}");
for entry in WalkDir::new(path).into_iter().filter_entry(|e| !is_cache_dir(e)) {
let entry = entry.unwrap();
@@ -306,13 +303,16 @@ impl CrateSource {
impl Crate {
/// Run `cargo clippy` on the `Crate` and collect and return all the lint warnings that clippy
/// issued
+ #[allow(clippy::too_many_arguments)]
fn run_clippy_lints(
&self,
cargo_clippy_path: &Path,
+ clippy_driver_path: &Path,
target_dir_index: &AtomicUsize,
total_crates_to_lint: usize,
config: &LintcheckConfig,
lint_filter: &Vec<String>,
+ server: &Option<LintcheckServer>,
) -> Vec<ClippyWarning> {
// advance the atomic index by one
let index = target_dir_index.fetch_add(1, Ordering::SeqCst);
@@ -336,36 +336,64 @@ impl Crate {
let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir");
- let mut args = if config.fix {
+ let mut cargo_clippy_args = if config.fix {
vec!["--fix", "--"]
} else {
vec!["--", "--message-format=json", "--"]
};
+ let mut clippy_args = Vec::<&str>::new();
if let Some(options) = &self.options {
for opt in options {
- args.push(opt);
+ clippy_args.push(opt);
}
} else {
- args.extend(&["-Wclippy::pedantic", "-Wclippy::cargo"])
+ clippy_args.extend(["-Wclippy::pedantic", "-Wclippy::cargo"]);
}
if lint_filter.is_empty() {
- args.push("--cap-lints=warn");
+ clippy_args.push("--cap-lints=warn");
} else {
- args.push("--cap-lints=allow");
- args.extend(lint_filter.iter().map(|filter| filter.as_str()))
+ clippy_args.push("--cap-lints=allow");
+ clippy_args.extend(lint_filter.iter().map(std::string::String::as_str));
}
- let all_output = std::process::Command::new(&cargo_clippy_path)
+ if let Some(server) = server {
+ let target = shared_target_dir.join("recursive");
+
+ // `cargo clippy` is a wrapper around `cargo check` that mainly sets `RUSTC_WORKSPACE_WRAPPER` to
+ // `clippy-driver`. We do the same thing here with a couple changes:
+ //
+ // `RUSTC_WRAPPER` is used instead of `RUSTC_WORKSPACE_WRAPPER` so that we can lint all crate
+ // dependencies rather than only workspace members
+ //
+ // The wrapper is set to the `lintcheck` so we can force enable linting and ignore certain crates
+ // (see `crate::driver`)
+ let status = Command::new("cargo")
+ .arg("check")
+ .arg("--quiet")
+ .current_dir(&self.path)
+ .env("CLIPPY_ARGS", clippy_args.join("__CLIPPY_HACKERY__"))
+ .env("CARGO_TARGET_DIR", target)
+ .env("RUSTC_WRAPPER", env::current_exe().unwrap())
+ // Pass the absolute path so `crate::driver` can find `clippy-driver`, as it's executed in various
+ // different working directories
+ .env("CLIPPY_DRIVER", clippy_driver_path)
+ .env("LINTCHECK_SERVER", server.local_addr.to_string())
+ .status()
+ .expect("failed to run cargo");
+
+ assert_eq!(status.code(), Some(0));
+
+ return Vec::new();
+ }
+
+ cargo_clippy_args.extend(clippy_args);
+
+ let all_output = Command::new(&cargo_clippy_path)
// use the looping index to create individual target dirs
- .env(
- "CARGO_TARGET_DIR",
- shared_target_dir.join(format!("_{:?}", thread_index)),
- )
- // lint warnings will look like this:
- // src/cargo/ops/cargo_compile.rs:127:35: warning: usage of `FromIterator::from_iter`
- .args(&args)
+ .env("CARGO_TARGET_DIR", shared_target_dir.join(format!("_{thread_index:?}")))
+ .args(&cargo_clippy_args)
.current_dir(&self.path)
.output()
.unwrap_or_else(|error| {
@@ -394,8 +422,8 @@ impl Crate {
{
let subcrate = &stderr[63..];
println!(
- "ERROR: failed to apply some suggetion to {} / to (sub)crate {}",
- self.name, subcrate
+ "ERROR: failed to apply some suggetion to {} / to (sub)crate {subcrate}",
+ self.name
);
}
// fast path, we don't need the warnings anyway
@@ -404,7 +432,10 @@ impl Crate {
// get all clippy warnings and ICEs
let warnings: Vec<ClippyWarning> = Message::parse_stream(stdout.as_bytes())
- .filter_map(|msg| ClippyWarning::new(msg.unwrap(), &self))
+ .filter_map(|msg| match msg {
+ Ok(Message::CompilerMessage(message)) => ClippyWarning::new(message.message, &self.name, &self.version),
+ _ => None,
+ })
.collect();
warnings
@@ -423,23 +454,19 @@ fn build_clippy() {
}
}
-/// Read a `toml` file and return a list of `CrateSources` that we want to check with clippy
-fn read_crates(toml_path: &Path) -> Vec<CrateSource> {
+/// Read a `lintcheck_crates.toml` file
+fn read_crates(toml_path: &Path) -> (Vec<CrateSource>, RecursiveOptions) {
let toml_content: String =
- std::fs::read_to_string(&toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display()));
+ std::fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display()));
let crate_list: SourceList =
- toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{}", toml_path.display(), e));
+ toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{e}", toml_path.display()));
// parse the hashmap of the toml file into a list of crates
- let tomlcrates: Vec<TomlCrate> = crate_list
- .crates
- .into_iter()
- .map(|(_cratename, tomlcrate)| tomlcrate)
- .collect();
+ let tomlcrates: Vec<TomlCrate> = crate_list.crates.into_values().collect();
// flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate =>
// multiple Cratesources)
let mut crate_sources = Vec::new();
- tomlcrates.into_iter().for_each(|tk| {
+ for tk in tomlcrates {
if let Some(ref path) = tk.path {
crate_sources.push(CrateSource::Path {
name: tk.name.clone(),
@@ -448,13 +475,13 @@ fn read_crates(toml_path: &Path) -> Vec<CrateSource> {
});
} else if let Some(ref versions) = tk.versions {
// if we have multiple versions, save each one
- versions.iter().for_each(|ver| {
+ for ver in versions.iter() {
crate_sources.push(CrateSource::CratesIo {
name: tk.name.clone(),
version: ver.to_string(),
options: tk.options.clone(),
});
- })
+ }
} else if tk.git_url.is_some() && tk.git_hash.is_some() {
// otherwise, we should have a git source
crate_sources.push(CrateSource::Git {
@@ -471,20 +498,23 @@ fn read_crates(toml_path: &Path) -> Vec<CrateSource> {
if tk.versions.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some())
|| tk.git_hash.is_some() != tk.git_url.is_some()
{
- eprintln!("tomlkrate: {:?}", tk);
- if tk.git_hash.is_some() != tk.git_url.is_some() {
- panic!("Error: Encountered TomlCrate with only one of git_hash and git_url!");
- }
- if tk.path.is_some() && (tk.git_hash.is_some() || tk.versions.is_some()) {
- panic!("Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields");
- }
+ eprintln!("tomlkrate: {tk:?}");
+ assert_eq!(
+ tk.git_hash.is_some(),
+ tk.git_url.is_some(),
+ "Error: Encountered TomlCrate with only one of git_hash and git_url!"
+ );
+ assert!(
+ tk.path.is_none() || (tk.git_hash.is_none() && tk.versions.is_none()),
+ "Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields"
+ );
unreachable!("Failed to translate TomlCrate into CrateSource!");
}
- });
+ }
// sort the crates
crate_sources.sort();
- crate_sources
+ (crate_sources, crate_list.recursive)
}
/// Generate a short list of occurring lints-types and their count
@@ -499,13 +529,13 @@ fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String,
let mut stats: Vec<(&&String, &usize)> = counter.iter().map(|(lint, count)| (lint, count)).collect();
// sort by "000{count} {clippy::lintname}"
// to not have a lint with 200 and 2 warnings take the same spot
- stats.sort_by_key(|(lint, count)| format!("{:0>4}, {}", count, lint));
+ stats.sort_by_key(|(lint, count)| format!("{count:0>4}, {lint}"));
let mut header = String::from("| lint | count |\n");
header.push_str("| -------------------------------------------------- | ----- |\n");
let stats_string = stats
.iter()
- .map(|(lint, count)| format!("| {:<50} | {:>4} |\n", lint, count))
+ .map(|(lint, count)| format!("| {lint:<50} | {count:>4} |\n"))
.fold(header, |mut table, line| {
table.push_str(&line);
table
@@ -516,20 +546,20 @@ fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String,
/// check if the latest modification of the logfile is older than the modification date of the
/// clippy binary, if this is true, we should clean the lintchec shared target directory and recheck
-fn lintcheck_needs_rerun(lintcheck_logs_path: &Path) -> bool {
+fn lintcheck_needs_rerun(lintcheck_logs_path: &Path, paths: [&Path; 2]) -> bool {
if !lintcheck_logs_path.exists() {
return true;
}
let clippy_modified: std::time::SystemTime = {
- let mut times = [CLIPPY_DRIVER_PATH, CARGO_CLIPPY_PATH].iter().map(|p| {
+ let [cargo, driver] = paths.map(|p| {
std::fs::metadata(p)
.expect("failed to get metadata of file")
.modified()
.expect("failed to get modification date")
});
// the oldest modification of either of the binaries
- std::cmp::max(times.next().unwrap(), times.next().unwrap())
+ std::cmp::max(cargo, driver)
};
let logs_modified: std::time::SystemTime = std::fs::metadata(lintcheck_logs_path)
@@ -542,7 +572,13 @@ fn lintcheck_needs_rerun(lintcheck_logs_path: &Path) -> bool {
logs_modified < clippy_modified
}
+#[allow(clippy::too_many_lines)]
fn main() {
+ // We're being executed as a `RUSTC_WRAPPER` as part of `--recursive`
+ if let Ok(addr) = env::var("LINTCHECK_SERVER") {
+ driver::drive(&addr);
+ }
+
// assert that we launch lintcheck from the repo root (via cargo lintcheck)
if std::fs::metadata("lintcheck/Cargo.toml").is_err() {
eprintln!("lintcheck needs to be run from clippy's repo root!\nUse `cargo lintcheck` alternatively.");
@@ -555,24 +591,26 @@ fn main() {
build_clippy();
println!("Done compiling");
+ let cargo_clippy_path = fs::canonicalize(format!("target/debug/cargo-clippy{EXE_SUFFIX}")).unwrap();
+ let clippy_driver_path = fs::canonicalize(format!("target/debug/clippy-driver{EXE_SUFFIX}")).unwrap();
+
// if the clippy bin is newer than our logs, throw away target dirs to force clippy to
// refresh the logs
- if lintcheck_needs_rerun(&config.lintcheck_results_path) {
+ if lintcheck_needs_rerun(
+ &config.lintcheck_results_path,
+ [&cargo_clippy_path, &clippy_driver_path],
+ ) {
let shared_target_dir = "target/lintcheck/shared_target_dir";
// if we get an Err here, the shared target dir probably does simply not exist
- if let Ok(metadata) = std::fs::metadata(&shared_target_dir) {
+ if let Ok(metadata) = std::fs::metadata(shared_target_dir) {
if metadata.is_dir() {
println!("Clippy is newer than lint check logs, clearing lintcheck shared target dir...");
- std::fs::remove_dir_all(&shared_target_dir)
+ std::fs::remove_dir_all(shared_target_dir)
.expect("failed to remove target/lintcheck/shared_target_dir");
}
}
}
- let cargo_clippy_path: PathBuf = PathBuf::from(CARGO_CLIPPY_PATH)
- .canonicalize()
- .expect("failed to canonicalize path to clippy binary");
-
// assert that clippy is found
assert!(
cargo_clippy_path.is_file(),
@@ -580,7 +618,7 @@ fn main() {
cargo_clippy_path.display()
);
- let clippy_ver = std::process::Command::new(CARGO_CLIPPY_PATH)
+ let clippy_ver = std::process::Command::new(&cargo_clippy_path)
.arg("--version")
.output()
.map(|o| String::from_utf8_lossy(&o.stdout).into_owned())
@@ -589,7 +627,7 @@ fn main() {
// download and extract the crates, then run clippy on them and collect clippy's warnings
// flatten into one big list of warnings
- let crates = read_crates(&config.sources_toml_path);
+ let (crates, recursive_options) = read_crates(&config.sources_toml_path);
let old_stats = read_stats_from_file(&config.lintcheck_results_path);
let counter = AtomicUsize::new(1);
@@ -639,11 +677,31 @@ fn main() {
.build_global()
.unwrap();
- let clippy_warnings: Vec<ClippyWarning> = crates
+ let server = config.recursive.then(|| {
+ fs::remove_dir_all("target/lintcheck/shared_target_dir/recursive").unwrap_or_default();
+
+ LintcheckServer::spawn(recursive_options)
+ });
+
+ let mut clippy_warnings: Vec<ClippyWarning> = crates
.par_iter()
- .flat_map(|krate| krate.run_clippy_lints(&cargo_clippy_path, &counter, crates.len(), &config, &lint_filter))
+ .flat_map(|krate| {
+ krate.run_clippy_lints(
+ &cargo_clippy_path,
+ &clippy_driver_path,
+ &counter,
+ crates.len(),
+ &config,
+ &lint_filter,
+ &server,
+ )
+ })
.collect();
+ if let Some(server) = server {
+ clippy_warnings.extend(server.warnings());
+ }
+
// if we are in --fix mode, don't change the log files, terminate here
if config.fix {
return;
@@ -676,13 +734,13 @@ fn main() {
}
write!(text, "{}", all_msgs.join("")).unwrap();
text.push_str("\n\n### ICEs:\n");
- for (cratename, msg) in ices.iter() {
- let _ = write!(text, "{}: '{}'", cratename, msg);
+ for (cratename, msg) in &ices {
+ let _ = write!(text, "{cratename}: '{msg}'");
}
println!("Writing logs to {}", config.lintcheck_results_path.display());
- std::fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap();
- write(&config.lintcheck_results_path, text).unwrap();
+ fs::create_dir_all(config.lintcheck_results_path.parent().unwrap()).unwrap();
+ fs::write(&config.lintcheck_results_path, text).unwrap();
print_stats(old_stats, new_stats, &config.lint_filter);
}
@@ -721,7 +779,7 @@ fn read_stats_from_file(file_path: &Path) -> HashMap<String, usize> {
fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, usize>, lint_filter: &Vec<String>) {
let same_in_both_hashmaps = old_stats
.iter()
- .filter(|(old_key, old_val)| new_stats.get::<&String>(&old_key) == Some(old_val))
+ .filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val))
.map(|(k, v)| (k.to_string(), *v))
.collect::<Vec<(String, usize)>>();
@@ -729,37 +787,37 @@ fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, us
let mut new_stats_deduped = new_stats;
// remove duplicates from both hashmaps
- same_in_both_hashmaps.iter().for_each(|(k, v)| {
+ for (k, v) in &same_in_both_hashmaps {
assert!(old_stats_deduped.remove(k) == Some(*v));
assert!(new_stats_deduped.remove(k) == Some(*v));
- });
+ }
println!("\nStats:");
// list all new counts (key is in new stats but not in old stats)
new_stats_deduped
.iter()
- .filter(|(new_key, _)| old_stats_deduped.get::<str>(&new_key).is_none())
+ .filter(|(new_key, _)| old_stats_deduped.get::<str>(new_key).is_none())
.for_each(|(new_key, new_value)| {
- println!("{} 0 => {}", new_key, new_value);
+ println!("{new_key} 0 => {new_value}");
});
// list all changed counts (key is in both maps but value differs)
new_stats_deduped
.iter()
- .filter(|(new_key, _new_val)| old_stats_deduped.get::<str>(&new_key).is_some())
+ .filter(|(new_key, _new_val)| old_stats_deduped.get::<str>(new_key).is_some())
.for_each(|(new_key, new_val)| {
- let old_val = old_stats_deduped.get::<str>(&new_key).unwrap();
- println!("{} {} => {}", new_key, old_val, new_val);
+ let old_val = old_stats_deduped.get::<str>(new_key).unwrap();
+ println!("{new_key} {old_val} => {new_val}");
});
// list all gone counts (key is in old status but not in new stats)
old_stats_deduped
.iter()
- .filter(|(old_key, _)| new_stats_deduped.get::<&String>(&old_key).is_none())
+ .filter(|(old_key, _)| new_stats_deduped.get::<&String>(old_key).is_none())
.filter(|(old_key, _)| lint_filter.is_empty() || lint_filter.contains(old_key))
.for_each(|(old_key, old_value)| {
- println!("{} {} => 0", old_key, old_value);
+ println!("{old_key} {old_value} => 0");
});
}
@@ -770,19 +828,21 @@ fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, us
/// This function panics if creating one of the dirs fails.
fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) {
std::fs::create_dir("target/lintcheck/").unwrap_or_else(|err| {
- if err.kind() != ErrorKind::AlreadyExists {
- panic!("cannot create lintcheck target dir");
- }
+ assert_eq!(
+ err.kind(),
+ ErrorKind::AlreadyExists,
+ "cannot create lintcheck target dir"
+ );
});
- std::fs::create_dir(&krate_download_dir).unwrap_or_else(|err| {
- if err.kind() != ErrorKind::AlreadyExists {
- panic!("cannot create crate download dir");
- }
+ std::fs::create_dir(krate_download_dir).unwrap_or_else(|err| {
+ assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir");
});
- std::fs::create_dir(&extract_dir).unwrap_or_else(|err| {
- if err.kind() != ErrorKind::AlreadyExists {
- panic!("cannot create crate extraction dir");
- }
+ std::fs::create_dir(extract_dir).unwrap_or_else(|err| {
+ assert_eq!(
+ err.kind(),
+ ErrorKind::AlreadyExists,
+ "cannot create crate extraction dir"
+ );
});
}
@@ -805,7 +865,7 @@ fn lintcheck_test() {
"lintcheck/test_sources.toml",
];
let status = std::process::Command::new("cargo")
- .args(&args)
+ .args(args)
.current_dir("..") // repo root
.status();
//.output();
diff --git a/src/tools/clippy/lintcheck/src/recursive.rs b/src/tools/clippy/lintcheck/src/recursive.rs
new file mode 100644
index 000000000..49072e651
--- /dev/null
+++ b/src/tools/clippy/lintcheck/src/recursive.rs
@@ -0,0 +1,123 @@
+//! In `--recursive` mode we set the `lintcheck` binary as the `RUSTC_WRAPPER` of `cargo check`,
+//! this allows [`crate::driver`] to be run for every dependency. The driver connects to
+//! [`LintcheckServer`] to ask if it should be skipped, and if not sends the stderr of running
+//! clippy on the crate to the server
+
+use crate::ClippyWarning;
+use crate::RecursiveOptions;
+
+use std::collections::HashSet;
+use std::io::{BufRead, BufReader, Read, Write};
+use std::net::{SocketAddr, TcpListener, TcpStream};
+use std::sync::{Arc, Mutex};
+use std::thread;
+
+use cargo_metadata::diagnostic::Diagnostic;
+use crossbeam_channel::{Receiver, Sender};
+use serde::de::DeserializeOwned;
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Eq, Hash, PartialEq, Clone, Serialize, Deserialize)]
+pub(crate) struct DriverInfo {
+ pub package_name: String,
+ pub crate_name: String,
+ pub version: String,
+}
+
+pub(crate) fn serialize_line<T, W>(value: &T, writer: &mut W)
+where
+ T: Serialize,
+ W: Write,
+{
+ let mut buf = serde_json::to_vec(&value).expect("failed to serialize");
+ buf.push(b'\n');
+ writer.write_all(&buf).expect("write_all failed");
+}
+
+pub(crate) fn deserialize_line<T, R>(reader: &mut R) -> T
+where
+ T: DeserializeOwned,
+ R: BufRead,
+{
+ let mut string = String::new();
+ reader.read_line(&mut string).expect("read_line failed");
+ serde_json::from_str(&string).expect("failed to deserialize")
+}
+
+fn process_stream(
+ stream: TcpStream,
+ sender: &Sender<ClippyWarning>,
+ options: &RecursiveOptions,
+ seen: &Mutex<HashSet<DriverInfo>>,
+) {
+ let mut stream = BufReader::new(stream);
+
+ let driver_info: DriverInfo = deserialize_line(&mut stream);
+
+ let unseen = seen.lock().unwrap().insert(driver_info.clone());
+ let ignored = options.ignore.contains(&driver_info.package_name);
+ let should_run = unseen && !ignored;
+
+ serialize_line(&should_run, stream.get_mut());
+
+ let mut stderr = String::new();
+ stream.read_to_string(&mut stderr).unwrap();
+
+ let messages = stderr
+ .lines()
+ .filter_map(|json_msg| serde_json::from_str::<Diagnostic>(json_msg).ok())
+ .filter_map(|diag| ClippyWarning::new(diag, &driver_info.package_name, &driver_info.version));
+
+ for message in messages {
+ sender.send(message).unwrap();
+ }
+}
+
+pub(crate) struct LintcheckServer {
+ pub local_addr: SocketAddr,
+ receiver: Receiver<ClippyWarning>,
+ sender: Arc<Sender<ClippyWarning>>,
+}
+
+impl LintcheckServer {
+ pub fn spawn(options: RecursiveOptions) -> Self {
+ let listener = TcpListener::bind("localhost:0").unwrap();
+ let local_addr = listener.local_addr().unwrap();
+
+ let (sender, receiver) = crossbeam_channel::unbounded::<ClippyWarning>();
+ let sender = Arc::new(sender);
+ // The spawned threads hold a `Weak<Sender>` so that they don't keep the channel connected
+ // indefinitely
+ let sender_weak = Arc::downgrade(&sender);
+
+ // Ignore dependencies multiple times, e.g. for when it's both checked and compiled for a
+ // build dependency
+ let seen = Mutex::default();
+
+ thread::spawn(move || {
+ thread::scope(|s| {
+ s.spawn(|| {
+ while let Ok((stream, _)) = listener.accept() {
+ let sender = sender_weak.upgrade().expect("received connection after server closed");
+ let options = &options;
+ let seen = &seen;
+ s.spawn(move || process_stream(stream, &sender, options, seen));
+ }
+ });
+ });
+ });
+
+ Self {
+ local_addr,
+ receiver,
+ sender,
+ }
+ }
+
+ pub fn warnings(self) -> impl Iterator<Item = ClippyWarning> {
+ // causes the channel to become disconnected so that the receiver iterator ends
+ drop(self.sender);
+
+ self.receiver.into_iter()
+ }
+}
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 23ba7c712..748d8a317 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
[toolchain]
-channel = "nightly-2022-07-28"
+channel = "nightly-2022-10-20"
components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/rustc_tools_util/Cargo.toml b/src/tools/clippy/rustc_tools_util/Cargo.toml
index 9554d4d6c..89c3d6aaa 100644
--- a/src/tools/clippy/rustc_tools_util/Cargo.toml
+++ b/src/tools/clippy/rustc_tools_util/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "rustc_tools_util"
-version = "0.2.0"
+version = "0.2.1"
description = "small helper to generate version information for git packages"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
diff --git a/src/tools/clippy/rustc_tools_util/README.md b/src/tools/clippy/rustc_tools_util/README.md
index 01891b51d..e947f9c7e 100644
--- a/src/tools/clippy/rustc_tools_util/README.md
+++ b/src/tools/clippy/rustc_tools_util/README.md
@@ -6,17 +6,17 @@ for packages installed from a git repo
## Usage
Add a `build.rs` file to your repo and list it in `Cargo.toml`
-````
+````toml
build = "build.rs"
````
List rustc_tools_util as regular AND build dependency.
-````
+````toml
[dependencies]
-rustc_tools_util = "0.1"
+rustc_tools_util = "0.2.1"
[build-dependencies]
-rustc_tools_util = "0.1"
+rustc_tools_util = "0.2.1"
````
In `build.rs`, generate the data in your `main()`
diff --git a/src/tools/clippy/rustc_tools_util/src/lib.rs b/src/tools/clippy/rustc_tools_util/src/lib.rs
index 5f289918a..01d25c531 100644
--- a/src/tools/clippy/rustc_tools_util/src/lib.rs
+++ b/src/tools/clippy/rustc_tools_util/src/lib.rs
@@ -48,8 +48,8 @@ impl std::fmt::Display for VersionInfo {
if (hash_trimmed.len() + date_trimmed.len()) > 0 {
write!(
f,
- "{} {}.{}.{} ({} {})",
- self.crate_name, self.major, self.minor, self.patch, hash_trimmed, date_trimmed,
+ "{} {}.{}.{} ({hash_trimmed} {date_trimmed})",
+ self.crate_name, self.major, self.minor, self.patch,
)?;
} else {
write!(f, "{} {}.{}.{}", self.crate_name, self.major, self.minor, self.patch)?;
@@ -84,7 +84,7 @@ impl std::fmt::Debug for VersionInfo {
#[must_use]
pub fn get_commit_hash() -> Option<String> {
std::process::Command::new("git")
- .args(&["rev-parse", "--short", "HEAD"])
+ .args(["rev-parse", "--short", "HEAD"])
.output()
.ok()
.and_then(|r| String::from_utf8(r.stdout).ok())
@@ -93,7 +93,7 @@ pub fn get_commit_hash() -> Option<String> {
#[must_use]
pub fn get_commit_date() -> Option<String> {
std::process::Command::new("git")
- .args(&["log", "-1", "--date=short", "--pretty=format:%cd"])
+ .args(["log", "-1", "--date=short", "--pretty=format:%cd"])
.output()
.ok()
.and_then(|r| String::from_utf8(r.stdout).ok())
@@ -137,7 +137,7 @@ mod test {
let vi = get_version_info!();
assert_eq!(vi.major, 0);
assert_eq!(vi.minor, 2);
- assert_eq!(vi.patch, 0);
+ assert_eq!(vi.patch, 1);
assert_eq!(vi.crate_name, "rustc_tools_util");
// hard to make positive tests for these since they will always change
assert!(vi.commit_hash.is_none());
@@ -147,16 +147,16 @@ mod test {
#[test]
fn test_display_local() {
let vi = get_version_info!();
- assert_eq!(vi.to_string(), "rustc_tools_util 0.2.0");
+ assert_eq!(vi.to_string(), "rustc_tools_util 0.2.1");
}
#[test]
fn test_debug_local() {
let vi = get_version_info!();
- let s = format!("{:?}", vi);
+ let s = format!("{vi:?}");
assert_eq!(
s,
- "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 2, patch: 0 }"
+ "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 2, patch: 1 }"
);
}
}
diff --git a/src/tools/clippy/src/docs.rs b/src/tools/clippy/src/docs.rs
new file mode 100644
index 000000000..c033ad294
--- /dev/null
+++ b/src/tools/clippy/src/docs.rs
@@ -0,0 +1,606 @@
+// autogenerated. Please look at /clippy_dev/src/update_lints.rs
+
+macro_rules! include_lint {
+ ($file_name: expr) => {
+ include_str!($file_name)
+ };
+}
+
+macro_rules! docs {
+ ($($lint_name: expr,)*) => {
+ pub fn explain(lint: &str) {
+ println!("{}", match lint {
+ $(
+ $lint_name => include_lint!(concat!("docs/", concat!($lint_name, ".txt"))),
+ )*
+ _ => "unknown lint",
+ })
+ }
+ }
+}
+
+docs! {
+ "absurd_extreme_comparisons",
+ "alloc_instead_of_core",
+ "allow_attributes_without_reason",
+ "almost_complete_letter_range",
+ "almost_swapped",
+ "approx_constant",
+ "arithmetic_side_effects",
+ "as_conversions",
+ "as_ptr_cast_mut",
+ "as_underscore",
+ "assertions_on_constants",
+ "assertions_on_result_states",
+ "assign_op_pattern",
+ "async_yields_async",
+ "await_holding_invalid_type",
+ "await_holding_lock",
+ "await_holding_refcell_ref",
+ "bad_bit_mask",
+ "bind_instead_of_map",
+ "blanket_clippy_restriction_lints",
+ "blocks_in_if_conditions",
+ "bool_assert_comparison",
+ "bool_comparison",
+ "bool_to_int_with_if",
+ "borrow_as_ptr",
+ "borrow_deref_ref",
+ "borrow_interior_mutable_const",
+ "borrowed_box",
+ "box_collection",
+ "box_default",
+ "boxed_local",
+ "branches_sharing_code",
+ "builtin_type_shadow",
+ "bytes_count_to_len",
+ "bytes_nth",
+ "cargo_common_metadata",
+ "case_sensitive_file_extension_comparisons",
+ "cast_abs_to_unsigned",
+ "cast_enum_constructor",
+ "cast_enum_truncation",
+ "cast_lossless",
+ "cast_nan_to_int",
+ "cast_possible_truncation",
+ "cast_possible_wrap",
+ "cast_precision_loss",
+ "cast_ptr_alignment",
+ "cast_ref_to_mut",
+ "cast_sign_loss",
+ "cast_slice_different_sizes",
+ "cast_slice_from_raw_parts",
+ "char_lit_as_u8",
+ "chars_last_cmp",
+ "chars_next_cmp",
+ "checked_conversions",
+ "clone_double_ref",
+ "clone_on_copy",
+ "clone_on_ref_ptr",
+ "cloned_instead_of_copied",
+ "cmp_nan",
+ "cmp_null",
+ "cmp_owned",
+ "cognitive_complexity",
+ "collapsible_else_if",
+ "collapsible_if",
+ "collapsible_match",
+ "collapsible_str_replace",
+ "comparison_chain",
+ "comparison_to_empty",
+ "copy_iterator",
+ "crate_in_macro_def",
+ "create_dir",
+ "crosspointer_transmute",
+ "dbg_macro",
+ "debug_assert_with_mut_call",
+ "decimal_literal_representation",
+ "declare_interior_mutable_const",
+ "default_instead_of_iter_empty",
+ "default_numeric_fallback",
+ "default_trait_access",
+ "default_union_representation",
+ "deprecated_cfg_attr",
+ "deprecated_semver",
+ "deref_addrof",
+ "deref_by_slicing",
+ "derivable_impls",
+ "derive_hash_xor_eq",
+ "derive_ord_xor_partial_ord",
+ "derive_partial_eq_without_eq",
+ "disallowed_macros",
+ "disallowed_methods",
+ "disallowed_names",
+ "disallowed_script_idents",
+ "disallowed_types",
+ "diverging_sub_expression",
+ "doc_link_with_quotes",
+ "doc_markdown",
+ "double_comparisons",
+ "double_must_use",
+ "double_neg",
+ "double_parens",
+ "drop_copy",
+ "drop_non_drop",
+ "drop_ref",
+ "duplicate_mod",
+ "duplicate_underscore_argument",
+ "duration_subsec",
+ "else_if_without_else",
+ "empty_drop",
+ "empty_enum",
+ "empty_line_after_outer_attr",
+ "empty_loop",
+ "empty_structs_with_brackets",
+ "enum_clike_unportable_variant",
+ "enum_glob_use",
+ "enum_variant_names",
+ "eq_op",
+ "equatable_if_let",
+ "erasing_op",
+ "err_expect",
+ "excessive_precision",
+ "exhaustive_enums",
+ "exhaustive_structs",
+ "exit",
+ "expect_fun_call",
+ "expect_used",
+ "expl_impl_clone_on_copy",
+ "explicit_auto_deref",
+ "explicit_counter_loop",
+ "explicit_deref_methods",
+ "explicit_into_iter_loop",
+ "explicit_iter_loop",
+ "explicit_write",
+ "extend_with_drain",
+ "extra_unused_lifetimes",
+ "fallible_impl_from",
+ "field_reassign_with_default",
+ "filetype_is_file",
+ "filter_map_identity",
+ "filter_map_next",
+ "filter_next",
+ "flat_map_identity",
+ "flat_map_option",
+ "float_arithmetic",
+ "float_cmp",
+ "float_cmp_const",
+ "float_equality_without_abs",
+ "fn_address_comparisons",
+ "fn_params_excessive_bools",
+ "fn_to_numeric_cast",
+ "fn_to_numeric_cast_any",
+ "fn_to_numeric_cast_with_truncation",
+ "for_kv_map",
+ "forget_copy",
+ "forget_non_drop",
+ "forget_ref",
+ "format_in_format_args",
+ "format_push_string",
+ "from_iter_instead_of_collect",
+ "from_over_into",
+ "from_str_radix_10",
+ "future_not_send",
+ "get_first",
+ "get_last_with_len",
+ "get_unwrap",
+ "identity_op",
+ "if_let_mutex",
+ "if_not_else",
+ "if_same_then_else",
+ "if_then_some_else_none",
+ "ifs_same_cond",
+ "implicit_clone",
+ "implicit_hasher",
+ "implicit_return",
+ "implicit_saturating_add",
+ "implicit_saturating_sub",
+ "imprecise_flops",
+ "inconsistent_digit_grouping",
+ "inconsistent_struct_constructor",
+ "index_refutable_slice",
+ "indexing_slicing",
+ "ineffective_bit_mask",
+ "inefficient_to_string",
+ "infallible_destructuring_match",
+ "infinite_iter",
+ "inherent_to_string",
+ "inherent_to_string_shadow_display",
+ "init_numbered_fields",
+ "inline_always",
+ "inline_asm_x86_att_syntax",
+ "inline_asm_x86_intel_syntax",
+ "inline_fn_without_body",
+ "inspect_for_each",
+ "int_plus_one",
+ "integer_arithmetic",
+ "integer_division",
+ "into_iter_on_ref",
+ "invalid_null_ptr_usage",
+ "invalid_regex",
+ "invalid_upcast_comparisons",
+ "invalid_utf8_in_unchecked",
+ "invisible_characters",
+ "is_digit_ascii_radix",
+ "items_after_statements",
+ "iter_cloned_collect",
+ "iter_count",
+ "iter_kv_map",
+ "iter_next_loop",
+ "iter_next_slice",
+ "iter_not_returning_iterator",
+ "iter_nth",
+ "iter_nth_zero",
+ "iter_on_empty_collections",
+ "iter_on_single_items",
+ "iter_overeager_cloned",
+ "iter_skip_next",
+ "iter_with_drain",
+ "iterator_step_by_zero",
+ "just_underscores_and_digits",
+ "large_const_arrays",
+ "large_digit_groups",
+ "large_enum_variant",
+ "large_include_file",
+ "large_stack_arrays",
+ "large_types_passed_by_value",
+ "len_without_is_empty",
+ "len_zero",
+ "let_and_return",
+ "let_underscore_drop",
+ "let_underscore_lock",
+ "let_underscore_must_use",
+ "let_unit_value",
+ "linkedlist",
+ "lossy_float_literal",
+ "macro_use_imports",
+ "main_recursion",
+ "manual_assert",
+ "manual_async_fn",
+ "manual_bits",
+ "manual_clamp",
+ "manual_filter",
+ "manual_filter_map",
+ "manual_find",
+ "manual_find_map",
+ "manual_flatten",
+ "manual_instant_elapsed",
+ "manual_map",
+ "manual_memcpy",
+ "manual_non_exhaustive",
+ "manual_ok_or",
+ "manual_range_contains",
+ "manual_rem_euclid",
+ "manual_retain",
+ "manual_saturating_arithmetic",
+ "manual_split_once",
+ "manual_str_repeat",
+ "manual_string_new",
+ "manual_strip",
+ "manual_swap",
+ "manual_unwrap_or",
+ "many_single_char_names",
+ "map_clone",
+ "map_collect_result_unit",
+ "map_entry",
+ "map_err_ignore",
+ "map_flatten",
+ "map_identity",
+ "map_unwrap_or",
+ "match_as_ref",
+ "match_bool",
+ "match_like_matches_macro",
+ "match_on_vec_items",
+ "match_overlapping_arm",
+ "match_ref_pats",
+ "match_result_ok",
+ "match_same_arms",
+ "match_single_binding",
+ "match_str_case_mismatch",
+ "match_wild_err_arm",
+ "match_wildcard_for_single_variants",
+ "maybe_infinite_iter",
+ "mem_forget",
+ "mem_replace_option_with_none",
+ "mem_replace_with_default",
+ "mem_replace_with_uninit",
+ "min_max",
+ "mismatched_target_os",
+ "mismatching_type_param_order",
+ "misrefactored_assign_op",
+ "missing_const_for_fn",
+ "missing_docs_in_private_items",
+ "missing_enforced_import_renames",
+ "missing_errors_doc",
+ "missing_inline_in_public_items",
+ "missing_panics_doc",
+ "missing_safety_doc",
+ "missing_spin_loop",
+ "missing_trait_methods",
+ "mistyped_literal_suffixes",
+ "mixed_case_hex_literals",
+ "mixed_read_write_in_expression",
+ "mod_module_files",
+ "module_inception",
+ "module_name_repetitions",
+ "modulo_arithmetic",
+ "modulo_one",
+ "multi_assignments",
+ "multiple_crate_versions",
+ "multiple_inherent_impl",
+ "must_use_candidate",
+ "must_use_unit",
+ "mut_from_ref",
+ "mut_mut",
+ "mut_mutex_lock",
+ "mut_range_bound",
+ "mutable_key_type",
+ "mutex_atomic",
+ "mutex_integer",
+ "naive_bytecount",
+ "needless_arbitrary_self_type",
+ "needless_bitwise_bool",
+ "needless_bool",
+ "needless_borrow",
+ "needless_borrowed_reference",
+ "needless_collect",
+ "needless_continue",
+ "needless_doctest_main",
+ "needless_for_each",
+ "needless_late_init",
+ "needless_lifetimes",
+ "needless_match",
+ "needless_option_as_deref",
+ "needless_option_take",
+ "needless_parens_on_range_literals",
+ "needless_pass_by_value",
+ "needless_question_mark",
+ "needless_range_loop",
+ "needless_return",
+ "needless_splitn",
+ "needless_update",
+ "neg_cmp_op_on_partial_ord",
+ "neg_multiply",
+ "negative_feature_names",
+ "never_loop",
+ "new_ret_no_self",
+ "new_without_default",
+ "no_effect",
+ "no_effect_replace",
+ "no_effect_underscore_binding",
+ "non_ascii_literal",
+ "non_octal_unix_permissions",
+ "non_send_fields_in_send_ty",
+ "nonminimal_bool",
+ "nonsensical_open_options",
+ "nonstandard_macro_braces",
+ "not_unsafe_ptr_arg_deref",
+ "obfuscated_if_else",
+ "octal_escapes",
+ "ok_expect",
+ "only_used_in_recursion",
+ "op_ref",
+ "option_as_ref_deref",
+ "option_env_unwrap",
+ "option_filter_map",
+ "option_if_let_else",
+ "option_map_or_none",
+ "option_map_unit_fn",
+ "option_option",
+ "or_fun_call",
+ "or_then_unwrap",
+ "out_of_bounds_indexing",
+ "overflow_check_conditional",
+ "overly_complex_bool_expr",
+ "panic",
+ "panic_in_result_fn",
+ "panicking_unwrap",
+ "partial_pub_fields",
+ "partialeq_ne_impl",
+ "partialeq_to_none",
+ "path_buf_push_overwrite",
+ "pattern_type_mismatch",
+ "possible_missing_comma",
+ "precedence",
+ "print_in_format_impl",
+ "print_literal",
+ "print_stderr",
+ "print_stdout",
+ "print_with_newline",
+ "println_empty_string",
+ "ptr_arg",
+ "ptr_as_ptr",
+ "ptr_eq",
+ "ptr_offset_with_cast",
+ "pub_use",
+ "question_mark",
+ "range_minus_one",
+ "range_plus_one",
+ "range_zip_with_len",
+ "rc_buffer",
+ "rc_clone_in_vec_init",
+ "rc_mutex",
+ "read_zero_byte_vec",
+ "recursive_format_impl",
+ "redundant_allocation",
+ "redundant_clone",
+ "redundant_closure",
+ "redundant_closure_call",
+ "redundant_closure_for_method_calls",
+ "redundant_else",
+ "redundant_feature_names",
+ "redundant_field_names",
+ "redundant_pattern",
+ "redundant_pattern_matching",
+ "redundant_pub_crate",
+ "redundant_slicing",
+ "redundant_static_lifetimes",
+ "ref_binding_to_reference",
+ "ref_option_ref",
+ "repeat_once",
+ "rest_pat_in_fully_bound_structs",
+ "result_large_err",
+ "result_map_or_into_option",
+ "result_map_unit_fn",
+ "result_unit_err",
+ "return_self_not_must_use",
+ "reversed_empty_ranges",
+ "same_functions_in_if_condition",
+ "same_item_push",
+ "same_name_method",
+ "search_is_some",
+ "self_assignment",
+ "self_named_constructors",
+ "self_named_module_files",
+ "semicolon_if_nothing_returned",
+ "separated_literal_suffix",
+ "serde_api_misuse",
+ "shadow_reuse",
+ "shadow_same",
+ "shadow_unrelated",
+ "short_circuit_statement",
+ "should_implement_trait",
+ "significant_drop_in_scrutinee",
+ "similar_names",
+ "single_char_add_str",
+ "single_char_lifetime_names",
+ "single_char_pattern",
+ "single_component_path_imports",
+ "single_element_loop",
+ "single_match",
+ "single_match_else",
+ "size_of_in_element_count",
+ "skip_while_next",
+ "slow_vector_initialization",
+ "stable_sort_primitive",
+ "std_instead_of_alloc",
+ "std_instead_of_core",
+ "str_to_string",
+ "string_add",
+ "string_add_assign",
+ "string_extend_chars",
+ "string_from_utf8_as_bytes",
+ "string_lit_as_bytes",
+ "string_slice",
+ "string_to_string",
+ "strlen_on_c_strings",
+ "struct_excessive_bools",
+ "suboptimal_flops",
+ "suspicious_arithmetic_impl",
+ "suspicious_assignment_formatting",
+ "suspicious_else_formatting",
+ "suspicious_map",
+ "suspicious_op_assign_impl",
+ "suspicious_operation_groupings",
+ "suspicious_splitn",
+ "suspicious_to_owned",
+ "suspicious_unary_op_formatting",
+ "swap_ptr_to_ref",
+ "tabs_in_doc_comments",
+ "temporary_assignment",
+ "to_digit_is_some",
+ "to_string_in_format_args",
+ "todo",
+ "too_many_arguments",
+ "too_many_lines",
+ "toplevel_ref_arg",
+ "trailing_empty_array",
+ "trait_duplication_in_bounds",
+ "transmute_bytes_to_str",
+ "transmute_float_to_int",
+ "transmute_int_to_bool",
+ "transmute_int_to_char",
+ "transmute_int_to_float",
+ "transmute_num_to_bytes",
+ "transmute_ptr_to_ptr",
+ "transmute_ptr_to_ref",
+ "transmute_undefined_repr",
+ "transmutes_expressible_as_ptr_casts",
+ "transmuting_null",
+ "trim_split_whitespace",
+ "trivial_regex",
+ "trivially_copy_pass_by_ref",
+ "try_err",
+ "type_complexity",
+ "type_repetition_in_bounds",
+ "undocumented_unsafe_blocks",
+ "undropped_manually_drops",
+ "unicode_not_nfc",
+ "unimplemented",
+ "uninit_assumed_init",
+ "uninit_vec",
+ "uninlined_format_args",
+ "unit_arg",
+ "unit_cmp",
+ "unit_hash",
+ "unit_return_expecting_ord",
+ "unnecessary_cast",
+ "unnecessary_filter_map",
+ "unnecessary_find_map",
+ "unnecessary_fold",
+ "unnecessary_join",
+ "unnecessary_lazy_evaluations",
+ "unnecessary_mut_passed",
+ "unnecessary_operation",
+ "unnecessary_owned_empty_strings",
+ "unnecessary_self_imports",
+ "unnecessary_sort_by",
+ "unnecessary_to_owned",
+ "unnecessary_unwrap",
+ "unnecessary_wraps",
+ "unneeded_field_pattern",
+ "unneeded_wildcard_pattern",
+ "unnested_or_patterns",
+ "unreachable",
+ "unreadable_literal",
+ "unsafe_derive_deserialize",
+ "unsafe_removed_from_name",
+ "unseparated_literal_suffix",
+ "unsound_collection_transmute",
+ "unused_async",
+ "unused_format_specs",
+ "unused_io_amount",
+ "unused_peekable",
+ "unused_rounding",
+ "unused_self",
+ "unused_unit",
+ "unusual_byte_groupings",
+ "unwrap_in_result",
+ "unwrap_or_else_default",
+ "unwrap_used",
+ "upper_case_acronyms",
+ "use_debug",
+ "use_self",
+ "used_underscore_binding",
+ "useless_asref",
+ "useless_attribute",
+ "useless_conversion",
+ "useless_format",
+ "useless_let_if_seq",
+ "useless_transmute",
+ "useless_vec",
+ "vec_box",
+ "vec_init_then_push",
+ "vec_resize_to_zero",
+ "verbose_bit_mask",
+ "verbose_file_reads",
+ "vtable_address_comparisons",
+ "while_immutable_condition",
+ "while_let_loop",
+ "while_let_on_iterator",
+ "wildcard_dependencies",
+ "wildcard_enum_match_arm",
+ "wildcard_imports",
+ "wildcard_in_or_patterns",
+ "write_literal",
+ "write_with_newline",
+ "writeln_empty_string",
+ "wrong_self_convention",
+ "wrong_transmute",
+ "zero_divided_by_zero",
+ "zero_prefixed_literal",
+ "zero_ptr",
+ "zero_sized_map_values",
+ "zst_offset",
+
+}
diff --git a/src/tools/clippy/src/docs/absurd_extreme_comparisons.txt b/src/tools/clippy/src/docs/absurd_extreme_comparisons.txt
new file mode 100644
index 000000000..590bee28a
--- /dev/null
+++ b/src/tools/clippy/src/docs/absurd_extreme_comparisons.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for comparisons where one side of the relation is
+either the minimum or maximum value for its type and warns if it involves a
+case that is always true or always false. Only integer and boolean types are
+checked.
+
+### Why is this bad?
+An expression like `min <= x` may misleadingly imply
+that it is possible for `x` to be less than the minimum. Expressions like
+`max < x` are probably mistakes.
+
+### Known problems
+For `usize` the size of the current compile target will
+be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
+a comparison to detect target pointer width will trigger this lint. One can
+use `mem::sizeof` and compare its value or conditional compilation
+attributes
+like `#[cfg(target_pointer_width = "64")] ..` instead.
+
+### Example
+```
+let vec: Vec<isize> = Vec::new();
+if vec.len() <= 0 {}
+if 100 > i32::MAX {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/alloc_instead_of_core.txt b/src/tools/clippy/src/docs/alloc_instead_of_core.txt
new file mode 100644
index 000000000..488a36e92
--- /dev/null
+++ b/src/tools/clippy/src/docs/alloc_instead_of_core.txt
@@ -0,0 +1,18 @@
+### What it does
+
+Finds items imported through `alloc` when available through `core`.
+
+### Why is this bad?
+
+Crates which have `no_std` compatibility and may optionally require alloc may wish to ensure types are
+imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint
+is also useful for crates migrating to become `no_std` compatible.
+
+### Example
+```
+use alloc::slice::from_ref;
+```
+Use instead:
+```
+use core::slice::from_ref;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/allow_attributes_without_reason.txt b/src/tools/clippy/src/docs/allow_attributes_without_reason.txt
new file mode 100644
index 000000000..fcc4f49b0
--- /dev/null
+++ b/src/tools/clippy/src/docs/allow_attributes_without_reason.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for attributes that allow lints without a reason.
+
+(This requires the `lint_reasons` feature)
+
+### Why is this bad?
+Allowing a lint should always have a reason. This reason should be documented to
+ensure that others understand the reasoning
+
+### Example
+```
+#![feature(lint_reasons)]
+
+#![allow(clippy::some_lint)]
+```
+
+Use instead:
+```
+#![feature(lint_reasons)]
+
+#![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")]
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/almost_complete_letter_range.txt b/src/tools/clippy/src/docs/almost_complete_letter_range.txt
new file mode 100644
index 000000000..01cbaf9ea
--- /dev/null
+++ b/src/tools/clippy/src/docs/almost_complete_letter_range.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for ranges which almost include the entire range of letters from 'a' to 'z', but
+don't because they're a half open range.
+
+### Why is this bad?
+This (`'a'..'z'`) is almost certainly a typo meant to include all letters.
+
+### Example
+```
+let _ = 'a'..'z';
+```
+Use instead:
+```
+let _ = 'a'..='z';
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/almost_swapped.txt b/src/tools/clippy/src/docs/almost_swapped.txt
new file mode 100644
index 000000000..cd10a8d54
--- /dev/null
+++ b/src/tools/clippy/src/docs/almost_swapped.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for `foo = bar; bar = foo` sequences.
+
+### Why is this bad?
+This looks like a failed attempt to swap.
+
+### Example
+```
+a = b;
+b = a;
+```
+If swapping is intended, use `swap()` instead:
+```
+std::mem::swap(&mut a, &mut b);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/approx_constant.txt b/src/tools/clippy/src/docs/approx_constant.txt
new file mode 100644
index 000000000..393fa4b5e
--- /dev/null
+++ b/src/tools/clippy/src/docs/approx_constant.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for floating point literals that approximate
+constants which are defined in
+[`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants)
+or
+[`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants),
+respectively, suggesting to use the predefined constant.
+
+### Why is this bad?
+Usually, the definition in the standard library is more
+precise than what people come up with. If you find that your definition is
+actually more precise, please [file a Rust
+issue](https://github.com/rust-lang/rust/issues).
+
+### Example
+```
+let x = 3.14;
+let y = 1_f64 / x;
+```
+Use instead:
+```
+let x = std::f32::consts::PI;
+let y = std::f64::consts::FRAC_1_PI;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/arithmetic_side_effects.txt b/src/tools/clippy/src/docs/arithmetic_side_effects.txt
new file mode 100644
index 000000000..4ae8bce88
--- /dev/null
+++ b/src/tools/clippy/src/docs/arithmetic_side_effects.txt
@@ -0,0 +1,33 @@
+### What it does
+Checks any kind of arithmetic operation of any type.
+
+Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust
+Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
+or can panic (`/`, `%`).
+
+Known safe built-in types like `Wrapping` or `Saturating`, floats, operations in constant
+environments, allowed types and non-constant operations that won't overflow are ignored.
+
+### Why is this bad?
+For integers, overflow will trigger a panic in debug builds or wrap the result in
+release mode; division by zero will cause a panic in either mode. As a result, it is
+desirable to explicitly call checked, wrapping or saturating arithmetic methods.
+
+#### Example
+```
+// `n` can be any number, including `i32::MAX`.
+fn foo(n: i32) -> i32 {
+ n + 1
+}
+```
+
+Third-party types can also overflow or present unwanted side-effects.
+
+#### Example
+```
+use rust_decimal::Decimal;
+let _n = Decimal::MAX + Decimal::MAX;
+```
+
+### Allowed types
+Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter. \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/as_conversions.txt b/src/tools/clippy/src/docs/as_conversions.txt
new file mode 100644
index 000000000..4af479bd8
--- /dev/null
+++ b/src/tools/clippy/src/docs/as_conversions.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for usage of `as` conversions.
+
+Note that this lint is specialized in linting *every single* use of `as`
+regardless of whether good alternatives exist or not.
+If you want more precise lints for `as`, please consider using these separate lints:
+`unnecessary_cast`, `cast_lossless/cast_possible_truncation/cast_possible_wrap/cast_precision_loss/cast_sign_loss`,
+`fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`.
+There is a good explanation the reason why this lint should work in this way and how it is useful
+[in this issue](https://github.com/rust-lang/rust-clippy/issues/5122).
+
+### Why is this bad?
+`as` conversions will perform many kinds of
+conversions, including silently lossy conversions and dangerous coercions.
+There are cases when it makes sense to use `as`, so the lint is
+Allow by default.
+
+### Example
+```
+let a: u32;
+...
+f(a as u16);
+```
+
+Use instead:
+```
+f(a.try_into()?);
+
+// or
+
+f(a.try_into().expect("Unexpected u16 overflow in f"));
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/as_ptr_cast_mut.txt b/src/tools/clippy/src/docs/as_ptr_cast_mut.txt
new file mode 100644
index 000000000..228dde996
--- /dev/null
+++ b/src/tools/clippy/src/docs/as_ptr_cast_mut.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer
+
+### Why is this bad?
+Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior
+mutability is used, making it unlikely that having it as a mutable pointer is correct.
+
+### Example
+```
+let string = String::with_capacity(1);
+let ptr = string.as_ptr() as *mut u8;
+unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR
+```
+Use instead:
+```
+let mut string = String::with_capacity(1);
+let ptr = string.as_mut_ptr();
+unsafe { ptr.write(4) };
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/as_underscore.txt b/src/tools/clippy/src/docs/as_underscore.txt
new file mode 100644
index 000000000..2d9b0c358
--- /dev/null
+++ b/src/tools/clippy/src/docs/as_underscore.txt
@@ -0,0 +1,21 @@
+### What it does
+Check for the usage of `as _` conversion using inferred type.
+
+### Why is this bad?
+The conversion might include lossy conversion and dangerous cast that might go
+undetected due to the type being inferred.
+
+The lint is allowed by default as using `_` is less wordy than always specifying the type.
+
+### Example
+```
+fn foo(n: usize) {}
+let n: u16 = 256;
+foo(n as _);
+```
+Use instead:
+```
+fn foo(n: usize) {}
+let n: u16 = 256;
+foo(n as usize);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/assertions_on_constants.txt b/src/tools/clippy/src/docs/assertions_on_constants.txt
new file mode 100644
index 000000000..270c1e3b6
--- /dev/null
+++ b/src/tools/clippy/src/docs/assertions_on_constants.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for `assert!(true)` and `assert!(false)` calls.
+
+### Why is this bad?
+Will be optimized out by the compiler or should probably be replaced by a
+`panic!()` or `unreachable!()`
+
+### Example
+```
+assert!(false)
+assert!(true)
+const B: bool = false;
+assert!(B)
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/assertions_on_result_states.txt b/src/tools/clippy/src/docs/assertions_on_result_states.txt
new file mode 100644
index 000000000..0889084fd
--- /dev/null
+++ b/src/tools/clippy/src/docs/assertions_on_result_states.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for `assert!(r.is_ok())` or `assert!(r.is_err())` calls.
+
+### Why is this bad?
+An assertion failure cannot output an useful message of the error.
+
+### Known problems
+The suggested replacement decreases the readability of code and log output.
+
+### Example
+```
+assert!(r.is_ok());
+assert!(r.is_err());
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/assign_op_pattern.txt b/src/tools/clippy/src/docs/assign_op_pattern.txt
new file mode 100644
index 000000000..f355c0cc1
--- /dev/null
+++ b/src/tools/clippy/src/docs/assign_op_pattern.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for `a = a op b` or `a = b commutative_op a`
+patterns.
+
+### Why is this bad?
+These can be written as the shorter `a op= b`.
+
+### Known problems
+While forbidden by the spec, `OpAssign` traits may have
+implementations that differ from the regular `Op` impl.
+
+### Example
+```
+let mut a = 5;
+let b = 0;
+// ...
+
+a = a + b;
+```
+
+Use instead:
+```
+let mut a = 5;
+let b = 0;
+// ...
+
+a += b;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/async_yields_async.txt b/src/tools/clippy/src/docs/async_yields_async.txt
new file mode 100644
index 000000000..a40de6d2e
--- /dev/null
+++ b/src/tools/clippy/src/docs/async_yields_async.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for async blocks that yield values of types
+that can themselves be awaited.
+
+### Why is this bad?
+An await is likely missing.
+
+### Example
+```
+async fn foo() {}
+
+fn bar() {
+ let x = async {
+ foo()
+ };
+}
+```
+
+Use instead:
+```
+async fn foo() {}
+
+fn bar() {
+ let x = async {
+ foo().await
+ };
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/await_holding_invalid_type.txt b/src/tools/clippy/src/docs/await_holding_invalid_type.txt
new file mode 100644
index 000000000..e9c768772
--- /dev/null
+++ b/src/tools/clippy/src/docs/await_holding_invalid_type.txt
@@ -0,0 +1,29 @@
+### What it does
+Allows users to configure types which should not be held across `await`
+suspension points.
+
+### Why is this bad?
+There are some types which are perfectly "safe" to be used concurrently
+from a memory access perspective but will cause bugs at runtime if they
+are held in such a way.
+
+### Example
+
+```
+await-holding-invalid-types = [
+ # You can specify a type name
+ "CustomLockType",
+ # You can (optionally) specify a reason
+ { path = "OtherCustomLockType", reason = "Relies on a thread local" }
+]
+```
+
+```
+struct CustomLockType;
+struct OtherCustomLockType;
+async fn foo() {
+ let _x = CustomLockType;
+ let _y = OtherCustomLockType;
+ baz().await; // Lint violation
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/await_holding_lock.txt b/src/tools/clippy/src/docs/await_holding_lock.txt
new file mode 100644
index 000000000..0f450a111
--- /dev/null
+++ b/src/tools/clippy/src/docs/await_holding_lock.txt
@@ -0,0 +1,51 @@
+### What it does
+Checks for calls to await while holding a non-async-aware MutexGuard.
+
+### Why is this bad?
+The Mutex types found in std::sync and parking_lot
+are not designed to operate in an async context across await points.
+
+There are two potential solutions. One is to use an async-aware Mutex
+type. Many asynchronous foundation crates provide such a Mutex type. The
+other solution is to ensure the mutex is unlocked before calling await,
+either by introducing a scope or an explicit call to Drop::drop.
+
+### Known problems
+Will report false positive for explicitly dropped guards
+([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is
+to wrap the `.lock()` call in a block instead of explicitly dropping the guard.
+
+### Example
+```
+async fn foo(x: &Mutex<u32>) {
+ let mut guard = x.lock().unwrap();
+ *guard += 1;
+ baz().await;
+}
+
+async fn bar(x: &Mutex<u32>) {
+ let mut guard = x.lock().unwrap();
+ *guard += 1;
+ drop(guard); // explicit drop
+ baz().await;
+}
+```
+
+Use instead:
+```
+async fn foo(x: &Mutex<u32>) {
+ {
+ let mut guard = x.lock().unwrap();
+ *guard += 1;
+ }
+ baz().await;
+}
+
+async fn bar(x: &Mutex<u32>) {
+ {
+ let mut guard = x.lock().unwrap();
+ *guard += 1;
+ } // guard dropped here at end of scope
+ baz().await;
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/await_holding_refcell_ref.txt b/src/tools/clippy/src/docs/await_holding_refcell_ref.txt
new file mode 100644
index 000000000..226a261b9
--- /dev/null
+++ b/src/tools/clippy/src/docs/await_holding_refcell_ref.txt
@@ -0,0 +1,47 @@
+### What it does
+Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`.
+
+### Why is this bad?
+`RefCell` refs only check for exclusive mutable access
+at runtime. Holding onto a `RefCell` ref across an `await` suspension point
+risks panics from a mutable ref shared while other refs are outstanding.
+
+### Known problems
+Will report false positive for explicitly dropped refs
+([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)). A workaround for this is
+to wrap the `.borrow[_mut]()` call in a block instead of explicitly dropping the ref.
+
+### Example
+```
+async fn foo(x: &RefCell<u32>) {
+ let mut y = x.borrow_mut();
+ *y += 1;
+ baz().await;
+}
+
+async fn bar(x: &RefCell<u32>) {
+ let mut y = x.borrow_mut();
+ *y += 1;
+ drop(y); // explicit drop
+ baz().await;
+}
+```
+
+Use instead:
+```
+async fn foo(x: &RefCell<u32>) {
+ {
+ let mut y = x.borrow_mut();
+ *y += 1;
+ }
+ baz().await;
+}
+
+async fn bar(x: &RefCell<u32>) {
+ {
+ let mut y = x.borrow_mut();
+ *y += 1;
+ } // y dropped here at end of scope
+ baz().await;
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/bad_bit_mask.txt b/src/tools/clippy/src/docs/bad_bit_mask.txt
new file mode 100644
index 000000000..d40024ee5
--- /dev/null
+++ b/src/tools/clippy/src/docs/bad_bit_mask.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for incompatible bit masks in comparisons.
+
+The formula for detecting if an expression of the type `_ <bit_op> m
+<cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of
+{`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
+table:
+
+|Comparison |Bit Op|Example |is always|Formula |
+|------------|------|-------------|---------|----------------------|
+|`==` or `!=`| `&` |`x & 2 == 3` |`false` |`c & m != c` |
+|`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` |
+|`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` |
+|`==` or `!=`| `\|` |`x \| 1 == 0`|`false` |`c \| m != c` |
+|`<` or `>=`| `\|` |`x \| 1 < 1` |`false` |`m >= c` |
+|`<=` or `>` | `\|` |`x \| 1 > 0` |`true` |`m > c` |
+
+### Why is this bad?
+If the bits that the comparison cares about are always
+set to zero or one by the bit mask, the comparison is constant `true` or
+`false` (depending on mask, compared value, and operators).
+
+So the code is actively misleading, and the only reason someone would write
+this intentionally is to win an underhanded Rust contest or create a
+test-case for this lint.
+
+### Example
+```
+if (x & 1 == 2) { }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/bind_instead_of_map.txt b/src/tools/clippy/src/docs/bind_instead_of_map.txt
new file mode 100644
index 000000000..148575803
--- /dev/null
+++ b/src/tools/clippy/src/docs/bind_instead_of_map.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or
+`_.or_else(|x| Err(y))`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.map(|x| y)` or `_.map_err(|x| y)`.
+
+### Example
+```
+let _ = opt().and_then(|s| Some(s.len()));
+let _ = res().and_then(|s| if s.len() == 42 { Ok(10) } else { Ok(20) });
+let _ = res().or_else(|s| if s.len() == 42 { Err(10) } else { Err(20) });
+```
+
+The correct use would be:
+
+```
+let _ = opt().map(|s| s.len());
+let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 });
+let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 });
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/blanket_clippy_restriction_lints.txt b/src/tools/clippy/src/docs/blanket_clippy_restriction_lints.txt
new file mode 100644
index 000000000..28a4ebf71
--- /dev/null
+++ b/src/tools/clippy/src/docs/blanket_clippy_restriction_lints.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category.
+
+### Why is this bad?
+Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust.
+These lints should only be enabled on a lint-by-lint basis and with careful consideration.
+
+### Example
+```
+#![deny(clippy::restriction)]
+```
+
+Use instead:
+```
+#![deny(clippy::as_conversions)]
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/blocks_in_if_conditions.txt b/src/tools/clippy/src/docs/blocks_in_if_conditions.txt
new file mode 100644
index 000000000..3afa14853
--- /dev/null
+++ b/src/tools/clippy/src/docs/blocks_in_if_conditions.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for `if` conditions that use blocks containing an
+expression, statements or conditions that use closures with blocks.
+
+### Why is this bad?
+Style, using blocks in the condition makes it hard to read.
+
+### Examples
+```
+if { true } { /* ... */ }
+
+if { let x = somefunc(); x } { /* ... */ }
+```
+
+Use instead:
+```
+if true { /* ... */ }
+
+let res = { let x = somefunc(); x };
+if res { /* ... */ }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/bool_assert_comparison.txt b/src/tools/clippy/src/docs/bool_assert_comparison.txt
new file mode 100644
index 000000000..df7ca00cc
--- /dev/null
+++ b/src/tools/clippy/src/docs/bool_assert_comparison.txt
@@ -0,0 +1,16 @@
+### What it does
+This lint warns about boolean comparisons in assert-like macros.
+
+### Why is this bad?
+It is shorter to use the equivalent.
+
+### Example
+```
+assert_eq!("a".is_empty(), false);
+assert_ne!("a".is_empty(), true);
+```
+
+Use instead:
+```
+assert!(!"a".is_empty());
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/bool_comparison.txt b/src/tools/clippy/src/docs/bool_comparison.txt
new file mode 100644
index 000000000..0996f60ce
--- /dev/null
+++ b/src/tools/clippy/src/docs/bool_comparison.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for expressions of the form `x == true`,
+`x != true` and order comparisons such as `x < true` (or vice versa) and
+suggest using the variable directly.
+
+### Why is this bad?
+Unnecessary code.
+
+### Example
+```
+if x == true {}
+if y == false {}
+```
+use `x` directly:
+```
+if x {}
+if !y {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/bool_to_int_with_if.txt b/src/tools/clippy/src/docs/bool_to_int_with_if.txt
new file mode 100644
index 000000000..63535b454
--- /dev/null
+++ b/src/tools/clippy/src/docs/bool_to_int_with_if.txt
@@ -0,0 +1,26 @@
+### What it does
+Instead of using an if statement to convert a bool to an int,
+this lint suggests using a `from()` function or an `as` coercion.
+
+### Why is this bad?
+Coercion or `from()` is idiomatic way to convert bool to a number.
+Both methods are guaranteed to return 1 for true, and 0 for false.
+
+See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E
+
+### Example
+```
+if condition {
+ 1_i64
+} else {
+ 0
+};
+```
+Use instead:
+```
+i64::from(condition);
+```
+or
+```
+condition as i64;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/borrow_as_ptr.txt b/src/tools/clippy/src/docs/borrow_as_ptr.txt
new file mode 100644
index 000000000..0be865abd
--- /dev/null
+++ b/src/tools/clippy/src/docs/borrow_as_ptr.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for the usage of `&expr as *const T` or
+`&mut expr as *mut T`, and suggest using `ptr::addr_of` or
+`ptr::addr_of_mut` instead.
+
+### Why is this bad?
+This would improve readability and avoid creating a reference
+that points to an uninitialized value or unaligned place.
+Read the `ptr::addr_of` docs for more information.
+
+### Example
+```
+let val = 1;
+let p = &val as *const i32;
+
+let mut val_mut = 1;
+let p_mut = &mut val_mut as *mut i32;
+```
+Use instead:
+```
+let val = 1;
+let p = std::ptr::addr_of!(val);
+
+let mut val_mut = 1;
+let p_mut = std::ptr::addr_of_mut!(val_mut);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/borrow_deref_ref.txt b/src/tools/clippy/src/docs/borrow_deref_ref.txt
new file mode 100644
index 000000000..352480d3f
--- /dev/null
+++ b/src/tools/clippy/src/docs/borrow_deref_ref.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for `&*(&T)`.
+
+### Why is this bad?
+Dereferencing and then borrowing a reference value has no effect in most cases.
+
+### Known problems
+False negative on such code:
+```
+let x = &12;
+let addr_x = &x as *const _ as usize;
+let addr_y = &&*x as *const _ as usize; // assert ok now, and lint triggered.
+ // But if we fix it, assert will fail.
+assert_ne!(addr_x, addr_y);
+```
+
+### Example
+```
+let s = &String::new();
+
+let a: &String = &* s;
+```
+
+Use instead:
+```
+let a: &String = s;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/borrow_interior_mutable_const.txt b/src/tools/clippy/src/docs/borrow_interior_mutable_const.txt
new file mode 100644
index 000000000..e55b6a77e
--- /dev/null
+++ b/src/tools/clippy/src/docs/borrow_interior_mutable_const.txt
@@ -0,0 +1,40 @@
+### What it does
+Checks if `const` items which is interior mutable (e.g.,
+contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly.
+
+### Why is this bad?
+Consts are copied everywhere they are referenced, i.e.,
+every time you refer to the const a fresh instance of the `Cell` or `Mutex`
+or `AtomicXxxx` will be created, which defeats the whole purpose of using
+these types in the first place.
+
+The `const` value should be stored inside a `static` item.
+
+### Known problems
+When an enum has variants with interior mutability, use of its non
+interior mutable variants can generate false positives. See issue
+[#3962](https://github.com/rust-lang/rust-clippy/issues/3962)
+
+Types that have underlying or potential interior mutability trigger the lint whether
+the interior mutable field is used or not. See issues
+[#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
+[#3825](https://github.com/rust-lang/rust-clippy/issues/3825)
+
+### Example
+```
+use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
+
+CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
+assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
+```
+
+Use instead:
+```
+use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
+
+static STATIC_ATOM: AtomicUsize = CONST_ATOM;
+STATIC_ATOM.store(9, SeqCst);
+assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/borrowed_box.txt b/src/tools/clippy/src/docs/borrowed_box.txt
new file mode 100644
index 000000000..d7089be66
--- /dev/null
+++ b/src/tools/clippy/src/docs/borrowed_box.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for use of `&Box<T>` anywhere in the code.
+Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
+
+### Why is this bad?
+A `&Box<T>` parameter requires the function caller to box `T` first before passing it to a function.
+Using `&T` defines a concrete type for the parameter and generalizes the function, this would also
+auto-deref to `&T` at the function call site if passed a `&Box<T>`.
+
+### Example
+```
+fn foo(bar: &Box<T>) { ... }
+```
+
+Better:
+
+```
+fn foo(bar: &T) { ... }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/box_collection.txt b/src/tools/clippy/src/docs/box_collection.txt
new file mode 100644
index 000000000..053f24c46
--- /dev/null
+++ b/src/tools/clippy/src/docs/box_collection.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for use of `Box<T>` where T is a collection such as Vec anywhere in the code.
+Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
+
+### Why is this bad?
+Collections already keeps their contents in a separate area on
+the heap. So if you `Box` them, you just add another level of indirection
+without any benefit whatsoever.
+
+### Example
+```
+struct X {
+ values: Box<Vec<Foo>>,
+}
+```
+
+Better:
+
+```
+struct X {
+ values: Vec<Foo>,
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/box_default.txt b/src/tools/clippy/src/docs/box_default.txt
new file mode 100644
index 000000000..1c670c773
--- /dev/null
+++ b/src/tools/clippy/src/docs/box_default.txt
@@ -0,0 +1,17 @@
+### What it does
+checks for `Box::new(T::default())`, which is better written as
+`Box::<T>::default()`.
+
+### Why is this bad?
+First, it's more complex, involving two calls instead of one.
+Second, `Box::default()` can be faster
+[in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box).
+
+### Example
+```
+let x: Box<String> = Box::new(Default::default());
+```
+Use instead:
+```
+let x: Box<String> = Box::default();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/boxed_local.txt b/src/tools/clippy/src/docs/boxed_local.txt
new file mode 100644
index 000000000..8b1febf14
--- /dev/null
+++ b/src/tools/clippy/src/docs/boxed_local.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for usage of `Box<T>` where an unboxed `T` would
+work fine.
+
+### Why is this bad?
+This is an unnecessary allocation, and bad for
+performance. It is only necessary to allocate if you wish to move the box
+into something.
+
+### Example
+```
+fn foo(x: Box<u32>) {}
+```
+
+Use instead:
+```
+fn foo(x: u32) {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/branches_sharing_code.txt b/src/tools/clippy/src/docs/branches_sharing_code.txt
new file mode 100644
index 000000000..79be61247
--- /dev/null
+++ b/src/tools/clippy/src/docs/branches_sharing_code.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks if the `if` and `else` block contain shared code that can be
+moved out of the blocks.
+
+### Why is this bad?
+Duplicate code is less maintainable.
+
+### Known problems
+* The lint doesn't check if the moved expressions modify values that are being used in
+ the if condition. The suggestion can in that case modify the behavior of the program.
+ See [rust-clippy#7452](https://github.com/rust-lang/rust-clippy/issues/7452)
+
+### Example
+```
+let foo = if … {
+ println!("Hello World");
+ 13
+} else {
+ println!("Hello World");
+ 42
+};
+```
+
+Use instead:
+```
+println!("Hello World");
+let foo = if … {
+ 13
+} else {
+ 42
+};
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/builtin_type_shadow.txt b/src/tools/clippy/src/docs/builtin_type_shadow.txt
new file mode 100644
index 000000000..15b1c9df7
--- /dev/null
+++ b/src/tools/clippy/src/docs/builtin_type_shadow.txt
@@ -0,0 +1,15 @@
+### What it does
+Warns if a generic shadows a built-in type.
+
+### Why is this bad?
+This gives surprising type errors.
+
+### Example
+
+```
+impl<u32> Foo<u32> {
+ fn impl_func(&self) -> u32 {
+ 42
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/bytes_count_to_len.txt b/src/tools/clippy/src/docs/bytes_count_to_len.txt
new file mode 100644
index 000000000..ca7bf9a38
--- /dev/null
+++ b/src/tools/clippy/src/docs/bytes_count_to_len.txt
@@ -0,0 +1,18 @@
+### What it does
+It checks for `str::bytes().count()` and suggests replacing it with
+`str::len()`.
+
+### Why is this bad?
+`str::bytes().count()` is longer and may not be as performant as using
+`str::len()`.
+
+### Example
+```
+"hello".bytes().count();
+String::from("hello").bytes().count();
+```
+Use instead:
+```
+"hello".len();
+String::from("hello").len();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/bytes_nth.txt b/src/tools/clippy/src/docs/bytes_nth.txt
new file mode 100644
index 000000000..260de3433
--- /dev/null
+++ b/src/tools/clippy/src/docs/bytes_nth.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for the use of `.bytes().nth()`.
+
+### Why is this bad?
+`.as_bytes().get()` is more efficient and more
+readable.
+
+### Example
+```
+"Hello".bytes().nth(3);
+```
+
+Use instead:
+```
+"Hello".as_bytes().get(3);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cargo_common_metadata.txt b/src/tools/clippy/src/docs/cargo_common_metadata.txt
new file mode 100644
index 000000000..1998647a9
--- /dev/null
+++ b/src/tools/clippy/src/docs/cargo_common_metadata.txt
@@ -0,0 +1,33 @@
+### What it does
+Checks to see if all common metadata is defined in
+`Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata
+
+### Why is this bad?
+It will be more difficult for users to discover the
+purpose of the crate, and key information related to it.
+
+### Example
+```
+[package]
+name = "clippy"
+version = "0.0.212"
+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"]
+```
+
+Should include a description field like:
+
+```
+[package]
+name = "clippy"
+version = "0.0.212"
+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"]
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/case_sensitive_file_extension_comparisons.txt b/src/tools/clippy/src/docs/case_sensitive_file_extension_comparisons.txt
new file mode 100644
index 000000000..8e6e18ed4
--- /dev/null
+++ b/src/tools/clippy/src/docs/case_sensitive_file_extension_comparisons.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for calls to `ends_with` with possible file extensions
+and suggests to use a case-insensitive approach instead.
+
+### Why is this bad?
+`ends_with` is case-sensitive and may not detect files with a valid extension.
+
+### Example
+```
+fn is_rust_file(filename: &str) -> bool {
+ filename.ends_with(".rs")
+}
+```
+Use instead:
+```
+fn is_rust_file(filename: &str) -> bool {
+ let filename = std::path::Path::new(filename);
+ filename.extension()
+ .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_abs_to_unsigned.txt b/src/tools/clippy/src/docs/cast_abs_to_unsigned.txt
new file mode 100644
index 000000000..c5d8ee034
--- /dev/null
+++ b/src/tools/clippy/src/docs/cast_abs_to_unsigned.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for uses of the `abs()` method that cast the result to unsigned.
+
+### Why is this bad?
+The `unsigned_abs()` method avoids panic when called on the MIN value.
+
+### Example
+```
+let x: i32 = -42;
+let y: u32 = x.abs() as u32;
+```
+Use instead:
+```
+let x: i32 = -42;
+let y: u32 = x.unsigned_abs();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_enum_constructor.txt b/src/tools/clippy/src/docs/cast_enum_constructor.txt
new file mode 100644
index 000000000..675c03a42
--- /dev/null
+++ b/src/tools/clippy/src/docs/cast_enum_constructor.txt
@@ -0,0 +1,11 @@
+### What it does
+Checks for casts from an enum tuple constructor to an integer.
+
+### Why is this bad?
+The cast is easily confused with casting a c-like enum value to an integer.
+
+### Example
+```
+enum E { X(i32) };
+let _ = E::X as usize;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_enum_truncation.txt b/src/tools/clippy/src/docs/cast_enum_truncation.txt
new file mode 100644
index 000000000..abe32a829
--- /dev/null
+++ b/src/tools/clippy/src/docs/cast_enum_truncation.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for casts from an enum type to an integral type which will definitely truncate the
+value.
+
+### Why is this bad?
+The resulting integral value will not match the value of the variant it came from.
+
+### Example
+```
+enum E { X = 256 };
+let _ = E::X as u8;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_lossless.txt b/src/tools/clippy/src/docs/cast_lossless.txt
new file mode 100644
index 000000000..c3a61dd47
--- /dev/null
+++ b/src/tools/clippy/src/docs/cast_lossless.txt
@@ -0,0 +1,26 @@
+### 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
+```
+fn as_u64(x: u8) -> u64 {
+ x as u64
+}
+```
+
+Using `::from` would look like this:
+
+```
+fn as_u64(x: u8) -> u64 {
+ u64::from(x)
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_nan_to_int.txt b/src/tools/clippy/src/docs/cast_nan_to_int.txt
new file mode 100644
index 000000000..122f5da0c
--- /dev/null
+++ b/src/tools/clippy/src/docs/cast_nan_to_int.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for a known NaN float being cast to an integer
+
+### Why is this bad?
+NaNs are cast into zero, so one could simply use this and make the
+code more readable. The lint could also hint at a programmer error.
+
+### Example
+```
+let _: (0.0_f32 / 0.0) as u64;
+```
+Use instead:
+```
+let _: = 0_u64;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_possible_truncation.txt b/src/tools/clippy/src/docs/cast_possible_truncation.txt
new file mode 100644
index 000000000..0b164848c
--- /dev/null
+++ b/src/tools/clippy/src/docs/cast_possible_truncation.txt
@@ -0,0 +1,16 @@
+### 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
+```
+fn as_u8(x: u64) -> u8 {
+ x as u8
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_possible_wrap.txt b/src/tools/clippy/src/docs/cast_possible_wrap.txt
new file mode 100644
index 000000000..f883fc9cf
--- /dev/null
+++ b/src/tools/clippy/src/docs/cast_possible_wrap.txt
@@ -0,0 +1,17 @@
+### 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
+```
+u32::MAX as i32; // will yield a value of `-1`
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_precision_loss.txt b/src/tools/clippy/src/docs/cast_precision_loss.txt
new file mode 100644
index 000000000..f915d9f8a
--- /dev/null
+++ b/src/tools/clippy/src/docs/cast_precision_loss.txt
@@ -0,0 +1,19 @@
+### 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
+```
+let x = u64::MAX;
+x as f64;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_ptr_alignment.txt b/src/tools/clippy/src/docs/cast_ptr_alignment.txt
new file mode 100644
index 000000000..6a6d4dcaa
--- /dev/null
+++ b/src/tools/clippy/src/docs/cast_ptr_alignment.txt
@@ -0,0 +1,21 @@
+### 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
+```
+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>();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_ref_to_mut.txt b/src/tools/clippy/src/docs/cast_ref_to_mut.txt
new file mode 100644
index 000000000..fb5b4dbb6
--- /dev/null
+++ b/src/tools/clippy/src/docs/cast_ref_to_mut.txt
@@ -0,0 +1,28 @@
+### 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 behavior.
+`UnsafeCell` is the only way to obtain aliasable data that is considered
+mutable.
+
+### Example
+```
+fn x(r: &i32) {
+ unsafe {
+ *(r as *const _ as *mut _) += 1;
+ }
+}
+```
+
+Instead consider using interior mutability types.
+
+```
+use std::cell::UnsafeCell;
+
+fn x(r: &UnsafeCell<i32>) {
+ unsafe {
+ *r.get() += 1;
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_sign_loss.txt b/src/tools/clippy/src/docs/cast_sign_loss.txt
new file mode 100644
index 000000000..d64fe1b07
--- /dev/null
+++ b/src/tools/clippy/src/docs/cast_sign_loss.txt
@@ -0,0 +1,15 @@
+### 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
+```
+let y: i8 = -1;
+y as u128; // will return 18446744073709551615
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_slice_different_sizes.txt b/src/tools/clippy/src/docs/cast_slice_different_sizes.txt
new file mode 100644
index 000000000..c01ef0ba9
--- /dev/null
+++ b/src/tools/clippy/src/docs/cast_slice_different_sizes.txt
@@ -0,0 +1,38 @@
+### What it does
+Checks for `as` casts between raw pointers to slices with differently sized elements.
+
+### Why is this bad?
+The produced raw pointer to a slice does not update its length metadata. The produced
+pointer will point to a different number of bytes than the original pointer because the
+length metadata of a raw slice pointer is in elements rather than bytes.
+Producing a slice reference from the raw pointer will either create a slice with
+less data (which can be surprising) or create a slice with more data and cause Undefined Behavior.
+
+### Example
+// Missing data
+```
+let a = [1_i32, 2, 3, 4];
+let p = &a as *const [i32] as *const [u8];
+unsafe {
+ println!("{:?}", &*p);
+}
+```
+// Undefined Behavior (note: also potential alignment issues)
+```
+let a = [1_u8, 2, 3, 4];
+let p = &a as *const [u8] as *const [u32];
+unsafe {
+ println!("{:?}", &*p);
+}
+```
+Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length
+```
+let a = [1_i32, 2, 3, 4];
+let old_ptr = &a as *const [i32];
+// The data pointer is cast to a pointer to the target `u8` not `[u8]`
+// The length comes from the known length of 4 i32s times the 4 bytes per i32
+let new_ptr = core::ptr::slice_from_raw_parts(old_ptr as *const u8, 16);
+unsafe {
+ println!("{:?}", &*new_ptr);
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cast_slice_from_raw_parts.txt b/src/tools/clippy/src/docs/cast_slice_from_raw_parts.txt
new file mode 100644
index 000000000..b58c73976
--- /dev/null
+++ b/src/tools/clippy/src/docs/cast_slice_from_raw_parts.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for a raw slice being cast to a slice pointer
+
+### Why is this bad?
+This can result in multiple `&mut` references to the same location when only a pointer is
+required.
+`ptr::slice_from_raw_parts` is a safe alternative that doesn't require
+the same [safety requirements] to be upheld.
+
+### Example
+```
+let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _;
+let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _;
+```
+Use instead:
+```
+let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len);
+let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len);
+```
+[safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/char_lit_as_u8.txt b/src/tools/clippy/src/docs/char_lit_as_u8.txt
new file mode 100644
index 000000000..00d60b9a4
--- /dev/null
+++ b/src/tools/clippy/src/docs/char_lit_as_u8.txt
@@ -0,0 +1,21 @@
+### 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
+```
+'x' as u8
+```
+
+A better version, using the byte literal:
+
+```
+b'x'
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/chars_last_cmp.txt b/src/tools/clippy/src/docs/chars_last_cmp.txt
new file mode 100644
index 000000000..4c1d88389
--- /dev/null
+++ b/src/tools/clippy/src/docs/chars_last_cmp.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for usage of `_.chars().last()` or
+`_.chars().next_back()` on a `str` to check if it ends with a given char.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.ends_with(_)`.
+
+### Example
+```
+name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
+```
+
+Use instead:
+```
+name.ends_with('_') || name.ends_with('-');
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/chars_next_cmp.txt b/src/tools/clippy/src/docs/chars_next_cmp.txt
new file mode 100644
index 000000000..77cbce2de
--- /dev/null
+++ b/src/tools/clippy/src/docs/chars_next_cmp.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `.chars().next()` on a `str` to check
+if it starts with a given char.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.starts_with(_)`.
+
+### Example
+```
+let name = "foo";
+if name.chars().next() == Some('_') {};
+```
+
+Use instead:
+```
+let name = "foo";
+if name.starts_with('_') {};
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/checked_conversions.txt b/src/tools/clippy/src/docs/checked_conversions.txt
new file mode 100644
index 000000000..536b01294
--- /dev/null
+++ b/src/tools/clippy/src/docs/checked_conversions.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for explicit bounds checking when casting.
+
+### Why is this bad?
+Reduces the readability of statements & is error prone.
+
+### Example
+```
+foo <= i32::MAX as u32;
+```
+
+Use instead:
+```
+i32::try_from(foo).is_ok();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/clone_double_ref.txt b/src/tools/clippy/src/docs/clone_double_ref.txt
new file mode 100644
index 000000000..2729635bd
--- /dev/null
+++ b/src/tools/clippy/src/docs/clone_double_ref.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `.clone()` on an `&&T`.
+
+### Why is this bad?
+Cloning an `&&T` copies the inner `&T`, instead of
+cloning the underlying `T`.
+
+### Example
+```
+fn main() {
+ let x = vec![1];
+ let y = &&x;
+ let z = y.clone();
+ println!("{:p} {:p}", *y, z); // prints out the same pointer
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/clone_on_copy.txt b/src/tools/clippy/src/docs/clone_on_copy.txt
new file mode 100644
index 000000000..99a0bdb4c
--- /dev/null
+++ b/src/tools/clippy/src/docs/clone_on_copy.txt
@@ -0,0 +1,11 @@
+### What it does
+Checks for usage of `.clone()` on a `Copy` type.
+
+### Why is this bad?
+The only reason `Copy` types implement `Clone` is for
+generics, not for using the `clone` method on a concrete type.
+
+### Example
+```
+42u64.clone();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/clone_on_ref_ptr.txt b/src/tools/clippy/src/docs/clone_on_ref_ptr.txt
new file mode 100644
index 000000000..2d83f8fef
--- /dev/null
+++ b/src/tools/clippy/src/docs/clone_on_ref_ptr.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for usage of `.clone()` on a ref-counted pointer,
+(`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified
+function syntax instead (e.g., `Rc::clone(foo)`).
+
+### Why is this bad?
+Calling '.clone()' on an Rc, Arc, or Weak
+can obscure the fact that only the pointer is being cloned, not the underlying
+data.
+
+### Example
+```
+let x = Rc::new(1);
+
+x.clone();
+```
+
+Use instead:
+```
+Rc::clone(&x);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cloned_instead_of_copied.txt b/src/tools/clippy/src/docs/cloned_instead_of_copied.txt
new file mode 100644
index 000000000..2f2014d5f
--- /dev/null
+++ b/src/tools/clippy/src/docs/cloned_instead_of_copied.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usages of `cloned()` on an `Iterator` or `Option` where
+`copied()` could be used instead.
+
+### Why is this bad?
+`copied()` is better because it guarantees that the type being cloned
+implements `Copy`.
+
+### Example
+```
+[1, 2, 3].iter().cloned();
+```
+Use instead:
+```
+[1, 2, 3].iter().copied();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cmp_nan.txt b/src/tools/clippy/src/docs/cmp_nan.txt
new file mode 100644
index 000000000..e2ad04d93
--- /dev/null
+++ b/src/tools/clippy/src/docs/cmp_nan.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for comparisons to NaN.
+
+### Why is this bad?
+NaN does not compare meaningfully to anything – not
+even itself – so those comparisons are simply wrong.
+
+### Example
+```
+if x == f32::NAN { }
+```
+
+Use instead:
+```
+if x.is_nan() { }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cmp_null.txt b/src/tools/clippy/src/docs/cmp_null.txt
new file mode 100644
index 000000000..02fd15124
--- /dev/null
+++ b/src/tools/clippy/src/docs/cmp_null.txt
@@ -0,0 +1,23 @@
+### 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
+```
+use std::ptr;
+
+if x == ptr::null {
+ // ..
+}
+```
+
+Use instead:
+```
+if x.is_null() {
+ // ..
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cmp_owned.txt b/src/tools/clippy/src/docs/cmp_owned.txt
new file mode 100644
index 000000000..f8d4956ff
--- /dev/null
+++ b/src/tools/clippy/src/docs/cmp_owned.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for conversions to owned values just for the sake
+of a comparison.
+
+### Why is this bad?
+The comparison can operate on a reference, so creating
+an owned value effectively throws it away directly afterwards, which is
+needlessly consuming code and heap space.
+
+### Example
+```
+if x.to_owned() == y {}
+```
+
+Use instead:
+```
+if x == y {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/cognitive_complexity.txt b/src/tools/clippy/src/docs/cognitive_complexity.txt
new file mode 100644
index 000000000..fdd75f647
--- /dev/null
+++ b/src/tools/clippy/src/docs/cognitive_complexity.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for methods with high cognitive complexity.
+
+### Why is this bad?
+Methods of high cognitive complexity tend to be hard to
+both read and maintain. Also LLVM will tend to optimize small methods better.
+
+### Known problems
+Sometimes it's hard to find a way to reduce the
+complexity.
+
+### Example
+You'll see it when you get the warning. \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/collapsible_else_if.txt b/src/tools/clippy/src/docs/collapsible_else_if.txt
new file mode 100644
index 000000000..4ddfca177
--- /dev/null
+++ b/src/tools/clippy/src/docs/collapsible_else_if.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for collapsible `else { if ... }` expressions
+that can be collapsed to `else if ...`.
+
+### Why is this bad?
+Each `if`-statement adds one level of nesting, which
+makes code look more complex than it really is.
+
+### Example
+```
+
+if x {
+ …
+} else {
+ if y {
+ …
+ }
+}
+```
+
+Should be written:
+
+```
+if x {
+ …
+} else if y {
+ …
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/collapsible_if.txt b/src/tools/clippy/src/docs/collapsible_if.txt
new file mode 100644
index 000000000..e1264ee06
--- /dev/null
+++ b/src/tools/clippy/src/docs/collapsible_if.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for nested `if` statements which can be collapsed
+by `&&`-combining their conditions.
+
+### Why is this bad?
+Each `if`-statement adds one level of nesting, which
+makes code look more complex than it really is.
+
+### Example
+```
+if x {
+ if y {
+ // …
+ }
+}
+```
+
+Use instead:
+```
+if x && y {
+ // …
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/collapsible_match.txt b/src/tools/clippy/src/docs/collapsible_match.txt
new file mode 100644
index 000000000..0d59594a0
--- /dev/null
+++ b/src/tools/clippy/src/docs/collapsible_match.txt
@@ -0,0 +1,31 @@
+### What it does
+Finds nested `match` or `if let` expressions where the patterns may be "collapsed" together
+without adding any branches.
+
+Note that this lint is not intended to find _all_ cases where nested match patterns can be merged, but only
+cases where merging would most likely make the code more readable.
+
+### Why is this bad?
+It is unnecessarily verbose and complex.
+
+### Example
+```
+fn func(opt: Option<Result<u64, String>>) {
+ let n = match opt {
+ Some(n) => match n {
+ Ok(n) => n,
+ _ => return,
+ }
+ None => return,
+ };
+}
+```
+Use instead:
+```
+fn func(opt: Option<Result<u64, String>>) {
+ let n = match opt {
+ Some(Ok(n)) => n,
+ _ => return,
+ };
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/collapsible_str_replace.txt b/src/tools/clippy/src/docs/collapsible_str_replace.txt
new file mode 100644
index 000000000..c24c25a30
--- /dev/null
+++ b/src/tools/clippy/src/docs/collapsible_str_replace.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for consecutive calls to `str::replace` (2 or more)
+that can be collapsed into a single call.
+
+### Why is this bad?
+Consecutive `str::replace` calls scan the string multiple times
+with repetitive code.
+
+### Example
+```
+let hello = "hesuo worpd"
+ .replace('s', "l")
+ .replace("u", "l")
+ .replace('p', "l");
+```
+Use instead:
+```
+let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/comparison_chain.txt b/src/tools/clippy/src/docs/comparison_chain.txt
new file mode 100644
index 000000000..43b09f31f
--- /dev/null
+++ b/src/tools/clippy/src/docs/comparison_chain.txt
@@ -0,0 +1,36 @@
+### What it does
+Checks comparison chains written with `if` that can be
+rewritten with `match` and `cmp`.
+
+### Why is this bad?
+`if` is not guaranteed to be exhaustive and conditionals can get
+repetitive
+
+### Known problems
+The match statement may be slower due to the compiler
+not inlining the call to cmp. See issue [#5354](https://github.com/rust-lang/rust-clippy/issues/5354)
+
+### Example
+```
+fn f(x: u8, y: u8) {
+ if x > y {
+ a()
+ } else if x < y {
+ b()
+ } else {
+ c()
+ }
+}
+```
+
+Use instead:
+```
+use std::cmp::Ordering;
+fn f(x: u8, y: u8) {
+ match x.cmp(&y) {
+ Ordering::Greater => a(),
+ Ordering::Less => b(),
+ Ordering::Equal => c()
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/comparison_to_empty.txt b/src/tools/clippy/src/docs/comparison_to_empty.txt
new file mode 100644
index 000000000..db6f74fe2
--- /dev/null
+++ b/src/tools/clippy/src/docs/comparison_to_empty.txt
@@ -0,0 +1,31 @@
+### What it does
+Checks for comparing to an empty slice such as `""` or `[]`,
+and suggests using `.is_empty()` where applicable.
+
+### Why is this bad?
+Some structures can answer `.is_empty()` much faster
+than checking for equality. So it is good to get into the habit of using
+`.is_empty()`, and having it is cheap.
+Besides, it makes the intent clearer than a manual comparison in some contexts.
+
+### Example
+
+```
+if s == "" {
+ ..
+}
+
+if arr == [] {
+ ..
+}
+```
+Use instead:
+```
+if s.is_empty() {
+ ..
+}
+
+if arr.is_empty() {
+ ..
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/copy_iterator.txt b/src/tools/clippy/src/docs/copy_iterator.txt
new file mode 100644
index 000000000..5f9a2a015
--- /dev/null
+++ b/src/tools/clippy/src/docs/copy_iterator.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for types that implement `Copy` as well as
+`Iterator`.
+
+### Why is this bad?
+Implicit copies can be confusing when working with
+iterator combinators.
+
+### Example
+```
+#[derive(Copy, Clone)]
+struct Countdown(u8);
+
+impl Iterator for Countdown {
+ // ...
+}
+
+let a: Vec<_> = my_iterator.take(1).collect();
+let b: Vec<_> = my_iterator.collect();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/crate_in_macro_def.txt b/src/tools/clippy/src/docs/crate_in_macro_def.txt
new file mode 100644
index 000000000..047e986de
--- /dev/null
+++ b/src/tools/clippy/src/docs/crate_in_macro_def.txt
@@ -0,0 +1,35 @@
+### What it does
+Checks for use of `crate` as opposed to `$crate` in a macro definition.
+
+### Why is this bad?
+`crate` refers to the macro call's crate, whereas `$crate` refers to the macro definition's
+crate. Rarely is the former intended. See:
+https://doc.rust-lang.org/reference/macros-by-example.html#hygiene
+
+### Example
+```
+#[macro_export]
+macro_rules! print_message {
+ () => {
+ println!("{}", crate::MESSAGE);
+ };
+}
+pub const MESSAGE: &str = "Hello!";
+```
+Use instead:
+```
+#[macro_export]
+macro_rules! print_message {
+ () => {
+ println!("{}", $crate::MESSAGE);
+ };
+}
+pub const MESSAGE: &str = "Hello!";
+```
+
+Note that if the use of `crate` is intentional, an `allow` attribute can be applied to the
+macro definition, e.g.:
+```
+#[allow(clippy::crate_in_macro_def)]
+macro_rules! ok { ... crate::foo ... }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/create_dir.txt b/src/tools/clippy/src/docs/create_dir.txt
new file mode 100644
index 000000000..e4e793768
--- /dev/null
+++ b/src/tools/clippy/src/docs/create_dir.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead.
+
+### Why is this bad?
+Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`.
+
+### Example
+```
+std::fs::create_dir("foo");
+```
+
+Use instead:
+```
+std::fs::create_dir_all("foo");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/crosspointer_transmute.txt b/src/tools/clippy/src/docs/crosspointer_transmute.txt
new file mode 100644
index 000000000..49dea1549
--- /dev/null
+++ b/src/tools/clippy/src/docs/crosspointer_transmute.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for transmutes between a type `T` and `*T`.
+
+### Why is this bad?
+It's easy to mistakenly transmute between a type and a
+pointer to that type.
+
+### Example
+```
+core::intrinsics::transmute(t) // where the result type is the same as
+ // `*t` or `&t`'s
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/dbg_macro.txt b/src/tools/clippy/src/docs/dbg_macro.txt
new file mode 100644
index 000000000..3e1a9a043
--- /dev/null
+++ b/src/tools/clippy/src/docs/dbg_macro.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of dbg!() macro.
+
+### Why is this bad?
+`dbg!` macro is intended as a debugging tool. It
+should not be in version control.
+
+### Example
+```
+dbg!(true)
+```
+
+Use instead:
+```
+true
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/debug_assert_with_mut_call.txt b/src/tools/clippy/src/docs/debug_assert_with_mut_call.txt
new file mode 100644
index 000000000..2c44abe1f
--- /dev/null
+++ b/src/tools/clippy/src/docs/debug_assert_with_mut_call.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for function/method calls with a mutable
+parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros.
+
+### Why is this bad?
+In release builds `debug_assert!` macros are optimized out by the
+compiler.
+Therefore mutating something in a `debug_assert!` macro results in different behavior
+between a release and debug build.
+
+### Example
+```
+debug_assert_eq!(vec![3].pop(), Some(3));
+
+// or
+
+debug_assert!(takes_a_mut_parameter(&mut x));
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/decimal_literal_representation.txt b/src/tools/clippy/src/docs/decimal_literal_representation.txt
new file mode 100644
index 000000000..daca9bbb3
--- /dev/null
+++ b/src/tools/clippy/src/docs/decimal_literal_representation.txt
@@ -0,0 +1,13 @@
+### What it does
+Warns if there is a better representation for a numeric literal.
+
+### Why is this bad?
+Especially for big powers of 2 a hexadecimal representation is more
+readable than a decimal representation.
+
+### Example
+```
+`255` => `0xFF`
+`65_535` => `0xFFFF`
+`4_042_322_160` => `0xF0F0_F0F0`
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/declare_interior_mutable_const.txt b/src/tools/clippy/src/docs/declare_interior_mutable_const.txt
new file mode 100644
index 000000000..2801b5ccf
--- /dev/null
+++ b/src/tools/clippy/src/docs/declare_interior_mutable_const.txt
@@ -0,0 +1,46 @@
+### What it does
+Checks for declaration of `const` items which is interior
+mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.).
+
+### Why is this bad?
+Consts are copied everywhere they are referenced, i.e.,
+every time you refer to the const a fresh instance of the `Cell` or `Mutex`
+or `AtomicXxxx` will be created, which defeats the whole purpose of using
+these types in the first place.
+
+The `const` should better be replaced by a `static` item if a global
+variable is wanted, or replaced by a `const fn` if a constructor is wanted.
+
+### Known problems
+A "non-constant" const item is a legacy way to supply an
+initialized value to downstream `static` items (e.g., the
+`std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
+and this lint should be suppressed.
+
+Even though the lint avoids triggering on a constant whose type has enums that have variants
+with interior mutability, and its value uses non interior mutable variants (see
+[#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and
+[#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples);
+it complains about associated constants without default values only based on its types;
+which might not be preferable.
+There're other enums plus associated constants cases that the lint cannot handle.
+
+Types that have underlying or potential interior mutability trigger the lint whether
+the interior mutable field is used or not. See issues
+[#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
+
+### Example
+```
+use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+
+const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
+CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
+assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
+```
+
+Use instead:
+```
+static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15);
+STATIC_ATOM.store(9, SeqCst);
+assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/default_instead_of_iter_empty.txt b/src/tools/clippy/src/docs/default_instead_of_iter_empty.txt
new file mode 100644
index 000000000..b63ef3d18
--- /dev/null
+++ b/src/tools/clippy/src/docs/default_instead_of_iter_empty.txt
@@ -0,0 +1,15 @@
+### What it does
+It checks for `std::iter::Empty::default()` and suggests replacing it with
+`std::iter::empty()`.
+### Why is this bad?
+`std::iter::empty()` is the more idiomatic way.
+### Example
+```
+let _ = std::iter::Empty::<usize>::default();
+let iter: std::iter::Empty<usize> = std::iter::Empty::default();
+```
+Use instead:
+```
+let _ = std::iter::empty::<usize>();
+let iter: std::iter::Empty<usize> = std::iter::empty();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/default_numeric_fallback.txt b/src/tools/clippy/src/docs/default_numeric_fallback.txt
new file mode 100644
index 000000000..15076a0a6
--- /dev/null
+++ b/src/tools/clippy/src/docs/default_numeric_fallback.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for usage of unconstrained numeric literals which may cause default numeric fallback in type
+inference.
+
+Default numeric fallback means that if numeric types have not yet been bound to concrete
+types at the end of type inference, then integer type is bound to `i32`, and similarly
+floating type is bound to `f64`.
+
+See [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-int-fallback.md) for more information about the fallback.
+
+### Why is this bad?
+For those who are very careful about types, default numeric fallback
+can be a pitfall that cause unexpected runtime behavior.
+
+### Known problems
+This lint can only be allowed at the function level or above.
+
+### Example
+```
+let i = 10;
+let f = 1.23;
+```
+
+Use instead:
+```
+let i = 10i32;
+let f = 1.23f64;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/default_trait_access.txt b/src/tools/clippy/src/docs/default_trait_access.txt
new file mode 100644
index 000000000..e69298969
--- /dev/null
+++ b/src/tools/clippy/src/docs/default_trait_access.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for literal calls to `Default::default()`.
+
+### Why is this bad?
+It's easier for the reader if the name of the type is used, rather than the
+generic `Default`.
+
+### Example
+```
+let s: String = Default::default();
+```
+
+Use instead:
+```
+let s = String::default();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/default_union_representation.txt b/src/tools/clippy/src/docs/default_union_representation.txt
new file mode 100644
index 000000000..f79ff9760
--- /dev/null
+++ b/src/tools/clippy/src/docs/default_union_representation.txt
@@ -0,0 +1,36 @@
+### What it does
+Displays a warning when a union is declared with the default representation (without a `#[repr(C)]` attribute).
+
+### Why is this bad?
+Unions in Rust have unspecified layout by default, despite many people thinking that they
+lay out each field at the start of the union (like C does). That is, there are no guarantees
+about the offset of the fields for unions with multiple non-ZST fields without an explicitly
+specified layout. These cases may lead to undefined behavior in unsafe blocks.
+
+### Example
+```
+union Foo {
+ a: i32,
+ b: u32,
+}
+
+fn main() {
+ let _x: u32 = unsafe {
+ Foo { a: 0_i32 }.b // Undefined behavior: `b` is allowed to be padding
+ };
+}
+```
+Use instead:
+```
+#[repr(C)]
+union Foo {
+ a: i32,
+ b: u32,
+}
+
+fn main() {
+ let _x: u32 = unsafe {
+ Foo { a: 0_i32 }.b // Now defined behavior, this is just an i32 -> u32 transmute
+ };
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/deprecated_cfg_attr.txt b/src/tools/clippy/src/docs/deprecated_cfg_attr.txt
new file mode 100644
index 000000000..9f264887a
--- /dev/null
+++ b/src/tools/clippy/src/docs/deprecated_cfg_attr.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it
+with `#[rustfmt::skip]`.
+
+### Why is this bad?
+Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690))
+are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes.
+
+### Known problems
+This lint doesn't detect crate level inner attributes, because they get
+processed before the PreExpansionPass lints get executed. See
+[#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765)
+
+### Example
+```
+#[cfg_attr(rustfmt, rustfmt_skip)]
+fn main() { }
+```
+
+Use instead:
+```
+#[rustfmt::skip]
+fn main() { }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/deprecated_semver.txt b/src/tools/clippy/src/docs/deprecated_semver.txt
new file mode 100644
index 000000000..c9574a99b
--- /dev/null
+++ b/src/tools/clippy/src/docs/deprecated_semver.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for `#[deprecated]` annotations with a `since`
+field that is not a valid semantic version.
+
+### Why is this bad?
+For checking the version of the deprecation, it must be
+a valid semver. Failing that, the contained information is useless.
+
+### Example
+```
+#[deprecated(since = "forever")]
+fn something_else() { /* ... */ }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/deref_addrof.txt b/src/tools/clippy/src/docs/deref_addrof.txt
new file mode 100644
index 000000000..fa711b924
--- /dev/null
+++ b/src/tools/clippy/src/docs/deref_addrof.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `*&` and `*&mut` in expressions.
+
+### Why is this bad?
+Immediately dereferencing a reference is no-op and
+makes the code less clear.
+
+### Known problems
+Multiple dereference/addrof pairs are not handled so
+the suggested fix for `x = **&&y` is `x = *&y`, which is still incorrect.
+
+### Example
+```
+let a = f(*&mut b);
+let c = *&d;
+```
+
+Use instead:
+```
+let a = f(b);
+let c = d;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/deref_by_slicing.txt b/src/tools/clippy/src/docs/deref_by_slicing.txt
new file mode 100644
index 000000000..4dad24ac0
--- /dev/null
+++ b/src/tools/clippy/src/docs/deref_by_slicing.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for slicing expressions which are equivalent to dereferencing the
+value.
+
+### Why is this bad?
+Some people may prefer to dereference rather than slice.
+
+### Example
+```
+let vec = vec![1, 2, 3];
+let slice = &vec[..];
+```
+Use instead:
+```
+let vec = vec![1, 2, 3];
+let slice = &*vec;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/derivable_impls.txt b/src/tools/clippy/src/docs/derivable_impls.txt
new file mode 100644
index 000000000..5cee43956
--- /dev/null
+++ b/src/tools/clippy/src/docs/derivable_impls.txt
@@ -0,0 +1,35 @@
+### What it does
+Detects manual `std::default::Default` implementations that are identical to a derived implementation.
+
+### Why is this bad?
+It is less concise.
+
+### Example
+```
+struct Foo {
+ bar: bool
+}
+
+impl Default for Foo {
+ fn default() -> Self {
+ Self {
+ bar: false
+ }
+ }
+}
+```
+
+Use instead:
+```
+#[derive(Default)]
+struct Foo {
+ bar: bool
+}
+```
+
+### Known problems
+Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925)
+in generic types and the user defined `impl` may be more generalized or
+specialized than what derive will produce. This lint can't detect the manual `impl`
+has exactly equal bounds, and therefore this lint is disabled for types with
+generic parameters. \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/derive_hash_xor_eq.txt b/src/tools/clippy/src/docs/derive_hash_xor_eq.txt
new file mode 100644
index 000000000..fbf623d5a
--- /dev/null
+++ b/src/tools/clippy/src/docs/derive_hash_xor_eq.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for deriving `Hash` but implementing `PartialEq`
+explicitly or vice versa.
+
+### Why is this bad?
+The implementation of these traits must agree (for
+example for use with `HashMap`) so it’s probably a bad idea to use a
+default-generated `Hash` implementation with an explicitly defined
+`PartialEq`. In particular, the following must hold for any type:
+
+```
+k1 == k2 ⇒ hash(k1) == hash(k2)
+```
+
+### Example
+```
+#[derive(Hash)]
+struct Foo;
+
+impl PartialEq for Foo {
+ ...
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/derive_ord_xor_partial_ord.txt b/src/tools/clippy/src/docs/derive_ord_xor_partial_ord.txt
new file mode 100644
index 000000000..f2107a5f6
--- /dev/null
+++ b/src/tools/clippy/src/docs/derive_ord_xor_partial_ord.txt
@@ -0,0 +1,44 @@
+### What it does
+Checks for deriving `Ord` but implementing `PartialOrd`
+explicitly or vice versa.
+
+### Why is this bad?
+The implementation of these traits must agree (for
+example for use with `sort`) so it’s probably a bad idea to use a
+default-generated `Ord` implementation with an explicitly defined
+`PartialOrd`. In particular, the following must hold for any type
+implementing `Ord`:
+
+```
+k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()
+```
+
+### Example
+```
+#[derive(Ord, PartialEq, Eq)]
+struct Foo;
+
+impl PartialOrd for Foo {
+ ...
+}
+```
+Use instead:
+```
+#[derive(PartialEq, Eq)]
+struct Foo;
+
+impl PartialOrd for Foo {
+ fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Foo {
+ ...
+}
+```
+or, if you don't need a custom ordering:
+```
+#[derive(Ord, PartialOrd, PartialEq, Eq)]
+struct Foo;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/derive_partial_eq_without_eq.txt b/src/tools/clippy/src/docs/derive_partial_eq_without_eq.txt
new file mode 100644
index 000000000..932fabad6
--- /dev/null
+++ b/src/tools/clippy/src/docs/derive_partial_eq_without_eq.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for types that derive `PartialEq` and could implement `Eq`.
+
+### Why is this bad?
+If a type `T` derives `PartialEq` and all of its members implement `Eq`,
+then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used
+in APIs that require `Eq` types. It also allows structs containing `T` to derive
+`Eq` themselves.
+
+### Example
+```
+#[derive(PartialEq)]
+struct Foo {
+ i_am_eq: i32,
+ i_am_eq_too: Vec<String>,
+}
+```
+Use instead:
+```
+#[derive(PartialEq, Eq)]
+struct Foo {
+ i_am_eq: i32,
+ i_am_eq_too: Vec<String>,
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/disallowed_macros.txt b/src/tools/clippy/src/docs/disallowed_macros.txt
new file mode 100644
index 000000000..96fa15afa
--- /dev/null
+++ b/src/tools/clippy/src/docs/disallowed_macros.txt
@@ -0,0 +1,36 @@
+### What it does
+Denies the configured macros in clippy.toml
+
+Note: Even though this lint is warn-by-default, it will only trigger if
+macros are defined in the clippy.toml file.
+
+### Why is this bad?
+Some macros are undesirable in certain contexts, and it's beneficial to
+lint for them as needed.
+
+### Example
+An example clippy.toml configuration:
+```
+disallowed-macros = [
+ # Can use a string as the path of the disallowed macro.
+ "std::print",
+ # Can also use an inline table with a `path` key.
+ { path = "std::println" },
+ # When using an inline table, can add a `reason` for why the macro
+ # is disallowed.
+ { path = "serde::Serialize", reason = "no serializing" },
+]
+```
+```
+use serde::Serialize;
+
+// Example code where clippy issues a warning
+println!("warns");
+
+// The diagnostic will contain the message "no serializing"
+#[derive(Serialize)]
+struct Data {
+ name: String,
+ value: usize,
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/disallowed_methods.txt b/src/tools/clippy/src/docs/disallowed_methods.txt
new file mode 100644
index 000000000..d8ad5b6a6
--- /dev/null
+++ b/src/tools/clippy/src/docs/disallowed_methods.txt
@@ -0,0 +1,41 @@
+### What it does
+Denies the configured methods and functions in clippy.toml
+
+Note: Even though this lint is warn-by-default, it will only trigger if
+methods are defined in the clippy.toml file.
+
+### Why is this bad?
+Some methods are undesirable in certain contexts, and it's beneficial to
+lint for them as needed.
+
+### Example
+An example clippy.toml configuration:
+```
+disallowed-methods = [
+ # Can use a string as the path of the disallowed method.
+ "std::boxed::Box::new",
+ # Can also use an inline table with a `path` key.
+ { path = "std::time::Instant::now" },
+ # When using an inline table, can add a `reason` for why the method
+ # is disallowed.
+ { path = "std::vec::Vec::leak", reason = "no leaking memory" },
+]
+```
+
+```
+// Example code where clippy issues a warning
+let xs = vec![1, 2, 3, 4];
+xs.leak(); // Vec::leak is disallowed in the config.
+// The diagnostic contains the message "no leaking memory".
+
+let _now = Instant::now(); // Instant::now is disallowed in the config.
+
+let _box = Box::new(3); // Box::new is disallowed in the config.
+```
+
+Use instead:
+```
+// Example code which does not raise clippy warning
+let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config.
+xs.push(123); // Vec::push is _not_ disallowed in the config.
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/disallowed_names.txt b/src/tools/clippy/src/docs/disallowed_names.txt
new file mode 100644
index 000000000..f4aaee9c7
--- /dev/null
+++ b/src/tools/clippy/src/docs/disallowed_names.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for usage of disallowed names for variables, such
+as `foo`.
+
+### Why is this bad?
+These names are usually placeholder names and should be
+avoided.
+
+### Example
+```
+let foo = 3.14;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/disallowed_script_idents.txt b/src/tools/clippy/src/docs/disallowed_script_idents.txt
new file mode 100644
index 000000000..2151b7a20
--- /dev/null
+++ b/src/tools/clippy/src/docs/disallowed_script_idents.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for usage of unicode scripts other than those explicitly allowed
+by the lint config.
+
+This lint doesn't take into account non-text scripts such as `Unknown` and `Linear_A`.
+It also ignores the `Common` script type.
+While configuring, be sure to use official script name [aliases] from
+[the list of supported scripts][supported_scripts].
+
+See also: [`non_ascii_idents`].
+
+[aliases]: http://www.unicode.org/reports/tr24/tr24-31.html#Script_Value_Aliases
+[supported_scripts]: https://www.unicode.org/iso15924/iso15924-codes.html
+
+### Why is this bad?
+It may be not desired to have many different scripts for
+identifiers in the codebase.
+
+Note that if you only want to allow plain English, you might want to use
+built-in [`non_ascii_idents`] lint instead.
+
+[`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents
+
+### Example
+```
+// Assuming that `clippy.toml` contains the following line:
+// allowed-locales = ["Latin", "Cyrillic"]
+let counter = 10; // OK, latin is allowed.
+let счётчик = 10; // OK, cyrillic is allowed.
+let zähler = 10; // OK, it's still latin.
+let カウンタ = 10; // Will spawn the lint.
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/disallowed_types.txt b/src/tools/clippy/src/docs/disallowed_types.txt
new file mode 100644
index 000000000..2bcbcddee
--- /dev/null
+++ b/src/tools/clippy/src/docs/disallowed_types.txt
@@ -0,0 +1,33 @@
+### What it does
+Denies the configured types in clippy.toml.
+
+Note: Even though this lint is warn-by-default, it will only trigger if
+types are defined in the clippy.toml file.
+
+### Why is this bad?
+Some types are undesirable in certain contexts.
+
+### Example:
+An example clippy.toml configuration:
+```
+disallowed-types = [
+ # Can use a string as the path of the disallowed type.
+ "std::collections::BTreeMap",
+ # Can also use an inline table with a `path` key.
+ { path = "std::net::TcpListener" },
+ # When using an inline table, can add a `reason` for why the type
+ # is disallowed.
+ { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
+]
+```
+
+```
+use std::collections::BTreeMap;
+// or its use
+let x = std::collections::BTreeMap::new();
+```
+Use instead:
+```
+// A similar type that is allowed by the config
+use std::collections::HashMap;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/diverging_sub_expression.txt b/src/tools/clippy/src/docs/diverging_sub_expression.txt
new file mode 100644
index 000000000..194362218
--- /dev/null
+++ b/src/tools/clippy/src/docs/diverging_sub_expression.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for diverging calls that are not match arms or
+statements.
+
+### Why is this bad?
+It is often confusing to read. In addition, the
+sub-expression evaluation order for Rust is not well documented.
+
+### Known problems
+Someone might want to use `some_bool || panic!()` as a
+shorthand.
+
+### Example
+```
+let a = b() || panic!() || c();
+// `c()` is dead, `panic!()` is only called if `b()` returns `false`
+let x = (a, b, c, panic!());
+// can simply be replaced by `panic!()`
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/doc_link_with_quotes.txt b/src/tools/clippy/src/docs/doc_link_with_quotes.txt
new file mode 100644
index 000000000..107c8ac11
--- /dev/null
+++ b/src/tools/clippy/src/docs/doc_link_with_quotes.txt
@@ -0,0 +1,16 @@
+### What it does
+Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks)
+outside of code blocks
+### Why is this bad?
+It is likely a typo when defining an intra-doc link
+
+### Example
+```
+/// See also: ['foo']
+fn bar() {}
+```
+Use instead:
+```
+/// See also: [`foo`]
+fn bar() {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/doc_markdown.txt b/src/tools/clippy/src/docs/doc_markdown.txt
new file mode 100644
index 000000000..94f54c587
--- /dev/null
+++ b/src/tools/clippy/src/docs/doc_markdown.txt
@@ -0,0 +1,35 @@
+### What it does
+Checks for the presence of `_`, `::` or camel-case words
+outside ticks in documentation.
+
+### Why is this bad?
+*Rustdoc* supports markdown formatting, `_`, `::` and
+camel-case probably indicates some code which should be included between
+ticks. `_` can also be used for emphasis in markdown, this lint tries to
+consider that.
+
+### Known problems
+Lots of bad docs won’t be fixed, what the lint checks
+for is limited, and there are still false positives. HTML elements and their
+content are not linted.
+
+In addition, when writing documentation comments, including `[]` brackets
+inside a link text would trip the parser. Therefore, documenting link with
+`[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec
+would fail.
+
+### Examples
+```
+/// 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) {}
+```
+
+```
+// 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() {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/double_comparisons.txt b/src/tools/clippy/src/docs/double_comparisons.txt
new file mode 100644
index 000000000..7dc681877
--- /dev/null
+++ b/src/tools/clippy/src/docs/double_comparisons.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for double comparisons that could be simplified to a single expression.
+
+
+### Why is this bad?
+Readability.
+
+### Example
+```
+if x == y || x < y {}
+```
+
+Use instead:
+
+```
+if x <= y {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/double_must_use.txt b/src/tools/clippy/src/docs/double_must_use.txt
new file mode 100644
index 000000000..0017d10d4
--- /dev/null
+++ b/src/tools/clippy/src/docs/double_must_use.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for a `#[must_use]` attribute without
+further information on functions and methods that return a type already
+marked as `#[must_use]`.
+
+### Why is this bad?
+The attribute isn't needed. Not using the result
+will already be reported. Alternatively, one can add some text to the
+attribute to improve the lint message.
+
+### Examples
+```
+#[must_use]
+fn double_must_use() -> Result<(), ()> {
+ unimplemented!();
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/double_neg.txt b/src/tools/clippy/src/docs/double_neg.txt
new file mode 100644
index 000000000..a07f67496
--- /dev/null
+++ b/src/tools/clippy/src/docs/double_neg.txt
@@ -0,0 +1,12 @@
+### 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
+```
+let mut x = 3;
+--x;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/double_parens.txt b/src/tools/clippy/src/docs/double_parens.txt
new file mode 100644
index 000000000..260d7dd57
--- /dev/null
+++ b/src/tools/clippy/src/docs/double_parens.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for unnecessary double parentheses.
+
+### Why is this bad?
+This makes code harder to read and might indicate a
+mistake.
+
+### Example
+```
+fn simple_double_parens() -> i32 {
+ ((0))
+}
+
+foo((0));
+```
+
+Use instead:
+```
+fn simple_no_parens() -> i32 {
+ 0
+}
+
+foo(0);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/drop_copy.txt b/src/tools/clippy/src/docs/drop_copy.txt
new file mode 100644
index 000000000..f917ca8ed
--- /dev/null
+++ b/src/tools/clippy/src/docs/drop_copy.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for calls to `std::mem::drop` with a value
+that derives the Copy trait
+
+### Why is this bad?
+Calling `std::mem::drop` [does nothing for types that
+implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the
+value will be copied and moved into the function on invocation.
+
+### Example
+```
+let x: i32 = 42; // i32 implements Copy
+std::mem::drop(x) // A copy of x is passed to the function, leaving the
+ // original unaffected
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/drop_non_drop.txt b/src/tools/clippy/src/docs/drop_non_drop.txt
new file mode 100644
index 000000000..ee1e3a6c2
--- /dev/null
+++ b/src/tools/clippy/src/docs/drop_non_drop.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for calls to `std::mem::drop` with a value that does not implement `Drop`.
+
+### Why is this bad?
+Calling `std::mem::drop` is no different than dropping such a type. A different value may
+have been intended.
+
+### Example
+```
+struct Foo;
+let x = Foo;
+std::mem::drop(x);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/drop_ref.txt b/src/tools/clippy/src/docs/drop_ref.txt
new file mode 100644
index 000000000..c4f7adf0c
--- /dev/null
+++ b/src/tools/clippy/src/docs/drop_ref.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for calls to `std::mem::drop` with a reference
+instead of an owned value.
+
+### Why is this bad?
+Calling `drop` on a reference will only drop the
+reference itself, which is a no-op. It will not call the `drop` method (from
+the `Drop` trait implementation) on the underlying referenced value, which
+is likely what was intended.
+
+### Example
+```
+let mut lock_guard = mutex.lock();
+std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex
+// still locked
+operation_that_requires_mutex_to_be_unlocked();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/duplicate_mod.txt b/src/tools/clippy/src/docs/duplicate_mod.txt
new file mode 100644
index 000000000..709a9aba0
--- /dev/null
+++ b/src/tools/clippy/src/docs/duplicate_mod.txt
@@ -0,0 +1,31 @@
+### What it does
+Checks for files that are included as modules multiple times.
+
+### Why is this bad?
+Loading a file as a module more than once causes it to be compiled
+multiple times, taking longer and putting duplicate content into the
+module tree.
+
+### Example
+```
+// lib.rs
+mod a;
+mod b;
+```
+```
+// a.rs
+#[path = "./b.rs"]
+mod b;
+```
+
+Use instead:
+
+```
+// lib.rs
+mod a;
+mod b;
+```
+```
+// a.rs
+use crate::b;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/duplicate_underscore_argument.txt b/src/tools/clippy/src/docs/duplicate_underscore_argument.txt
new file mode 100644
index 000000000..a8fcd6a9f
--- /dev/null
+++ b/src/tools/clippy/src/docs/duplicate_underscore_argument.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for function arguments having the similar names
+differing by an underscore.
+
+### Why is this bad?
+It affects code readability.
+
+### Example
+```
+fn foo(a: i32, _a: i32) {}
+```
+
+Use instead:
+```
+fn bar(a: i32, _b: i32) {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/duration_subsec.txt b/src/tools/clippy/src/docs/duration_subsec.txt
new file mode 100644
index 000000000..e7e0ca887
--- /dev/null
+++ b/src/tools/clippy/src/docs/duration_subsec.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for calculation of subsecond microseconds or milliseconds
+from other `Duration` methods.
+
+### Why is this bad?
+It's more concise to call `Duration::subsec_micros()` or
+`Duration::subsec_millis()` than to calculate them.
+
+### Example
+```
+let micros = duration.subsec_nanos() / 1_000;
+let millis = duration.subsec_nanos() / 1_000_000;
+```
+
+Use instead:
+```
+let micros = duration.subsec_micros();
+let millis = duration.subsec_millis();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/else_if_without_else.txt b/src/tools/clippy/src/docs/else_if_without_else.txt
new file mode 100644
index 000000000..33f5d0f91
--- /dev/null
+++ b/src/tools/clippy/src/docs/else_if_without_else.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for usage of if expressions with an `else if` branch,
+but without a final `else` branch.
+
+### Why is this bad?
+Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10).
+
+### Example
+```
+if x.is_positive() {
+ a();
+} else if x.is_negative() {
+ b();
+}
+```
+
+Use instead:
+
+```
+if x.is_positive() {
+ a();
+} else if x.is_negative() {
+ b();
+} else {
+ // We don't care about zero.
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/empty_drop.txt b/src/tools/clippy/src/docs/empty_drop.txt
new file mode 100644
index 000000000..d0c0c24a9
--- /dev/null
+++ b/src/tools/clippy/src/docs/empty_drop.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for empty `Drop` implementations.
+
+### Why is this bad?
+Empty `Drop` implementations have no effect when dropping an instance of the type. They are
+most likely useless. However, an empty `Drop` implementation prevents a type from being
+destructured, which might be the intention behind adding the implementation as a marker.
+
+### Example
+```
+struct S;
+
+impl Drop for S {
+ fn drop(&mut self) {}
+}
+```
+Use instead:
+```
+struct S;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/empty_enum.txt b/src/tools/clippy/src/docs/empty_enum.txt
new file mode 100644
index 000000000..f7b41c41e
--- /dev/null
+++ b/src/tools/clippy/src/docs/empty_enum.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for `enum`s with no variants.
+
+As of this writing, the `never_type` is still a
+nightly-only experimental API. Therefore, this lint is only triggered
+if the `never_type` is enabled.
+
+### Why is this bad?
+If you want to introduce a type which
+can't be instantiated, you should use `!` (the primitive type "never"),
+or a wrapper around it, because `!` has more extensive
+compiler support (type inference, etc...) and wrappers
+around it are the conventional way to define an uninhabited type.
+For further information visit [never type documentation](https://doc.rust-lang.org/std/primitive.never.html)
+
+
+### Example
+```
+enum Test {}
+```
+
+Use instead:
+```
+#![feature(never_type)]
+
+struct Test(!);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/empty_line_after_outer_attr.txt b/src/tools/clippy/src/docs/empty_line_after_outer_attr.txt
new file mode 100644
index 000000000..c85242bbe
--- /dev/null
+++ b/src/tools/clippy/src/docs/empty_line_after_outer_attr.txt
@@ -0,0 +1,35 @@
+### What it does
+Checks for empty lines after outer attributes
+
+### Why is this bad?
+Most likely the attribute was meant to be an inner attribute using a '!'.
+If it was meant to be an outer attribute, then the following item
+should not be separated by empty lines.
+
+### Known problems
+Can cause false positives.
+
+From the clippy side it's difficult to detect empty lines between an attributes and the
+following item because empty lines and comments are not part of the AST. The parsing
+currently works for basic cases but is not perfect.
+
+### Example
+```
+#[allow(dead_code)]
+
+fn not_quite_good_code() { }
+```
+
+Use instead:
+```
+// Good (as inner attribute)
+#![allow(dead_code)]
+
+fn this_is_fine() { }
+
+// or
+
+// Good (as outer attribute)
+#[allow(dead_code)]
+fn this_is_fine_too() { }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/empty_loop.txt b/src/tools/clippy/src/docs/empty_loop.txt
new file mode 100644
index 000000000..fea49a74d
--- /dev/null
+++ b/src/tools/clippy/src/docs/empty_loop.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for empty `loop` expressions.
+
+### Why is this bad?
+These busy loops burn CPU cycles without doing
+anything. It is _almost always_ a better idea to `panic!` than to have
+a busy loop.
+
+If panicking isn't possible, think of the environment and either:
+ - block on something
+ - sleep the thread for some microseconds
+ - yield or pause the thread
+
+For `std` targets, this can be done with
+[`std::thread::sleep`](https://doc.rust-lang.org/std/thread/fn.sleep.html)
+or [`std::thread::yield_now`](https://doc.rust-lang.org/std/thread/fn.yield_now.html).
+
+For `no_std` targets, doing this is more complicated, especially because
+`#[panic_handler]`s can't panic. To stop/pause the thread, you will
+probably need to invoke some target-specific intrinsic. Examples include:
+ - [`x86_64::instructions::hlt`](https://docs.rs/x86_64/0.12.2/x86_64/instructions/fn.hlt.html)
+ - [`cortex_m::asm::wfi`](https://docs.rs/cortex-m/0.6.3/cortex_m/asm/fn.wfi.html)
+
+### Example
+```
+loop {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/empty_structs_with_brackets.txt b/src/tools/clippy/src/docs/empty_structs_with_brackets.txt
new file mode 100644
index 000000000..ab5e35ae2
--- /dev/null
+++ b/src/tools/clippy/src/docs/empty_structs_with_brackets.txt
@@ -0,0 +1,14 @@
+### What it does
+Finds structs without fields (a so-called "empty struct") that are declared with brackets.
+
+### Why is this bad?
+Empty brackets after a struct declaration can be omitted.
+
+### Example
+```
+struct Cookie {}
+```
+Use instead:
+```
+struct Cookie;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/enum_clike_unportable_variant.txt b/src/tools/clippy/src/docs/enum_clike_unportable_variant.txt
new file mode 100644
index 000000000..d30a973a5
--- /dev/null
+++ b/src/tools/clippy/src/docs/enum_clike_unportable_variant.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for C-like enumerations that are
+`repr(isize/usize)` and have values that don't fit into an `i32`.
+
+### Why is this bad?
+This will truncate the variant value on 32 bit
+architectures, but works fine on 64 bit.
+
+### Example
+```
+#[repr(usize)]
+enum NonPortable {
+ X = 0x1_0000_0000,
+ Y = 0,
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/enum_glob_use.txt b/src/tools/clippy/src/docs/enum_glob_use.txt
new file mode 100644
index 000000000..3776822c3
--- /dev/null
+++ b/src/tools/clippy/src/docs/enum_glob_use.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for `use Enum::*`.
+
+### Why is this bad?
+It is usually better style to use the prefixed name of
+an enumeration variant, rather than importing variants.
+
+### Known problems
+Old-style enumerations that prefix the variants are
+still around.
+
+### Example
+```
+use std::cmp::Ordering::*;
+
+foo(Less);
+```
+
+Use instead:
+```
+use std::cmp::Ordering;
+
+foo(Ordering::Less)
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/enum_variant_names.txt b/src/tools/clippy/src/docs/enum_variant_names.txt
new file mode 100644
index 000000000..e726925ed
--- /dev/null
+++ b/src/tools/clippy/src/docs/enum_variant_names.txt
@@ -0,0 +1,30 @@
+### 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.
+
+### Limitations
+Characters with no casing will be considered when comparing prefixes/suffixes
+This applies to numbers and non-ascii characters without casing
+e.g. `Foo1` and `Foo2` is considered to have different prefixes
+(the prefixes are `Foo1` and `Foo2` respectively), as also `Bar螃`, `Bar蟹`
+
+### Example
+```
+enum Cake {
+ BlackForestCake,
+ HummingbirdCake,
+ BattenbergCake,
+}
+```
+Use instead:
+```
+enum Cake {
+ BlackForest,
+ Hummingbird,
+ Battenberg,
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/eq_op.txt b/src/tools/clippy/src/docs/eq_op.txt
new file mode 100644
index 000000000..2d75a0ec5
--- /dev/null
+++ b/src/tools/clippy/src/docs/eq_op.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for equal operands to comparison, logical and
+bitwise, difference and division binary operators (`==`, `>`, etc., `&&`,
+`||`, `&`, `|`, `^`, `-` and `/`).
+
+### Why is this bad?
+This is usually just a typo or a copy and paste error.
+
+### Known problems
+False negatives: We had some false positives regarding
+calls (notably [racer](https://github.com/phildawes/racer) had one instance
+of `x.pop() && x.pop()`), so we removed matching any function or method
+calls. We may introduce a list of known pure functions in the future.
+
+### Example
+```
+if x + 1 == x + 1 {}
+
+// or
+
+assert_eq!(a, a);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/equatable_if_let.txt b/src/tools/clippy/src/docs/equatable_if_let.txt
new file mode 100644
index 000000000..999704695
--- /dev/null
+++ b/src/tools/clippy/src/docs/equatable_if_let.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for pattern matchings that can be expressed using equality.
+
+### Why is this bad?
+
+* It reads better and has less cognitive load because equality won't cause binding.
+* It is a [Yoda condition](https://en.wikipedia.org/wiki/Yoda_conditions). Yoda conditions are widely
+criticized for increasing the cognitive load of reading the code.
+* Equality is a simple bool expression and can be merged with `&&` and `||` and
+reuse if blocks
+
+### Example
+```
+if let Some(2) = x {
+ do_thing();
+}
+```
+Use instead:
+```
+if x == Some(2) {
+ do_thing();
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/erasing_op.txt b/src/tools/clippy/src/docs/erasing_op.txt
new file mode 100644
index 000000000..3d285a6d8
--- /dev/null
+++ b/src/tools/clippy/src/docs/erasing_op.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for erasing operations, e.g., `x * 0`.
+
+### Why is this bad?
+The whole expression can be replaced by zero.
+This is most likely not the intended outcome and should probably be
+corrected
+
+### Example
+```
+let x = 1;
+0 / x;
+0 * x;
+x & 0;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/err_expect.txt b/src/tools/clippy/src/docs/err_expect.txt
new file mode 100644
index 000000000..1dc83c5ce
--- /dev/null
+++ b/src/tools/clippy/src/docs/err_expect.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for `.err().expect()` calls on the `Result` type.
+
+### Why is this bad?
+`.expect_err()` can be called directly to avoid the extra type conversion from `err()`.
+
+### Example
+```
+let x: Result<u32, &str> = Ok(10);
+x.err().expect("Testing err().expect()");
+```
+Use instead:
+```
+let x: Result<u32, &str> = Ok(10);
+x.expect_err("Testing expect_err");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/excessive_precision.txt b/src/tools/clippy/src/docs/excessive_precision.txt
new file mode 100644
index 000000000..517879c47
--- /dev/null
+++ b/src/tools/clippy/src/docs/excessive_precision.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for float literals with a precision greater
+than that supported by the underlying type.
+
+### Why is this bad?
+Rust will truncate the literal silently.
+
+### Example
+```
+let v: f32 = 0.123_456_789_9;
+println!("{}", v); // 0.123_456_789
+```
+
+Use instead:
+```
+let v: f64 = 0.123_456_789_9;
+println!("{}", v); // 0.123_456_789_9
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/exhaustive_enums.txt b/src/tools/clippy/src/docs/exhaustive_enums.txt
new file mode 100644
index 000000000..d1032a7a2
--- /dev/null
+++ b/src/tools/clippy/src/docs/exhaustive_enums.txt
@@ -0,0 +1,23 @@
+### What it does
+Warns on any exported `enum`s that are not tagged `#[non_exhaustive]`
+
+### Why is this bad?
+Exhaustive enums are typically fine, but a project which does
+not wish to make a stability commitment around exported enums may wish to
+disable them by default.
+
+### Example
+```
+enum Foo {
+ Bar,
+ Baz
+}
+```
+Use instead:
+```
+#[non_exhaustive]
+enum Foo {
+ Bar,
+ Baz
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/exhaustive_structs.txt b/src/tools/clippy/src/docs/exhaustive_structs.txt
new file mode 100644
index 000000000..fd6e4f5ca
--- /dev/null
+++ b/src/tools/clippy/src/docs/exhaustive_structs.txt
@@ -0,0 +1,23 @@
+### What it does
+Warns on any exported `structs`s that are not tagged `#[non_exhaustive]`
+
+### Why is this bad?
+Exhaustive structs are typically fine, but a project which does
+not wish to make a stability commitment around exported structs may wish to
+disable them by default.
+
+### Example
+```
+struct Foo {
+ bar: u8,
+ baz: String,
+}
+```
+Use instead:
+```
+#[non_exhaustive]
+struct Foo {
+ bar: u8,
+ baz: String,
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/exit.txt b/src/tools/clippy/src/docs/exit.txt
new file mode 100644
index 000000000..1e6154d43
--- /dev/null
+++ b/src/tools/clippy/src/docs/exit.txt
@@ -0,0 +1,12 @@
+### What it does
+`exit()` terminates the program and doesn't provide a
+stack trace.
+
+### Why is this bad?
+Ideally a program is terminated by finishing
+the main function.
+
+### Example
+```
+std::process::exit(0)
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/expect_fun_call.txt b/src/tools/clippy/src/docs/expect_fun_call.txt
new file mode 100644
index 000000000..d82d9aa9b
--- /dev/null
+++ b/src/tools/clippy/src/docs/expect_fun_call.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`,
+etc., and suggests to use `unwrap_or_else` instead
+
+### Why is this bad?
+The function will always be called.
+
+### Known problems
+If the function has side-effects, not calling it will
+change the semantics of the program, but you shouldn't rely on that anyway.
+
+### Example
+```
+foo.expect(&format!("Err {}: {}", err_code, err_msg));
+
+// or
+
+foo.expect(format!("Err {}: {}", err_code, err_msg).as_str());
+```
+
+Use instead:
+```
+foo.unwrap_or_else(|| panic!("Err {}: {}", err_code, err_msg));
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/expect_used.txt b/src/tools/clippy/src/docs/expect_used.txt
new file mode 100644
index 000000000..4a6981e33
--- /dev/null
+++ b/src/tools/clippy/src/docs/expect_used.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s.
+
+### Why is this bad?
+Usually it is better to handle the `None` or `Err` case.
+Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why
+this lint is `Allow` by default.
+
+`result.expect()` will let the thread panic on `Err`
+values. Normally, you want to implement more sophisticated error handling,
+and propagate errors upwards with `?` operator.
+
+### Examples
+```
+option.expect("one");
+result.expect("one");
+```
+
+Use instead:
+```
+option?;
+
+// or
+
+result?;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/expl_impl_clone_on_copy.txt b/src/tools/clippy/src/docs/expl_impl_clone_on_copy.txt
new file mode 100644
index 000000000..391d93b67
--- /dev/null
+++ b/src/tools/clippy/src/docs/expl_impl_clone_on_copy.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for explicit `Clone` implementations for `Copy`
+types.
+
+### Why is this bad?
+To avoid surprising behavior, these traits should
+agree and the behavior of `Copy` cannot be overridden. In almost all
+situations a `Copy` type should have a `Clone` implementation that does
+nothing more than copy the object, which is what `#[derive(Copy, Clone)]`
+gets you.
+
+### Example
+```
+#[derive(Copy)]
+struct Foo;
+
+impl Clone for Foo {
+ // ..
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/explicit_auto_deref.txt b/src/tools/clippy/src/docs/explicit_auto_deref.txt
new file mode 100644
index 000000000..65b256317
--- /dev/null
+++ b/src/tools/clippy/src/docs/explicit_auto_deref.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for dereferencing expressions which would be covered by auto-deref.
+
+### Why is this bad?
+This unnecessarily complicates the code.
+
+### Example
+```
+let x = String::new();
+let y: &str = &*x;
+```
+Use instead:
+```
+let x = String::new();
+let y: &str = &x;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/explicit_counter_loop.txt b/src/tools/clippy/src/docs/explicit_counter_loop.txt
new file mode 100644
index 000000000..2661a43e1
--- /dev/null
+++ b/src/tools/clippy/src/docs/explicit_counter_loop.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks `for` loops over slices with an explicit counter
+and suggests the use of `.enumerate()`.
+
+### Why is this bad?
+Using `.enumerate()` makes the intent more clear,
+declutters the code and may be faster in some instances.
+
+### Example
+```
+let mut i = 0;
+for item in &v {
+ bar(i, *item);
+ i += 1;
+}
+```
+
+Use instead:
+```
+for (i, item) in v.iter().enumerate() { bar(i, *item); }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/explicit_deref_methods.txt b/src/tools/clippy/src/docs/explicit_deref_methods.txt
new file mode 100644
index 000000000..e14e981c7
--- /dev/null
+++ b/src/tools/clippy/src/docs/explicit_deref_methods.txt
@@ -0,0 +1,24 @@
+### 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
+```
+use std::ops::Deref;
+let a: &mut String = &mut String::from("foo");
+let b: &str = a.deref();
+```
+
+Use instead:
+```
+let a: &mut String = &mut String::from("foo");
+let b = &*a;
+```
+
+This lint excludes:
+```
+let _ = d.unwrap().deref();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/explicit_into_iter_loop.txt b/src/tools/clippy/src/docs/explicit_into_iter_loop.txt
new file mode 100644
index 000000000..3931dfd69
--- /dev/null
+++ b/src/tools/clippy/src/docs/explicit_into_iter_loop.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for loops on `y.into_iter()` where `y` will do, and
+suggests the latter.
+
+### Why is this bad?
+Readability.
+
+### Example
+```
+// with `y` a `Vec` or slice:
+for x in y.into_iter() {
+ // ..
+}
+```
+can be rewritten to
+```
+for x in y {
+ // ..
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/explicit_iter_loop.txt b/src/tools/clippy/src/docs/explicit_iter_loop.txt
new file mode 100644
index 000000000..cabe72e91
--- /dev/null
+++ b/src/tools/clippy/src/docs/explicit_iter_loop.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for loops on `x.iter()` where `&x` will do, and
+suggests the latter.
+
+### Why is this bad?
+Readability.
+
+### Known problems
+False negatives. We currently only warn on some known
+types.
+
+### Example
+```
+// with `y` a `Vec` or slice:
+for x in y.iter() {
+ // ..
+}
+```
+
+Use instead:
+```
+for x in &y {
+ // ..
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/explicit_write.txt b/src/tools/clippy/src/docs/explicit_write.txt
new file mode 100644
index 000000000..eafed5d39
--- /dev/null
+++ b/src/tools/clippy/src/docs/explicit_write.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for usage of `write!()` / `writeln()!` which can be
+replaced with `(e)print!()` / `(e)println!()`
+
+### Why is this bad?
+Using `(e)println! is clearer and more concise
+
+### Example
+```
+writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap();
+writeln!(&mut std::io::stdout(), "foo: {:?}", bar).unwrap();
+```
+
+Use instead:
+```
+eprintln!("foo: {:?}", bar);
+println!("foo: {:?}", bar);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/extend_with_drain.txt b/src/tools/clippy/src/docs/extend_with_drain.txt
new file mode 100644
index 000000000..2f31dcf5f
--- /dev/null
+++ b/src/tools/clippy/src/docs/extend_with_drain.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for occurrences where one vector gets extended instead of append
+
+### Why is this bad?
+Using `append` instead of `extend` is more concise and faster
+
+### Example
+```
+let mut a = vec![1, 2, 3];
+let mut b = vec![4, 5, 6];
+
+a.extend(b.drain(..));
+```
+
+Use instead:
+```
+let mut a = vec![1, 2, 3];
+let mut b = vec![4, 5, 6];
+
+a.append(&mut b);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/extra_unused_lifetimes.txt b/src/tools/clippy/src/docs/extra_unused_lifetimes.txt
new file mode 100644
index 000000000..bc1814aa4
--- /dev/null
+++ b/src/tools/clippy/src/docs/extra_unused_lifetimes.txt
@@ -0,0 +1,23 @@
+### 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
+```
+// unnecessary lifetimes
+fn unused_lifetime<'a>(x: u8) {
+ // ..
+}
+```
+
+Use instead:
+```
+fn no_lifetime(x: u8) {
+ // ...
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/fallible_impl_from.txt b/src/tools/clippy/src/docs/fallible_impl_from.txt
new file mode 100644
index 000000000..588a5bb10
--- /dev/null
+++ b/src/tools/clippy/src/docs/fallible_impl_from.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`
+
+### Why is this bad?
+`TryFrom` should be used if there's a possibility of failure.
+
+### Example
+```
+struct Foo(i32);
+
+impl From<String> for Foo {
+ fn from(s: String) -> Self {
+ Foo(s.parse().unwrap())
+ }
+}
+```
+
+Use instead:
+```
+struct Foo(i32);
+
+impl TryFrom<String> for Foo {
+ type Error = ();
+ fn try_from(s: String) -> Result<Self, Self::Error> {
+ if let Ok(parsed) = s.parse() {
+ Ok(Foo(parsed))
+ } else {
+ Err(())
+ }
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/field_reassign_with_default.txt b/src/tools/clippy/src/docs/field_reassign_with_default.txt
new file mode 100644
index 000000000..e58b7239f
--- /dev/null
+++ b/src/tools/clippy/src/docs/field_reassign_with_default.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for immediate reassignment of fields initialized
+with Default::default().
+
+### Why is this bad?
+It's more idiomatic to use the [functional update syntax](https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax).
+
+### Known problems
+Assignments to patterns that are of tuple type are not linted.
+
+### Example
+```
+let mut a: A = Default::default();
+a.i = 42;
+```
+
+Use instead:
+```
+let a = A {
+ i: 42,
+ .. Default::default()
+};
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/filetype_is_file.txt b/src/tools/clippy/src/docs/filetype_is_file.txt
new file mode 100644
index 000000000..ad14bd62c
--- /dev/null
+++ b/src/tools/clippy/src/docs/filetype_is_file.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for `FileType::is_file()`.
+
+### Why is this bad?
+When people testing a file type with `FileType::is_file`
+they are testing whether a path is something they can get bytes from. But
+`is_file` doesn't cover special file types in unix-like systems, and doesn't cover
+symlink in windows. Using `!FileType::is_dir()` is a better way to that intention.
+
+### Example
+```
+let metadata = std::fs::metadata("foo.txt")?;
+let filetype = metadata.file_type();
+
+if filetype.is_file() {
+ // read file
+}
+```
+
+should be written as:
+
+```
+let metadata = std::fs::metadata("foo.txt")?;
+let filetype = metadata.file_type();
+
+if !filetype.is_dir() {
+ // read file
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/filter_map_identity.txt b/src/tools/clippy/src/docs/filter_map_identity.txt
new file mode 100644
index 000000000..83b666f2e
--- /dev/null
+++ b/src/tools/clippy/src/docs/filter_map_identity.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for usage of `filter_map(|x| x)`.
+
+### Why is this bad?
+Readability, this can be written more concisely by using `flatten`.
+
+### Example
+```
+iter.filter_map(|x| x);
+```
+Use instead:
+```
+iter.flatten();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/filter_map_next.txt b/src/tools/clippy/src/docs/filter_map_next.txt
new file mode 100644
index 000000000..b38620b56
--- /dev/null
+++ b/src/tools/clippy/src/docs/filter_map_next.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `_.filter_map(_).next()`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.find_map(_)`.
+
+### Example
+```
+ (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next();
+```
+Can be written as
+
+```
+ (0..3).find_map(|x| if x == 2 { Some(x) } else { None });
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/filter_next.txt b/src/tools/clippy/src/docs/filter_next.txt
new file mode 100644
index 000000000..898a74166
--- /dev/null
+++ b/src/tools/clippy/src/docs/filter_next.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `_.filter(_).next()`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.find(_)`.
+
+### Example
+```
+vec.iter().filter(|x| **x == 0).next();
+```
+
+Use instead:
+```
+vec.iter().find(|x| **x == 0);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/flat_map_identity.txt b/src/tools/clippy/src/docs/flat_map_identity.txt
new file mode 100644
index 000000000..a5ee79b49
--- /dev/null
+++ b/src/tools/clippy/src/docs/flat_map_identity.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for usage of `flat_map(|x| x)`.
+
+### Why is this bad?
+Readability, this can be written more concisely by using `flatten`.
+
+### Example
+```
+iter.flat_map(|x| x);
+```
+Can be written as
+```
+iter.flatten();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/flat_map_option.txt b/src/tools/clippy/src/docs/flat_map_option.txt
new file mode 100644
index 000000000..d50b9156d
--- /dev/null
+++ b/src/tools/clippy/src/docs/flat_map_option.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usages of `Iterator::flat_map()` where `filter_map()` could be
+used instead.
+
+### Why is this bad?
+When applicable, `filter_map()` is more clear since it shows that
+`Option` is used to produce 0 or 1 items.
+
+### Example
+```
+let nums: Vec<i32> = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect();
+```
+Use instead:
+```
+let nums: Vec<i32> = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/float_arithmetic.txt b/src/tools/clippy/src/docs/float_arithmetic.txt
new file mode 100644
index 000000000..1f9bce5ab
--- /dev/null
+++ b/src/tools/clippy/src/docs/float_arithmetic.txt
@@ -0,0 +1,11 @@
+### What it does
+Checks for float arithmetic.
+
+### Why is this bad?
+For some embedded systems or kernel development, it
+can be useful to rule out floating-point numbers.
+
+### Example
+```
+a + 1.0;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/float_cmp.txt b/src/tools/clippy/src/docs/float_cmp.txt
new file mode 100644
index 000000000..c19907c90
--- /dev/null
+++ b/src/tools/clippy/src/docs/float_cmp.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for (in-)equality comparisons on floating-point
+values (apart from zero), except in functions called `*eq*` (which probably
+implement equality for a type involving floats).
+
+### Why is this bad?
+Floating point calculations are usually imprecise, so
+asking if two values are *exactly* equal is asking for trouble. For a good
+guide on what to do, see [the floating point
+guide](http://www.floating-point-gui.de/errors/comparison).
+
+### Example
+```
+let x = 1.2331f64;
+let y = 1.2332f64;
+
+if y == 1.23f64 { }
+if y != x {} // where both are floats
+```
+
+Use instead:
+```
+let error_margin = f64::EPSILON; // Use an epsilon for comparison
+// Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
+// let error_margin = std::f64::EPSILON;
+if (y - 1.23f64).abs() < error_margin { }
+if (y - x).abs() > error_margin { }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/float_cmp_const.txt b/src/tools/clippy/src/docs/float_cmp_const.txt
new file mode 100644
index 000000000..9208feaac
--- /dev/null
+++ b/src/tools/clippy/src/docs/float_cmp_const.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for (in-)equality comparisons on floating-point
+value and constant, except in functions called `*eq*` (which probably
+implement equality for a type involving floats).
+
+### Why is this bad?
+Floating point calculations are usually imprecise, so
+asking if two values are *exactly* equal is asking for trouble. For a good
+guide on what to do, see [the floating point
+guide](http://www.floating-point-gui.de/errors/comparison).
+
+### Example
+```
+let x: f64 = 1.0;
+const ONE: f64 = 1.00;
+
+if x == ONE { } // where both are floats
+```
+
+Use instead:
+```
+let error_margin = f64::EPSILON; // Use an epsilon for comparison
+// Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
+// let error_margin = std::f64::EPSILON;
+if (x - ONE).abs() < error_margin { }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/float_equality_without_abs.txt b/src/tools/clippy/src/docs/float_equality_without_abs.txt
new file mode 100644
index 000000000..556b574e1
--- /dev/null
+++ b/src/tools/clippy/src/docs/float_equality_without_abs.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for statements of the form `(a - b) < f32::EPSILON` or
+`(a - b) < f64::EPSILON`. Notes the missing `.abs()`.
+
+### Why is this bad?
+The code without `.abs()` is more likely to have a bug.
+
+### Known problems
+If the user can ensure that b is larger than a, the `.abs()` is
+technically unnecessary. However, it will make the code more robust and doesn't have any
+large performance implications. If the abs call was deliberately left out for performance
+reasons, it is probably better to state this explicitly in the code, which then can be done
+with an allow.
+
+### Example
+```
+pub fn is_roughly_equal(a: f32, b: f32) -> bool {
+ (a - b) < f32::EPSILON
+}
+```
+Use instead:
+```
+pub fn is_roughly_equal(a: f32, b: f32) -> bool {
+ (a - b).abs() < f32::EPSILON
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/fn_address_comparisons.txt b/src/tools/clippy/src/docs/fn_address_comparisons.txt
new file mode 100644
index 000000000..7d2b7b681
--- /dev/null
+++ b/src/tools/clippy/src/docs/fn_address_comparisons.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for comparisons with an address of a function item.
+
+### Why is this bad?
+Function item address is not guaranteed to be unique and could vary
+between different code generation units. Furthermore different function items could have
+the same address after being merged together.
+
+### Example
+```
+type F = fn();
+fn a() {}
+let f: F = a;
+if f == a {
+ // ...
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/fn_params_excessive_bools.txt b/src/tools/clippy/src/docs/fn_params_excessive_bools.txt
new file mode 100644
index 000000000..2eae05633
--- /dev/null
+++ b/src/tools/clippy/src/docs/fn_params_excessive_bools.txt
@@ -0,0 +1,31 @@
+### What it does
+Checks for excessive use of
+bools in function definitions.
+
+### Why is this bad?
+Calls to such functions
+are confusing and error prone, because it's
+hard to remember argument order and you have
+no type system support to back you up. Using
+two-variant enums instead of bools often makes
+API easier to use.
+
+### Example
+```
+fn f(is_round: bool, is_hot: bool) { ... }
+```
+
+Use instead:
+```
+enum Shape {
+ Round,
+ Spiky,
+}
+
+enum Temperature {
+ Hot,
+ IceCold,
+}
+
+fn f(shape: Shape, temperature: Temperature) { ... }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/fn_to_numeric_cast.txt b/src/tools/clippy/src/docs/fn_to_numeric_cast.txt
new file mode 100644
index 000000000..1f587f6d7
--- /dev/null
+++ b/src/tools/clippy/src/docs/fn_to_numeric_cast.txt
@@ -0,0 +1,21 @@
+### 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
+```
+fn fun() -> i32 { 1 }
+let _ = fun as i64;
+```
+
+Use instead:
+```
+let _ = fun as usize;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/fn_to_numeric_cast_any.txt b/src/tools/clippy/src/docs/fn_to_numeric_cast_any.txt
new file mode 100644
index 000000000..ee3c33d23
--- /dev/null
+++ b/src/tools/clippy/src/docs/fn_to_numeric_cast_any.txt
@@ -0,0 +1,35 @@
+### 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 parentheses 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
+```
+// fn1 is cast as `usize`
+fn fn1() -> u16 {
+ 1
+};
+let _ = fn1 as usize;
+```
+
+Use instead:
+```
+// maybe you intended to call the function?
+fn fn2() -> u16 {
+ 1
+};
+let _ = fn2() as usize;
+
+// or
+
+// maybe you intended to cast it to a function type?
+fn fn3() -> u16 {
+ 1
+}
+let _ = fn3 as fn() -> u16;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/fn_to_numeric_cast_with_truncation.txt b/src/tools/clippy/src/docs/fn_to_numeric_cast_with_truncation.txt
new file mode 100644
index 000000000..69f12fa31
--- /dev/null
+++ b/src/tools/clippy/src/docs/fn_to_numeric_cast_with_truncation.txt
@@ -0,0 +1,26 @@
+### 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
+```
+fn fn1() -> i16 {
+ 1
+};
+let _ = fn1 as i32;
+```
+
+Use instead:
+```
+// Cast to usize first, then comment with the reason for the truncation
+fn fn1() -> i16 {
+ 1
+};
+let fn_ptr = fn1 as usize;
+let fn_ptr_truncated = fn_ptr as i32;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/for_kv_map.txt b/src/tools/clippy/src/docs/for_kv_map.txt
new file mode 100644
index 000000000..a9a2ffee9
--- /dev/null
+++ b/src/tools/clippy/src/docs/for_kv_map.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for iterating a map (`HashMap` or `BTreeMap`) and
+ignoring either the keys or values.
+
+### Why is this bad?
+Readability. There are `keys` and `values` methods that
+can be used to express that don't need the values or keys.
+
+### Example
+```
+for (k, _) in &map {
+ ..
+}
+```
+
+could be replaced by
+
+```
+for k in map.keys() {
+ ..
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/forget_copy.txt b/src/tools/clippy/src/docs/forget_copy.txt
new file mode 100644
index 000000000..1d100912e
--- /dev/null
+++ b/src/tools/clippy/src/docs/forget_copy.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for calls to `std::mem::forget` with a value that
+derives the Copy trait
+
+### Why is this bad?
+Calling `std::mem::forget` [does nothing for types that
+implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the
+value will be copied and moved into the function on invocation.
+
+An alternative, but also valid, explanation is that Copy types do not
+implement
+the Drop trait, which means they have no destructors. Without a destructor,
+there
+is nothing for `std::mem::forget` to ignore.
+
+### Example
+```
+let x: i32 = 42; // i32 implements Copy
+std::mem::forget(x) // A copy of x is passed to the function, leaving the
+ // original unaffected
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/forget_non_drop.txt b/src/tools/clippy/src/docs/forget_non_drop.txt
new file mode 100644
index 000000000..3307d654c
--- /dev/null
+++ b/src/tools/clippy/src/docs/forget_non_drop.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for calls to `std::mem::forget` with a value that does not implement `Drop`.
+
+### Why is this bad?
+Calling `std::mem::forget` is no different than dropping such a type. A different value may
+have been intended.
+
+### Example
+```
+struct Foo;
+let x = Foo;
+std::mem::forget(x);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/forget_ref.txt b/src/tools/clippy/src/docs/forget_ref.txt
new file mode 100644
index 000000000..874fb8786
--- /dev/null
+++ b/src/tools/clippy/src/docs/forget_ref.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for calls to `std::mem::forget` with a reference
+instead of an owned value.
+
+### Why is this bad?
+Calling `forget` on a reference will only forget the
+reference itself, which is a no-op. It will not forget the underlying
+referenced
+value, which is likely what was intended.
+
+### Example
+```
+let x = Box::new(1);
+std::mem::forget(&x) // Should have been forget(x), x will still be dropped
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/format_in_format_args.txt b/src/tools/clippy/src/docs/format_in_format_args.txt
new file mode 100644
index 000000000..ac498472f
--- /dev/null
+++ b/src/tools/clippy/src/docs/format_in_format_args.txt
@@ -0,0 +1,16 @@
+### What it does
+Detects `format!` within the arguments of another macro that does
+formatting such as `format!` itself, `write!` or `println!`. Suggests
+inlining the `format!` call.
+
+### Why is this bad?
+The recommended code is both shorter and avoids a temporary allocation.
+
+### Example
+```
+println!("error: {}", format!("something failed at {}", Location::caller()));
+```
+Use instead:
+```
+println!("error: something failed at {}", Location::caller());
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/format_push_string.txt b/src/tools/clippy/src/docs/format_push_string.txt
new file mode 100644
index 000000000..ca409ebc7
--- /dev/null
+++ b/src/tools/clippy/src/docs/format_push_string.txt
@@ -0,0 +1,26 @@
+### What it does
+Detects cases where the result of a `format!` call is
+appended to an existing `String`.
+
+### Why is this bad?
+Introduces an extra, avoidable heap allocation.
+
+### Known problems
+`format!` returns a `String` but `write!` returns a `Result`.
+Thus you are forced to ignore the `Err` variant to achieve the same API.
+
+While using `write!` in the suggested way should never fail, this isn't necessarily clear to the programmer.
+
+### Example
+```
+let mut s = String::new();
+s += &format!("0x{:X}", 1024);
+s.push_str(&format!("0x{:X}", 1024));
+```
+Use instead:
+```
+use std::fmt::Write as _; // import without risk of name clashing
+
+let mut s = String::new();
+let _ = write!(s, "0x{:X}", 1024);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/from_iter_instead_of_collect.txt b/src/tools/clippy/src/docs/from_iter_instead_of_collect.txt
new file mode 100644
index 000000000..f3fd27597
--- /dev/null
+++ b/src/tools/clippy/src/docs/from_iter_instead_of_collect.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for `from_iter()` function calls on types that implement the `FromIterator`
+trait.
+
+### Why is this bad?
+It is recommended style to use collect. See
+[FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)
+
+### Example
+```
+let five_fives = std::iter::repeat(5).take(5);
+
+let v = Vec::from_iter(five_fives);
+
+assert_eq!(v, vec![5, 5, 5, 5, 5]);
+```
+Use instead:
+```
+let five_fives = std::iter::repeat(5).take(5);
+
+let v: Vec<i32> = five_fives.collect();
+
+assert_eq!(v, vec![5, 5, 5, 5, 5]);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/from_over_into.txt b/src/tools/clippy/src/docs/from_over_into.txt
new file mode 100644
index 000000000..0770bcc42
--- /dev/null
+++ b/src/tools/clippy/src/docs/from_over_into.txt
@@ -0,0 +1,26 @@
+### What it does
+Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead.
+
+### Why is this bad?
+According the std docs implementing `From<..>` is preferred since it gives you `Into<..>` for free where the reverse isn't true.
+
+### Example
+```
+struct StringWrapper(String);
+
+impl Into<StringWrapper> for String {
+ fn into(self) -> StringWrapper {
+ StringWrapper(self)
+ }
+}
+```
+Use instead:
+```
+struct StringWrapper(String);
+
+impl From<String> for StringWrapper {
+ fn from(s: String) -> StringWrapper {
+ StringWrapper(s)
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/from_str_radix_10.txt b/src/tools/clippy/src/docs/from_str_radix_10.txt
new file mode 100644
index 000000000..f6f319d3e
--- /dev/null
+++ b/src/tools/clippy/src/docs/from_str_radix_10.txt
@@ -0,0 +1,25 @@
+### What it does
+
+Checks for function invocations of the form `primitive::from_str_radix(s, 10)`
+
+### Why is this bad?
+
+This specific common use case can be rewritten as `s.parse::<primitive>()`
+(and in most cases, the turbofish can be removed), which reduces code length
+and complexity.
+
+### Known problems
+
+This lint may suggest using (&<expression>).parse() instead of <expression>.parse() directly
+in some cases, which is correct but adds unnecessary complexity to the code.
+
+### Example
+```
+let input: &str = get_input();
+let num = u16::from_str_radix(input, 10)?;
+```
+Use instead:
+```
+let input: &str = get_input();
+let num: u16 = input.parse()?;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/future_not_send.txt b/src/tools/clippy/src/docs/future_not_send.txt
new file mode 100644
index 000000000..0aa048d27
--- /dev/null
+++ b/src/tools/clippy/src/docs/future_not_send.txt
@@ -0,0 +1,29 @@
+### What it does
+This lint requires Future implementations returned from
+functions and methods to implement the `Send` marker trait. It is mostly
+used by library authors (public and internal) that target an audience where
+multithreaded executors are likely to be used for running these Futures.
+
+### Why is this bad?
+A Future implementation captures some state that it
+needs to eventually produce its final value. When targeting a multithreaded
+executor (which is the norm on non-embedded devices) this means that this
+state may need to be transported to other threads, in other words the
+whole Future needs to implement the `Send` marker trait. If it does not,
+then the resulting Future cannot be submitted to a thread pool in the
+end user’s code.
+
+Especially for generic functions it can be confusing to leave the
+discovery of this problem to the end user: the reported error location
+will be far from its cause and can in many cases not even be fixed without
+modifying the library where the offending Future implementation is
+produced.
+
+### Example
+```
+async fn not_send(bytes: std::rc::Rc<[u8]>) {}
+```
+Use instead:
+```
+async fn is_send(bytes: std::sync::Arc<[u8]>) {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/get_first.txt b/src/tools/clippy/src/docs/get_first.txt
new file mode 100644
index 000000000..c905a737d
--- /dev/null
+++ b/src/tools/clippy/src/docs/get_first.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for using `x.get(0)` instead of
+`x.first()`.
+
+### Why is this bad?
+Using `x.first()` is easier to read and has the same
+result.
+
+### Example
+```
+let x = vec![2, 3, 5];
+let first_element = x.get(0);
+```
+
+Use instead:
+```
+let x = vec![2, 3, 5];
+let first_element = x.first();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/get_last_with_len.txt b/src/tools/clippy/src/docs/get_last_with_len.txt
new file mode 100644
index 000000000..31c7f2695
--- /dev/null
+++ b/src/tools/clippy/src/docs/get_last_with_len.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for using `x.get(x.len() - 1)` instead of
+`x.last()`.
+
+### Why is this bad?
+Using `x.last()` is easier to read and has the same
+result.
+
+Note that using `x[x.len() - 1]` is semantically different from
+`x.last()`. Indexing into the array will panic on out-of-bounds
+accesses, while `x.get()` and `x.last()` will return `None`.
+
+There is another lint (get_unwrap) that covers the case of using
+`x.get(index).unwrap()` instead of `x[index]`.
+
+### Example
+```
+let x = vec![2, 3, 5];
+let last_element = x.get(x.len() - 1);
+```
+
+Use instead:
+```
+let x = vec![2, 3, 5];
+let last_element = x.last();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/get_unwrap.txt b/src/tools/clippy/src/docs/get_unwrap.txt
new file mode 100644
index 000000000..8defc2224
--- /dev/null
+++ b/src/tools/clippy/src/docs/get_unwrap.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for use of `.get().unwrap()` (or
+`.get_mut().unwrap`) on a standard library type which implements `Index`
+
+### Why is this bad?
+Using the Index trait (`[]`) is more clear and more
+concise.
+
+### Known problems
+Not a replacement for error handling: Using either
+`.unwrap()` or the Index trait (`[]`) carries the risk of causing a `panic`
+if the value being accessed is `None`. If the use of `.get().unwrap()` is a
+temporary placeholder for dealing with the `Option` type, then this does
+not mitigate the need for error handling. If there is a chance that `.get()`
+will be `None` in your program, then it is advisable that the `None` case
+is handled in a future refactor instead of using `.unwrap()` or the Index
+trait.
+
+### Example
+```
+let mut some_vec = vec![0, 1, 2, 3];
+let last = some_vec.get(3).unwrap();
+*some_vec.get_mut(0).unwrap() = 1;
+```
+The correct use would be:
+```
+let mut some_vec = vec![0, 1, 2, 3];
+let last = some_vec[3];
+some_vec[0] = 1;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/identity_op.txt b/src/tools/clippy/src/docs/identity_op.txt
new file mode 100644
index 000000000..a8e40bb43
--- /dev/null
+++ b/src/tools/clippy/src/docs/identity_op.txt
@@ -0,0 +1,11 @@
+### What it does
+Checks for identity operations, e.g., `x + 0`.
+
+### Why is this bad?
+This code can be removed without changing the
+meaning. So it just obscures what's going on. Delete it mercilessly.
+
+### Example
+```
+x / 1 + 0 * 1 - 0 | 0;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/if_let_mutex.txt b/src/tools/clippy/src/docs/if_let_mutex.txt
new file mode 100644
index 000000000..4d873ade9
--- /dev/null
+++ b/src/tools/clippy/src/docs/if_let_mutex.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for `Mutex::lock` calls in `if let` expression
+with lock calls in any of the else blocks.
+
+### Why is this bad?
+The Mutex lock remains held for the whole
+`if let ... else` block and deadlocks.
+
+### Example
+```
+if let Ok(thing) = mutex.lock() {
+ do_thing();
+} else {
+ mutex.lock();
+}
+```
+Should be written
+```
+let locked = mutex.lock();
+if let Ok(thing) = locked {
+ do_thing(thing);
+} else {
+ use_locked(locked);
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/if_not_else.txt b/src/tools/clippy/src/docs/if_not_else.txt
new file mode 100644
index 000000000..0e5ac4ce6
--- /dev/null
+++ b/src/tools/clippy/src/docs/if_not_else.txt
@@ -0,0 +1,25 @@
+### 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
+```
+if !v.is_empty() {
+ a()
+} else {
+ b()
+}
+```
+
+Could be written:
+
+```
+if v.is_empty() {
+ b()
+} else {
+ a()
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/if_same_then_else.txt b/src/tools/clippy/src/docs/if_same_then_else.txt
new file mode 100644
index 000000000..75127016b
--- /dev/null
+++ b/src/tools/clippy/src/docs/if_same_then_else.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for `if/else` with the same body as the *then* part
+and the *else* part.
+
+### Why is this bad?
+This is probably a copy & paste error.
+
+### Example
+```
+let foo = if … {
+ 42
+} else {
+ 42
+};
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/if_then_some_else_none.txt b/src/tools/clippy/src/docs/if_then_some_else_none.txt
new file mode 100644
index 000000000..13744f920
--- /dev/null
+++ b/src/tools/clippy/src/docs/if_then_some_else_none.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for if-else that could be written using either `bool::then` or `bool::then_some`.
+
+### Why is this bad?
+Looks a little redundant. Using `bool::then` is more concise and incurs no loss of clarity.
+For simple calculations and known values, use `bool::then_some`, which is eagerly evaluated
+in comparison to `bool::then`.
+
+### Example
+```
+let a = if v.is_empty() {
+ println!("true!");
+ Some(42)
+} else {
+ None
+};
+```
+
+Could be written:
+
+```
+let a = v.is_empty().then(|| {
+ println!("true!");
+ 42
+});
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ifs_same_cond.txt b/src/tools/clippy/src/docs/ifs_same_cond.txt
new file mode 100644
index 000000000..024ba5df9
--- /dev/null
+++ b/src/tools/clippy/src/docs/ifs_same_cond.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for consecutive `if`s with the same condition.
+
+### Why is this bad?
+This is probably a copy & paste error.
+
+### Example
+```
+if a == b {
+ …
+} else if a == b {
+ …
+}
+```
+
+Note that this lint ignores all conditions with a function call as it could
+have side effects:
+
+```
+if foo() {
+ …
+} else if foo() { // not linted
+ …
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/implicit_clone.txt b/src/tools/clippy/src/docs/implicit_clone.txt
new file mode 100644
index 000000000..f5aa112c5
--- /dev/null
+++ b/src/tools/clippy/src/docs/implicit_clone.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer.
+
+### Why is this bad?
+These methods do the same thing as `_.clone()` but may be confusing as
+to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned.
+
+### Example
+```
+let a = vec![1, 2, 3];
+let b = a.to_vec();
+let c = a.to_owned();
+```
+Use instead:
+```
+let a = vec![1, 2, 3];
+let b = a.clone();
+let c = a.clone();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/implicit_hasher.txt b/src/tools/clippy/src/docs/implicit_hasher.txt
new file mode 100644
index 000000000..0c1f76620
--- /dev/null
+++ b/src/tools/clippy/src/docs/implicit_hasher.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for public `impl` or `fn` missing generalization
+over different hashers and implicitly defaulting to the default hashing
+algorithm (`SipHash`).
+
+### Why is this bad?
+`HashMap` or `HashSet` with custom hashers cannot be
+used with them.
+
+### Known problems
+Suggestions for replacing constructors can contain
+false-positives. Also applying suggestions can require modification of other
+pieces of code, possibly including external crates.
+
+### Example
+```
+impl<K: Hash + Eq, V> Serialize for HashMap<K, V> { }
+
+pub fn foo(map: &mut HashMap<i32, i32>) { }
+```
+could be rewritten as
+```
+impl<K: Hash + Eq, V, S: BuildHasher> Serialize for HashMap<K, V, S> { }
+
+pub fn foo<S: BuildHasher>(map: &mut HashMap<i32, i32, S>) { }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/implicit_return.txt b/src/tools/clippy/src/docs/implicit_return.txt
new file mode 100644
index 000000000..ee65a636b
--- /dev/null
+++ b/src/tools/clippy/src/docs/implicit_return.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for missing return statements at the end of a block.
+
+### Why is this bad?
+Actually omitting the return keyword is idiomatic Rust code. Programmers
+coming from other languages might prefer the expressiveness of `return`. It's possible to miss
+the last returning statement because the only difference is a missing `;`. Especially in bigger
+code with multiple return paths having a `return` keyword makes it easier to find the
+corresponding statements.
+
+### Example
+```
+fn foo(x: usize) -> usize {
+ x
+}
+```
+add return
+```
+fn foo(x: usize) -> usize {
+ return x;
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/implicit_saturating_add.txt b/src/tools/clippy/src/docs/implicit_saturating_add.txt
new file mode 100644
index 000000000..5883a5363
--- /dev/null
+++ b/src/tools/clippy/src/docs/implicit_saturating_add.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for implicit saturating addition.
+
+### Why is this bad?
+The built-in function is more readable and may be faster.
+
+### Example
+```
+let mut u:u32 = 7000;
+
+if u != u32::MAX {
+ u += 1;
+}
+```
+Use instead:
+```
+let mut u:u32 = 7000;
+
+u = u.saturating_add(1);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/implicit_saturating_sub.txt b/src/tools/clippy/src/docs/implicit_saturating_sub.txt
new file mode 100644
index 000000000..03b47905a
--- /dev/null
+++ b/src/tools/clippy/src/docs/implicit_saturating_sub.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for implicit saturating subtraction.
+
+### Why is this bad?
+Simplicity and readability. Instead we can easily use an builtin function.
+
+### Example
+```
+let mut i: u32 = end - start;
+
+if i != 0 {
+ i -= 1;
+}
+```
+
+Use instead:
+```
+let mut i: u32 = end - start;
+
+i = i.saturating_sub(1);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/imprecise_flops.txt b/src/tools/clippy/src/docs/imprecise_flops.txt
new file mode 100644
index 000000000..e84d81cea
--- /dev/null
+++ b/src/tools/clippy/src/docs/imprecise_flops.txt
@@ -0,0 +1,23 @@
+### What it does
+Looks for floating-point expressions that
+can be expressed using built-in methods to improve accuracy
+at the cost of performance.
+
+### Why is this bad?
+Negatively impacts accuracy.
+
+### Example
+```
+let a = 3f32;
+let _ = a.powf(1.0 / 3.0);
+let _ = (1.0 + a).ln();
+let _ = a.exp() - 1.0;
+```
+
+Use instead:
+```
+let a = 3f32;
+let _ = a.cbrt();
+let _ = a.ln_1p();
+let _ = a.exp_m1();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inconsistent_digit_grouping.txt b/src/tools/clippy/src/docs/inconsistent_digit_grouping.txt
new file mode 100644
index 000000000..aa0b072de
--- /dev/null
+++ b/src/tools/clippy/src/docs/inconsistent_digit_grouping.txt
@@ -0,0 +1,17 @@
+### What it does
+Warns if an integral or floating-point constant is
+grouped inconsistently with underscores.
+
+### Why is this bad?
+Readers may incorrectly interpret inconsistently
+grouped digits.
+
+### Example
+```
+618_64_9189_73_511
+```
+
+Use instead:
+```
+61_864_918_973_511
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inconsistent_struct_constructor.txt b/src/tools/clippy/src/docs/inconsistent_struct_constructor.txt
new file mode 100644
index 000000000..eb682109a
--- /dev/null
+++ b/src/tools/clippy/src/docs/inconsistent_struct_constructor.txt
@@ -0,0 +1,40 @@
+### What it does
+Checks for struct constructors where all fields are shorthand and
+the order of the field init shorthand in the constructor is inconsistent
+with the order in the struct definition.
+
+### Why is this bad?
+Since the order of fields in a constructor doesn't affect the
+resulted instance as the below example indicates,
+
+```
+#[derive(Debug, PartialEq, Eq)]
+struct Foo {
+ x: i32,
+ y: i32,
+}
+let x = 1;
+let y = 2;
+
+// This assertion never fails:
+assert_eq!(Foo { x, y }, Foo { y, x });
+```
+
+inconsistent order can be confusing and decreases readability and consistency.
+
+### Example
+```
+struct Foo {
+ x: i32,
+ y: i32,
+}
+let x = 1;
+let y = 2;
+
+Foo { y, x };
+```
+
+Use instead:
+```
+Foo { x, y };
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/index_refutable_slice.txt b/src/tools/clippy/src/docs/index_refutable_slice.txt
new file mode 100644
index 000000000..8a7d52761
--- /dev/null
+++ b/src/tools/clippy/src/docs/index_refutable_slice.txt
@@ -0,0 +1,29 @@
+### What it does
+The lint checks for slice bindings in patterns that are only used to
+access individual slice values.
+
+### Why is this bad?
+Accessing slice values using indices can lead to panics. Using refutable
+patterns can avoid these. Binding to individual values also improves the
+readability as they can be named.
+
+### Limitations
+This lint currently only checks for immutable access inside `if let`
+patterns.
+
+### Example
+```
+let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+
+if let Some(slice) = slice {
+ println!("{}", slice[0]);
+}
+```
+Use instead:
+```
+let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+
+if let Some(&[first, ..]) = slice {
+ println!("{}", first);
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/indexing_slicing.txt b/src/tools/clippy/src/docs/indexing_slicing.txt
new file mode 100644
index 000000000..76ca6ed31
--- /dev/null
+++ b/src/tools/clippy/src/docs/indexing_slicing.txt
@@ -0,0 +1,33 @@
+### What it does
+Checks for usage of indexing or slicing. Arrays are special cases, this lint
+does report on arrays if we can tell that slicing operations are in bounds and does not
+lint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint.
+
+### Why is this bad?
+Indexing and slicing can panic at runtime and there are
+safe alternatives.
+
+### Example
+```
+// Vector
+let x = vec![0; 5];
+
+x[2];
+&x[2..100];
+
+// Array
+let y = [0, 1, 2, 3];
+
+&y[10..100];
+&y[10..];
+```
+
+Use instead:
+```
+
+x.get(2);
+x.get(2..100);
+
+y.get(10);
+y.get(10..100);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ineffective_bit_mask.txt b/src/tools/clippy/src/docs/ineffective_bit_mask.txt
new file mode 100644
index 000000000..f6e7ef556
--- /dev/null
+++ b/src/tools/clippy/src/docs/ineffective_bit_mask.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for bit masks in comparisons which can be removed
+without changing the outcome. The basic structure can be seen in the
+following table:
+
+|Comparison| Bit Op |Example |equals |
+|----------|----------|------------|-------|
+|`>` / `<=`|`\|` / `^`|`x \| 2 > 3`|`x > 3`|
+|`<` / `>=`|`\|` / `^`|`x ^ 1 < 4` |`x < 4`|
+
+### Why is this bad?
+Not equally evil as [`bad_bit_mask`](#bad_bit_mask),
+but still a bit misleading, because the bit mask is ineffective.
+
+### Known problems
+False negatives: This lint will only match instances
+where we have figured out the math (which is for a power-of-two compared
+value). This means things like `x | 1 >= 7` (which would be better written
+as `x >= 6`) will not be reported (but bit masks like this are fairly
+uncommon).
+
+### Example
+```
+if (x | 1 > 3) { }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inefficient_to_string.txt b/src/tools/clippy/src/docs/inefficient_to_string.txt
new file mode 100644
index 000000000..f7061d1ce
--- /dev/null
+++ b/src/tools/clippy/src/docs/inefficient_to_string.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for usage of `.to_string()` on an `&&T` where
+`T` implements `ToString` directly (like `&&str` or `&&String`).
+
+### Why is this bad?
+This bypasses the specialized implementation of
+`ToString` and instead goes through the more expensive string formatting
+facilities.
+
+### Example
+```
+// Generic implementation for `T: Display` is used (slow)
+["foo", "bar"].iter().map(|s| s.to_string());
+
+// OK, the specialized impl is used
+["foo", "bar"].iter().map(|&s| s.to_string());
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/infallible_destructuring_match.txt b/src/tools/clippy/src/docs/infallible_destructuring_match.txt
new file mode 100644
index 000000000..4b5d3c4ba
--- /dev/null
+++ b/src/tools/clippy/src/docs/infallible_destructuring_match.txt
@@ -0,0 +1,29 @@
+### 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
+```
+enum Wrapper {
+ Data(i32),
+}
+
+let wrapper = Wrapper::Data(42);
+
+let data = match wrapper {
+ Wrapper::Data(i) => i,
+};
+```
+
+The correct use would be:
+```
+enum Wrapper {
+ Data(i32),
+}
+
+let wrapper = Wrapper::Data(42);
+let Wrapper::Data(data) = wrapper;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/infinite_iter.txt b/src/tools/clippy/src/docs/infinite_iter.txt
new file mode 100644
index 000000000..8a22fabc5
--- /dev/null
+++ b/src/tools/clippy/src/docs/infinite_iter.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for iteration that is guaranteed to be infinite.
+
+### Why is this bad?
+While there may be places where this is acceptable
+(e.g., in event streams), in most cases this is simply an error.
+
+### Example
+```
+use std::iter;
+
+iter::repeat(1_u8).collect::<Vec<_>>();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inherent_to_string.txt b/src/tools/clippy/src/docs/inherent_to_string.txt
new file mode 100644
index 000000000..b18e600e9
--- /dev/null
+++ b/src/tools/clippy/src/docs/inherent_to_string.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`.
+
+### Why is this bad?
+This method is also implicitly defined if a type implements the `Display` trait. As the functionality of `Display` is much more versatile, it should be preferred.
+
+### Example
+```
+pub struct A;
+
+impl A {
+ pub fn to_string(&self) -> String {
+ "I am A".to_string()
+ }
+}
+```
+
+Use instead:
+```
+use std::fmt;
+
+pub struct A;
+
+impl fmt::Display for A {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "I am A")
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inherent_to_string_shadow_display.txt b/src/tools/clippy/src/docs/inherent_to_string_shadow_display.txt
new file mode 100644
index 000000000..a4bd0b622
--- /dev/null
+++ b/src/tools/clippy/src/docs/inherent_to_string_shadow_display.txt
@@ -0,0 +1,37 @@
+### What it does
+Checks for the definition of inherent methods with a signature of `to_string(&self) -> String` and if the type implementing this method also implements the `Display` trait.
+
+### Why is this bad?
+This method is also implicitly defined if a type implements the `Display` trait. The less versatile inherent method will then shadow the implementation introduced by `Display`.
+
+### Example
+```
+use std::fmt;
+
+pub struct A;
+
+impl A {
+ pub fn to_string(&self) -> String {
+ "I am A".to_string()
+ }
+}
+
+impl fmt::Display for A {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "I am A, too")
+ }
+}
+```
+
+Use instead:
+```
+use std::fmt;
+
+pub struct A;
+
+impl fmt::Display for A {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "I am A")
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/init_numbered_fields.txt b/src/tools/clippy/src/docs/init_numbered_fields.txt
new file mode 100644
index 000000000..ba40af6a5
--- /dev/null
+++ b/src/tools/clippy/src/docs/init_numbered_fields.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for tuple structs initialized with field syntax.
+It will however not lint if a base initializer is present.
+The lint will also ignore code in macros.
+
+### Why is this bad?
+This may be confusing to the uninitiated and adds no
+benefit as opposed to tuple initializers
+
+### Example
+```
+struct TupleStruct(u8, u16);
+
+let _ = TupleStruct {
+ 0: 1,
+ 1: 23,
+};
+
+// should be written as
+let base = TupleStruct(1, 23);
+
+// This is OK however
+let _ = TupleStruct { 0: 42, ..base };
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inline_always.txt b/src/tools/clippy/src/docs/inline_always.txt
new file mode 100644
index 000000000..7721da4c4
--- /dev/null
+++ b/src/tools/clippy/src/docs/inline_always.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for items annotated with `#[inline(always)]`,
+unless the annotated function is empty or simply panics.
+
+### Why is this bad?
+While there are valid uses of this annotation (and once
+you know when to use it, by all means `allow` this lint), it's a common
+newbie-mistake to pepper one's code with it.
+
+As a rule of thumb, before slapping `#[inline(always)]` on a function,
+measure if that additional function call really affects your runtime profile
+sufficiently to make up for the increase in compile time.
+
+### Known problems
+False positives, big time. This lint is meant to be
+deactivated by everyone doing serious performance work. This means having
+done the measurement.
+
+### Example
+```
+#[inline(always)]
+fn not_quite_hot_code(..) { ... }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inline_asm_x86_att_syntax.txt b/src/tools/clippy/src/docs/inline_asm_x86_att_syntax.txt
new file mode 100644
index 000000000..8eb49d122
--- /dev/null
+++ b/src/tools/clippy/src/docs/inline_asm_x86_att_syntax.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of AT&T x86 assembly syntax.
+
+### Why is this bad?
+The lint has been enabled to indicate a preference
+for Intel x86 assembly syntax.
+
+### Example
+
+```
+asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
+```
+Use instead:
+```
+asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inline_asm_x86_intel_syntax.txt b/src/tools/clippy/src/docs/inline_asm_x86_intel_syntax.txt
new file mode 100644
index 000000000..5aa22c8ed
--- /dev/null
+++ b/src/tools/clippy/src/docs/inline_asm_x86_intel_syntax.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of Intel x86 assembly syntax.
+
+### Why is this bad?
+The lint has been enabled to indicate a preference
+for AT&T x86 assembly syntax.
+
+### Example
+
+```
+asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
+```
+Use instead:
+```
+asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inline_fn_without_body.txt b/src/tools/clippy/src/docs/inline_fn_without_body.txt
new file mode 100644
index 000000000..127c161aa
--- /dev/null
+++ b/src/tools/clippy/src/docs/inline_fn_without_body.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for `#[inline]` on trait methods without bodies
+
+### Why is this bad?
+Only implementations of trait methods may be inlined.
+The inline attribute is ignored for trait methods without bodies.
+
+### Example
+```
+trait Animal {
+ #[inline]
+ fn name(&self) -> &'static str;
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/inspect_for_each.txt b/src/tools/clippy/src/docs/inspect_for_each.txt
new file mode 100644
index 000000000..01a46d6c4
--- /dev/null
+++ b/src/tools/clippy/src/docs/inspect_for_each.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for usage of `inspect().for_each()`.
+
+### Why is this bad?
+It is the same as performing the computation
+inside `inspect` at the beginning of the closure in `for_each`.
+
+### Example
+```
+[1,2,3,4,5].iter()
+.inspect(|&x| println!("inspect the number: {}", x))
+.for_each(|&x| {
+ assert!(x >= 0);
+});
+```
+Can be written as
+```
+[1,2,3,4,5].iter()
+.for_each(|&x| {
+ println!("inspect the number: {}", x);
+ assert!(x >= 0);
+});
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/int_plus_one.txt b/src/tools/clippy/src/docs/int_plus_one.txt
new file mode 100644
index 000000000..1b68f3eeb
--- /dev/null
+++ b/src/tools/clippy/src/docs/int_plus_one.txt
@@ -0,0 +1,15 @@
+### 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
+```
+if x >= y + 1 {}
+```
+
+Use instead:
+```
+if x > y {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/integer_arithmetic.txt b/src/tools/clippy/src/docs/integer_arithmetic.txt
new file mode 100644
index 000000000..ea57a2ef9
--- /dev/null
+++ b/src/tools/clippy/src/docs/integer_arithmetic.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for integer arithmetic operations which could overflow or panic.
+
+Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable
+of overflowing according to the [Rust
+Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
+or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is
+attempted.
+
+### Why is this bad?
+Integer overflow will trigger a panic in debug builds or will wrap in
+release mode. Division by zero will cause a panic in either mode. In some applications one
+wants explicitly checked, wrapping or saturating arithmetic.
+
+### Example
+```
+a + 1;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/integer_division.txt b/src/tools/clippy/src/docs/integer_division.txt
new file mode 100644
index 000000000..f6d334981
--- /dev/null
+++ b/src/tools/clippy/src/docs/integer_division.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for division of integers
+
+### Why is this bad?
+When outside of some very specific algorithms,
+integer division is very often a mistake because it discards the
+remainder.
+
+### Example
+```
+let x = 3 / 2;
+println!("{}", x);
+```
+
+Use instead:
+```
+let x = 3f32 / 2f32;
+println!("{}", x);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/into_iter_on_ref.txt b/src/tools/clippy/src/docs/into_iter_on_ref.txt
new file mode 100644
index 000000000..acb6bd474
--- /dev/null
+++ b/src/tools/clippy/src/docs/into_iter_on_ref.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for `into_iter` calls on references which should be replaced by `iter`
+or `iter_mut`.
+
+### Why is this bad?
+Readability. Calling `into_iter` on a reference will not move out its
+content into the resulting iterator, which is confusing. It is better just call `iter` or
+`iter_mut` directly.
+
+### Example
+```
+(&vec).into_iter();
+```
+
+Use instead:
+```
+(&vec).iter();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/invalid_null_ptr_usage.txt b/src/tools/clippy/src/docs/invalid_null_ptr_usage.txt
new file mode 100644
index 000000000..6fb3fa3f8
--- /dev/null
+++ b/src/tools/clippy/src/docs/invalid_null_ptr_usage.txt
@@ -0,0 +1,16 @@
+### What it does
+This lint checks for invalid usages of `ptr::null`.
+
+### Why is this bad?
+This causes undefined behavior.
+
+### Example
+```
+// Undefined behavior
+unsafe { std::slice::from_raw_parts(ptr::null(), 0); }
+```
+
+Use instead:
+```
+unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/invalid_regex.txt b/src/tools/clippy/src/docs/invalid_regex.txt
new file mode 100644
index 000000000..6c9969b6e
--- /dev/null
+++ b/src/tools/clippy/src/docs/invalid_regex.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks [regex](https://crates.io/crates/regex) creation
+(with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`) for correct
+regex syntax.
+
+### Why is this bad?
+This will lead to a runtime panic.
+
+### Example
+```
+Regex::new("(")
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/invalid_upcast_comparisons.txt b/src/tools/clippy/src/docs/invalid_upcast_comparisons.txt
new file mode 100644
index 000000000..77cb03308
--- /dev/null
+++ b/src/tools/clippy/src/docs/invalid_upcast_comparisons.txt
@@ -0,0 +1,18 @@
+### 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
+```
+let x: u8 = 1;
+(x as u32) > 300;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/invalid_utf8_in_unchecked.txt b/src/tools/clippy/src/docs/invalid_utf8_in_unchecked.txt
new file mode 100644
index 000000000..afb5acbe9
--- /dev/null
+++ b/src/tools/clippy/src/docs/invalid_utf8_in_unchecked.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for `std::str::from_utf8_unchecked` with an invalid UTF-8 literal
+
+### Why is this bad?
+Creating such a `str` would result in undefined behavior
+
+### Example
+```
+unsafe {
+ std::str::from_utf8_unchecked(b"cl\x82ippy");
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/invisible_characters.txt b/src/tools/clippy/src/docs/invisible_characters.txt
new file mode 100644
index 000000000..3dda38091
--- /dev/null
+++ b/src/tools/clippy/src/docs/invisible_characters.txt
@@ -0,0 +1,10 @@
+### 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. \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/is_digit_ascii_radix.txt b/src/tools/clippy/src/docs/is_digit_ascii_radix.txt
new file mode 100644
index 000000000..9f11cf430
--- /dev/null
+++ b/src/tools/clippy/src/docs/is_digit_ascii_radix.txt
@@ -0,0 +1,20 @@
+### What it does
+Finds usages of [`char::is_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit) that
+can be replaced with [`is_ascii_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_digit) or
+[`is_ascii_hexdigit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_hexdigit).
+
+### Why is this bad?
+`is_digit(..)` is slower and requires specifying the radix.
+
+### Example
+```
+let c: char = '6';
+c.is_digit(10);
+c.is_digit(16);
+```
+Use instead:
+```
+let c: char = '6';
+c.is_ascii_digit();
+c.is_ascii_hexdigit();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/items_after_statements.txt b/src/tools/clippy/src/docs/items_after_statements.txt
new file mode 100644
index 000000000..6fdfff50d
--- /dev/null
+++ b/src/tools/clippy/src/docs/items_after_statements.txt
@@ -0,0 +1,37 @@
+### What it does
+Checks for items declared after some statement in a block.
+
+### Why is this bad?
+Items live for the entire scope they are declared
+in. But statements are processed in order. This might cause confusion as
+it's hard to figure out which item is meant in a statement.
+
+### Example
+```
+fn foo() {
+ println!("cake");
+}
+
+fn main() {
+ foo(); // prints "foo"
+ fn foo() {
+ println!("foo");
+ }
+ foo(); // prints "foo"
+}
+```
+
+Use instead:
+```
+fn foo() {
+ println!("cake");
+}
+
+fn main() {
+ fn foo() {
+ println!("foo");
+ }
+ foo(); // prints "foo"
+ foo(); // prints "foo"
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_cloned_collect.txt b/src/tools/clippy/src/docs/iter_cloned_collect.txt
new file mode 100644
index 000000000..90dc9ebb4
--- /dev/null
+++ b/src/tools/clippy/src/docs/iter_cloned_collect.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for the use of `.cloned().collect()` on slice to
+create a `Vec`.
+
+### Why is this bad?
+`.to_vec()` is clearer
+
+### Example
+```
+let s = [1, 2, 3, 4, 5];
+let s2: Vec<isize> = s[..].iter().cloned().collect();
+```
+The better use would be:
+```
+let s = [1, 2, 3, 4, 5];
+let s2: Vec<isize> = s.to_vec();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_count.txt b/src/tools/clippy/src/docs/iter_count.txt
new file mode 100644
index 000000000..f3db4a26c
--- /dev/null
+++ b/src/tools/clippy/src/docs/iter_count.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for the use of `.iter().count()`.
+
+### Why is this bad?
+`.len()` is more efficient and more
+readable.
+
+### Example
+```
+let some_vec = vec![0, 1, 2, 3];
+
+some_vec.iter().count();
+&some_vec[..].iter().count();
+```
+
+Use instead:
+```
+let some_vec = vec![0, 1, 2, 3];
+
+some_vec.len();
+&some_vec[..].len();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_kv_map.txt b/src/tools/clippy/src/docs/iter_kv_map.txt
new file mode 100644
index 000000000..a063c8195
--- /dev/null
+++ b/src/tools/clippy/src/docs/iter_kv_map.txt
@@ -0,0 +1,22 @@
+### What it does
+
+Checks for iterating a map (`HashMap` or `BTreeMap`) and
+ignoring either the keys or values.
+
+### Why is this bad?
+
+Readability. There are `keys` and `values` methods that
+can be used to express that we only need the keys or the values.
+
+### Example
+
+```
+let map: HashMap<u32, u32> = HashMap::new();
+let values = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
+```
+
+Use instead:
+```
+let map: HashMap<u32, u32> = HashMap::new();
+let values = map.values().collect::<Vec<_>>();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_next_loop.txt b/src/tools/clippy/src/docs/iter_next_loop.txt
new file mode 100644
index 000000000..b33eb39d6
--- /dev/null
+++ b/src/tools/clippy/src/docs/iter_next_loop.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for loops on `x.next()`.
+
+### Why is this bad?
+`next()` returns either `Some(value)` if there was a
+value, or `None` otherwise. The insidious thing is that `Option<_>`
+implements `IntoIterator`, so that possibly one value will be iterated,
+leading to some hard to find bugs. No one will want to write such code
+[except to win an Underhanded Rust
+Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr).
+
+### Example
+```
+for x in y.next() {
+ ..
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_next_slice.txt b/src/tools/clippy/src/docs/iter_next_slice.txt
new file mode 100644
index 000000000..1cea25eaf
--- /dev/null
+++ b/src/tools/clippy/src/docs/iter_next_slice.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `iter().next()` on a Slice or an Array
+
+### Why is this bad?
+These can be shortened into `.get()`
+
+### Example
+```
+a[2..].iter().next();
+b.iter().next();
+```
+should be written as:
+```
+a.get(2);
+b.get(0);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_not_returning_iterator.txt b/src/tools/clippy/src/docs/iter_not_returning_iterator.txt
new file mode 100644
index 000000000..0ca862910
--- /dev/null
+++ b/src/tools/clippy/src/docs/iter_not_returning_iterator.txt
@@ -0,0 +1,26 @@
+### What it does
+Detects methods named `iter` or `iter_mut` that do not have a return type that implements `Iterator`.
+
+### Why is this bad?
+Methods named `iter` or `iter_mut` conventionally return an `Iterator`.
+
+### Example
+```
+// `String` does not implement `Iterator`
+struct Data {}
+impl Data {
+ fn iter(&self) -> String {
+ todo!()
+ }
+}
+```
+Use instead:
+```
+use std::str::Chars;
+struct Data {}
+impl Data {
+ fn iter(&self) -> Chars<'static> {
+ todo!()
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_nth.txt b/src/tools/clippy/src/docs/iter_nth.txt
new file mode 100644
index 000000000..3d67d583f
--- /dev/null
+++ b/src/tools/clippy/src/docs/iter_nth.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for use of `.iter().nth()` (and the related
+`.iter_mut().nth()`) on standard library types with *O*(1) element access.
+
+### Why is this bad?
+`.get()` and `.get_mut()` are more efficient and more
+readable.
+
+### Example
+```
+let some_vec = vec![0, 1, 2, 3];
+let bad_vec = some_vec.iter().nth(3);
+let bad_slice = &some_vec[..].iter().nth(3);
+```
+The correct use would be:
+```
+let some_vec = vec![0, 1, 2, 3];
+let bad_vec = some_vec.get(3);
+let bad_slice = &some_vec[..].get(3);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_nth_zero.txt b/src/tools/clippy/src/docs/iter_nth_zero.txt
new file mode 100644
index 000000000..8efe47a16
--- /dev/null
+++ b/src/tools/clippy/src/docs/iter_nth_zero.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for the use of `iter.nth(0)`.
+
+### Why is this bad?
+`iter.next()` is equivalent to
+`iter.nth(0)`, as they both consume the next element,
+ but is more readable.
+
+### Example
+```
+let x = s.iter().nth(0);
+```
+
+Use instead:
+```
+let x = s.iter().next();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_on_empty_collections.txt b/src/tools/clippy/src/docs/iter_on_empty_collections.txt
new file mode 100644
index 000000000..87c4ec12a
--- /dev/null
+++ b/src/tools/clippy/src/docs/iter_on_empty_collections.txt
@@ -0,0 +1,25 @@
+### What it does
+
+Checks for calls to `iter`, `iter_mut` or `into_iter` on empty collections
+
+### Why is this bad?
+
+It is simpler to use the empty function from the standard library:
+
+### Example
+
+```
+use std::{slice, option};
+let a: slice::Iter<i32> = [].iter();
+let f: option::IntoIter<i32> = None.into_iter();
+```
+Use instead:
+```
+use std::iter;
+let a: iter::Empty<i32> = iter::empty();
+let b: iter::Empty<i32> = iter::empty();
+```
+
+### Known problems
+
+The type of the resulting iterator might become incompatible with its usage \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_on_single_items.txt b/src/tools/clippy/src/docs/iter_on_single_items.txt
new file mode 100644
index 000000000..d0388f25d
--- /dev/null
+++ b/src/tools/clippy/src/docs/iter_on_single_items.txt
@@ -0,0 +1,24 @@
+### What it does
+
+Checks for calls to `iter`, `iter_mut` or `into_iter` on collections containing a single item
+
+### Why is this bad?
+
+It is simpler to use the once function from the standard library:
+
+### Example
+
+```
+let a = [123].iter();
+let b = Some(123).into_iter();
+```
+Use instead:
+```
+use std::iter;
+let a = iter::once(&123);
+let b = iter::once(123);
+```
+
+### Known problems
+
+The type of the resulting iterator might become incompatible with its usage \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_overeager_cloned.txt b/src/tools/clippy/src/docs/iter_overeager_cloned.txt
new file mode 100644
index 000000000..2f902a0c2
--- /dev/null
+++ b/src/tools/clippy/src/docs/iter_overeager_cloned.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `_.cloned().<func>()` where call to `.cloned()` can be postponed.
+
+### Why is this bad?
+It's often inefficient to clone all elements of an iterator, when eventually, only some
+of them will be consumed.
+
+### Known Problems
+This `lint` removes the side of effect of cloning items in the iterator.
+A code that relies on that side-effect could fail.
+
+### Examples
+```
+vec.iter().cloned().take(10);
+vec.iter().cloned().last();
+```
+
+Use instead:
+```
+vec.iter().take(10).cloned();
+vec.iter().last().cloned();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_skip_next.txt b/src/tools/clippy/src/docs/iter_skip_next.txt
new file mode 100644
index 000000000..da226b041
--- /dev/null
+++ b/src/tools/clippy/src/docs/iter_skip_next.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for use of `.skip(x).next()` on iterators.
+
+### Why is this bad?
+`.nth(x)` is cleaner
+
+### Example
+```
+let some_vec = vec![0, 1, 2, 3];
+let bad_vec = some_vec.iter().skip(3).next();
+let bad_slice = &some_vec[..].iter().skip(3).next();
+```
+The correct use would be:
+```
+let some_vec = vec![0, 1, 2, 3];
+let bad_vec = some_vec.iter().nth(3);
+let bad_slice = &some_vec[..].iter().nth(3);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iter_with_drain.txt b/src/tools/clippy/src/docs/iter_with_drain.txt
new file mode 100644
index 000000000..2c52b99f7
--- /dev/null
+++ b/src/tools/clippy/src/docs/iter_with_drain.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for use of `.drain(..)` on `Vec` and `VecDeque` for iteration.
+
+### Why is this bad?
+`.into_iter()` is simpler with better performance.
+
+### Example
+```
+let mut foo = vec![0, 1, 2, 3];
+let bar: HashSet<usize> = foo.drain(..).collect();
+```
+Use instead:
+```
+let foo = vec![0, 1, 2, 3];
+let bar: HashSet<usize> = foo.into_iter().collect();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/iterator_step_by_zero.txt b/src/tools/clippy/src/docs/iterator_step_by_zero.txt
new file mode 100644
index 000000000..73ecc99ac
--- /dev/null
+++ b/src/tools/clippy/src/docs/iterator_step_by_zero.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for calling `.step_by(0)` on iterators which panics.
+
+### Why is this bad?
+This very much looks like an oversight. Use `panic!()` instead if you
+actually intend to panic.
+
+### Example
+```
+for x in (0..100).step_by(0) {
+ //..
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/just_underscores_and_digits.txt b/src/tools/clippy/src/docs/just_underscores_and_digits.txt
new file mode 100644
index 000000000..a8790bcf2
--- /dev/null
+++ b/src/tools/clippy/src/docs/just_underscores_and_digits.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks if you have variables whose name consists of just
+underscores and digits.
+
+### Why is this bad?
+It's hard to memorize what a variable means without a
+descriptive name.
+
+### Example
+```
+let _1 = 1;
+let ___1 = 1;
+let __1___2 = 11;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/large_const_arrays.txt b/src/tools/clippy/src/docs/large_const_arrays.txt
new file mode 100644
index 000000000..71f67854f
--- /dev/null
+++ b/src/tools/clippy/src/docs/large_const_arrays.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for large `const` arrays that should
+be defined as `static` instead.
+
+### Why is this bad?
+Performance: const variables are inlined upon use.
+Static items result in only one instance and has a fixed location in memory.
+
+### Example
+```
+pub const a = [0u32; 1_000_000];
+```
+
+Use instead:
+```
+pub static a = [0u32; 1_000_000];
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/large_digit_groups.txt b/src/tools/clippy/src/docs/large_digit_groups.txt
new file mode 100644
index 000000000..f60b19345
--- /dev/null
+++ b/src/tools/clippy/src/docs/large_digit_groups.txt
@@ -0,0 +1,12 @@
+### What it does
+Warns if the digits of an integral or floating-point
+constant are grouped into groups that
+are too large.
+
+### Why is this bad?
+Negatively impacts readability.
+
+### Example
+```
+let x: u64 = 6186491_8973511;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/large_enum_variant.txt b/src/tools/clippy/src/docs/large_enum_variant.txt
new file mode 100644
index 000000000..1f9543079
--- /dev/null
+++ b/src/tools/clippy/src/docs/large_enum_variant.txt
@@ -0,0 +1,41 @@
+### What it does
+Checks for large size differences between variants on
+`enum`s.
+
+### Why is this bad?
+Enum size is bounded by the largest variant. Having one
+large variant can penalize the memory layout of that enum.
+
+### Known problems
+This lint obviously cannot take the distribution of
+variants in your running program into account. It is possible that the
+smaller variants make up less than 1% of all instances, in which case
+the overhead is negligible and the boxing is counter-productive. Always
+measure the change this lint suggests.
+
+For types that implement `Copy`, the suggestion to `Box` a variant's
+data would require removing the trait impl. The types can of course
+still be `Clone`, but that is worse ergonomically. Depending on the
+use case it may be possible to store the large data in an auxiliary
+structure (e.g. Arena or ECS).
+
+The lint will ignore the impact of generic types to the type layout by
+assuming every type parameter is zero-sized. Depending on your use case,
+this may lead to a false positive.
+
+### Example
+```
+enum Test {
+ A(i32),
+ B([i32; 8000]),
+}
+```
+
+Use instead:
+```
+// Possibly better
+enum Test2 {
+ A(i32),
+ B(Box<[i32; 8000]>),
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/large_include_file.txt b/src/tools/clippy/src/docs/large_include_file.txt
new file mode 100644
index 000000000..b2a54bd2e
--- /dev/null
+++ b/src/tools/clippy/src/docs/large_include_file.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for the inclusion of large files via `include_bytes!()`
+and `include_str!()`
+
+### Why is this bad?
+Including large files can increase the size of the binary
+
+### Example
+```
+let included_str = include_str!("very_large_file.txt");
+let included_bytes = include_bytes!("very_large_file.txt");
+```
+
+Use instead:
+```
+use std::fs;
+
+// You can load the file at runtime
+let string = fs::read_to_string("very_large_file.txt")?;
+let bytes = fs::read("very_large_file.txt")?;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/large_stack_arrays.txt b/src/tools/clippy/src/docs/large_stack_arrays.txt
new file mode 100644
index 000000000..4a6f34785
--- /dev/null
+++ b/src/tools/clippy/src/docs/large_stack_arrays.txt
@@ -0,0 +1,10 @@
+### What it does
+Checks for local arrays that may be too large.
+
+### Why is this bad?
+Large local arrays may cause stack overflow.
+
+### Example
+```
+let a = [0u32; 1_000_000];
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/large_types_passed_by_value.txt b/src/tools/clippy/src/docs/large_types_passed_by_value.txt
new file mode 100644
index 000000000..bca07f3ac
--- /dev/null
+++ b/src/tools/clippy/src/docs/large_types_passed_by_value.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for functions taking arguments by value, where
+the argument type is `Copy` and large enough to be worth considering
+passing by reference. Does not trigger if the function is being exported,
+because that might induce API breakage, if the parameter is declared as mutable,
+or if the argument is a `self`.
+
+### Why is this bad?
+Arguments passed by value might result in an unnecessary
+shallow copy, taking up more space in the stack and requiring a call to
+`memcpy`, which can be expensive.
+
+### Example
+```
+#[derive(Clone, Copy)]
+struct TooLarge([u8; 2048]);
+
+fn foo(v: TooLarge) {}
+```
+
+Use instead:
+```
+fn foo(v: &TooLarge) {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/len_without_is_empty.txt b/src/tools/clippy/src/docs/len_without_is_empty.txt
new file mode 100644
index 000000000..47a2e8575
--- /dev/null
+++ b/src/tools/clippy/src/docs/len_without_is_empty.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for items that implement `.len()` but not
+`.is_empty()`.
+
+### Why is this bad?
+It is good custom to have both methods, because for
+some data structures, asking about the length will be a costly operation,
+whereas `.is_empty()` can usually answer in constant time. Also it used to
+lead to false positives on the [`len_zero`](#len_zero) lint – currently that
+lint will ignore such entities.
+
+### Example
+```
+impl X {
+ pub fn len(&self) -> usize {
+ ..
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/len_zero.txt b/src/tools/clippy/src/docs/len_zero.txt
new file mode 100644
index 000000000..664124bd3
--- /dev/null
+++ b/src/tools/clippy/src/docs/len_zero.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for getting the length of something via `.len()`
+just to compare to zero, and suggests using `.is_empty()` where applicable.
+
+### Why is this bad?
+Some structures can answer `.is_empty()` much faster
+than calculating their length. So it is good to get into the habit of using
+`.is_empty()`, and having it is cheap.
+Besides, it makes the intent clearer than a manual comparison in some contexts.
+
+### Example
+```
+if x.len() == 0 {
+ ..
+}
+if y.len() != 0 {
+ ..
+}
+```
+instead use
+```
+if x.is_empty() {
+ ..
+}
+if !y.is_empty() {
+ ..
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/let_and_return.txt b/src/tools/clippy/src/docs/let_and_return.txt
new file mode 100644
index 000000000..eba5a90dd
--- /dev/null
+++ b/src/tools/clippy/src/docs/let_and_return.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for `let`-bindings, which are subsequently
+returned.
+
+### Why is this bad?
+It is just extraneous code. Remove it to make your code
+more rusty.
+
+### Example
+```
+fn foo() -> String {
+ let x = String::new();
+ x
+}
+```
+instead, use
+```
+fn foo() -> String {
+ String::new()
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/let_underscore_drop.txt b/src/tools/clippy/src/docs/let_underscore_drop.txt
new file mode 100644
index 000000000..29ce9bf50
--- /dev/null
+++ b/src/tools/clippy/src/docs/let_underscore_drop.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for `let _ = <expr>`
+where expr has a type that implements `Drop`
+
+### Why is this bad?
+This statement immediately drops the initializer
+expression instead of extending its lifetime to the end of the scope, which
+is often not intended. To extend the expression's lifetime to the end of the
+scope, use an underscore-prefixed name instead (i.e. _var). If you want to
+explicitly drop the expression, `std::mem::drop` conveys your intention
+better and is less error-prone.
+
+### Example
+```
+{
+ let _ = DroppableItem;
+ // ^ dropped here
+ /* more code */
+}
+```
+
+Use instead:
+```
+{
+ let _droppable = DroppableItem;
+ /* more code */
+ // dropped at end of scope
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/let_underscore_lock.txt b/src/tools/clippy/src/docs/let_underscore_lock.txt
new file mode 100644
index 000000000..bd8217fb5
--- /dev/null
+++ b/src/tools/clippy/src/docs/let_underscore_lock.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for `let _ = sync_lock`.
+This supports `mutex` and `rwlock` in `std::sync` and `parking_lot`.
+
+### Why is this bad?
+This statement immediately drops the lock instead of
+extending its lifetime to the end of the scope, which is often not intended.
+To extend lock lifetime to the end of the scope, use an underscore-prefixed
+name instead (i.e. _lock). If you want to explicitly drop the lock,
+`std::mem::drop` conveys your intention better and is less error-prone.
+
+### Example
+```
+let _ = mutex.lock();
+```
+
+Use instead:
+```
+let _lock = mutex.lock();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/let_underscore_must_use.txt b/src/tools/clippy/src/docs/let_underscore_must_use.txt
new file mode 100644
index 000000000..270b81d9a
--- /dev/null
+++ b/src/tools/clippy/src/docs/let_underscore_must_use.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for `let _ = <expr>` where expr is `#[must_use]`
+
+### Why is this bad?
+It's better to explicitly handle the value of a `#[must_use]`
+expr
+
+### Example
+```
+fn f() -> Result<u32, u32> {
+ Ok(0)
+}
+
+let _ = f();
+// is_ok() is marked #[must_use]
+let _ = f().is_ok();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/let_unit_value.txt b/src/tools/clippy/src/docs/let_unit_value.txt
new file mode 100644
index 000000000..bc16d5b3d
--- /dev/null
+++ b/src/tools/clippy/src/docs/let_unit_value.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for binding a unit value.
+
+### Why is this bad?
+A unit value cannot usefully be used anywhere. So
+binding one is kind of pointless.
+
+### Example
+```
+let x = {
+ 1;
+};
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/linkedlist.txt b/src/tools/clippy/src/docs/linkedlist.txt
new file mode 100644
index 000000000..986ff1369
--- /dev/null
+++ b/src/tools/clippy/src/docs/linkedlist.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for usage of any `LinkedList`, suggesting to use a
+`Vec` or a `VecDeque` (formerly called `RingBuf`).
+
+### Why is this bad?
+Gankro says:
+
+> The TL;DR of `LinkedList` is that it's built on a massive amount of
+pointers and indirection.
+> It wastes memory, it has terrible cache locality, and is all-around slow.
+`RingBuf`, while
+> "only" amortized for push/pop, should be faster in the general case for
+almost every possible
+> workload, and isn't even amortized at all if you can predict the capacity
+you need.
+>
+> `LinkedList`s are only really good if you're doing a lot of merging or
+splitting of lists.
+> This is because they can just mangle some pointers instead of actually
+copying the data. Even
+> if you're doing a lot of insertion in the middle of the list, `RingBuf`
+can still be better
+> because of how expensive it is to seek to the middle of a `LinkedList`.
+
+### Known problems
+False positives – the instances where using a
+`LinkedList` makes sense are few and far between, but they can still happen.
+
+### Example
+```
+let x: LinkedList<usize> = LinkedList::new();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/lossy_float_literal.txt b/src/tools/clippy/src/docs/lossy_float_literal.txt
new file mode 100644
index 000000000..bbcb9115e
--- /dev/null
+++ b/src/tools/clippy/src/docs/lossy_float_literal.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for whole number float literals that
+cannot be represented as the underlying type without loss.
+
+### Why is this bad?
+Rust will silently lose precision during
+conversion to a float.
+
+### Example
+```
+let _: f32 = 16_777_217.0; // 16_777_216.0
+```
+
+Use instead:
+```
+let _: f32 = 16_777_216.0;
+let _: f64 = 16_777_217.0;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/macro_use_imports.txt b/src/tools/clippy/src/docs/macro_use_imports.txt
new file mode 100644
index 000000000..6a8180a60
--- /dev/null
+++ b/src/tools/clippy/src/docs/macro_use_imports.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for `#[macro_use] use...`.
+
+### Why is this bad?
+Since the Rust 2018 edition you can import
+macro's directly, this is considered idiomatic.
+
+### Example
+```
+#[macro_use]
+use some_macro;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/main_recursion.txt b/src/tools/clippy/src/docs/main_recursion.txt
new file mode 100644
index 000000000..e49becd15
--- /dev/null
+++ b/src/tools/clippy/src/docs/main_recursion.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for recursion using the entrypoint.
+
+### Why is this bad?
+Apart from special setups (which we could detect following attributes like #![no_std]),
+recursing into main() seems like an unintuitive anti-pattern we should be able to detect.
+
+### Example
+```
+fn main() {
+ main();
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_assert.txt b/src/tools/clippy/src/docs/manual_assert.txt
new file mode 100644
index 000000000..93653081a
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_assert.txt
@@ -0,0 +1,18 @@
+### 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
+```
+let sad_people: Vec<&str> = vec![];
+if !sad_people.is_empty() {
+ panic!("there are sad people: {:?}", sad_people);
+}
+```
+Use instead:
+```
+let sad_people: Vec<&str> = vec![];
+assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_async_fn.txt b/src/tools/clippy/src/docs/manual_async_fn.txt
new file mode 100644
index 000000000..d01ac402e
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_async_fn.txt
@@ -0,0 +1,16 @@
+### What it does
+It checks for manual implementations of `async` functions.
+
+### Why is this bad?
+It's more idiomatic to use the dedicated syntax.
+
+### Example
+```
+use std::future::Future;
+
+fn foo() -> impl Future<Output = i32> { async { 42 } }
+```
+Use instead:
+```
+async fn foo() -> i32 { 42 }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_bits.txt b/src/tools/clippy/src/docs/manual_bits.txt
new file mode 100644
index 000000000..b96c2eb15
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_bits.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for uses of `std::mem::size_of::<T>() * 8` when
+`T::BITS` is available.
+
+### Why is this bad?
+Can be written as the shorter `T::BITS`.
+
+### Example
+```
+std::mem::size_of::<usize>() * 8;
+```
+Use instead:
+```
+usize::BITS as usize;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_clamp.txt b/src/tools/clippy/src/docs/manual_clamp.txt
new file mode 100644
index 000000000..8993f6683
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_clamp.txt
@@ -0,0 +1,46 @@
+### What it does
+Identifies good opportunities for a clamp function from std or core, and suggests using it.
+
+### Why is this bad?
+clamp is much shorter, easier to read, and doesn't use any control flow.
+
+### Known issue(s)
+If the clamped variable is NaN this suggestion will cause the code to propagate NaN
+rather than returning either `max` or `min`.
+
+`clamp` functions will panic if `max < min`, `max.is_nan()`, or `min.is_nan()`.
+Some may consider panicking in these situations to be desirable, but it also may
+introduce panicking where there wasn't any before.
+
+### Examples
+```
+if input > max {
+ max
+} else if input < min {
+ min
+} else {
+ input
+}
+```
+
+```
+input.max(min).min(max)
+```
+
+```
+match input {
+ x if x > max => max,
+ x if x < min => min,
+ x => x,
+}
+```
+
+```
+let mut x = input;
+if x < min { x = min; }
+if x > max { x = max; }
+```
+Use instead:
+```
+input.clamp(min, max)
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_filter.txt b/src/tools/clippy/src/docs/manual_filter.txt
new file mode 100644
index 000000000..19a4d9319
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_filter.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for usages of `match` which could be implemented using `filter`
+
+### Why is this bad?
+Using the `filter` method is clearer and more concise.
+
+### Example
+```
+match Some(0) {
+ Some(x) => if x % 2 == 0 {
+ Some(x)
+ } else {
+ None
+ },
+ None => None,
+};
+```
+Use instead:
+```
+Some(0).filter(|&x| x % 2 == 0);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_filter_map.txt b/src/tools/clippy/src/docs/manual_filter_map.txt
new file mode 100644
index 000000000..3b6860798
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_filter_map.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `_.filter(_).map(_)` that can be written more simply
+as `filter_map(_)`.
+
+### Why is this bad?
+Redundant code in the `filter` and `map` operations is poor style and
+less performant.
+
+### Example
+```
+(0_i32..10)
+ .filter(|n| n.checked_add(1).is_some())
+ .map(|n| n.checked_add(1).unwrap());
+```
+
+Use instead:
+```
+(0_i32..10).filter_map(|n| n.checked_add(1));
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_find.txt b/src/tools/clippy/src/docs/manual_find.txt
new file mode 100644
index 000000000..e3e07a277
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_find.txt
@@ -0,0 +1,24 @@
+### What it does
+Check for manual implementations of Iterator::find
+
+### Why is this bad?
+It doesn't affect performance, but using `find` is shorter and easier to read.
+
+### Example
+
+```
+fn example(arr: Vec<i32>) -> Option<i32> {
+ for el in arr {
+ if el == 1 {
+ return Some(el);
+ }
+ }
+ None
+}
+```
+Use instead:
+```
+fn example(arr: Vec<i32>) -> Option<i32> {
+ arr.into_iter().find(|&el| el == 1)
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_find_map.txt b/src/tools/clippy/src/docs/manual_find_map.txt
new file mode 100644
index 000000000..83b22060c
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_find_map.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `_.find(_).map(_)` that can be written more simply
+as `find_map(_)`.
+
+### Why is this bad?
+Redundant code in the `find` and `map` operations is poor style and
+less performant.
+
+### Example
+```
+(0_i32..10)
+ .find(|n| n.checked_add(1).is_some())
+ .map(|n| n.checked_add(1).unwrap());
+```
+
+Use instead:
+```
+(0_i32..10).find_map(|n| n.checked_add(1));
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_flatten.txt b/src/tools/clippy/src/docs/manual_flatten.txt
new file mode 100644
index 000000000..62d5f3ec9
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_flatten.txt
@@ -0,0 +1,25 @@
+### What it does
+Check for unnecessary `if let` usage in a for loop
+where only the `Some` or `Ok` variant of the iterator element is used.
+
+### Why is this bad?
+It is verbose and can be simplified
+by first calling the `flatten` method on the `Iterator`.
+
+### Example
+
+```
+let x = vec![Some(1), Some(2), Some(3)];
+for n in x {
+ if let Some(n) = n {
+ println!("{}", n);
+ }
+}
+```
+Use instead:
+```
+let x = vec![Some(1), Some(2), Some(3)];
+for n in x.into_iter().flatten() {
+ println!("{}", n);
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_instant_elapsed.txt b/src/tools/clippy/src/docs/manual_instant_elapsed.txt
new file mode 100644
index 000000000..dde3d493c
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_instant_elapsed.txt
@@ -0,0 +1,21 @@
+### What it does
+Lints subtraction between `Instant::now()` and another `Instant`.
+
+### Why is this bad?
+It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns
+as `Instant` subtraction saturates.
+
+`prev_instant.elapsed()` also more clearly signals intention.
+
+### Example
+```
+use std::time::Instant;
+let prev_instant = Instant::now();
+let duration = Instant::now() - prev_instant;
+```
+Use instead:
+```
+use std::time::Instant;
+let prev_instant = Instant::now();
+let duration = prev_instant.elapsed();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_map.txt b/src/tools/clippy/src/docs/manual_map.txt
new file mode 100644
index 000000000..7f68ccd10
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_map.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for usages of `match` which could be implemented using `map`
+
+### Why is this bad?
+Using the `map` method is clearer and more concise.
+
+### Example
+```
+match Some(0) {
+ Some(x) => Some(x + 1),
+ None => None,
+};
+```
+Use instead:
+```
+Some(0).map(|x| x + 1);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_memcpy.txt b/src/tools/clippy/src/docs/manual_memcpy.txt
new file mode 100644
index 000000000..d7690bf25
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_memcpy.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for for-loops that manually copy items between
+slices that could be optimized by having a memcpy.
+
+### Why is this bad?
+It is not as fast as a memcpy.
+
+### Example
+```
+for i in 0..src.len() {
+ dst[i + 64] = src[i];
+}
+```
+
+Use instead:
+```
+dst[64..(src.len() + 64)].clone_from_slice(&src[..]);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_non_exhaustive.txt b/src/tools/clippy/src/docs/manual_non_exhaustive.txt
new file mode 100644
index 000000000..fb021393b
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_non_exhaustive.txt
@@ -0,0 +1,41 @@
+### What it does
+Checks for manual implementations of the non-exhaustive pattern.
+
+### Why is this bad?
+Using the #[non_exhaustive] attribute expresses better the intent
+and allows possible optimizations when applied to enums.
+
+### Example
+```
+struct S {
+ pub a: i32,
+ pub b: i32,
+ _c: (),
+}
+
+enum E {
+ A,
+ B,
+ #[doc(hidden)]
+ _C,
+}
+
+struct T(pub i32, pub i32, ());
+```
+Use instead:
+```
+#[non_exhaustive]
+struct S {
+ pub a: i32,
+ pub b: i32,
+}
+
+#[non_exhaustive]
+enum E {
+ A,
+ B,
+}
+
+#[non_exhaustive]
+struct T(pub i32, pub i32);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_ok_or.txt b/src/tools/clippy/src/docs/manual_ok_or.txt
new file mode 100644
index 000000000..5accdf259
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_ok_or.txt
@@ -0,0 +1,19 @@
+### What it does
+
+Finds patterns that reimplement `Option::ok_or`.
+
+### Why is this bad?
+
+Concise code helps focusing on behavior instead of boilerplate.
+
+### Examples
+```
+let foo: Option<i32> = None;
+foo.map_or(Err("error"), |v| Ok(v));
+```
+
+Use instead:
+```
+let foo: Option<i32> = None;
+foo.ok_or("error");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_range_contains.txt b/src/tools/clippy/src/docs/manual_range_contains.txt
new file mode 100644
index 000000000..0ade26951
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_range_contains.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for expressions like `x >= 3 && x < 8` that could
+be more readably expressed as `(3..8).contains(x)`.
+
+### Why is this bad?
+`contains` expresses the intent better and has less
+failure modes (such as fencepost errors or using `||` instead of `&&`).
+
+### Example
+```
+// given
+let x = 6;
+
+assert!(x >= 3 && x < 8);
+```
+Use instead:
+```
+assert!((3..8).contains(&x));
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_rem_euclid.txt b/src/tools/clippy/src/docs/manual_rem_euclid.txt
new file mode 100644
index 000000000..d3bb8c613
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_rem_euclid.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for an expression like `((x % 4) + 4) % 4` which is a common manual reimplementation
+of `x.rem_euclid(4)`.
+
+### Why is this bad?
+It's simpler and more readable.
+
+### Example
+```
+let x: i32 = 24;
+let rem = ((x % 4) + 4) % 4;
+```
+Use instead:
+```
+let x: i32 = 24;
+let rem = x.rem_euclid(4);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_retain.txt b/src/tools/clippy/src/docs/manual_retain.txt
new file mode 100644
index 000000000..cd4f65a93
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_retain.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for code to be replaced by `.retain()`.
+### Why is this bad?
+`.retain()` is simpler and avoids needless allocation.
+### Example
+```
+let mut vec = vec![0, 1, 2];
+vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect();
+vec = vec.into_iter().filter(|x| x % 2 == 0).collect();
+```
+Use instead:
+```
+let mut vec = vec![0, 1, 2];
+vec.retain(|x| x % 2 == 0);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_saturating_arithmetic.txt b/src/tools/clippy/src/docs/manual_saturating_arithmetic.txt
new file mode 100644
index 000000000..d9f5d3d11
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_saturating_arithmetic.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`.
+
+### Why is this bad?
+These can be written simply with `saturating_add/sub` methods.
+
+### Example
+```
+let add = x.checked_add(y).unwrap_or(u32::MAX);
+let sub = x.checked_sub(y).unwrap_or(u32::MIN);
+```
+
+can be written using dedicated methods for saturating addition/subtraction as:
+
+```
+let add = x.saturating_add(y);
+let sub = x.saturating_sub(y);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_split_once.txt b/src/tools/clippy/src/docs/manual_split_once.txt
new file mode 100644
index 000000000..291ae447d
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_split_once.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for usages of `str::splitn(2, _)`
+
+### Why is this bad?
+`split_once` is both clearer in intent and slightly more efficient.
+
+### Example
+```
+let s = "key=value=add";
+let (key, value) = s.splitn(2, '=').next_tuple()?;
+let value = s.splitn(2, '=').nth(1)?;
+
+let mut parts = s.splitn(2, '=');
+let key = parts.next()?;
+let value = parts.next()?;
+```
+
+Use instead:
+```
+let s = "key=value=add";
+let (key, value) = s.split_once('=')?;
+let value = s.split_once('=')?.1;
+
+let (key, value) = s.split_once('=')?;
+```
+
+### Limitations
+The multiple statement variant currently only detects `iter.next()?`/`iter.next().unwrap()`
+in two separate `let` statements that immediately follow the `splitn()` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_str_repeat.txt b/src/tools/clippy/src/docs/manual_str_repeat.txt
new file mode 100644
index 000000000..1d4a7a48e
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_str_repeat.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for manual implementations of `str::repeat`
+
+### Why is this bad?
+These are both harder to read, as well as less performant.
+
+### Example
+```
+let x: String = std::iter::repeat('x').take(10).collect();
+```
+
+Use instead:
+```
+let x: String = "x".repeat(10);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_string_new.txt b/src/tools/clippy/src/docs/manual_string_new.txt
new file mode 100644
index 000000000..4cbc43f8f
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_string_new.txt
@@ -0,0 +1,20 @@
+### What it does
+
+Checks for usage of `""` to create a `String`, such as `"".to_string()`, `"".to_owned()`,
+`String::from("")` and others.
+
+### Why is this bad?
+
+Different ways of creating an empty string makes your code less standardized, which can
+be confusing.
+
+### Example
+```
+let a = "".to_string();
+let b: String = "".into();
+```
+Use instead:
+```
+let a = String::new();
+let b = String::new();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_strip.txt b/src/tools/clippy/src/docs/manual_strip.txt
new file mode 100644
index 000000000..f32d8e7a0
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_strip.txt
@@ -0,0 +1,24 @@
+### What it does
+Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using
+the pattern's length.
+
+### Why is this bad?
+Using `str:strip_{prefix,suffix}` is safer and may have better performance as there is no
+slicing which may panic and the compiler does not need to insert this panic code. It is
+also sometimes more readable as it removes the need for duplicating or storing the pattern
+used by `str::{starts,ends}_with` and in the slicing.
+
+### Example
+```
+let s = "hello, world!";
+if s.starts_with("hello, ") {
+ assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
+}
+```
+Use instead:
+```
+let s = "hello, world!";
+if let Some(end) = s.strip_prefix("hello, ") {
+ assert_eq!(end.to_uppercase(), "WORLD!");
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_swap.txt b/src/tools/clippy/src/docs/manual_swap.txt
new file mode 100644
index 000000000..bd9526288
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_swap.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for manual swapping.
+
+### Why is this bad?
+The `std::mem::swap` function exposes the intent better
+without deinitializing or copying either variable.
+
+### Example
+```
+let mut a = 42;
+let mut b = 1337;
+
+let t = b;
+b = a;
+a = t;
+```
+Use std::mem::swap():
+```
+let mut a = 1;
+let mut b = 2;
+std::mem::swap(&mut a, &mut b);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_unwrap_or.txt b/src/tools/clippy/src/docs/manual_unwrap_or.txt
new file mode 100644
index 000000000..1fd7d831b
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_unwrap_or.txt
@@ -0,0 +1,20 @@
+### What it does
+Finds patterns that reimplement `Option::unwrap_or` or `Result::unwrap_or`.
+
+### Why is this bad?
+Concise code helps focusing on behavior instead of boilerplate.
+
+### Example
+```
+let foo: Option<i32> = None;
+match foo {
+ Some(v) => v,
+ None => 1,
+};
+```
+
+Use instead:
+```
+let foo: Option<i32> = None;
+foo.unwrap_or(1);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/many_single_char_names.txt b/src/tools/clippy/src/docs/many_single_char_names.txt
new file mode 100644
index 000000000..55ee5da55
--- /dev/null
+++ b/src/tools/clippy/src/docs/many_single_char_names.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for too many variables whose name consists of a
+single character.
+
+### Why is this bad?
+It's hard to memorize what a variable means without a
+descriptive name.
+
+### Example
+```
+let (a, b, c, d, e, f, g) = (...);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/map_clone.txt b/src/tools/clippy/src/docs/map_clone.txt
new file mode 100644
index 000000000..3ee27f072
--- /dev/null
+++ b/src/tools/clippy/src/docs/map_clone.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `map(|x| x.clone())` or
+dereferencing closures for `Copy` types, on `Iterator` or `Option`,
+and suggests `cloned()` or `copied()` instead
+
+### Why is this bad?
+Readability, this can be written more concisely
+
+### Example
+```
+let x = vec![42, 43];
+let y = x.iter();
+let z = y.map(|i| *i);
+```
+
+The correct use would be:
+
+```
+let x = vec![42, 43];
+let y = x.iter();
+let z = y.cloned();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/map_collect_result_unit.txt b/src/tools/clippy/src/docs/map_collect_result_unit.txt
new file mode 100644
index 000000000..9b7206124
--- /dev/null
+++ b/src/tools/clippy/src/docs/map_collect_result_unit.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for usage of `_.map(_).collect::<Result<(), _>()`.
+
+### Why is this bad?
+Using `try_for_each` instead is more readable and idiomatic.
+
+### Example
+```
+(0..3).map(|t| Err(t)).collect::<Result<(), _>>();
+```
+Use instead:
+```
+(0..3).try_for_each(|t| Err(t));
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/map_entry.txt b/src/tools/clippy/src/docs/map_entry.txt
new file mode 100644
index 000000000..20dba1798
--- /dev/null
+++ b/src/tools/clippy/src/docs/map_entry.txt
@@ -0,0 +1,28 @@
+### 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.
+```
+let mut map = std::collections::HashMap::new();
+let _ = if !map.contains_key(&0) {
+ map.insert(0, 0)
+} else {
+ None
+};
+```
+
+### Example
+```
+if !map.contains_key(&k) {
+ map.insert(k, v);
+}
+```
+Use instead:
+```
+map.entry(k).or_insert(v);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/map_err_ignore.txt b/src/tools/clippy/src/docs/map_err_ignore.txt
new file mode 100644
index 000000000..2606c13a7
--- /dev/null
+++ b/src/tools/clippy/src/docs/map_err_ignore.txt
@@ -0,0 +1,93 @@
+### What it does
+Checks for instances of `map_err(|_| Some::Enum)`
+
+### Why is this bad?
+This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error
+
+### Example
+Before:
+```
+use std::fmt;
+
+#[derive(Debug)]
+enum Error {
+ Indivisible,
+ Remainder(u8),
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Error::Indivisible => write!(f, "could not divide input by three"),
+ Error::Remainder(remainder) => write!(
+ f,
+ "input is not divisible by three, remainder = {}",
+ remainder
+ ),
+ }
+ }
+}
+
+impl std::error::Error for Error {}
+
+fn divisible_by_3(input: &str) -> Result<(), Error> {
+ input
+ .parse::<i32>()
+ .map_err(|_| Error::Indivisible)
+ .map(|v| v % 3)
+ .and_then(|remainder| {
+ if remainder == 0 {
+ Ok(())
+ } else {
+ Err(Error::Remainder(remainder as u8))
+ }
+ })
+}
+ ```
+
+ After:
+ ```rust
+use std::{fmt, num::ParseIntError};
+
+#[derive(Debug)]
+enum Error {
+ Indivisible(ParseIntError),
+ Remainder(u8),
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Error::Indivisible(_) => write!(f, "could not divide input by three"),
+ Error::Remainder(remainder) => write!(
+ f,
+ "input is not divisible by three, remainder = {}",
+ remainder
+ ),
+ }
+ }
+}
+
+impl std::error::Error for Error {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ Error::Indivisible(source) => Some(source),
+ _ => None,
+ }
+ }
+}
+
+fn divisible_by_3(input: &str) -> Result<(), Error> {
+ input
+ .parse::<i32>()
+ .map_err(Error::Indivisible)
+ .map(|v| v % 3)
+ .and_then(|remainder| {
+ if remainder == 0 {
+ Ok(())
+ } else {
+ Err(Error::Remainder(remainder as u8))
+ }
+ })
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/map_flatten.txt b/src/tools/clippy/src/docs/map_flatten.txt
new file mode 100644
index 000000000..73c0e5140
--- /dev/null
+++ b/src/tools/clippy/src/docs/map_flatten.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for usage of `_.map(_).flatten(_)` on `Iterator` and `Option`
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option`
+
+### Example
+```
+let vec = vec![vec![1]];
+let opt = Some(5);
+
+vec.iter().map(|x| x.iter()).flatten();
+opt.map(|x| Some(x * 2)).flatten();
+```
+
+Use instead:
+```
+vec.iter().flat_map(|x| x.iter());
+opt.and_then(|x| Some(x * 2));
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/map_identity.txt b/src/tools/clippy/src/docs/map_identity.txt
new file mode 100644
index 000000000..e2e7af0be
--- /dev/null
+++ b/src/tools/clippy/src/docs/map_identity.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for instances of `map(f)` where `f` is the identity function.
+
+### Why is this bad?
+It can be written more concisely without the call to `map`.
+
+### Example
+```
+let x = [1, 2, 3];
+let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect();
+```
+Use instead:
+```
+let x = [1, 2, 3];
+let y: Vec<_> = x.iter().map(|x| 2*x).collect();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/map_unwrap_or.txt b/src/tools/clippy/src/docs/map_unwrap_or.txt
new file mode 100644
index 000000000..485b29f01
--- /dev/null
+++ b/src/tools/clippy/src/docs/map_unwrap_or.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or
+`result.map(_).unwrap_or_else(_)`.
+
+### Why is this bad?
+Readability, these can be written more concisely (resp.) as
+`option.map_or(_, _)`, `option.map_or_else(_, _)` and `result.map_or_else(_, _)`.
+
+### Known problems
+The order of the arguments is not in execution order
+
+### Examples
+```
+option.map(|a| a + 1).unwrap_or(0);
+result.map(|a| a + 1).unwrap_or_else(some_function);
+```
+
+Use instead:
+```
+option.map_or(0, |a| a + 1);
+result.map_or_else(some_function, |a| a + 1);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_as_ref.txt b/src/tools/clippy/src/docs/match_as_ref.txt
new file mode 100644
index 000000000..5e5f3d645
--- /dev/null
+++ b/src/tools/clippy/src/docs/match_as_ref.txt
@@ -0,0 +1,23 @@
+### 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
+```
+let x: Option<()> = None;
+
+let r: Option<&()> = match x {
+ None => None,
+ Some(ref v) => Some(v),
+};
+```
+
+Use instead:
+```
+let x: Option<()> = None;
+
+let r: Option<&()> = x.as_ref();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_bool.txt b/src/tools/clippy/src/docs/match_bool.txt
new file mode 100644
index 000000000..96f9e1f8b
--- /dev/null
+++ b/src/tools/clippy/src/docs/match_bool.txt
@@ -0,0 +1,24 @@
+### 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
+```
+let condition: bool = true;
+match condition {
+ true => foo(),
+ false => bar(),
+}
+```
+Use if/else instead:
+```
+let condition: bool = true;
+if condition {
+ foo();
+} else {
+ bar();
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_like_matches_macro.txt b/src/tools/clippy/src/docs/match_like_matches_macro.txt
new file mode 100644
index 000000000..643e2ddc9
--- /dev/null
+++ b/src/tools/clippy/src/docs/match_like_matches_macro.txt
@@ -0,0 +1,32 @@
+### 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
+```
+let x = Some(5);
+
+let a = match x {
+ Some(0) => true,
+ _ => false,
+};
+
+let a = if let Some(0) = x {
+ true
+} else {
+ false
+};
+```
+
+Use instead:
+```
+let x = Some(5);
+let a = matches!(x, Some(0));
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_on_vec_items.txt b/src/tools/clippy/src/docs/match_on_vec_items.txt
new file mode 100644
index 000000000..981d18d0f
--- /dev/null
+++ b/src/tools/clippy/src/docs/match_on_vec_items.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for `match vec[idx]` or `match vec[n..m]`.
+
+### Why is this bad?
+This can panic at runtime.
+
+### Example
+```
+let arr = vec![0, 1, 2, 3];
+let idx = 1;
+
+match arr[idx] {
+ 0 => println!("{}", 0),
+ 1 => println!("{}", 3),
+ _ => {},
+}
+```
+
+Use instead:
+```
+let arr = vec![0, 1, 2, 3];
+let idx = 1;
+
+match arr.get(idx) {
+ Some(0) => println!("{}", 0),
+ Some(1) => println!("{}", 3),
+ _ => {},
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_overlapping_arm.txt b/src/tools/clippy/src/docs/match_overlapping_arm.txt
new file mode 100644
index 000000000..841c091bd
--- /dev/null
+++ b/src/tools/clippy/src/docs/match_overlapping_arm.txt
@@ -0,0 +1,16 @@
+### 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
+```
+let x = 5;
+match x {
+ 1..=10 => println!("1 ... 10"),
+ 5..=15 => println!("5 ... 15"),
+ _ => (),
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_ref_pats.txt b/src/tools/clippy/src/docs/match_ref_pats.txt
new file mode 100644
index 000000000..b1d902995
--- /dev/null
+++ b/src/tools/clippy/src/docs/match_ref_pats.txt
@@ -0,0 +1,26 @@
+### 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
+```
+match x {
+ &A(ref y) => foo(y),
+ &B => bar(),
+ _ => frob(&x),
+}
+```
+
+Use instead:
+```
+match *x {
+ A(ref y) => foo(y),
+ B => bar(),
+ _ => frob(x),
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_result_ok.txt b/src/tools/clippy/src/docs/match_result_ok.txt
new file mode 100644
index 000000000..eea7c8e00
--- /dev/null
+++ b/src/tools/clippy/src/docs/match_result_ok.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for unnecessary `ok()` in `while let`.
+
+### Why is this bad?
+Calling `ok()` in `while let` is unnecessary, instead match
+on `Ok(pat)`
+
+### Example
+```
+while let Some(value) = iter.next().ok() {
+ vec.push(value)
+}
+
+if let Some(value) = iter.next().ok() {
+ vec.push(value)
+}
+```
+Use instead:
+```
+while let Ok(value) = iter.next() {
+ vec.push(value)
+}
+
+if let Ok(value) = iter.next() {
+ vec.push(value)
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_same_arms.txt b/src/tools/clippy/src/docs/match_same_arms.txt
new file mode 100644
index 000000000..14edf1203
--- /dev/null
+++ b/src/tools/clippy/src/docs/match_same_arms.txt
@@ -0,0 +1,38 @@
+### 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
+```
+match foo {
+ Bar => bar(),
+ Quz => quz(),
+ Baz => bar(), // <= oops
+}
+```
+
+This should probably be
+```
+match foo {
+ Bar => bar(),
+ Quz => quz(),
+ Baz => baz(), // <= fixed
+}
+```
+
+or if the original code was not a typo:
+```
+match foo {
+ Bar | Baz => bar(), // <= shows the intent better
+ Quz => quz(),
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_single_binding.txt b/src/tools/clippy/src/docs/match_single_binding.txt
new file mode 100644
index 000000000..67ded0bbd
--- /dev/null
+++ b/src/tools/clippy/src/docs/match_single_binding.txt
@@ -0,0 +1,23 @@
+### 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
+```
+match (a, b) {
+ (c, d) => {
+ // useless match
+ }
+}
+```
+
+Use instead:
+```
+let (c, d) = (a, b);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_str_case_mismatch.txt b/src/tools/clippy/src/docs/match_str_case_mismatch.txt
new file mode 100644
index 000000000..19e74c208
--- /dev/null
+++ b/src/tools/clippy/src/docs/match_str_case_mismatch.txt
@@ -0,0 +1,22 @@
+### 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
+```
+match &*text.to_ascii_lowercase() {
+ "foo" => {},
+ "Bar" => {},
+ _ => {},
+}
+```
+Use instead:
+```
+match &*text.to_ascii_lowercase() {
+ "foo" => {},
+ "bar" => {},
+ _ => {},
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_wild_err_arm.txt b/src/tools/clippy/src/docs/match_wild_err_arm.txt
new file mode 100644
index 000000000..f89b3a23a
--- /dev/null
+++ b/src/tools/clippy/src/docs/match_wild_err_arm.txt
@@ -0,0 +1,16 @@
+### 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
+```
+let x: Result<i32, &str> = Ok(3);
+match x {
+ Ok(_) => println!("ok"),
+ Err(_) => panic!("err"),
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/match_wildcard_for_single_variants.txt b/src/tools/clippy/src/docs/match_wildcard_for_single_variants.txt
new file mode 100644
index 000000000..25559b9ec
--- /dev/null
+++ b/src/tools/clippy/src/docs/match_wildcard_for_single_variants.txt
@@ -0,0 +1,27 @@
+### 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
+```
+match x {
+ Foo::A => {},
+ Foo::B => {},
+ _ => {},
+}
+```
+
+Use instead:
+```
+match x {
+ Foo::A => {},
+ Foo::B => {},
+ Foo::C => {},
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/maybe_infinite_iter.txt b/src/tools/clippy/src/docs/maybe_infinite_iter.txt
new file mode 100644
index 000000000..1204a49b4
--- /dev/null
+++ b/src/tools/clippy/src/docs/maybe_infinite_iter.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for iteration that may be infinite.
+
+### Why is this bad?
+While there may be places where this is acceptable
+(e.g., in event streams), in most cases this is simply an error.
+
+### Known problems
+The code may have a condition to stop iteration, but
+this lint is not clever enough to analyze it.
+
+### Example
+```
+let infinite_iter = 0..;
+[0..].iter().zip(infinite_iter.take_while(|x| *x > 5));
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mem_forget.txt b/src/tools/clippy/src/docs/mem_forget.txt
new file mode 100644
index 000000000..a6888c48f
--- /dev/null
+++ b/src/tools/clippy/src/docs/mem_forget.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for usage of `std::mem::forget(t)` where `t` is
+`Drop`.
+
+### Why is this bad?
+`std::mem::forget(t)` prevents `t` from running its
+destructor, possibly causing leaks.
+
+### Example
+```
+mem::forget(Rc::new(55))
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mem_replace_option_with_none.txt b/src/tools/clippy/src/docs/mem_replace_option_with_none.txt
new file mode 100644
index 000000000..7f243d1c1
--- /dev/null
+++ b/src/tools/clippy/src/docs/mem_replace_option_with_none.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for `mem::replace()` on an `Option` with
+`None`.
+
+### Why is this bad?
+`Option` already has the method `take()` for
+taking its current value (Some(..) or None) and replacing it with
+`None`.
+
+### Example
+```
+use std::mem;
+
+let mut an_option = Some(0);
+let replaced = mem::replace(&mut an_option, None);
+```
+Is better expressed with:
+```
+let mut an_option = Some(0);
+let taken = an_option.take();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mem_replace_with_default.txt b/src/tools/clippy/src/docs/mem_replace_with_default.txt
new file mode 100644
index 000000000..24e0913a3
--- /dev/null
+++ b/src/tools/clippy/src/docs/mem_replace_with_default.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for `std::mem::replace` on a value of type
+`T` with `T::default()`.
+
+### Why is this bad?
+`std::mem` module already has the method `take` to
+take the current value and replace it with the default value of that type.
+
+### Example
+```
+let mut text = String::from("foo");
+let replaced = std::mem::replace(&mut text, String::default());
+```
+Is better expressed with:
+```
+let mut text = String::from("foo");
+let taken = std::mem::take(&mut text);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mem_replace_with_uninit.txt b/src/tools/clippy/src/docs/mem_replace_with_uninit.txt
new file mode 100644
index 000000000..0bb483668
--- /dev/null
+++ b/src/tools/clippy/src/docs/mem_replace_with_uninit.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for `mem::replace(&mut _, mem::uninitialized())`
+and `mem::replace(&mut _, mem::zeroed())`.
+
+### Why is this bad?
+This will lead to undefined behavior even if the
+value is overwritten later, because the uninitialized value may be
+observed in the case of a panic.
+
+### Example
+```
+use std::mem;
+
+#[allow(deprecated, invalid_value)]
+fn myfunc (v: &mut Vec<i32>) {
+ let taken_v = unsafe { mem::replace(v, mem::uninitialized()) };
+ let new_v = may_panic(taken_v); // undefined behavior on panic
+ mem::forget(mem::replace(v, new_v));
+}
+```
+
+The [take_mut](https://docs.rs/take_mut) crate offers a sound solution,
+at the cost of either lazily creating a replacement value or aborting
+on panic, to ensure that the uninitialized value cannot be observed. \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/min_max.txt b/src/tools/clippy/src/docs/min_max.txt
new file mode 100644
index 000000000..6acf0f932
--- /dev/null
+++ b/src/tools/clippy/src/docs/min_max.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for expressions where `std::cmp::min` and `max` are
+used to clamp values, but switched so that the result is constant.
+
+### Why is this bad?
+This is in all probability not the intended outcome. At
+the least it hurts readability of the code.
+
+### Example
+```
+min(0, max(100, x))
+
+// or
+
+x.max(100).min(0)
+```
+It will always be equal to `0`. Probably the author meant to clamp the value
+between 0 and 100, but has erroneously swapped `min` and `max`. \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mismatched_target_os.txt b/src/tools/clippy/src/docs/mismatched_target_os.txt
new file mode 100644
index 000000000..51e5ec6e7
--- /dev/null
+++ b/src/tools/clippy/src/docs/mismatched_target_os.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for cfg attributes having operating systems used in target family position.
+
+### Why is this bad?
+The configuration option will not be recognised and the related item will not be included
+by the conditional compilation engine.
+
+### Example
+```
+#[cfg(linux)]
+fn conditional() { }
+```
+
+Use instead:
+```
+#[cfg(target_os = "linux")]
+fn conditional() { }
+
+// or
+
+#[cfg(unix)]
+fn conditional() { }
+```
+Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details. \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mismatching_type_param_order.txt b/src/tools/clippy/src/docs/mismatching_type_param_order.txt
new file mode 100644
index 000000000..ffc7f32d0
--- /dev/null
+++ b/src/tools/clippy/src/docs/mismatching_type_param_order.txt
@@ -0,0 +1,33 @@
+### What it does
+Checks for type parameters which are positioned inconsistently between
+a type definition and impl block. Specifically, a parameter in an impl
+block which has the same name as a parameter in the type def, but is in
+a different place.
+
+### Why is this bad?
+Type parameters are determined by their position rather than name.
+Naming type parameters inconsistently may cause you to refer to the
+wrong type parameter.
+
+### Limitations
+This lint only applies to impl blocks with simple generic params, e.g.
+`A`. If there is anything more complicated, such as a tuple, it will be
+ignored.
+
+### Example
+```
+struct Foo<A, B> {
+ x: A,
+ y: B,
+}
+// inside the impl, B refers to Foo::A
+impl<B, A> Foo<B, A> {}
+```
+Use instead:
+```
+struct Foo<A, B> {
+ x: A,
+ y: B,
+}
+impl<A, B> Foo<A, B> {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/misrefactored_assign_op.txt b/src/tools/clippy/src/docs/misrefactored_assign_op.txt
new file mode 100644
index 000000000..3d691fe41
--- /dev/null
+++ b/src/tools/clippy/src/docs/misrefactored_assign_op.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for `a op= a op b` or `a op= b op a` patterns.
+
+### Why is this bad?
+Most likely these are bugs where one meant to write `a
+op= b`.
+
+### Known problems
+Clippy cannot know for sure if `a op= a op b` should have
+been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both.
+If `a op= a op b` is really the correct behavior it should be
+written as `a = a op a op b` as it's less confusing.
+
+### Example
+```
+let mut a = 5;
+let b = 2;
+// ...
+a += a + b;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_const_for_fn.txt b/src/tools/clippy/src/docs/missing_const_for_fn.txt
new file mode 100644
index 000000000..067614d4c
--- /dev/null
+++ b/src/tools/clippy/src/docs/missing_const_for_fn.txt
@@ -0,0 +1,40 @@
+### What it does
+Suggests the use of `const` in functions and methods where possible.
+
+### Why is this bad?
+Not having the function const prevents callers of the function from being const as well.
+
+### Known problems
+Const functions are currently still being worked on, with some features only being available
+on nightly. This lint does not consider all edge cases currently and the suggestions may be
+incorrect if you are using this lint on stable.
+
+Also, the lint only runs one pass over the code. Consider these two non-const functions:
+
+```
+fn a() -> i32 {
+ 0
+}
+fn b() -> i32 {
+ a()
+}
+```
+
+When running Clippy, the lint will only suggest to make `a` const, because `b` at this time
+can't be const as it calls a non-const function. Making `a` const and running Clippy again,
+will suggest to make `b` const, too.
+
+### Example
+```
+fn new() -> Self {
+ Self { random_number: 42 }
+}
+```
+
+Could be a const fn:
+
+```
+const fn new() -> Self {
+ Self { random_number: 42 }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_docs_in_private_items.txt b/src/tools/clippy/src/docs/missing_docs_in_private_items.txt
new file mode 100644
index 000000000..5d37505bb
--- /dev/null
+++ b/src/tools/clippy/src/docs/missing_docs_in_private_items.txt
@@ -0,0 +1,9 @@
+### What it does
+Warns if there is missing doc for any documentable item
+(public or private).
+
+### Why is this bad?
+Doc is good. *rustc* has a `MISSING_DOCS`
+allowed-by-default lint for
+public members, but has no way to enforce documentation of private items.
+This lint fixes that. \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_enforced_import_renames.txt b/src/tools/clippy/src/docs/missing_enforced_import_renames.txt
new file mode 100644
index 000000000..8f4649bd5
--- /dev/null
+++ b/src/tools/clippy/src/docs/missing_enforced_import_renames.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for imports that do not rename the item as specified
+in the `enforce-import-renames` config option.
+
+### Why is this bad?
+Consistency is important, if a project has defined import
+renames they should be followed. More practically, some item names are too
+vague outside of their defining scope this can enforce a more meaningful naming.
+
+### Example
+An example clippy.toml configuration:
+```
+enforced-import-renames = [ { path = "serde_json::Value", rename = "JsonValue" }]
+```
+
+```
+use serde_json::Value;
+```
+Use instead:
+```
+use serde_json::Value as JsonValue;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_errors_doc.txt b/src/tools/clippy/src/docs/missing_errors_doc.txt
new file mode 100644
index 000000000..028778d85
--- /dev/null
+++ b/src/tools/clippy/src/docs/missing_errors_doc.txt
@@ -0,0 +1,21 @@
+### 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:
+
+```
+/// # 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!();
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_inline_in_public_items.txt b/src/tools/clippy/src/docs/missing_inline_in_public_items.txt
new file mode 100644
index 000000000..d90c50fe7
--- /dev/null
+++ b/src/tools/clippy/src/docs/missing_inline_in_public_items.txt
@@ -0,0 +1,45 @@
+### What it does
+It lints if an exported function, method, trait method with default impl,
+or trait method impl is not `#[inline]`.
+
+### Why is this bad?
+In general, it is not. Functions can be inlined across
+crates when that's profitable as long as any form of LTO is used. When LTO is disabled,
+functions that are not `#[inline]` cannot be inlined across crates. Certain types of crates
+might intend for most of the methods in their public API to be able to be inlined across
+crates even when LTO is disabled. For these types of crates, enabling this lint might make
+sense. It allows the crate to require all exported methods to be `#[inline]` by default, and
+then opt out for specific methods where this might not make sense.
+
+### Example
+```
+pub fn foo() {} // missing #[inline]
+fn ok() {} // ok
+#[inline] pub fn bar() {} // ok
+#[inline(always)] pub fn baz() {} // ok
+
+pub trait Bar {
+ fn bar(); // ok
+ fn def_bar() {} // missing #[inline]
+}
+
+struct Baz;
+impl Baz {
+ fn private() {} // ok
+}
+
+impl Bar for Baz {
+ fn bar() {} // ok - Baz is not exported
+}
+
+pub struct PubBaz;
+impl PubBaz {
+ fn private() {} // ok
+ pub fn not_private() {} // missing #[inline]
+}
+
+impl Bar for PubBaz {
+ fn bar() {} // missing #[inline]
+ fn def_bar() {} // missing #[inline]
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_panics_doc.txt b/src/tools/clippy/src/docs/missing_panics_doc.txt
new file mode 100644
index 000000000..e5e39a824
--- /dev/null
+++ b/src/tools/clippy/src/docs/missing_panics_doc.txt
@@ -0,0 +1,24 @@
+### 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:
+
+```
+/// # 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
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_safety_doc.txt b/src/tools/clippy/src/docs/missing_safety_doc.txt
new file mode 100644
index 000000000..6492eb84f
--- /dev/null
+++ b/src/tools/clippy/src/docs/missing_safety_doc.txt
@@ -0,0 +1,26 @@
+### 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
+```
+/// This function should really be documented
+pub unsafe fn start_apocalypse(u: &mut Universe) {
+ unimplemented!();
+}
+```
+
+At least write a line about safety:
+
+```
+/// # Safety
+///
+/// This function should not be called before the horsemen are ready.
+pub unsafe fn start_apocalypse(u: &mut Universe) {
+ unimplemented!();
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_spin_loop.txt b/src/tools/clippy/src/docs/missing_spin_loop.txt
new file mode 100644
index 000000000..3a06a91d7
--- /dev/null
+++ b/src/tools/clippy/src/docs/missing_spin_loop.txt
@@ -0,0 +1,27 @@
+### What it does
+Check for empty spin loops
+
+### Why is this bad?
+The loop body should have something like `thread::park()` or at least
+`std::hint::spin_loop()` to avoid needlessly burning cycles and conserve
+energy. Perhaps even better use an actual lock, if possible.
+
+### Known problems
+This lint doesn't currently trigger on `while let` or
+`loop { match .. { .. } }` loops, which would be considered idiomatic in
+combination with e.g. `AtomicBool::compare_exchange_weak`.
+
+### Example
+
+```
+use core::sync::atomic::{AtomicBool, Ordering};
+let b = AtomicBool::new(true);
+// give a ref to `b` to another thread,wait for it to become false
+while b.load(Ordering::Acquire) {};
+```
+Use instead:
+```
+while b.load(Ordering::Acquire) {
+ std::hint::spin_loop()
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_trait_methods.txt b/src/tools/clippy/src/docs/missing_trait_methods.txt
new file mode 100644
index 000000000..788ad764f
--- /dev/null
+++ b/src/tools/clippy/src/docs/missing_trait_methods.txt
@@ -0,0 +1,40 @@
+### What it does
+Checks if a provided method is used implicitly by a trait
+implementation. A usage example would be a wrapper where every method
+should perform some operation before delegating to the inner type's
+implemenation.
+
+This lint should typically be enabled on a specific trait `impl` item
+rather than globally.
+
+### Why is this bad?
+Indicates that a method is missing.
+
+### Example
+```
+trait Trait {
+ fn required();
+
+ fn provided() {}
+}
+
+#[warn(clippy::missing_trait_methods)]
+impl Trait for Type {
+ fn required() { /* ... */ }
+}
+```
+Use instead:
+```
+trait Trait {
+ fn required();
+
+ fn provided() {}
+}
+
+#[warn(clippy::missing_trait_methods)]
+impl Trait for Type {
+ fn required() { /* ... */ }
+
+ fn provided() { /* ... */ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mistyped_literal_suffixes.txt b/src/tools/clippy/src/docs/mistyped_literal_suffixes.txt
new file mode 100644
index 000000000..1760fcbfe
--- /dev/null
+++ b/src/tools/clippy/src/docs/mistyped_literal_suffixes.txt
@@ -0,0 +1,15 @@
+### What it does
+Warns for mistyped suffix in literals
+
+### Why is this bad?
+This is most probably a typo
+
+### Known problems
+- Does not match on integers too large to fit in the corresponding unsigned type
+- Does not match on `_127` since that is a valid grouping for decimal and octal numbers
+
+### Example
+```
+`2_32` => `2_i32`
+`250_8 => `250_u8`
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mixed_case_hex_literals.txt b/src/tools/clippy/src/docs/mixed_case_hex_literals.txt
new file mode 100644
index 000000000..d2d01e0c9
--- /dev/null
+++ b/src/tools/clippy/src/docs/mixed_case_hex_literals.txt
@@ -0,0 +1,16 @@
+### What it does
+Warns on hexadecimal literals with mixed-case letter
+digits.
+
+### Why is this bad?
+It looks confusing.
+
+### Example
+```
+0x1a9BAcD
+```
+
+Use instead:
+```
+0x1A9BACD
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mixed_read_write_in_expression.txt b/src/tools/clippy/src/docs/mixed_read_write_in_expression.txt
new file mode 100644
index 000000000..02d1c5d05
--- /dev/null
+++ b/src/tools/clippy/src/docs/mixed_read_write_in_expression.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for a read and a write to the same variable where
+whether the read occurs before or after the write depends on the evaluation
+order of sub-expressions.
+
+### Why is this bad?
+It is often confusing to read. As described [here](https://doc.rust-lang.org/reference/expressions.html?highlight=subexpression#evaluation-order-of-operands),
+the operands of these expressions are evaluated before applying the effects of the expression.
+
+### Known problems
+Code which intentionally depends on the evaluation
+order, or which is correct for any evaluation order.
+
+### Example
+```
+let mut x = 0;
+
+let a = {
+ x = 1;
+ 1
+} + x;
+// Unclear whether a is 1 or 2.
+```
+
+Use instead:
+```
+let tmp = {
+ x = 1;
+ 1
+};
+let a = tmp + x;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mod_module_files.txt b/src/tools/clippy/src/docs/mod_module_files.txt
new file mode 100644
index 000000000..95bca583a
--- /dev/null
+++ b/src/tools/clippy/src/docs/mod_module_files.txt
@@ -0,0 +1,22 @@
+### 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
+```
+src/
+ stuff/
+ stuff_files.rs
+ mod.rs
+ lib.rs
+```
+Use instead:
+```
+src/
+ stuff/
+ stuff_files.rs
+ stuff.rs
+ lib.rs
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/module_inception.txt b/src/tools/clippy/src/docs/module_inception.txt
new file mode 100644
index 000000000..d80a1b8d8
--- /dev/null
+++ b/src/tools/clippy/src/docs/module_inception.txt
@@ -0,0 +1,24 @@
+### 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
+```
+// lib.rs
+mod foo;
+// foo.rs
+mod foo {
+ ...
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/module_name_repetitions.txt b/src/tools/clippy/src/docs/module_name_repetitions.txt
new file mode 100644
index 000000000..3bc05d027
--- /dev/null
+++ b/src/tools/clippy/src/docs/module_name_repetitions.txt
@@ -0,0 +1,20 @@
+### 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
+```
+mod cake {
+ struct BlackForestCake;
+}
+```
+
+Use instead:
+```
+mod cake {
+ struct BlackForest;
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/modulo_arithmetic.txt b/src/tools/clippy/src/docs/modulo_arithmetic.txt
new file mode 100644
index 000000000..ff7296f3c
--- /dev/null
+++ b/src/tools/clippy/src/docs/modulo_arithmetic.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for modulo arithmetic.
+
+### Why is this bad?
+The results of modulo (%) operation might differ
+depending on the language, when negative numbers are involved.
+If you interop with different languages it might be beneficial
+to double check all places that use modulo arithmetic.
+
+For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`.
+
+### Example
+```
+let x = -17 % 3;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/modulo_one.txt b/src/tools/clippy/src/docs/modulo_one.txt
new file mode 100644
index 000000000..bc8f95b0b
--- /dev/null
+++ b/src/tools/clippy/src/docs/modulo_one.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for getting the remainder of a division by one or minus
+one.
+
+### Why is this bad?
+The result for a divisor of one can only ever be zero; for
+minus one it can cause panic/overflow (if the left operand is the minimal value of
+the respective integer type) or results in zero. No one will write such code
+deliberately, unless trying to win an Underhanded Rust Contest. Even for that
+contest, it's probably a bad idea. Use something more underhanded.
+
+### Example
+```
+let a = x % 1;
+let a = x % -1;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/multi_assignments.txt b/src/tools/clippy/src/docs/multi_assignments.txt
new file mode 100644
index 000000000..ed1f1b420
--- /dev/null
+++ b/src/tools/clippy/src/docs/multi_assignments.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for nested assignments.
+
+### Why is this bad?
+While this is in most cases already a type mismatch,
+the result of an assignment being `()` can throw off people coming from languages like python or C,
+where such assignments return a copy of the assigned value.
+
+### Example
+```
+a = b = 42;
+```
+Use instead:
+```
+b = 42;
+a = b;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/multiple_crate_versions.txt b/src/tools/clippy/src/docs/multiple_crate_versions.txt
new file mode 100644
index 000000000..cf2d2c6ab
--- /dev/null
+++ b/src/tools/clippy/src/docs/multiple_crate_versions.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks to see if multiple versions of a crate are being
+used.
+
+### Why is this bad?
+This bloats the size of targets, and can lead to
+confusing error messages when structs or traits are used interchangeably
+between different versions of a crate.
+
+### Known problems
+Because this can be caused purely by the dependencies
+themselves, it's not always possible to fix this issue.
+
+### Example
+```
+[dependencies]
+ctrlc = "=3.1.0"
+ansi_term = "=0.11.0"
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/multiple_inherent_impl.txt b/src/tools/clippy/src/docs/multiple_inherent_impl.txt
new file mode 100644
index 000000000..9d4228656
--- /dev/null
+++ b/src/tools/clippy/src/docs/multiple_inherent_impl.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for multiple inherent implementations of a struct
+
+### Why is this bad?
+Splitting the implementation of a type makes the code harder to navigate.
+
+### Example
+```
+struct X;
+impl X {
+ fn one() {}
+}
+impl X {
+ fn other() {}
+}
+```
+
+Could be written:
+
+```
+struct X;
+impl X {
+ fn one() {}
+ fn other() {}
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/must_use_candidate.txt b/src/tools/clippy/src/docs/must_use_candidate.txt
new file mode 100644
index 000000000..70890346f
--- /dev/null
+++ b/src/tools/clippy/src/docs/must_use_candidate.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for public functions that have no
+`#[must_use]` attribute, but return something not already marked
+must-use, have no mutable arg and mutate no statics.
+
+### Why is this bad?
+Not bad at all, this lint just shows places where
+you could add the attribute.
+
+### Known problems
+The lint only checks the arguments for mutable
+types without looking if they are actually changed. On the other hand,
+it also ignores a broad range of potentially interesting side effects,
+because we cannot decide whether the programmer intends the function to
+be called for the side effect or the result. Expect many false
+positives. At least we don't lint if the result type is unit or already
+`#[must_use]`.
+
+### Examples
+```
+// this could be annotated with `#[must_use]`.
+fn id<T>(t: T) -> T { t }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/must_use_unit.txt b/src/tools/clippy/src/docs/must_use_unit.txt
new file mode 100644
index 000000000..cabbb23f8
--- /dev/null
+++ b/src/tools/clippy/src/docs/must_use_unit.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for a `#[must_use]` attribute on
+unit-returning functions and methods.
+
+### Why is this bad?
+Unit values are useless. The attribute is likely
+a remnant of a refactoring that removed the return type.
+
+### Examples
+```
+#[must_use]
+fn useless() { }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mut_from_ref.txt b/src/tools/clippy/src/docs/mut_from_ref.txt
new file mode 100644
index 000000000..cc1da1254
--- /dev/null
+++ b/src/tools/clippy/src/docs/mut_from_ref.txt
@@ -0,0 +1,26 @@
+### What it does
+This lint checks for functions that take immutable references and return
+mutable ones. This will not trigger if no unsafe code exists as there
+are multiple safe functions which will do this transformation
+
+To be on the conservative side, if there's at least one mutable
+reference with the output lifetime, this lint will not trigger.
+
+### Why is this bad?
+Creating a mutable reference which can be repeatably derived from an
+immutable reference is unsound as it allows creating multiple live
+mutable references to the same object.
+
+This [error](https://github.com/rust-lang/rust/issues/39465) actually
+lead to an interim Rust release 1.15.1.
+
+### Known problems
+This pattern is used by memory allocators to allow allocating multiple
+objects while returning mutable references to each one. So long as
+different mutable references are returned each time such a function may
+be safe.
+
+### Example
+```
+fn foo(&Foo) -> &mut Bar { .. }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mut_mut.txt b/src/tools/clippy/src/docs/mut_mut.txt
new file mode 100644
index 000000000..0bd34dd24
--- /dev/null
+++ b/src/tools/clippy/src/docs/mut_mut.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for instances of `mut mut` references.
+
+### Why is this bad?
+Multiple `mut`s don't add anything meaningful to the
+source. This is either a copy'n'paste error, or it shows a fundamental
+misunderstanding of references.
+
+### Example
+```
+let x = &mut &mut y;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mut_mutex_lock.txt b/src/tools/clippy/src/docs/mut_mutex_lock.txt
new file mode 100644
index 000000000..5e9ad8a3f
--- /dev/null
+++ b/src/tools/clippy/src/docs/mut_mutex_lock.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for `&mut Mutex::lock` calls
+
+### Why is this bad?
+`Mutex::lock` is less efficient than
+calling `Mutex::get_mut`. In addition you also have a statically
+guarantee that the mutex isn't locked, instead of just a runtime
+guarantee.
+
+### Example
+```
+use std::sync::{Arc, Mutex};
+
+let mut value_rc = Arc::new(Mutex::new(42_u8));
+let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
+
+let mut value = value_mutex.lock().unwrap();
+*value += 1;
+```
+Use instead:
+```
+use std::sync::{Arc, Mutex};
+
+let mut value_rc = Arc::new(Mutex::new(42_u8));
+let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
+
+let value = value_mutex.get_mut().unwrap();
+*value += 1;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mut_range_bound.txt b/src/tools/clippy/src/docs/mut_range_bound.txt
new file mode 100644
index 000000000..e9c38a543
--- /dev/null
+++ b/src/tools/clippy/src/docs/mut_range_bound.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for loops which have a range bound that is a mutable variable
+
+### Why is this bad?
+One might think that modifying the mutable variable changes the loop bounds
+
+### Known problems
+False positive when mutation is followed by a `break`, but the `break` is not immediately
+after the mutation:
+
+```
+let mut x = 5;
+for _ in 0..x {
+ x += 1; // x is a range bound that is mutated
+ ..; // some other expression
+ break; // leaves the loop, so mutation is not an issue
+}
+```
+
+False positive on nested loops ([#6072](https://github.com/rust-lang/rust-clippy/issues/6072))
+
+### Example
+```
+let mut foo = 42;
+for i in 0..foo {
+ foo -= 1;
+ println!("{}", i); // prints numbers from 0 to 42, not 0 to 21
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mutable_key_type.txt b/src/tools/clippy/src/docs/mutable_key_type.txt
new file mode 100644
index 000000000..15fe34f2b
--- /dev/null
+++ b/src/tools/clippy/src/docs/mutable_key_type.txt
@@ -0,0 +1,61 @@
+### What it does
+Checks for sets/maps with mutable key types.
+
+### Why is this bad?
+All of `HashMap`, `HashSet`, `BTreeMap` and
+`BtreeSet` rely on either the hash or the order of keys be unchanging,
+so having types with interior mutability is a bad idea.
+
+### Known problems
+
+#### False Positives
+It's correct to use a struct that contains interior mutability as a key, when its
+implementation of `Hash` or `Ord` doesn't access any of the interior mutable types.
+However, this lint is unable to recognize this, so it will often cause false positives in
+theses cases. The `bytes` crate is a great example of this.
+
+#### False Negatives
+For custom `struct`s/`enum`s, this lint is unable to check for interior mutability behind
+indirection. For example, `struct BadKey<'a>(&'a Cell<usize>)` will be seen as immutable
+and cause a false negative if its implementation of `Hash`/`Ord` accesses the `Cell`.
+
+This lint does check a few cases for indirection. Firstly, using some standard library
+types (`Option`, `Result`, `Box`, `Rc`, `Arc`, `Vec`, `VecDeque`, `BTreeMap` and
+`BTreeSet`) directly as keys (e.g. in `HashMap<Box<Cell<usize>>, ()>`) **will** trigger the
+lint, because the impls of `Hash`/`Ord` for these types directly call `Hash`/`Ord` on their
+contained type.
+
+Secondly, the implementations of `Hash` and `Ord` for raw pointers (`*const T` or `*mut T`)
+apply only to the **address** of the contained value. Therefore, interior mutability
+behind raw pointers (e.g. in `HashSet<*mut Cell<usize>>`) can't impact the value of `Hash`
+or `Ord`, and therefore will not trigger this link. For more info, see issue
+[#6745](https://github.com/rust-lang/rust-clippy/issues/6745).
+
+### Example
+```
+use std::cmp::{PartialEq, Eq};
+use std::collections::HashSet;
+use std::hash::{Hash, Hasher};
+use std::sync::atomic::AtomicUsize;
+
+struct Bad(AtomicUsize);
+impl PartialEq for Bad {
+ fn eq(&self, rhs: &Self) -> bool {
+ ..
+; unimplemented!();
+ }
+}
+
+impl Eq for Bad {}
+
+impl Hash for Bad {
+ fn hash<H: Hasher>(&self, h: &mut H) {
+ ..
+; unimplemented!();
+ }
+}
+
+fn main() {
+ let _: HashSet<Bad> = HashSet::new();
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mutex_atomic.txt b/src/tools/clippy/src/docs/mutex_atomic.txt
new file mode 100644
index 000000000..062ac8b32
--- /dev/null
+++ b/src/tools/clippy/src/docs/mutex_atomic.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usages of `Mutex<X>` where an atomic will do.
+
+### Why is this bad?
+Using a mutex just to make access to a plain bool or
+reference sequential is shooting flies with cannons.
+`std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and
+faster.
+
+### Known problems
+This lint cannot detect if the mutex is actually used
+for waiting before a critical section.
+
+### Example
+```
+let x = Mutex::new(&y);
+```
+
+Use instead:
+```
+let x = AtomicBool::new(y);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/mutex_integer.txt b/src/tools/clippy/src/docs/mutex_integer.txt
new file mode 100644
index 000000000..f9dbdfb90
--- /dev/null
+++ b/src/tools/clippy/src/docs/mutex_integer.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usages of `Mutex<X>` where `X` is an integral
+type.
+
+### Why is this bad?
+Using a mutex just to make access to a plain integer
+sequential is
+shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster.
+
+### Known problems
+This lint cannot detect if the mutex is actually used
+for waiting before a critical section.
+
+### Example
+```
+let x = Mutex::new(0usize);
+```
+
+Use instead:
+```
+let x = AtomicUsize::new(0usize);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/naive_bytecount.txt b/src/tools/clippy/src/docs/naive_bytecount.txt
new file mode 100644
index 000000000..24659dc79
--- /dev/null
+++ b/src/tools/clippy/src/docs/naive_bytecount.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for naive byte counts
+
+### Why is this bad?
+The [`bytecount`](https://crates.io/crates/bytecount)
+crate has methods to count your bytes faster, especially for large slices.
+
+### Known problems
+If you have predominantly small slices, the
+`bytecount::count(..)` method may actually be slower. However, if you can
+ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be
+faster in those cases.
+
+### Example
+```
+let count = vec.iter().filter(|x| **x == 0u8).count();
+```
+
+Use instead:
+```
+let count = bytecount::count(&vec, 0u8);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_arbitrary_self_type.txt b/src/tools/clippy/src/docs/needless_arbitrary_self_type.txt
new file mode 100644
index 000000000..8216a3a3f
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_arbitrary_self_type.txt
@@ -0,0 +1,44 @@
+### What it does
+The lint checks for `self` in fn parameters that
+specify the `Self`-type explicitly
+### Why is this bad?
+Increases the amount and decreases the readability of code
+
+### Example
+```
+enum ValType {
+ I32,
+ I64,
+ F32,
+ F64,
+}
+
+impl ValType {
+ pub fn bytes(self: Self) -> usize {
+ match self {
+ Self::I32 | Self::F32 => 4,
+ Self::I64 | Self::F64 => 8,
+ }
+ }
+}
+```
+
+Could be rewritten as
+
+```
+enum ValType {
+ I32,
+ I64,
+ F32,
+ F64,
+}
+
+impl ValType {
+ pub fn bytes(self) -> usize {
+ match self {
+ Self::I32 | Self::F32 => 4,
+ Self::I64 | Self::F64 => 8,
+ }
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_bitwise_bool.txt b/src/tools/clippy/src/docs/needless_bitwise_bool.txt
new file mode 100644
index 000000000..fcd7b730a
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_bitwise_bool.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using
+a lazy and.
+
+### Why is this bad?
+The bitwise operators do not support short-circuiting, so it may hinder code performance.
+Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold`
+
+### Known problems
+This lint evaluates only when the right side is determined to have no side effects. At this time, that
+determination is quite conservative.
+
+### Example
+```
+let (x,y) = (true, false);
+if x & !y {} // where both x and y are booleans
+```
+Use instead:
+```
+let (x,y) = (true, false);
+if x && !y {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_bool.txt b/src/tools/clippy/src/docs/needless_bool.txt
new file mode 100644
index 000000000..b5c78871f
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_bool.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for expressions of the form `if c { true } else {
+false }` (or vice versa) and suggests using the condition directly.
+
+### Why is this bad?
+Redundant code.
+
+### Known problems
+Maybe false positives: Sometimes, the two branches are
+painstakingly documented (which we, of course, do not detect), so they *may*
+have some value. Even then, the documentation can be rewritten to match the
+shorter code.
+
+### Example
+```
+if x {
+ false
+} else {
+ true
+}
+```
+
+Use instead:
+```
+!x
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_borrow.txt b/src/tools/clippy/src/docs/needless_borrow.txt
new file mode 100644
index 000000000..4debcf473
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_borrow.txt
@@ -0,0 +1,21 @@
+### 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
+```
+fn fun(_a: &i32) {}
+
+let x: &i32 = &&&&&&5;
+fun(&x);
+```
+
+Use instead:
+```
+let x: &i32 = &5;
+fun(x);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_borrowed_reference.txt b/src/tools/clippy/src/docs/needless_borrowed_reference.txt
new file mode 100644
index 000000000..152459ba1
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_borrowed_reference.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for bindings that needlessly destructure a reference and borrow the inner
+value with `&ref`.
+
+### Why is this bad?
+This pattern has no effect in almost all cases.
+
+### Example
+```
+let mut v = Vec::<String>::new();
+v.iter_mut().filter(|&ref a| a.is_empty());
+
+if let &[ref first, ref second] = v.as_slice() {}
+```
+
+Use instead:
+```
+let mut v = Vec::<String>::new();
+v.iter_mut().filter(|a| a.is_empty());
+
+if let [first, second] = v.as_slice() {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_collect.txt b/src/tools/clippy/src/docs/needless_collect.txt
new file mode 100644
index 000000000..275c39afc
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_collect.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for functions collecting an iterator when collect
+is not needed.
+
+### Why is this bad?
+`collect` causes the allocation of a new data structure,
+when this allocation may not be needed.
+
+### Example
+```
+let len = iterator.clone().collect::<Vec<_>>().len();
+// should be
+let len = iterator.count();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_continue.txt b/src/tools/clippy/src/docs/needless_continue.txt
new file mode 100644
index 000000000..2cee621c1
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_continue.txt
@@ -0,0 +1,61 @@
+### What it does
+The lint checks for `if`-statements appearing in loops
+that contain a `continue` statement in either their main blocks or their
+`else`-blocks, when omitting the `else`-block possibly with some
+rearrangement of code can make the code easier to understand.
+
+### Why is this bad?
+Having explicit `else` blocks for `if` statements
+containing `continue` in their THEN branch adds unnecessary branching and
+nesting to the code. Having an else block containing just `continue` can
+also be better written by grouping the statements following the whole `if`
+statement within the THEN block and omitting the else block completely.
+
+### Example
+```
+while condition() {
+ update_condition();
+ if x {
+ // ...
+ } else {
+ continue;
+ }
+ println!("Hello, world");
+}
+```
+
+Could be rewritten as
+
+```
+while condition() {
+ update_condition();
+ if x {
+ // ...
+ println!("Hello, world");
+ }
+}
+```
+
+As another example, the following code
+
+```
+loop {
+ if waiting() {
+ continue;
+ } else {
+ // Do something useful
+ }
+ # break;
+}
+```
+Could be rewritten as
+
+```
+loop {
+ if waiting() {
+ continue;
+ }
+ // Do something useful
+ # break;
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_doctest_main.txt b/src/tools/clippy/src/docs/needless_doctest_main.txt
new file mode 100644
index 000000000..8f91a7baa
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_doctest_main.txt
@@ -0,0 +1,22 @@
+### 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
+```
+/// An example of a doctest with a `main()` function
+///
+/// # Examples
+///
+/// ```
+/// fn main() {
+/// // this needs not be in an `fn`
+/// }
+/// ```
+fn needless_main() {
+ unimplemented!();
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_for_each.txt b/src/tools/clippy/src/docs/needless_for_each.txt
new file mode 100644
index 000000000..9ae6dd360
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_for_each.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for usage of `for_each` that would be more simply written as a
+`for` loop.
+
+### Why is this bad?
+`for_each` may be used after applying iterator transformers like
+`filter` for better readability and performance. It may also be used to fit a simple
+operation on one line.
+But when none of these apply, a simple `for` loop is more idiomatic.
+
+### Example
+```
+let v = vec![0, 1, 2];
+v.iter().for_each(|elem| {
+ println!("{}", elem);
+})
+```
+Use instead:
+```
+let v = vec![0, 1, 2];
+for elem in v.iter() {
+ println!("{}", elem);
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_late_init.txt b/src/tools/clippy/src/docs/needless_late_init.txt
new file mode 100644
index 000000000..9e7bbcea9
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_late_init.txt
@@ -0,0 +1,42 @@
+### What it does
+Checks for late initializations that can be replaced by a `let` statement
+with an initializer.
+
+### Why is this bad?
+Assigning in the `let` statement is less repetitive.
+
+### Example
+```
+let a;
+a = 1;
+
+let b;
+match 3 {
+ 0 => b = "zero",
+ 1 => b = "one",
+ _ => b = "many",
+}
+
+let c;
+if true {
+ c = 1;
+} else {
+ c = -1;
+}
+```
+Use instead:
+```
+let a = 1;
+
+let b = match 3 {
+ 0 => "zero",
+ 1 => "one",
+ _ => "many",
+};
+
+let c = if true {
+ 1
+} else {
+ -1
+};
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_lifetimes.txt b/src/tools/clippy/src/docs/needless_lifetimes.txt
new file mode 100644
index 000000000..b280caa66
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_lifetimes.txt
@@ -0,0 +1,29 @@
+### 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 potential 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
+```
+// Unnecessary lifetime annotations
+fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 {
+ x
+}
+```
+
+Use instead:
+```
+fn elided(x: &u8, y: u8) -> &u8 {
+ x
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_match.txt b/src/tools/clippy/src/docs/needless_match.txt
new file mode 100644
index 000000000..92b40a5df
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_match.txt
@@ -0,0 +1,36 @@
+### What it does
+Checks for unnecessary `match` or match-like `if let` returns for `Option` and `Result`
+when function signatures are the same.
+
+### Why is this bad?
+This `match` block does nothing and might not be what the coder intended.
+
+### Example
+```
+fn foo() -> Result<(), i32> {
+ match result {
+ Ok(val) => Ok(val),
+ Err(err) => Err(err),
+ }
+}
+
+fn bar() -> Option<i32> {
+ if let Some(val) = option {
+ Some(val)
+ } else {
+ None
+ }
+}
+```
+
+Could be replaced as
+
+```
+fn foo() -> Result<(), i32> {
+ result
+}
+
+fn bar() -> Option<i32> {
+ option
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_option_as_deref.txt b/src/tools/clippy/src/docs/needless_option_as_deref.txt
new file mode 100644
index 000000000..226396c97
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_option_as_deref.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for no-op uses of `Option::{as_deref, as_deref_mut}`,
+for example, `Option<&T>::as_deref()` returns the same type.
+
+### Why is this bad?
+Redundant code and improving readability.
+
+### Example
+```
+let a = Some(&1);
+let b = a.as_deref(); // goes from Option<&i32> to Option<&i32>
+```
+
+Use instead:
+```
+let a = Some(&1);
+let b = a;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_option_take.txt b/src/tools/clippy/src/docs/needless_option_take.txt
new file mode 100644
index 000000000..6bac65a13
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_option_take.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for calling `take` function after `as_ref`.
+
+### Why is this bad?
+Redundant code. `take` writes `None` to its argument.
+In this case the modification is useless as it's a temporary that cannot be read from afterwards.
+
+### Example
+```
+let x = Some(3);
+x.as_ref().take();
+```
+Use instead:
+```
+let x = Some(3);
+x.as_ref();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_parens_on_range_literals.txt b/src/tools/clippy/src/docs/needless_parens_on_range_literals.txt
new file mode 100644
index 000000000..85fab10cb
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_parens_on_range_literals.txt
@@ -0,0 +1,23 @@
+### What it does
+The lint checks for parenthesis on literals in range statements that are
+superfluous.
+
+### Why is this bad?
+Having superfluous parenthesis makes the code less readable
+overhead when reading.
+
+### Example
+
+```
+for i in (0)..10 {
+ println!("{i}");
+}
+```
+
+Use instead:
+
+```
+for i in 0..10 {
+ println!("{i}");
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_pass_by_value.txt b/src/tools/clippy/src/docs/needless_pass_by_value.txt
new file mode 100644
index 000000000..58c420b19
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_pass_by_value.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for functions taking arguments by value, but not
+consuming them in its
+body.
+
+### Why is this bad?
+Taking arguments by reference is more flexible and can
+sometimes avoid
+unnecessary allocations.
+
+### Known problems
+* This lint suggests taking an argument by reference,
+however sometimes it is better to let users decide the argument type
+(by using `Borrow` trait, for example), depending on how the function is used.
+
+### Example
+```
+fn foo(v: Vec<i32>) {
+ assert_eq!(v.len(), 42);
+}
+```
+should be
+```
+fn foo(v: &[i32]) {
+ assert_eq!(v.len(), 42);
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_question_mark.txt b/src/tools/clippy/src/docs/needless_question_mark.txt
new file mode 100644
index 000000000..540739fd4
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_question_mark.txt
@@ -0,0 +1,43 @@
+### What it does
+Suggests alternatives for useless applications of `?` in terminating expressions
+
+### Why is this bad?
+There's no reason to use `?` to short-circuit when execution of the body will end there anyway.
+
+### Example
+```
+struct TO {
+ magic: Option<usize>,
+}
+
+fn f(to: TO) -> Option<usize> {
+ Some(to.magic?)
+}
+
+struct TR {
+ magic: Result<usize, bool>,
+}
+
+fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
+ tr.and_then(|t| Ok(t.magic?))
+}
+
+```
+Use instead:
+```
+struct TO {
+ magic: Option<usize>,
+}
+
+fn f(to: TO) -> Option<usize> {
+ to.magic
+}
+
+struct TR {
+ magic: Result<usize, bool>,
+}
+
+fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
+ tr.and_then(|t| t.magic)
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_range_loop.txt b/src/tools/clippy/src/docs/needless_range_loop.txt
new file mode 100644
index 000000000..583c09b28
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_range_loop.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for looping over the range of `0..len` of some
+collection just to get the values by index.
+
+### Why is this bad?
+Just iterating the collection itself makes the intent
+more clear and is probably faster.
+
+### Example
+```
+let vec = vec!['a', 'b', 'c'];
+for i in 0..vec.len() {
+ println!("{}", vec[i]);
+}
+```
+
+Use instead:
+```
+let vec = vec!['a', 'b', 'c'];
+for i in vec {
+ println!("{}", i);
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_return.txt b/src/tools/clippy/src/docs/needless_return.txt
new file mode 100644
index 000000000..48782cb0c
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_return.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for return statements at the end of a block.
+
+### Why is this bad?
+Removing the `return` and semicolon will make the code
+more rusty.
+
+### Example
+```
+fn foo(x: usize) -> usize {
+ return x;
+}
+```
+simplify to
+```
+fn foo(x: usize) -> usize {
+ x
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_splitn.txt b/src/tools/clippy/src/docs/needless_splitn.txt
new file mode 100644
index 000000000..b10a84fbc
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_splitn.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usages of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same.
+### Why is this bad?
+The function `split` is simpler and there is no performance difference in these cases, considering
+that both functions return a lazy iterator.
+### Example
+```
+let str = "key=value=add";
+let _ = str.splitn(3, '=').next().unwrap();
+```
+
+Use instead:
+```
+let str = "key=value=add";
+let _ = str.split('=').next().unwrap();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/needless_update.txt b/src/tools/clippy/src/docs/needless_update.txt
new file mode 100644
index 000000000..82adabf64
--- /dev/null
+++ b/src/tools/clippy/src/docs/needless_update.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for needlessly including a base struct on update
+when all fields are changed anyway.
+
+This lint is not applied to structs marked with
+[non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html).
+
+### Why is this bad?
+This will cost resources (because the base has to be
+somewhere), and make the code less readable.
+
+### Example
+```
+Point {
+ x: 1,
+ y: 1,
+ z: 1,
+ ..zero_point
+};
+```
+
+Use instead:
+```
+// Missing field `z`
+Point {
+ x: 1,
+ y: 1,
+ ..zero_point
+};
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/neg_cmp_op_on_partial_ord.txt b/src/tools/clippy/src/docs/neg_cmp_op_on_partial_ord.txt
new file mode 100644
index 000000000..fa55c6cfd
--- /dev/null
+++ b/src/tools/clippy/src/docs/neg_cmp_op_on_partial_ord.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for the usage of negated comparison operators on types which only implement
+`PartialOrd` (e.g., `f64`).
+
+### Why is this bad?
+These operators make it easy to forget that the underlying types actually allow not only three
+potential Orderings (Less, Equal, Greater) but also a fourth one (Uncomparable). This is
+especially easy to miss if the operator based comparison result is negated.
+
+### Example
+```
+let a = 1.0;
+let b = f64::NAN;
+
+let not_less_or_equal = !(a <= b);
+```
+
+Use instead:
+```
+use std::cmp::Ordering;
+
+let _not_less_or_equal = match a.partial_cmp(&b) {
+ None | Some(Ordering::Greater) => true,
+ _ => false,
+};
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/neg_multiply.txt b/src/tools/clippy/src/docs/neg_multiply.txt
new file mode 100644
index 000000000..4e8b096eb
--- /dev/null
+++ b/src/tools/clippy/src/docs/neg_multiply.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for multiplication by -1 as a form of negation.
+
+### Why is this bad?
+It's more readable to just negate.
+
+### Known problems
+This only catches integers (for now).
+
+### Example
+```
+let a = x * -1;
+```
+
+Use instead:
+```
+let a = -x;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/negative_feature_names.txt b/src/tools/clippy/src/docs/negative_feature_names.txt
new file mode 100644
index 000000000..01ee9efb3
--- /dev/null
+++ b/src/tools/clippy/src/docs/negative_feature_names.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for negative feature names with prefix `no-` or `not-`
+
+### Why is this bad?
+Features are supposed to be additive, and negatively-named features violate it.
+
+### Example
+```
+[features]
+default = []
+no-abc = []
+not-def = []
+
+```
+Use instead:
+```
+[features]
+default = ["abc", "def"]
+abc = []
+def = []
+
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/never_loop.txt b/src/tools/clippy/src/docs/never_loop.txt
new file mode 100644
index 000000000..737ccf415
--- /dev/null
+++ b/src/tools/clippy/src/docs/never_loop.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for loops that will always `break`, `return` or
+`continue` an outer loop.
+
+### Why is this bad?
+This loop never loops, all it does is obfuscating the
+code.
+
+### Example
+```
+loop {
+ ..;
+ break;
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/new_ret_no_self.txt b/src/tools/clippy/src/docs/new_ret_no_self.txt
new file mode 100644
index 000000000..291bad24a
--- /dev/null
+++ b/src/tools/clippy/src/docs/new_ret_no_self.txt
@@ -0,0 +1,47 @@
+### What it does
+Checks for `new` not returning a type that contains `Self`.
+
+### Why is this bad?
+As a convention, `new` methods are used to make a new
+instance of a type.
+
+### Example
+In an impl block:
+```
+impl Foo {
+ fn new() -> NotAFoo {
+ }
+}
+```
+
+```
+struct Bar(Foo);
+impl Foo {
+ // Bad. The type name must contain `Self`
+ fn new() -> Bar {
+ }
+}
+```
+
+```
+impl Foo {
+ // Good. Return type contains `Self`
+ fn new() -> Result<Foo, FooError> {
+ }
+}
+```
+
+Or in a trait definition:
+```
+pub trait Trait {
+ // Bad. The type name must contain `Self`
+ fn new();
+}
+```
+
+```
+pub trait Trait {
+ // Good. Return type contains `Self`
+ fn new() -> Self;
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/new_without_default.txt b/src/tools/clippy/src/docs/new_without_default.txt
new file mode 100644
index 000000000..662d39c8e
--- /dev/null
+++ b/src/tools/clippy/src/docs/new_without_default.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for public types with a `pub fn new() -> Self` method and no
+implementation of
+[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html).
+
+### Why is this bad?
+The user might expect to be able to use
+[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the
+type can be constructed without arguments.
+
+### Example
+```
+pub struct Foo(Bar);
+
+impl Foo {
+ pub fn new() -> Self {
+ Foo(Bar::new())
+ }
+}
+```
+
+To fix the lint, add a `Default` implementation that delegates to `new`:
+
+```
+pub struct Foo(Bar);
+
+impl Default for Foo {
+ fn default() -> Self {
+ Foo::new()
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/no_effect.txt b/src/tools/clippy/src/docs/no_effect.txt
new file mode 100644
index 000000000..d4cc08fa8
--- /dev/null
+++ b/src/tools/clippy/src/docs/no_effect.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for statements which have no effect.
+
+### Why is this bad?
+Unlike dead code, these statements are actually
+executed. However, as they have no effect, all they do is make the code less
+readable.
+
+### Example
+```
+0;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/no_effect_replace.txt b/src/tools/clippy/src/docs/no_effect_replace.txt
new file mode 100644
index 000000000..646d45287
--- /dev/null
+++ b/src/tools/clippy/src/docs/no_effect_replace.txt
@@ -0,0 +1,11 @@
+### What it does
+Checks for `replace` statements which have no effect.
+
+### Why is this bad?
+It's either a mistake or confusing.
+
+### Example
+```
+"1234".replace("12", "12");
+"1234".replacen("12", "12", 1);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/no_effect_underscore_binding.txt b/src/tools/clippy/src/docs/no_effect_underscore_binding.txt
new file mode 100644
index 000000000..972f60dd0
--- /dev/null
+++ b/src/tools/clippy/src/docs/no_effect_underscore_binding.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for binding to underscore prefixed variable without side-effects.
+
+### Why is this bad?
+Unlike dead code, these bindings are actually
+executed. However, as they have no effect and shouldn't be used further on, all they
+do is make the code less readable.
+
+### Known problems
+Further usage of this variable is not checked, which can lead to false positives if it is
+used later in the code.
+
+### Example
+```
+let _i_serve_no_purpose = 1;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/non_ascii_literal.txt b/src/tools/clippy/src/docs/non_ascii_literal.txt
new file mode 100644
index 000000000..164902b47
--- /dev/null
+++ b/src/tools/clippy/src/docs/non_ascii_literal.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for non-ASCII characters in string and char 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
+```
+let x = String::from("€");
+```
+
+Use instead:
+```
+let x = String::from("\u{20ac}");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/non_octal_unix_permissions.txt b/src/tools/clippy/src/docs/non_octal_unix_permissions.txt
new file mode 100644
index 000000000..4a468e94d
--- /dev/null
+++ b/src/tools/clippy/src/docs/non_octal_unix_permissions.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for non-octal values used to set Unix file permissions.
+
+### Why is this bad?
+They will be converted into octal, creating potentially
+unintended file permissions.
+
+### Example
+```
+use std::fs::OpenOptions;
+use std::os::unix::fs::OpenOptionsExt;
+
+let mut options = OpenOptions::new();
+options.mode(644);
+```
+Use instead:
+```
+use std::fs::OpenOptions;
+use std::os::unix::fs::OpenOptionsExt;
+
+let mut options = OpenOptions::new();
+options.mode(0o644);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/non_send_fields_in_send_ty.txt b/src/tools/clippy/src/docs/non_send_fields_in_send_ty.txt
new file mode 100644
index 000000000..11e6f6e16
--- /dev/null
+++ b/src/tools/clippy/src/docs/non_send_fields_in_send_ty.txt
@@ -0,0 +1,36 @@
+### What it does
+This lint warns about a `Send` implementation for a type that
+contains fields that are not safe to be sent across threads.
+It tries to detect fields that can cause a soundness issue
+when sent to another thread (e.g., `Rc`) while allowing `!Send` fields
+that are expected to exist in a `Send` type, such as raw pointers.
+
+### Why is this bad?
+Sending the struct to another thread effectively sends all of its fields,
+and the fields that do not implement `Send` can lead to soundness bugs
+such as data races when accessed in a thread
+that is different from the thread that created it.
+
+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
+This lint relies on heuristics to distinguish types that are actually
+unsafe to be sent across threads and `!Send` types that are expected to
+exist in `Send` type. Its rule can 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
+```
+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`). \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/nonminimal_bool.txt b/src/tools/clippy/src/docs/nonminimal_bool.txt
new file mode 100644
index 000000000..488980ddf
--- /dev/null
+++ b/src/tools/clippy/src/docs/nonminimal_bool.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for boolean expressions that can be written more
+concisely.
+
+### Why is this bad?
+Readability of boolean expressions suffers from
+unnecessary duplication.
+
+### Known problems
+Ignores short circuiting behavior of `||` and
+`&&`. Ignores `|`, `&` and `^`.
+
+### Example
+```
+if a && true {}
+if !(a == b) {}
+```
+
+Use instead:
+```
+if a {}
+if a != b {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/nonsensical_open_options.txt b/src/tools/clippy/src/docs/nonsensical_open_options.txt
new file mode 100644
index 000000000..7a95443b5
--- /dev/null
+++ b/src/tools/clippy/src/docs/nonsensical_open_options.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for duplicate open options as well as combinations
+that make no sense.
+
+### Why is this bad?
+In the best case, the code will be harder to read than
+necessary. I don't know the worst case.
+
+### Example
+```
+use std::fs::OpenOptions;
+
+OpenOptions::new().read(true).truncate(true);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/nonstandard_macro_braces.txt b/src/tools/clippy/src/docs/nonstandard_macro_braces.txt
new file mode 100644
index 000000000..7e8d0d2d3
--- /dev/null
+++ b/src/tools/clippy/src/docs/nonstandard_macro_braces.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks that common macros are used with consistent bracing.
+
+### Why is this bad?
+This is mostly a consistency lint although using () or []
+doesn't give you a semicolon in item position, which can be unexpected.
+
+### Example
+```
+vec!{1, 2, 3};
+```
+Use instead:
+```
+vec![1, 2, 3];
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/not_unsafe_ptr_arg_deref.txt b/src/tools/clippy/src/docs/not_unsafe_ptr_arg_deref.txt
new file mode 100644
index 000000000..31355fbb7
--- /dev/null
+++ b/src/tools/clippy/src/docs/not_unsafe_ptr_arg_deref.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for public functions that dereference raw pointer
+arguments but are not marked `unsafe`.
+
+### Why is this bad?
+The function should probably be marked `unsafe`, since
+for an arbitrary raw pointer, there is no way of telling for sure if it is
+valid.
+
+### Known problems
+* It does not check functions recursively so if the pointer is passed to a
+private non-`unsafe` function which does the dereferencing, the lint won't
+trigger.
+* It only checks for arguments whose type are raw pointers, not raw pointers
+got from an argument in some other way (`fn foo(bar: &[*const u8])` or
+`some_argument.get_raw_ptr()`).
+
+### Example
+```
+pub fn foo(x: *const u8) {
+ println!("{}", unsafe { *x });
+}
+```
+
+Use instead:
+```
+pub unsafe fn foo(x: *const u8) {
+ println!("{}", unsafe { *x });
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/obfuscated_if_else.txt b/src/tools/clippy/src/docs/obfuscated_if_else.txt
new file mode 100644
index 000000000..638f63b0d
--- /dev/null
+++ b/src/tools/clippy/src/docs/obfuscated_if_else.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for usages of `.then_some(..).unwrap_or(..)`
+
+### Why is this bad?
+This can be written more clearly with `if .. else ..`
+
+### Limitations
+This lint currently only looks for usages of
+`.then_some(..).unwrap_or(..)`, but will be expanded
+to account for similar patterns.
+
+### Example
+```
+let x = true;
+x.then_some("a").unwrap_or("b");
+```
+Use instead:
+```
+let x = true;
+if x { "a" } else { "b" };
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/octal_escapes.txt b/src/tools/clippy/src/docs/octal_escapes.txt
new file mode 100644
index 000000000..eee820587
--- /dev/null
+++ b/src/tools/clippy/src/docs/octal_escapes.txt
@@ -0,0 +1,33 @@
+### What it does
+Checks for `\0` escapes in string and byte literals that look like octal
+character escapes in C.
+
+### Why is this bad?
+
+C and other languages support octal character escapes in strings, where
+a backslash is followed by up to three octal digits. For example, `\033`
+stands for the ASCII character 27 (ESC). Rust does not support this
+notation, but has the escape code `\0` which stands for a null
+byte/character, and any following digits do not form part of the escape
+sequence. Therefore, `\033` is not a compiler error but the result may
+be surprising.
+
+### Known problems
+The actual meaning can be the intended one. `\x00` can be used in these
+cases to be unambiguous.
+
+The lint does not trigger for format strings in `print!()`, `write!()`
+and friends since the string is already preprocessed when Clippy lints
+can see it.
+
+### Example
+```
+let one = "\033[1m Bold? \033[0m"; // \033 intended as escape
+let two = "\033\0"; // \033 intended as null-3-3
+```
+
+Use instead:
+```
+let one = "\x1b[1mWill this be bold?\x1b[0m";
+let two = "\x0033\x00";
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ok_expect.txt b/src/tools/clippy/src/docs/ok_expect.txt
new file mode 100644
index 000000000..fd5205d49
--- /dev/null
+++ b/src/tools/clippy/src/docs/ok_expect.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `ok().expect(..)`.
+
+### Why is this bad?
+Because you usually call `expect()` on the `Result`
+directly to get a better error message.
+
+### Known problems
+The error type needs to implement `Debug`
+
+### Example
+```
+x.ok().expect("why did I do this again?");
+```
+
+Use instead:
+```
+x.expect("why did I do this again?");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/only_used_in_recursion.txt b/src/tools/clippy/src/docs/only_used_in_recursion.txt
new file mode 100644
index 000000000..f19f47ff9
--- /dev/null
+++ b/src/tools/clippy/src/docs/only_used_in_recursion.txt
@@ -0,0 +1,58 @@
+### What it does
+Checks for arguments that are only used in recursion with no side-effects.
+
+### Why is this bad?
+It could contain a useless calculation and can make function simpler.
+
+The arguments can be involved in calculations and assignments but as long as
+the calculations have no side-effects (function calls or mutating dereference)
+and the assigned variables are also only in recursion, it is useless.
+
+### Known problems
+Too many code paths in the linting code are currently untested and prone to produce false
+positives or are prone to have performance implications.
+
+In some cases, this would not catch all useless arguments.
+
+```
+fn foo(a: usize, b: usize) -> usize {
+ let f = |x| x + 1;
+
+ if a == 0 {
+ 1
+ } else {
+ foo(a - 1, f(b))
+ }
+}
+```
+
+For example, the argument `b` is only used in recursion, but the lint would not catch it.
+
+List of some examples that can not be caught:
+- binary operation of non-primitive types
+- closure usage
+- some `break` relative operations
+- struct pattern binding
+
+Also, when you recurse the function name with path segments, it is not possible to detect.
+
+### Example
+```
+fn f(a: usize, b: usize) -> usize {
+ if a == 0 {
+ 1
+ } else {
+ f(a - 1, b + 1)
+ }
+}
+```
+Use instead:
+```
+fn f(a: usize) -> usize {
+ if a == 0 {
+ 1
+ } else {
+ f(a - 1)
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/op_ref.txt b/src/tools/clippy/src/docs/op_ref.txt
new file mode 100644
index 000000000..7a7ed1bc9
--- /dev/null
+++ b/src/tools/clippy/src/docs/op_ref.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for arguments to `==` which have their address
+taken to satisfy a bound
+and suggests to dereference the other argument instead
+
+### Why is this bad?
+It is more idiomatic to dereference the other argument.
+
+### Example
+```
+&x == y
+```
+
+Use instead:
+```
+x == *y
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/option_as_ref_deref.txt b/src/tools/clippy/src/docs/option_as_ref_deref.txt
new file mode 100644
index 000000000..ad7411d3d
--- /dev/null
+++ b/src/tools/clippy/src/docs/option_as_ref_deref.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str).
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.as_deref()`.
+
+### Example
+```
+opt.as_ref().map(String::as_str)
+```
+Can be written as
+```
+opt.as_deref()
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/option_env_unwrap.txt b/src/tools/clippy/src/docs/option_env_unwrap.txt
new file mode 100644
index 000000000..c952cba8e
--- /dev/null
+++ b/src/tools/clippy/src/docs/option_env_unwrap.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `option_env!(...).unwrap()` and
+suggests usage of the `env!` macro.
+
+### Why is this bad?
+Unwrapping the result of `option_env!` will panic
+at run-time if the environment variable doesn't exist, whereas `env!`
+catches it at compile-time.
+
+### Example
+```
+let _ = option_env!("HOME").unwrap();
+```
+
+Is better expressed as:
+
+```
+let _ = env!("HOME");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/option_filter_map.txt b/src/tools/clippy/src/docs/option_filter_map.txt
new file mode 100644
index 000000000..25f7bde7b
--- /dev/null
+++ b/src/tools/clippy/src/docs/option_filter_map.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for indirect collection of populated `Option`
+
+### Why is this bad?
+`Option` is like a collection of 0-1 things, so `flatten`
+automatically does this without suspicious-looking `unwrap` calls.
+
+### Example
+```
+let _ = std::iter::empty::<Option<i32>>().filter(Option::is_some).map(Option::unwrap);
+```
+Use instead:
+```
+let _ = std::iter::empty::<Option<i32>>().flatten();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/option_if_let_else.txt b/src/tools/clippy/src/docs/option_if_let_else.txt
new file mode 100644
index 000000000..43652db51
--- /dev/null
+++ b/src/tools/clippy/src/docs/option_if_let_else.txt
@@ -0,0 +1,46 @@
+### What it does
+Lints usage of `if let Some(v) = ... { y } else { x }` and
+`match .. { Some(v) => y, None/_ => x }` which are 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
+```
+let _ = if let Some(foo) = optional {
+ foo
+} else {
+ 5
+};
+let _ = match optional {
+ Some(val) => val + 1,
+ None => 5
+};
+let _ = if let Some(foo) = optional {
+ foo
+} else {
+ let y = do_complicated_function();
+ y*y
+};
+```
+
+should be
+
+```
+let _ = optional.map_or(5, |foo| foo);
+let _ = optional.map_or(5, |val| val + 1);
+let _ = optional.map_or_else(||{
+ let y = do_complicated_function();
+ y*y
+}, |foo| foo);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/option_map_or_none.txt b/src/tools/clippy/src/docs/option_map_or_none.txt
new file mode 100644
index 000000000..c86c65215
--- /dev/null
+++ b/src/tools/clippy/src/docs/option_map_or_none.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `_.map_or(None, _)`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.and_then(_)`.
+
+### Known problems
+The order of the arguments is not in execution order.
+
+### Example
+```
+opt.map_or(None, |a| Some(a + 1));
+```
+
+Use instead:
+```
+opt.and_then(|a| Some(a + 1));
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/option_map_unit_fn.txt b/src/tools/clippy/src/docs/option_map_unit_fn.txt
new file mode 100644
index 000000000..fc4b528f0
--- /dev/null
+++ b/src/tools/clippy/src/docs/option_map_unit_fn.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for usage of `option.map(f)` where f is a function
+or closure that returns the unit type `()`.
+
+### Why is this bad?
+Readability, this can be written more clearly with
+an if let statement
+
+### Example
+```
+let x: Option<String> = do_stuff();
+x.map(log_err_msg);
+x.map(|msg| log_err_msg(format_msg(msg)));
+```
+
+The correct use would be:
+
+```
+let x: Option<String> = do_stuff();
+if let Some(msg) = x {
+ log_err_msg(msg);
+}
+
+if let Some(msg) = x {
+ log_err_msg(format_msg(msg));
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/option_option.txt b/src/tools/clippy/src/docs/option_option.txt
new file mode 100644
index 000000000..b4324bd83
--- /dev/null
+++ b/src/tools/clippy/src/docs/option_option.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for use of `Option<Option<_>>` in function signatures and type
+definitions
+
+### Why is this bad?
+`Option<_>` represents an optional value. `Option<Option<_>>`
+represents an optional optional value which is logically the same thing as an optional
+value but has an unneeded extra level of wrapping.
+
+If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases,
+consider a custom `enum` instead, with clear names for each case.
+
+### Example
+```
+fn get_data() -> Option<Option<u32>> {
+ None
+}
+```
+
+Better:
+
+```
+pub enum Contents {
+ Data(Vec<u8>), // Was Some(Some(Vec<u8>))
+ NotYetFetched, // Was Some(None)
+ None, // Was None
+}
+
+fn get_data() -> Contents {
+ Contents::None
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/or_fun_call.txt b/src/tools/clippy/src/docs/or_fun_call.txt
new file mode 100644
index 000000000..6ce77cc26
--- /dev/null
+++ b/src/tools/clippy/src/docs/or_fun_call.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
+`.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`,
+`.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()`
+etc. instead.
+
+### Why is this bad?
+The function will always be called and potentially
+allocate an object acting as the default.
+
+### Known problems
+If the function has side-effects, not calling it will
+change the semantic of the program, but you shouldn't rely on that anyway.
+
+### Example
+```
+foo.unwrap_or(String::new());
+```
+
+Use instead:
+```
+foo.unwrap_or_else(String::new);
+
+// or
+
+foo.unwrap_or_default();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/or_then_unwrap.txt b/src/tools/clippy/src/docs/or_then_unwrap.txt
new file mode 100644
index 000000000..64ac53749
--- /dev/null
+++ b/src/tools/clippy/src/docs/or_then_unwrap.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for `.or(…).unwrap()` calls to Options and Results.
+
+### Why is this bad?
+You should use `.unwrap_or(…)` instead for clarity.
+
+### Example
+```
+// Result
+let value = result.or::<Error>(Ok(fallback)).unwrap();
+
+// Option
+let value = option.or(Some(fallback)).unwrap();
+```
+Use instead:
+```
+// Result
+let value = result.unwrap_or(fallback);
+
+// Option
+let value = option.unwrap_or(fallback);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/out_of_bounds_indexing.txt b/src/tools/clippy/src/docs/out_of_bounds_indexing.txt
new file mode 100644
index 000000000..5802eea29
--- /dev/null
+++ b/src/tools/clippy/src/docs/out_of_bounds_indexing.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for out of bounds array indexing with a constant
+index.
+
+### Why is this bad?
+This will always panic at runtime.
+
+### Example
+```
+let x = [1, 2, 3, 4];
+
+x[9];
+&x[2..9];
+```
+
+Use instead:
+```
+// Index within bounds
+
+x[0];
+x[3];
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/overflow_check_conditional.txt b/src/tools/clippy/src/docs/overflow_check_conditional.txt
new file mode 100644
index 000000000..a09cc18a0
--- /dev/null
+++ b/src/tools/clippy/src/docs/overflow_check_conditional.txt
@@ -0,0 +1,11 @@
+### What it does
+Detects classic underflow/overflow checks.
+
+### Why is this bad?
+Most classic C underflow/overflow checks will fail in
+Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
+
+### Example
+```
+a + b < a;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/overly_complex_bool_expr.txt b/src/tools/clippy/src/docs/overly_complex_bool_expr.txt
new file mode 100644
index 000000000..65ca18392
--- /dev/null
+++ b/src/tools/clippy/src/docs/overly_complex_bool_expr.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for boolean expressions that contain terminals that
+can be eliminated.
+
+### Why is this bad?
+This is most likely a logic bug.
+
+### Known problems
+Ignores short circuiting behavior.
+
+### Example
+```
+// The `b` is unnecessary, the expression is equivalent to `if a`.
+if a && b || a { ... }
+```
+
+Use instead:
+```
+if a {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/panic.txt b/src/tools/clippy/src/docs/panic.txt
new file mode 100644
index 000000000..f9bdc6e87
--- /dev/null
+++ b/src/tools/clippy/src/docs/panic.txt
@@ -0,0 +1,10 @@
+### What it does
+Checks for usage of `panic!`.
+
+### Why is this bad?
+`panic!` will stop the execution of the executable
+
+### Example
+```
+panic!("even with a good reason");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/panic_in_result_fn.txt b/src/tools/clippy/src/docs/panic_in_result_fn.txt
new file mode 100644
index 000000000..51c2f8ae5
--- /dev/null
+++ b/src/tools/clippy/src/docs/panic_in_result_fn.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `panic!`, `unimplemented!`, `todo!`, `unreachable!` or assertions in a function of type result.
+
+### Why is this bad?
+For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence panicking macros should be avoided.
+
+### Known problems
+Functions called from a function returning a `Result` may invoke a panicking macro. This is not checked.
+
+### Example
+```
+fn result_with_panic() -> Result<bool, String>
+{
+ panic!("error");
+}
+```
+Use instead:
+```
+fn result_without_panic() -> Result<bool, String> {
+ Err(String::from("error"))
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/panicking_unwrap.txt b/src/tools/clippy/src/docs/panicking_unwrap.txt
new file mode 100644
index 000000000..1fbc245c8
--- /dev/null
+++ b/src/tools/clippy/src/docs/panicking_unwrap.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for calls of `unwrap[_err]()` that will always fail.
+
+### Why is this bad?
+If panicking is desired, an explicit `panic!()` should be used.
+
+### Known problems
+This lint only checks `if` conditions not assignments.
+So something like `let x: Option<()> = None; x.unwrap();` will not be recognized.
+
+### Example
+```
+if option.is_none() {
+ do_something_with(option.unwrap())
+}
+```
+
+This code will always panic. The if condition should probably be inverted. \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/partial_pub_fields.txt b/src/tools/clippy/src/docs/partial_pub_fields.txt
new file mode 100644
index 000000000..b529adf15
--- /dev/null
+++ b/src/tools/clippy/src/docs/partial_pub_fields.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks whether partial fields of a struct are public.
+
+Either make all fields of a type public, or make none of them public
+
+### Why is this bad?
+Most types should either be:
+* Abstract data types: complex objects with opaque implementation which guard
+interior invariants and expose intentionally limited API to the outside world.
+* Data: relatively simple objects which group a bunch of related attributes together.
+
+### Example
+```
+pub struct Color {
+ pub r: u8,
+ pub g: u8,
+ b: u8,
+}
+```
+Use instead:
+```
+pub struct Color {
+ pub r: u8,
+ pub g: u8,
+ pub b: u8,
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/partialeq_ne_impl.txt b/src/tools/clippy/src/docs/partialeq_ne_impl.txt
new file mode 100644
index 000000000..78f55188b
--- /dev/null
+++ b/src/tools/clippy/src/docs/partialeq_ne_impl.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for manual re-implementations of `PartialEq::ne`.
+
+### Why is this bad?
+`PartialEq::ne` is required to always return the
+negated result of `PartialEq::eq`, which is exactly what the default
+implementation does. Therefore, there should never be any need to
+re-implement it.
+
+### Example
+```
+struct Foo;
+
+impl PartialEq for Foo {
+ fn eq(&self, other: &Foo) -> bool { true }
+ fn ne(&self, other: &Foo) -> bool { !(self == other) }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/partialeq_to_none.txt b/src/tools/clippy/src/docs/partialeq_to_none.txt
new file mode 100644
index 000000000..5cc07bf88
--- /dev/null
+++ b/src/tools/clippy/src/docs/partialeq_to_none.txt
@@ -0,0 +1,24 @@
+### What it does
+
+Checks for binary comparisons to a literal `Option::None`.
+
+### Why is this bad?
+
+A programmer checking if some `foo` is `None` via a comparison `foo == None`
+is usually inspired from other programming languages (e.g. `foo is None`
+in Python).
+Checking if a value of type `Option<T>` is (not) equal to `None` in that
+way relies on `T: PartialEq` to do the comparison, which is unneeded.
+
+### Example
+```
+fn foo(f: Option<u32>) -> &'static str {
+ if f != None { "yay" } else { "nay" }
+}
+```
+Use instead:
+```
+fn foo(f: Option<u32>) -> &'static str {
+ if f.is_some() { "yay" } else { "nay" }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/path_buf_push_overwrite.txt b/src/tools/clippy/src/docs/path_buf_push_overwrite.txt
new file mode 100644
index 000000000..34f8901da
--- /dev/null
+++ b/src/tools/clippy/src/docs/path_buf_push_overwrite.txt
@@ -0,0 +1,25 @@
+### What it does
+* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push)
+calls on `PathBuf` that can cause overwrites.
+
+### Why is this bad?
+Calling `push` with a root path at the start can overwrite the
+previous defined path.
+
+### Example
+```
+use std::path::PathBuf;
+
+let mut x = PathBuf::from("/foo");
+x.push("/bar");
+assert_eq!(x, PathBuf::from("/bar"));
+```
+Could be written:
+
+```
+use std::path::PathBuf;
+
+let mut x = PathBuf::from("/foo");
+x.push("bar");
+assert_eq!(x, PathBuf::from("/foo/bar"));
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/pattern_type_mismatch.txt b/src/tools/clippy/src/docs/pattern_type_mismatch.txt
new file mode 100644
index 000000000..64da881d5
--- /dev/null
+++ b/src/tools/clippy/src/docs/pattern_type_mismatch.txt
@@ -0,0 +1,64 @@
+### What it does
+Checks for patterns that aren't exact representations of the types
+they are applied to.
+
+To satisfy this lint, you will have to adjust either the expression that is matched
+against or the pattern itself, as well as the bindings that are introduced by the
+adjusted patterns. For matching you will have to either dereference the expression
+with the `*` operator, or amend the patterns to explicitly match against `&<pattern>`
+or `&mut <pattern>` depending on the reference mutability. For the bindings you need
+to use the inverse. You can leave them as plain bindings if you wish for the value
+to be copied, but you must use `ref mut <variable>` or `ref <variable>` to construct
+a reference into the matched structure.
+
+If you are looking for a way to learn about ownership semantics in more detail, it
+is recommended to look at IDE options available to you to highlight types, lifetimes
+and reference semantics in your code. The available tooling would expose these things
+in a general way even outside of the various pattern matching mechanics. Of course
+this lint can still be used to highlight areas of interest and ensure a good understanding
+of ownership semantics.
+
+### Why is this bad?
+It isn't bad in general. But in some contexts it can be desirable
+because it increases ownership hints in the code, and will guard against some changes
+in ownership.
+
+### Example
+This example shows the basic adjustments necessary to satisfy the lint. Note how
+the matched expression is explicitly dereferenced with `*` and the `inner` variable
+is bound to a shared borrow via `ref inner`.
+
+```
+// Bad
+let value = &Some(Box::new(23));
+match value {
+ Some(inner) => println!("{}", inner),
+ None => println!("none"),
+}
+
+// Good
+let value = &Some(Box::new(23));
+match *value {
+ Some(ref inner) => println!("{}", inner),
+ None => println!("none"),
+}
+```
+
+The following example demonstrates one of the advantages of the more verbose style.
+Note how the second version uses `ref mut a` to explicitly declare `a` a shared mutable
+borrow, while `b` is simply taken by value. This ensures that the loop body cannot
+accidentally modify the wrong part of the structure.
+
+```
+// Bad
+let mut values = vec![(2, 3), (3, 4)];
+for (a, b) in &mut values {
+ *a += *b;
+}
+
+// Good
+let mut values = vec![(2, 3), (3, 4)];
+for &mut (ref mut a, b) in &mut values {
+ *a += b;
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/possible_missing_comma.txt b/src/tools/clippy/src/docs/possible_missing_comma.txt
new file mode 100644
index 000000000..5d92f4cae
--- /dev/null
+++ b/src/tools/clippy/src/docs/possible_missing_comma.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for possible missing comma in an array. It lints if
+an array element is a binary operator expression and it lies on two lines.
+
+### Why is this bad?
+This could lead to unexpected results.
+
+### Example
+```
+let a = &[
+ -1, -2, -3 // <= no comma here
+ -4, -5, -6
+];
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/precedence.txt b/src/tools/clippy/src/docs/precedence.txt
new file mode 100644
index 000000000..fda0b831f
--- /dev/null
+++ b/src/tools/clippy/src/docs/precedence.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for operations where precedence may be unclear
+and suggests to add parentheses. Currently it catches the following:
+* mixed usage of arithmetic and bit shifting/combining operators without
+parentheses
+* a "negative" numeric literal (which is really a unary `-` followed by a
+numeric literal)
+ followed by a method call
+
+### Why is this bad?
+Not everyone knows the precedence of those operators by
+heart, so expressions like these may trip others trying to reason about the
+code.
+
+### Example
+* `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7
+* `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1 \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/print_in_format_impl.txt b/src/tools/clippy/src/docs/print_in_format_impl.txt
new file mode 100644
index 000000000..140d23d6f
--- /dev/null
+++ b/src/tools/clippy/src/docs/print_in_format_impl.txt
@@ -0,0 +1,34 @@
+### What it does
+Checks for use of `println`, `print`, `eprintln` or `eprint` in an
+implementation of a formatting trait.
+
+### Why is this bad?
+Using a print macro is likely unintentional since formatting traits
+should write to the `Formatter`, not stdout/stderr.
+
+### Example
+```
+use std::fmt::{Display, Error, Formatter};
+
+struct S;
+impl Display for S {
+ fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+ println!("S");
+
+ Ok(())
+ }
+}
+```
+Use instead:
+```
+use std::fmt::{Display, Error, Formatter};
+
+struct S;
+impl Display for S {
+ fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+ writeln!(f, "S");
+
+ Ok(())
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/print_literal.txt b/src/tools/clippy/src/docs/print_literal.txt
new file mode 100644
index 000000000..a6252a687
--- /dev/null
+++ b/src/tools/clippy/src/docs/print_literal.txt
@@ -0,0 +1,16 @@
+### What it does
+This lint warns about the use of literals as `print!`/`println!` args.
+
+### Why is this bad?
+Using literals as `println!` args is inefficient
+(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
+(i.e., just put the literal in the format string)
+
+### Example
+```
+println!("{}", "foo");
+```
+use the literal without formatting:
+```
+println!("foo");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/print_stderr.txt b/src/tools/clippy/src/docs/print_stderr.txt
new file mode 100644
index 000000000..9c6edeeef
--- /dev/null
+++ b/src/tools/clippy/src/docs/print_stderr.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for printing on *stderr*. The purpose of this lint
+is to catch debugging remnants.
+
+### Why is this bad?
+People often print on *stderr* while debugging an
+application and might forget to remove those prints afterward.
+
+### Known problems
+Only catches `eprint!` and `eprintln!` calls.
+
+### Example
+```
+eprintln!("Hello world!");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/print_stdout.txt b/src/tools/clippy/src/docs/print_stdout.txt
new file mode 100644
index 000000000..d2cbd811d
--- /dev/null
+++ b/src/tools/clippy/src/docs/print_stdout.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for printing on *stdout*. The purpose of this lint
+is to catch debugging remnants.
+
+### Why is this bad?
+People often print on *stdout* while debugging an
+application and might forget to remove those prints afterward.
+
+### Known problems
+Only catches `print!` and `println!` calls.
+
+### Example
+```
+println!("Hello world!");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/print_with_newline.txt b/src/tools/clippy/src/docs/print_with_newline.txt
new file mode 100644
index 000000000..640323e82
--- /dev/null
+++ b/src/tools/clippy/src/docs/print_with_newline.txt
@@ -0,0 +1,16 @@
+### What it does
+This lint warns when you use `print!()` with a format
+string that ends in a newline.
+
+### Why is this bad?
+You should use `println!()` instead, which appends the
+newline.
+
+### Example
+```
+print!("Hello {}!\n", name);
+```
+use println!() instead
+```
+println!("Hello {}!", name);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/println_empty_string.txt b/src/tools/clippy/src/docs/println_empty_string.txt
new file mode 100644
index 000000000..b98041302
--- /dev/null
+++ b/src/tools/clippy/src/docs/println_empty_string.txt
@@ -0,0 +1,16 @@
+### What it does
+This lint warns when you use `println!("")` to
+print a newline.
+
+### Why is this bad?
+You should use `println!()`, which is simpler.
+
+### Example
+```
+println!("");
+```
+
+Use instead:
+```
+println!();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ptr_arg.txt b/src/tools/clippy/src/docs/ptr_arg.txt
new file mode 100644
index 000000000..796b0a65b
--- /dev/null
+++ b/src/tools/clippy/src/docs/ptr_arg.txt
@@ -0,0 +1,29 @@
+### What it does
+This lint checks for function arguments of type `&String`, `&Vec`,
+`&PathBuf`, and `Cow<_>`. It will also suggest you replace `.clone()` calls
+with the appropriate `.to_owned()`/`to_string()` calls.
+
+### Why is this bad?
+Requiring the argument to be of the specific size
+makes the function less useful for no benefit; slices in the form of `&[T]`
+or `&str` usually suffice and can be obtained from other types, too.
+
+### Known problems
+There may be `fn(&Vec)`-typed references pointing to your function.
+If you have them, you will get a compiler error after applying this lint's
+suggestions. You then have the choice to undo your changes or change the
+type of the reference.
+
+Note that if the function is part of your public interface, there may be
+other crates referencing it, of which you may not be aware. Carefully
+deprecate the function before applying the lint suggestions in this case.
+
+### Example
+```
+fn foo(&Vec<u32>) { .. }
+```
+
+Use instead:
+```
+fn foo(&[u32]) { .. }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ptr_as_ptr.txt b/src/tools/clippy/src/docs/ptr_as_ptr.txt
new file mode 100644
index 000000000..8fb35c4aa
--- /dev/null
+++ b/src/tools/clippy/src/docs/ptr_as_ptr.txt
@@ -0,0 +1,22 @@
+### 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
+```
+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:
+```
+let ptr: *const u32 = &42_u32;
+let mut_ptr: *mut u32 = &mut 42_u32;
+let _ = ptr.cast::<i32>();
+let _ = mut_ptr.cast::<i32>();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ptr_eq.txt b/src/tools/clippy/src/docs/ptr_eq.txt
new file mode 100644
index 000000000..06b36ca55
--- /dev/null
+++ b/src/tools/clippy/src/docs/ptr_eq.txt
@@ -0,0 +1,22 @@
+### What it does
+Use `std::ptr::eq` when applicable
+
+### Why is this bad?
+`ptr::eq` can be used to compare `&T` references
+(which coerce to `*const T` implicitly) by their address rather than
+comparing the values they point to.
+
+### Example
+```
+let a = &[1, 2, 3];
+let b = &[1, 2, 3];
+
+assert!(a as *const _ as usize == b as *const _ as usize);
+```
+Use instead:
+```
+let a = &[1, 2, 3];
+let b = &[1, 2, 3];
+
+assert!(std::ptr::eq(a, b));
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ptr_offset_with_cast.txt b/src/tools/clippy/src/docs/ptr_offset_with_cast.txt
new file mode 100644
index 000000000..f204e769b
--- /dev/null
+++ b/src/tools/clippy/src/docs/ptr_offset_with_cast.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for usage of the `offset` pointer method with a `usize` casted to an
+`isize`.
+
+### Why is this bad?
+If we’re always increasing the pointer address, we can avoid the numeric
+cast by using the `add` method instead.
+
+### Example
+```
+let vec = vec![b'a', b'b', b'c'];
+let ptr = vec.as_ptr();
+let offset = 1_usize;
+
+unsafe {
+ ptr.offset(offset as isize);
+}
+```
+
+Could be written:
+
+```
+let vec = vec![b'a', b'b', b'c'];
+let ptr = vec.as_ptr();
+let offset = 1_usize;
+
+unsafe {
+ ptr.add(offset);
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/pub_use.txt b/src/tools/clippy/src/docs/pub_use.txt
new file mode 100644
index 000000000..407cafa01
--- /dev/null
+++ b/src/tools/clippy/src/docs/pub_use.txt
@@ -0,0 +1,28 @@
+### What it does
+
+Restricts the usage of `pub use ...`
+
+### Why is this bad?
+
+`pub use` is usually fine, but a project may wish to limit `pub use` instances to prevent
+unintentional exports or to encourage placing exported items directly in public modules
+
+### Example
+```
+pub mod outer {
+ mod inner {
+ pub struct Test {}
+ }
+ pub use inner::Test;
+}
+
+use outer::Test;
+```
+Use instead:
+```
+pub mod outer {
+ pub struct Test {}
+}
+
+use outer::Test;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/question_mark.txt b/src/tools/clippy/src/docs/question_mark.txt
new file mode 100644
index 000000000..4dc987be8
--- /dev/null
+++ b/src/tools/clippy/src/docs/question_mark.txt
@@ -0,0 +1,18 @@
+### 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
+```
+if option.is_none() {
+ return None;
+}
+```
+
+Could be written:
+
+```
+option?;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/range_minus_one.txt b/src/tools/clippy/src/docs/range_minus_one.txt
new file mode 100644
index 000000000..fcb96dcc3
--- /dev/null
+++ b/src/tools/clippy/src/docs/range_minus_one.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for inclusive ranges where 1 is subtracted from
+the upper bound, e.g., `x..=(y-1)`.
+
+### Why is this bad?
+The code is more readable with an exclusive range
+like `x..y`.
+
+### Known problems
+This will cause a warning that cannot be fixed if
+the consumer of the range only accepts a specific range type, instead of
+the generic `RangeBounds` trait
+([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
+
+### Example
+```
+for i in x..=(y-1) {
+ // ..
+}
+```
+
+Use instead:
+```
+for i in x..y {
+ // ..
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/range_plus_one.txt b/src/tools/clippy/src/docs/range_plus_one.txt
new file mode 100644
index 000000000..193c85f9c
--- /dev/null
+++ b/src/tools/clippy/src/docs/range_plus_one.txt
@@ -0,0 +1,36 @@
+### What it does
+Checks for exclusive ranges where 1 is added to the
+upper bound, e.g., `x..(y+1)`.
+
+### Why is this bad?
+The code is more readable with an inclusive range
+like `x..=y`.
+
+### Known problems
+Will add unnecessary pair of parentheses when the
+expression is not wrapped in a pair but starts with an opening parenthesis
+and ends with a closing one.
+I.e., `let _ = (f()+1)..(f()+1)` results in `let _ = ((f()+1)..=f())`.
+
+Also in many cases, inclusive ranges are still slower to run than
+exclusive ranges, because they essentially add an extra branch that
+LLVM may fail to hoist out of the loop.
+
+This will cause a warning that cannot be fixed if the consumer of the
+range only accepts a specific range type, instead of the generic
+`RangeBounds` trait
+([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
+
+### Example
+```
+for i in x..(y+1) {
+ // ..
+}
+```
+
+Use instead:
+```
+for i in x..=y {
+ // ..
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/range_zip_with_len.txt b/src/tools/clippy/src/docs/range_zip_with_len.txt
new file mode 100644
index 000000000..24c1efec7
--- /dev/null
+++ b/src/tools/clippy/src/docs/range_zip_with_len.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for zipping a collection with the range of
+`0.._.len()`.
+
+### Why is this bad?
+The code is better expressed with `.enumerate()`.
+
+### Example
+```
+let _ = x.iter().zip(0..x.len());
+```
+
+Use instead:
+```
+let _ = x.iter().enumerate();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/rc_buffer.txt b/src/tools/clippy/src/docs/rc_buffer.txt
new file mode 100644
index 000000000..82ac58eeb
--- /dev/null
+++ b/src/tools/clippy/src/docs/rc_buffer.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for `Rc<T>` and `Arc<T>` when `T` is a mutable buffer type such as `String` or `Vec`.
+
+### Why is this bad?
+Expressions such as `Rc<String>` usually have no advantage over `Rc<str>`, since
+it is larger and involves an extra level of indirection, and doesn't implement `Borrow<str>`.
+
+While mutating a buffer type would still be possible with `Rc::get_mut()`, it only
+works if there are no additional references yet, which usually defeats the purpose of
+enclosing it in a shared ownership type. Instead, additionally wrapping the inner
+type with an interior mutable container (such as `RefCell` or `Mutex`) would normally
+be used.
+
+### Known problems
+This pattern can be desirable to avoid the overhead of a `RefCell` or `Mutex` for
+cases where mutation only happens before there are any additional references.
+
+### Example
+```
+fn foo(interned: Rc<String>) { ... }
+```
+
+Better:
+
+```
+fn foo(interned: Rc<str>) { ... }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/rc_clone_in_vec_init.txt b/src/tools/clippy/src/docs/rc_clone_in_vec_init.txt
new file mode 100644
index 000000000..6fc08aaf9
--- /dev/null
+++ b/src/tools/clippy/src/docs/rc_clone_in_vec_init.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for reference-counted pointers (`Arc`, `Rc`, `rc::Weak`, and `sync::Weak`)
+in `vec![elem; len]`
+
+### Why is this bad?
+This will create `elem` once and clone it `len` times - doing so with `Arc`/`Rc`/`Weak`
+is a bit misleading, as it will create references to the same pointer, rather
+than different instances.
+
+### Example
+```
+let v = vec![std::sync::Arc::new("some data".to_string()); 100];
+// or
+let v = vec![std::rc::Rc::new("some data".to_string()); 100];
+```
+Use instead:
+```
+// Initialize each value separately:
+let mut data = Vec::with_capacity(100);
+for _ in 0..100 {
+ data.push(std::rc::Rc::new("some data".to_string()));
+}
+
+// Or if you want clones of the same reference,
+// Create the reference beforehand to clarify that
+// it should be cloned for each value
+let data = std::rc::Rc::new("some data".to_string());
+let v = vec![data; 100];
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/rc_mutex.txt b/src/tools/clippy/src/docs/rc_mutex.txt
new file mode 100644
index 000000000..ed7a1e344
--- /dev/null
+++ b/src/tools/clippy/src/docs/rc_mutex.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for `Rc<Mutex<T>>`.
+
+### Why is this bad?
+`Rc` is used in single thread and `Mutex` is used in multi thread.
+Consider using `Rc<RefCell<T>>` in single thread or `Arc<Mutex<T>>` in multi thread.
+
+### Known problems
+Sometimes combining generic types can lead to the requirement that a
+type use Rc in conjunction with Mutex. We must consider those cases false positives, but
+alas they are quite hard to rule out. Luckily they are also rare.
+
+### Example
+```
+use std::rc::Rc;
+use std::sync::Mutex;
+fn foo(interned: Rc<Mutex<i32>>) { ... }
+```
+
+Better:
+
+```
+use std::rc::Rc;
+use std::cell::RefCell
+fn foo(interned: Rc<RefCell<i32>>) { ... }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/read_zero_byte_vec.txt b/src/tools/clippy/src/docs/read_zero_byte_vec.txt
new file mode 100644
index 000000000..cef5604e0
--- /dev/null
+++ b/src/tools/clippy/src/docs/read_zero_byte_vec.txt
@@ -0,0 +1,30 @@
+### What it does
+This lint catches reads into a zero-length `Vec`.
+Especially in the case of a call to `with_capacity`, this lint warns that read
+gets the number of bytes from the `Vec`'s length, not its capacity.
+
+### Why is this bad?
+Reading zero bytes is almost certainly not the intended behavior.
+
+### Known problems
+In theory, a very unusual read implementation could assign some semantic meaning
+to zero-byte reads. But it seems exceptionally unlikely that code intending to do
+a zero-byte read would allocate a `Vec` for it.
+
+### Example
+```
+use std::io;
+fn foo<F: io::Read>(mut f: F) {
+ let mut data = Vec::with_capacity(100);
+ f.read(&mut data).unwrap();
+}
+```
+Use instead:
+```
+use std::io;
+fn foo<F: io::Read>(mut f: F) {
+ let mut data = Vec::with_capacity(100);
+ data.resize(100, 0);
+ f.read(&mut data).unwrap();
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/recursive_format_impl.txt b/src/tools/clippy/src/docs/recursive_format_impl.txt
new file mode 100644
index 000000000..32fffd84c
--- /dev/null
+++ b/src/tools/clippy/src/docs/recursive_format_impl.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for format trait implementations (e.g. `Display`) with a recursive call to itself
+which uses `self` as a parameter.
+This is typically done indirectly with the `write!` macro or with `to_string()`.
+
+### Why is this bad?
+This will lead to infinite recursion and a stack overflow.
+
+### Example
+
+```
+use std::fmt;
+
+struct Structure(i32);
+impl fmt::Display for Structure {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.to_string())
+ }
+}
+
+```
+Use instead:
+```
+use std::fmt;
+
+struct Structure(i32);
+impl fmt::Display for Structure {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.0)
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_allocation.txt b/src/tools/clippy/src/docs/redundant_allocation.txt
new file mode 100644
index 000000000..86bf51e8d
--- /dev/null
+++ b/src/tools/clippy/src/docs/redundant_allocation.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for use of redundant allocations anywhere in the code.
+
+### Why is this bad?
+Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Arc<T>>`, `Rc<Box<T>>`, `Arc<&T>`, `Arc<Rc<T>>`,
+`Arc<Arc<T>>`, `Arc<Box<T>>`, `Box<&T>`, `Box<Rc<T>>`, `Box<Arc<T>>`, `Box<Box<T>>`, add an unnecessary level of indirection.
+
+### Example
+```
+fn foo(bar: Rc<&usize>) {}
+```
+
+Better:
+
+```
+fn foo(bar: &usize) {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_clone.txt b/src/tools/clippy/src/docs/redundant_clone.txt
new file mode 100644
index 000000000..b29aed0b5
--- /dev/null
+++ b/src/tools/clippy/src/docs/redundant_clone.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for a redundant `clone()` (and its relatives) which clones an owned
+value that is going to be dropped without further use.
+
+### Why is this bad?
+It is not always possible for the compiler to eliminate useless
+allocations and deallocations generated by redundant `clone()`s.
+
+### Known problems
+False-negatives: analysis performed by this lint is conservative and limited.
+
+### Example
+```
+{
+ let x = Foo::new();
+ call(x.clone());
+ call(x.clone()); // this can just pass `x`
+}
+
+["lorem", "ipsum"].join(" ").to_string();
+
+Path::new("/a/b").join("c").to_path_buf();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_closure.txt b/src/tools/clippy/src/docs/redundant_closure.txt
new file mode 100644
index 000000000..0faa9513f
--- /dev/null
+++ b/src/tools/clippy/src/docs/redundant_closure.txt
@@ -0,0 +1,25 @@
+### 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
+```
+xs.map(|x| foo(x))
+```
+
+Use instead:
+```
+// where `foo(_)` is a plain function that takes the exact argument type of `x`.
+xs.map(foo)
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_closure_call.txt b/src/tools/clippy/src/docs/redundant_closure_call.txt
new file mode 100644
index 000000000..913d1a705
--- /dev/null
+++ b/src/tools/clippy/src/docs/redundant_closure_call.txt
@@ -0,0 +1,17 @@
+### What it does
+Detects closures called in the same expression where they
+are defined.
+
+### Why is this bad?
+It is unnecessarily adding to the expression's
+complexity.
+
+### Example
+```
+let a = (|| 42)();
+```
+
+Use instead:
+```
+let a = 42;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_closure_for_method_calls.txt b/src/tools/clippy/src/docs/redundant_closure_for_method_calls.txt
new file mode 100644
index 000000000..865510e14
--- /dev/null
+++ b/src/tools/clippy/src/docs/redundant_closure_for_method_calls.txt
@@ -0,0 +1,15 @@
+### 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
+```
+Some('a').map(|s| s.to_uppercase());
+```
+may be rewritten as
+```
+Some('a').map(char::to_uppercase);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_else.txt b/src/tools/clippy/src/docs/redundant_else.txt
new file mode 100644
index 000000000..3f4e86917
--- /dev/null
+++ b/src/tools/clippy/src/docs/redundant_else.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for `else` blocks that can be removed without changing semantics.
+
+### Why is this bad?
+The `else` block adds unnecessary indentation and verbosity.
+
+### Known problems
+Some may prefer to keep the `else` block for clarity.
+
+### Example
+```
+fn my_func(count: u32) {
+ if count == 0 {
+ print!("Nothing to do");
+ return;
+ } else {
+ print!("Moving on...");
+ }
+}
+```
+Use instead:
+```
+fn my_func(count: u32) {
+ if count == 0 {
+ print!("Nothing to do");
+ return;
+ }
+ print!("Moving on...");
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_feature_names.txt b/src/tools/clippy/src/docs/redundant_feature_names.txt
new file mode 100644
index 000000000..5bd6925ed
--- /dev/null
+++ b/src/tools/clippy/src/docs/redundant_feature_names.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for feature names with prefix `use-`, `with-` or suffix `-support`
+
+### Why is this bad?
+These prefixes and suffixes have no significant meaning.
+
+### Example
+```
+[features]
+default = ["use-abc", "with-def", "ghi-support"]
+use-abc = [] // redundant
+with-def = [] // redundant
+ghi-support = [] // redundant
+```
+
+Use instead:
+```
+[features]
+default = ["abc", "def", "ghi"]
+abc = []
+def = []
+ghi = []
+```
diff --git a/src/tools/clippy/src/docs/redundant_field_names.txt b/src/tools/clippy/src/docs/redundant_field_names.txt
new file mode 100644
index 000000000..35f20a466
--- /dev/null
+++ b/src/tools/clippy/src/docs/redundant_field_names.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for fields in struct literals where shorthands
+could be used.
+
+### Why is this bad?
+If the field and variable names are the same,
+the field name is redundant.
+
+### Example
+```
+let bar: u8 = 123;
+
+struct Foo {
+ bar: u8,
+}
+
+let foo = Foo { bar: bar };
+```
+the last line can be simplified to
+```
+let foo = Foo { bar };
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_pattern.txt b/src/tools/clippy/src/docs/redundant_pattern.txt
new file mode 100644
index 000000000..45f6cfc86
--- /dev/null
+++ b/src/tools/clippy/src/docs/redundant_pattern.txt
@@ -0,0 +1,22 @@
+### 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
+```
+match v {
+ Some(x) => (),
+ y @ _ => (),
+}
+```
+
+Use instead:
+```
+match v {
+ Some(x) => (),
+ y => (),
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_pattern_matching.txt b/src/tools/clippy/src/docs/redundant_pattern_matching.txt
new file mode 100644
index 000000000..77b1021e0
--- /dev/null
+++ b/src/tools/clippy/src/docs/redundant_pattern_matching.txt
@@ -0,0 +1,45 @@
+### 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
+```
+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:
+
+```
+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();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_pub_crate.txt b/src/tools/clippy/src/docs/redundant_pub_crate.txt
new file mode 100644
index 000000000..a527bb5ac
--- /dev/null
+++ b/src/tools/clippy/src/docs/redundant_pub_crate.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for items declared `pub(crate)` that are not crate visible because they
+are inside a private module.
+
+### Why is this bad?
+Writing `pub(crate)` is misleading when it's redundant due to the parent
+module's visibility.
+
+### Example
+```
+mod internal {
+ pub(crate) fn internal_fn() { }
+}
+```
+This function is not visible outside the module and it can be declared with `pub` or
+private visibility
+```
+mod internal {
+ pub fn internal_fn() { }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_slicing.txt b/src/tools/clippy/src/docs/redundant_slicing.txt
new file mode 100644
index 000000000..6798911ed
--- /dev/null
+++ b/src/tools/clippy/src/docs/redundant_slicing.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for redundant slicing expressions which use the full range, and
+do not change the type.
+
+### Why is this bad?
+It unnecessarily adds complexity to the expression.
+
+### Known problems
+If the type being sliced has an implementation of `Index<RangeFull>`
+that actually changes anything then it can't be removed. However, this would be surprising
+to people reading the code and should have a note with it.
+
+### Example
+```
+fn get_slice(x: &[u32]) -> &[u32] {
+ &x[..]
+}
+```
+Use instead:
+```
+fn get_slice(x: &[u32]) -> &[u32] {
+ x
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/redundant_static_lifetimes.txt b/src/tools/clippy/src/docs/redundant_static_lifetimes.txt
new file mode 100644
index 000000000..edb8e7b5c
--- /dev/null
+++ b/src/tools/clippy/src/docs/redundant_static_lifetimes.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for constants and statics with an explicit `'static` lifetime.
+
+### Why is this bad?
+Adding `'static` to every reference can create very
+complicated types.
+
+### Example
+```
+const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
+&[...]
+static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
+&[...]
+```
+This code can be rewritten as
+```
+ const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
+ static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ref_binding_to_reference.txt b/src/tools/clippy/src/docs/ref_binding_to_reference.txt
new file mode 100644
index 000000000..dc391cd98
--- /dev/null
+++ b/src/tools/clippy/src/docs/ref_binding_to_reference.txt
@@ -0,0 +1,21 @@
+### 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
+```
+let x = Some("");
+if let Some(ref x) = x {
+ // use `x` here
+}
+```
+
+Use instead:
+```
+let x = Some("");
+if let Some(x) = x {
+ // use `&x` here
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/ref_option_ref.txt b/src/tools/clippy/src/docs/ref_option_ref.txt
new file mode 100644
index 000000000..951c7bd7f
--- /dev/null
+++ b/src/tools/clippy/src/docs/ref_option_ref.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `&Option<&T>`.
+
+### Why is this bad?
+Since `&` is Copy, it's useless to have a
+reference on `Option<&T>`.
+
+### Known problems
+It may be irrelevant to use this lint on
+public API code as it will make a breaking change to apply it.
+
+### Example
+```
+let x: &Option<&u32> = &Some(&0u32);
+```
+Use instead:
+```
+let x: Option<&u32> = Some(&0u32);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/repeat_once.txt b/src/tools/clippy/src/docs/repeat_once.txt
new file mode 100644
index 000000000..3ba189c19
--- /dev/null
+++ b/src/tools/clippy/src/docs/repeat_once.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for usage of `.repeat(1)` and suggest the following method for each types.
+- `.to_string()` for `str`
+- `.clone()` for `String`
+- `.to_vec()` for `slice`
+
+The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if
+they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))
+
+### Why is this bad?
+For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning
+the string is the intention behind this, `clone()` should be used.
+
+### Example
+```
+fn main() {
+ let x = String::from("hello world").repeat(1);
+}
+```
+Use instead:
+```
+fn main() {
+ let x = String::from("hello world").clone();
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/rest_pat_in_fully_bound_structs.txt b/src/tools/clippy/src/docs/rest_pat_in_fully_bound_structs.txt
new file mode 100644
index 000000000..40ebbe754
--- /dev/null
+++ b/src/tools/clippy/src/docs/rest_pat_in_fully_bound_structs.txt
@@ -0,0 +1,24 @@
+### 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
+```
+let a = A { a: 5 };
+
+match a {
+ A { a: 5, .. } => {},
+ _ => {},
+}
+```
+
+Use instead:
+```
+match a {
+ A { a: 5 } => {},
+ _ => {},
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/result_large_err.txt b/src/tools/clippy/src/docs/result_large_err.txt
new file mode 100644
index 000000000..e5fab3c5c
--- /dev/null
+++ b/src/tools/clippy/src/docs/result_large_err.txt
@@ -0,0 +1,36 @@
+### What it does
+Checks for functions that return `Result` with an unusually large
+`Err`-variant.
+
+### Why is this bad?
+A `Result` is at least as large as the `Err`-variant. While we
+expect that variant to be seldomly used, the compiler needs to reserve
+and move that much memory every single time.
+
+### Known problems
+The size determined by Clippy is platform-dependent.
+
+### Examples
+```
+pub enum ParseError {
+ UnparsedBytes([u8; 512]),
+ UnexpectedEof,
+}
+
+// The `Result` has at least 512 bytes, even in the `Ok`-case
+pub fn parse() -> Result<(), ParseError> {
+ Ok(())
+}
+```
+should be
+```
+pub enum ParseError {
+ UnparsedBytes(Box<[u8; 512]>),
+ UnexpectedEof,
+}
+
+// The `Result` is slightly larger than a pointer
+pub fn parse() -> Result<(), ParseError> {
+ Ok(())
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/result_map_or_into_option.txt b/src/tools/clippy/src/docs/result_map_or_into_option.txt
new file mode 100644
index 000000000..899d98c30
--- /dev/null
+++ b/src/tools/clippy/src/docs/result_map_or_into_option.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `_.map_or(None, Some)`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.ok()`.
+
+### Example
+```
+assert_eq!(Some(1), r.map_or(None, Some));
+```
+
+Use instead:
+```
+assert_eq!(Some(1), r.ok());
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/result_map_unit_fn.txt b/src/tools/clippy/src/docs/result_map_unit_fn.txt
new file mode 100644
index 000000000..3455c5c1f
--- /dev/null
+++ b/src/tools/clippy/src/docs/result_map_unit_fn.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for usage of `result.map(f)` where f is a function
+or closure that returns the unit type `()`.
+
+### Why is this bad?
+Readability, this can be written more clearly with
+an if let statement
+
+### Example
+```
+let x: Result<String, String> = do_stuff();
+x.map(log_err_msg);
+x.map(|msg| log_err_msg(format_msg(msg)));
+```
+
+The correct use would be:
+
+```
+let x: Result<String, String> = do_stuff();
+if let Ok(msg) = x {
+ log_err_msg(msg);
+};
+if let Ok(msg) = x {
+ log_err_msg(format_msg(msg));
+};
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/result_unit_err.txt b/src/tools/clippy/src/docs/result_unit_err.txt
new file mode 100644
index 000000000..7c8ec2ffc
--- /dev/null
+++ b/src/tools/clippy/src/docs/result_unit_err.txt
@@ -0,0 +1,40 @@
+### What it does
+Checks for public functions that return a `Result`
+with an `Err` type of `()`. It suggests using a custom type that
+implements `std::error::Error`.
+
+### Why is this bad?
+Unit does not implement `Error` and carries no
+further information about what went wrong.
+
+### Known problems
+Of course, this lint assumes that `Result` is used
+for a fallible operation (which is after all the intended use). However
+code may opt to (mis)use it as a basic two-variant-enum. In that case,
+the suggestion is misguided, and the code should use a custom enum
+instead.
+
+### Examples
+```
+pub fn read_u8() -> Result<u8, ()> { Err(()) }
+```
+should become
+```
+use std::fmt;
+
+#[derive(Debug)]
+pub struct EndOfStream;
+
+impl fmt::Display for EndOfStream {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "End of Stream")
+ }
+}
+
+impl std::error::Error for EndOfStream { }
+
+pub fn read_u8() -> Result<u8, EndOfStream> { Err(EndOfStream) }
+```
+
+Note that there are crates that simplify creating the error type, e.g.
+[`thiserror`](https://docs.rs/thiserror). \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/return_self_not_must_use.txt b/src/tools/clippy/src/docs/return_self_not_must_use.txt
new file mode 100644
index 000000000..4a4fd2c6e
--- /dev/null
+++ b/src/tools/clippy/src/docs/return_self_not_must_use.txt
@@ -0,0 +1,46 @@
+### What it does
+This lint warns when a method returning `Self` doesn't have the `#[must_use]` attribute.
+
+### Why is this bad?
+Methods returning `Self` often create new values, having the `#[must_use]` attribute
+prevents users from "forgetting" to use the newly created value.
+
+The `#[must_use]` attribute can be added to the type itself to ensure that instances
+are never forgotten. Functions returning a type marked with `#[must_use]` will not be
+linted, as the usage is already enforced by the type attribute.
+
+### Limitations
+This lint is only applied on methods taking a `self` argument. It would be mostly noise
+if it was added on constructors for example.
+
+### Example
+```
+pub struct Bar;
+impl Bar {
+ // Missing attribute
+ pub fn bar(&self) -> Self {
+ Self
+ }
+}
+```
+
+Use instead:
+```
+// It's better to have the `#[must_use]` attribute on the method like this:
+pub struct Bar;
+impl Bar {
+ #[must_use]
+ pub fn bar(&self) -> Self {
+ Self
+ }
+}
+
+// Or on the type definition like this:
+#[must_use]
+pub struct Bar;
+impl Bar {
+ pub fn bar(&self) -> Self {
+ Self
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/reversed_empty_ranges.txt b/src/tools/clippy/src/docs/reversed_empty_ranges.txt
new file mode 100644
index 000000000..39f481193
--- /dev/null
+++ b/src/tools/clippy/src/docs/reversed_empty_ranges.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for range expressions `x..y` where both `x` and `y`
+are constant and `x` is greater or equal to `y`.
+
+### Why is this bad?
+Empty ranges yield no values so iterating them is a no-op.
+Moreover, trying to use a reversed range to index a slice will panic at run-time.
+
+### Example
+```
+fn main() {
+ (10..=0).for_each(|x| println!("{}", x));
+
+ let arr = [1, 2, 3, 4, 5];
+ let sub = &arr[3..1];
+}
+```
+Use instead:
+```
+fn main() {
+ (0..=10).rev().for_each(|x| println!("{}", x));
+
+ let arr = [1, 2, 3, 4, 5];
+ let sub = &arr[1..3];
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/same_functions_in_if_condition.txt b/src/tools/clippy/src/docs/same_functions_in_if_condition.txt
new file mode 100644
index 000000000..a0a90eec6
--- /dev/null
+++ b/src/tools/clippy/src/docs/same_functions_in_if_condition.txt
@@ -0,0 +1,41 @@
+### What it does
+Checks for consecutive `if`s with the same function call.
+
+### Why is this bad?
+This is probably a copy & paste error.
+Despite the fact that function can have side effects and `if` works as
+intended, such an approach is implicit and can be considered a "code smell".
+
+### Example
+```
+if foo() == bar {
+ …
+} else if foo() == bar {
+ …
+}
+```
+
+This probably should be:
+```
+if foo() == bar {
+ …
+} else if foo() == baz {
+ …
+}
+```
+
+or if the original code was not a typo and called function mutates a state,
+consider move the mutation out of the `if` condition to avoid similarity to
+a copy & paste error:
+
+```
+let first = foo();
+if first == bar {
+ …
+} else {
+ let second = foo();
+ if second == bar {
+ …
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/same_item_push.txt b/src/tools/clippy/src/docs/same_item_push.txt
new file mode 100644
index 000000000..7e724073f
--- /dev/null
+++ b/src/tools/clippy/src/docs/same_item_push.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks whether a for loop is being used to push a constant
+value into a Vec.
+
+### Why is this bad?
+This kind of operation can be expressed more succinctly with
+`vec![item; SIZE]` or `vec.resize(NEW_SIZE, item)` and using these alternatives may also
+have better performance.
+
+### Example
+```
+let item1 = 2;
+let item2 = 3;
+let mut vec: Vec<u8> = Vec::new();
+for _ in 0..20 {
+ vec.push(item1);
+}
+for _ in 0..30 {
+ vec.push(item2);
+}
+```
+
+Use instead:
+```
+let item1 = 2;
+let item2 = 3;
+let mut vec: Vec<u8> = vec![item1; 20];
+vec.resize(20 + 30, item2);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/same_name_method.txt b/src/tools/clippy/src/docs/same_name_method.txt
new file mode 100644
index 000000000..792dd717f
--- /dev/null
+++ b/src/tools/clippy/src/docs/same_name_method.txt
@@ -0,0 +1,23 @@
+### What it does
+It lints if a struct has two methods with the same name:
+one from a trait, another not from trait.
+
+### Why is this bad?
+Confusing.
+
+### Example
+```
+trait T {
+ fn foo(&self) {}
+}
+
+struct S;
+
+impl T for S {
+ fn foo(&self) {}
+}
+
+impl S {
+ fn foo(&self) {}
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/search_is_some.txt b/src/tools/clippy/src/docs/search_is_some.txt
new file mode 100644
index 000000000..67292d545
--- /dev/null
+++ b/src/tools/clippy/src/docs/search_is_some.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for an iterator or string search (such as `find()`,
+`position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`.
+
+### Why is this bad?
+Readability, this can be written more concisely as:
+* `_.any(_)`, or `_.contains(_)` for `is_some()`,
+* `!_.any(_)`, or `!_.contains(_)` for `is_none()`.
+
+### Example
+```
+let vec = vec![1];
+vec.iter().find(|x| **x == 0).is_some();
+
+"hello world".find("world").is_none();
+```
+
+Use instead:
+```
+let vec = vec![1];
+vec.iter().any(|x| *x == 0);
+
+!"hello world".contains("world");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/self_assignment.txt b/src/tools/clippy/src/docs/self_assignment.txt
new file mode 100644
index 000000000..ea60ea077
--- /dev/null
+++ b/src/tools/clippy/src/docs/self_assignment.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for explicit self-assignments.
+
+### Why is this bad?
+Self-assignments are redundant and unlikely to be
+intentional.
+
+### Known problems
+If expression contains any deref coercions or
+indexing operations they are assumed not to have any side effects.
+
+### Example
+```
+struct Event {
+ x: i32,
+}
+
+fn copy_position(a: &mut Event, b: &Event) {
+ a.x = a.x;
+}
+```
+
+Should be:
+```
+struct Event {
+ x: i32,
+}
+
+fn copy_position(a: &mut Event, b: &Event) {
+ a.x = b.x;
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/self_named_constructors.txt b/src/tools/clippy/src/docs/self_named_constructors.txt
new file mode 100644
index 000000000..a01669a84
--- /dev/null
+++ b/src/tools/clippy/src/docs/self_named_constructors.txt
@@ -0,0 +1,26 @@
+### What it does
+Warns when constructors have the same name as their types.
+
+### Why is this bad?
+Repeating the name of the type is redundant.
+
+### Example
+```
+struct Foo {}
+
+impl Foo {
+ pub fn foo() -> Foo {
+ Foo {}
+ }
+}
+```
+Use instead:
+```
+struct Foo {}
+
+impl Foo {
+ pub fn new() -> Foo {
+ Foo {}
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/self_named_module_files.txt b/src/tools/clippy/src/docs/self_named_module_files.txt
new file mode 100644
index 000000000..73e805136
--- /dev/null
+++ b/src/tools/clippy/src/docs/self_named_module_files.txt
@@ -0,0 +1,22 @@
+### 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
+```
+src/
+ stuff/
+ stuff_files.rs
+ stuff.rs
+ lib.rs
+```
+Use instead:
+```
+src/
+ stuff/
+ stuff_files.rs
+ mod.rs
+ lib.rs
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/semicolon_if_nothing_returned.txt b/src/tools/clippy/src/docs/semicolon_if_nothing_returned.txt
new file mode 100644
index 000000000..30c963ca2
--- /dev/null
+++ b/src/tools/clippy/src/docs/semicolon_if_nothing_returned.txt
@@ -0,0 +1,20 @@
+### What it does
+Looks for blocks of expressions and fires if the last expression returns
+`()` but is not followed by a semicolon.
+
+### Why is this bad?
+The semicolon might be optional but when extending the block with new
+code, it doesn't require a change in previous last line.
+
+### Example
+```
+fn main() {
+ println!("Hello world")
+}
+```
+Use instead:
+```
+fn main() {
+ println!("Hello world");
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/separated_literal_suffix.txt b/src/tools/clippy/src/docs/separated_literal_suffix.txt
new file mode 100644
index 000000000..226a6b8a9
--- /dev/null
+++ b/src/tools/clippy/src/docs/separated_literal_suffix.txt
@@ -0,0 +1,17 @@
+### 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
+```
+123832_i32
+```
+
+Use instead:
+```
+123832i32
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/serde_api_misuse.txt b/src/tools/clippy/src/docs/serde_api_misuse.txt
new file mode 100644
index 000000000..8a3c89ac1
--- /dev/null
+++ b/src/tools/clippy/src/docs/serde_api_misuse.txt
@@ -0,0 +1,10 @@
+### What it does
+Checks for mis-uses of the serde API.
+
+### Why is this bad?
+Serde is very finnicky about how its API should be
+used, but the type system can't be used to enforce it (yet?).
+
+### Example
+Implementing `Visitor::visit_string` but not
+`Visitor::visit_str`. \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/shadow_reuse.txt b/src/tools/clippy/src/docs/shadow_reuse.txt
new file mode 100644
index 000000000..9eb8e7ad1
--- /dev/null
+++ b/src/tools/clippy/src/docs/shadow_reuse.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for bindings that shadow other bindings already in
+scope, while reusing the original value.
+
+### Why is this bad?
+Not too much, in fact it's a common pattern in Rust
+code. Still, some argue that name shadowing like this hurts readability,
+because a value may be bound to different things depending on position in
+the code.
+
+### Example
+```
+let x = 2;
+let x = x + 1;
+```
+use different variable name:
+```
+let x = 2;
+let y = x + 1;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/shadow_same.txt b/src/tools/clippy/src/docs/shadow_same.txt
new file mode 100644
index 000000000..3cd96f560
--- /dev/null
+++ b/src/tools/clippy/src/docs/shadow_same.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for bindings that shadow other bindings already in
+scope, while just changing reference level or mutability.
+
+### Why is this bad?
+Not much, in fact it's a very common pattern in Rust
+code. Still, some may opt to avoid it in their code base, they can set this
+lint to `Warn`.
+
+### Example
+```
+let x = &x;
+```
+
+Use instead:
+```
+let y = &x; // use different variable name
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/shadow_unrelated.txt b/src/tools/clippy/src/docs/shadow_unrelated.txt
new file mode 100644
index 000000000..436251c52
--- /dev/null
+++ b/src/tools/clippy/src/docs/shadow_unrelated.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for bindings that shadow other bindings already in
+scope, either without an initialization or with one that does not even use
+the original value.
+
+### Why is this bad?
+Name shadowing can hurt readability, especially in
+large code bases, because it is easy to lose track of the active binding at
+any place in the code. This can be alleviated by either giving more specific
+names to bindings or introducing more scopes to contain the bindings.
+
+### Example
+```
+let x = y;
+let x = z; // shadows the earlier binding
+```
+
+Use instead:
+```
+let x = y;
+let w = z; // use different variable name
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/short_circuit_statement.txt b/src/tools/clippy/src/docs/short_circuit_statement.txt
new file mode 100644
index 000000000..31492bed0
--- /dev/null
+++ b/src/tools/clippy/src/docs/short_circuit_statement.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for the use of short circuit boolean conditions as
+a
+statement.
+
+### Why is this bad?
+Using a short circuit boolean condition as a statement
+may hide the fact that the second part is executed or not depending on the
+outcome of the first part.
+
+### Example
+```
+f() && g(); // We should write `if f() { g(); }`.
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/should_implement_trait.txt b/src/tools/clippy/src/docs/should_implement_trait.txt
new file mode 100644
index 000000000..02e74751a
--- /dev/null
+++ b/src/tools/clippy/src/docs/should_implement_trait.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for methods that should live in a trait
+implementation of a `std` trait (see [llogiq's blog
+post](http://llogiq.github.io/2015/07/30/traits.html) for further
+information) instead of an inherent implementation.
+
+### Why is this bad?
+Implementing the traits improve ergonomics for users of
+the code, often with very little cost. Also people seeing a `mul(...)`
+method
+may expect `*` to work equally, so you should have good reason to disappoint
+them.
+
+### Example
+```
+struct X;
+impl X {
+ fn add(&self, other: &X) -> X {
+ // ..
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/significant_drop_in_scrutinee.txt b/src/tools/clippy/src/docs/significant_drop_in_scrutinee.txt
new file mode 100644
index 000000000..f869def0d
--- /dev/null
+++ b/src/tools/clippy/src/docs/significant_drop_in_scrutinee.txt
@@ -0,0 +1,43 @@
+### What it does
+Check for temporaries returned from function calls in a match scrutinee that have the
+`clippy::has_significant_drop` attribute.
+
+### Why is this bad?
+The `clippy::has_significant_drop` attribute can be added to types whose Drop impls have
+an important side-effect, such as unlocking a mutex, making it important for users to be
+able to accurately understand their lifetimes. When a temporary is returned in a function
+call in a match scrutinee, its lifetime lasts until the end of the match block, which may
+be surprising.
+
+For `Mutex`es this can lead to a deadlock. This happens when the match scrutinee uses a
+function call that returns a `MutexGuard` and then tries to lock again in one of the match
+arms. In that case the `MutexGuard` in the scrutinee will not be dropped until the end of
+the match block and thus will not unlock.
+
+### Example
+```
+let mutex = Mutex::new(State {});
+
+match mutex.lock().unwrap().foo() {
+ true => {
+ mutex.lock().unwrap().bar(); // Deadlock!
+ }
+ false => {}
+};
+
+println!("All done!");
+```
+Use instead:
+```
+let mutex = Mutex::new(State {});
+
+let is_foo = mutex.lock().unwrap().foo();
+match is_foo {
+ true => {
+ mutex.lock().unwrap().bar();
+ }
+ false => {}
+};
+
+println!("All done!");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/similar_names.txt b/src/tools/clippy/src/docs/similar_names.txt
new file mode 100644
index 000000000..f9eff21b6
--- /dev/null
+++ b/src/tools/clippy/src/docs/similar_names.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for names that are very similar and thus confusing.
+
+Note: this lint looks for similar names throughout each
+scope. To allow it, you need to allow it on the scope
+level, not on the name that is reported.
+
+### Why is this bad?
+It's hard to distinguish between names that differ only
+by a single character.
+
+### Example
+```
+let checked_exp = something;
+let checked_expr = something_else;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/single_char_add_str.txt b/src/tools/clippy/src/docs/single_char_add_str.txt
new file mode 100644
index 000000000..cf23dc0c8
--- /dev/null
+++ b/src/tools/clippy/src/docs/single_char_add_str.txt
@@ -0,0 +1,18 @@
+### What it does
+Warns when using `push_str`/`insert_str` with a single-character string literal
+where `push`/`insert` with a `char` would work fine.
+
+### Why is this bad?
+It's less clear that we are pushing a single character.
+
+### Example
+```
+string.insert_str(0, "R");
+string.push_str("R");
+```
+
+Use instead:
+```
+string.insert(0, 'R');
+string.push('R');
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/single_char_lifetime_names.txt b/src/tools/clippy/src/docs/single_char_lifetime_names.txt
new file mode 100644
index 000000000..92dd24bf2
--- /dev/null
+++ b/src/tools/clippy/src/docs/single_char_lifetime_names.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for lifetimes with names which are one character
+long.
+
+### Why is this bad?
+A single character is likely not enough to express the
+purpose of a lifetime. Using a longer name can make code
+easier to understand, especially for those who are new to
+Rust.
+
+### Known problems
+Rust programmers and learning resources tend to use single
+character lifetimes, so this lint is at odds with the
+ecosystem at large. In addition, the lifetime's purpose may
+be obvious or, rarely, expressible in one character.
+
+### Example
+```
+struct DiagnosticCtx<'a> {
+ source: &'a str,
+}
+```
+Use instead:
+```
+struct DiagnosticCtx<'src> {
+ source: &'src str,
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/single_char_pattern.txt b/src/tools/clippy/src/docs/single_char_pattern.txt
new file mode 100644
index 000000000..9e5ad1e7d
--- /dev/null
+++ b/src/tools/clippy/src/docs/single_char_pattern.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for string methods that receive a single-character
+`str` as an argument, e.g., `_.split("x")`.
+
+### Why is this bad?
+Performing these methods using a `char` is faster than
+using a `str`.
+
+### Known problems
+Does not catch multi-byte unicode characters.
+
+### Example
+```
+_.split("x");
+```
+
+Use instead:
+```
+_.split('x');
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/single_component_path_imports.txt b/src/tools/clippy/src/docs/single_component_path_imports.txt
new file mode 100644
index 000000000..3a0263881
--- /dev/null
+++ b/src/tools/clippy/src/docs/single_component_path_imports.txt
@@ -0,0 +1,21 @@
+### What it does
+Checking for imports with single component use path.
+
+### Why is this bad?
+Import with single component use path such as `use cratename;`
+is not necessary, and thus should be removed.
+
+### Example
+```
+use regex;
+
+fn main() {
+ regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
+}
+```
+Better as
+```
+fn main() {
+ regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/single_element_loop.txt b/src/tools/clippy/src/docs/single_element_loop.txt
new file mode 100644
index 000000000..6f0c15a85
--- /dev/null
+++ b/src/tools/clippy/src/docs/single_element_loop.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks whether a for loop has a single element.
+
+### Why is this bad?
+There is no reason to have a loop of a
+single element.
+
+### Example
+```
+let item1 = 2;
+for item in &[item1] {
+ println!("{}", item);
+}
+```
+
+Use instead:
+```
+let item1 = 2;
+let item = &item1;
+println!("{}", item);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/single_match.txt b/src/tools/clippy/src/docs/single_match.txt
new file mode 100644
index 000000000..31dde4da8
--- /dev/null
+++ b/src/tools/clippy/src/docs/single_match.txt
@@ -0,0 +1,21 @@
+### 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
+```
+match x {
+ Some(ref foo) => bar(foo),
+ _ => (),
+}
+```
+
+Use instead:
+```
+if let Some(ref foo) = x {
+ bar(foo);
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/single_match_else.txt b/src/tools/clippy/src/docs/single_match_else.txt
new file mode 100644
index 000000000..29a447af0
--- /dev/null
+++ b/src/tools/clippy/src/docs/single_match_else.txt
@@ -0,0 +1,29 @@
+### 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`:
+
+```
+match x {
+ Some(ref foo) => bar(foo),
+ _ => bar(&other_ref),
+}
+```
+
+Using `if let` with `else`:
+
+```
+if let Some(ref foo) = x {
+ bar(foo);
+} else {
+ bar(&other_ref);
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/size_of_in_element_count.txt b/src/tools/clippy/src/docs/size_of_in_element_count.txt
new file mode 100644
index 000000000..d893ec6a2
--- /dev/null
+++ b/src/tools/clippy/src/docs/size_of_in_element_count.txt
@@ -0,0 +1,16 @@
+### What it does
+Detects expressions where
+`size_of::<T>` or `size_of_val::<T>` is used as a
+count of elements of type `T`
+
+### Why is this bad?
+These functions expect a count
+of `T` and not a number of bytes
+
+### Example
+```
+const SIZE: usize = 128;
+let x = [2u8; SIZE];
+let mut y = [2u8; SIZE];
+unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>() * SIZE) };
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/skip_while_next.txt b/src/tools/clippy/src/docs/skip_while_next.txt
new file mode 100644
index 000000000..1ec8a3a28
--- /dev/null
+++ b/src/tools/clippy/src/docs/skip_while_next.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `_.skip_while(condition).next()`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.find(!condition)`.
+
+### Example
+```
+vec.iter().skip_while(|x| **x == 0).next();
+```
+
+Use instead:
+```
+vec.iter().find(|x| **x != 0);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/slow_vector_initialization.txt b/src/tools/clippy/src/docs/slow_vector_initialization.txt
new file mode 100644
index 000000000..53442e179
--- /dev/null
+++ b/src/tools/clippy/src/docs/slow_vector_initialization.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks slow zero-filled vector initialization
+
+### Why is this bad?
+These structures are non-idiomatic and less efficient than simply using
+`vec![0; len]`.
+
+### Example
+```
+let mut vec1 = Vec::with_capacity(len);
+vec1.resize(len, 0);
+
+let mut vec1 = Vec::with_capacity(len);
+vec1.resize(vec1.capacity(), 0);
+
+let mut vec2 = Vec::with_capacity(len);
+vec2.extend(repeat(0).take(len));
+```
+
+Use instead:
+```
+let mut vec1 = vec![0; len];
+let mut vec2 = vec![0; len];
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/stable_sort_primitive.txt b/src/tools/clippy/src/docs/stable_sort_primitive.txt
new file mode 100644
index 000000000..6465dbee4
--- /dev/null
+++ b/src/tools/clippy/src/docs/stable_sort_primitive.txt
@@ -0,0 +1,31 @@
+### What it does
+When sorting primitive values (integers, bools, chars, as well
+as arrays, slices, and tuples of such items), it is typically better to
+use an unstable sort than a stable sort.
+
+### Why is this bad?
+Typically, using a stable sort consumes more memory and cpu cycles.
+Because values which compare equal are identical, preserving their
+relative order (the guarantee that a stable sort provides) means
+nothing, while the extra costs still apply.
+
+### Known problems
+
+As pointed out in
+[issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241),
+a stable sort can instead be significantly faster for certain scenarios
+(eg. when a sorted vector is extended with new data and resorted).
+
+For more information and benchmarking results, please refer to the
+issue linked above.
+
+### Example
+```
+let mut vec = vec![2, 1, 3];
+vec.sort();
+```
+Use instead:
+```
+let mut vec = vec![2, 1, 3];
+vec.sort_unstable();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/std_instead_of_alloc.txt b/src/tools/clippy/src/docs/std_instead_of_alloc.txt
new file mode 100644
index 000000000..c2d32704e
--- /dev/null
+++ b/src/tools/clippy/src/docs/std_instead_of_alloc.txt
@@ -0,0 +1,18 @@
+### What it does
+
+Finds items imported through `std` when available through `alloc`.
+
+### Why is this bad?
+
+Crates which have `no_std` compatibility and require alloc may wish to ensure types are imported from
+alloc to ensure disabling `std` does not cause the crate to fail to compile. This lint is also useful
+for crates migrating to become `no_std` compatible.
+
+### Example
+```
+use std::vec::Vec;
+```
+Use instead:
+```
+use alloc::vec::Vec;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/std_instead_of_core.txt b/src/tools/clippy/src/docs/std_instead_of_core.txt
new file mode 100644
index 000000000..f1e1518c6
--- /dev/null
+++ b/src/tools/clippy/src/docs/std_instead_of_core.txt
@@ -0,0 +1,18 @@
+### What it does
+
+Finds items imported through `std` when available through `core`.
+
+### Why is this bad?
+
+Crates which have `no_std` compatibility may wish to ensure types are imported from core to ensure
+disabling `std` does not cause the crate to fail to compile. This lint is also useful for crates
+migrating to become `no_std` compatible.
+
+### Example
+```
+use std::hash::Hasher;
+```
+Use instead:
+```
+use core::hash::Hasher;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/str_to_string.txt b/src/tools/clippy/src/docs/str_to_string.txt
new file mode 100644
index 000000000..a24755223
--- /dev/null
+++ b/src/tools/clippy/src/docs/str_to_string.txt
@@ -0,0 +1,18 @@
+### 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
+```
+// example code where clippy issues a warning
+let _ = "str".to_string();
+```
+Use instead:
+```
+// example code which does not raise clippy warning
+let _ = "str".to_owned();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/string_add.txt b/src/tools/clippy/src/docs/string_add.txt
new file mode 100644
index 000000000..23dafd0d0
--- /dev/null
+++ b/src/tools/clippy/src/docs/string_add.txt
@@ -0,0 +1,27 @@
+### 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
+```
+let x = "Hello".to_owned();
+x + ", World";
+```
+
+Use instead:
+```
+let mut x = "Hello".to_owned();
+x.push_str(", World");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/string_add_assign.txt b/src/tools/clippy/src/docs/string_add_assign.txt
new file mode 100644
index 000000000..7438be855
--- /dev/null
+++ b/src/tools/clippy/src/docs/string_add_assign.txt
@@ -0,0 +1,17 @@
+### 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
+```
+let mut x = "Hello".to_owned();
+x = x + ", World";
+
+// More readable
+x += ", World";
+x.push_str(", World");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/string_extend_chars.txt b/src/tools/clippy/src/docs/string_extend_chars.txt
new file mode 100644
index 000000000..619ea3e11
--- /dev/null
+++ b/src/tools/clippy/src/docs/string_extend_chars.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for the use of `.extend(s.chars())` where s is a
+`&str` or `String`.
+
+### Why is this bad?
+`.push_str(s)` is clearer
+
+### Example
+```
+let abc = "abc";
+let def = String::from("def");
+let mut s = String::new();
+s.extend(abc.chars());
+s.extend(def.chars());
+```
+The correct use would be:
+```
+let abc = "abc";
+let def = String::from("def");
+let mut s = String::new();
+s.push_str(abc);
+s.push_str(&def);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/string_from_utf8_as_bytes.txt b/src/tools/clippy/src/docs/string_from_utf8_as_bytes.txt
new file mode 100644
index 000000000..9102d7347
--- /dev/null
+++ b/src/tools/clippy/src/docs/string_from_utf8_as_bytes.txt
@@ -0,0 +1,15 @@
+### 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
+```
+std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap();
+```
+
+Use instead:
+```
+&"Hello World!"[6..11];
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/string_lit_as_bytes.txt b/src/tools/clippy/src/docs/string_lit_as_bytes.txt
new file mode 100644
index 000000000..a125b97ed
--- /dev/null
+++ b/src/tools/clippy/src/docs/string_lit_as_bytes.txt
@@ -0,0 +1,39 @@
+### 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.
+
+```
+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
+```
+let bstr = "a byte string".as_bytes();
+```
+
+Use instead:
+```
+let bstr = b"a byte string";
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/string_slice.txt b/src/tools/clippy/src/docs/string_slice.txt
new file mode 100644
index 000000000..3d9e49dd3
--- /dev/null
+++ b/src/tools/clippy/src/docs/string_slice.txt
@@ -0,0 +1,17 @@
+### 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
+```
+&"Ölkanne"[1..];
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/string_to_string.txt b/src/tools/clippy/src/docs/string_to_string.txt
new file mode 100644
index 000000000..deb7eebe7
--- /dev/null
+++ b/src/tools/clippy/src/docs/string_to_string.txt
@@ -0,0 +1,19 @@
+### 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
+```
+// example code where clippy issues a warning
+let msg = String::from("Hello World");
+let _ = msg.to_string();
+```
+Use instead:
+```
+// example code which does not raise clippy warning
+let msg = String::from("Hello World");
+let _ = msg.clone();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/strlen_on_c_strings.txt b/src/tools/clippy/src/docs/strlen_on_c_strings.txt
new file mode 100644
index 000000000..0454abf55
--- /dev/null
+++ b/src/tools/clippy/src/docs/strlen_on_c_strings.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for usage of `libc::strlen` on a `CString` or `CStr` value,
+and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instead.
+
+### Why is this bad?
+This avoids calling an unsafe `libc` function.
+Currently, it also avoids calculating the length.
+
+### Example
+```
+use std::ffi::CString;
+let cstring = CString::new("foo").expect("CString::new failed");
+let len = unsafe { libc::strlen(cstring.as_ptr()) };
+```
+Use instead:
+```
+use std::ffi::CString;
+let cstring = CString::new("foo").expect("CString::new failed");
+let len = cstring.as_bytes().len();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/struct_excessive_bools.txt b/src/tools/clippy/src/docs/struct_excessive_bools.txt
new file mode 100644
index 000000000..9e197c786
--- /dev/null
+++ b/src/tools/clippy/src/docs/struct_excessive_bools.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for excessive
+use of bools in structs.
+
+### Why is this bad?
+Excessive bools in a struct
+is often a sign that it's used as a state machine,
+which is much better implemented as an enum.
+If it's not the case, excessive bools usually benefit
+from refactoring into two-variant enums for better
+readability and API.
+
+### Example
+```
+struct S {
+ is_pending: bool,
+ is_processing: bool,
+ is_finished: bool,
+}
+```
+
+Use instead:
+```
+enum S {
+ Pending,
+ Processing,
+ Finished,
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suboptimal_flops.txt b/src/tools/clippy/src/docs/suboptimal_flops.txt
new file mode 100644
index 000000000..f1c9c665b
--- /dev/null
+++ b/src/tools/clippy/src/docs/suboptimal_flops.txt
@@ -0,0 +1,50 @@
+### What it does
+Looks for floating-point expressions that
+can be expressed using built-in methods to improve both
+accuracy and performance.
+
+### Why is this bad?
+Negatively impacts accuracy and performance.
+
+### Example
+```
+use std::f32::consts::E;
+
+let a = 3f32;
+let _ = (2f32).powf(a);
+let _ = E.powf(a);
+let _ = a.powf(1.0 / 2.0);
+let _ = a.log(2.0);
+let _ = a.log(10.0);
+let _ = a.log(E);
+let _ = a.powf(2.0);
+let _ = a * 2.0 + 4.0;
+let _ = if a < 0.0 {
+ -a
+} else {
+ a
+};
+let _ = if a < 0.0 {
+ a
+} else {
+ -a
+};
+```
+
+is better expressed as
+
+```
+use std::f32::consts::E;
+
+let a = 3f32;
+let _ = a.exp2();
+let _ = a.exp();
+let _ = a.sqrt();
+let _ = a.log2();
+let _ = a.log10();
+let _ = a.ln();
+let _ = a.powi(2);
+let _ = a.mul_add(2.0, 4.0);
+let _ = a.abs();
+let _ = -a.abs();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_arithmetic_impl.txt b/src/tools/clippy/src/docs/suspicious_arithmetic_impl.txt
new file mode 100644
index 000000000..d67ff2793
--- /dev/null
+++ b/src/tools/clippy/src/docs/suspicious_arithmetic_impl.txt
@@ -0,0 +1,17 @@
+### What it does
+Lints for suspicious operations in impls of arithmetic operators, e.g.
+subtracting elements in an Add impl.
+
+### Why is this bad?
+This is probably a typo or copy-and-paste error and not intended.
+
+### Example
+```
+impl Add for Foo {
+ type Output = Foo;
+
+ fn add(self, other: Foo) -> Foo {
+ Foo(self.0 - other.0)
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_assignment_formatting.txt b/src/tools/clippy/src/docs/suspicious_assignment_formatting.txt
new file mode 100644
index 000000000..b889827cd
--- /dev/null
+++ b/src/tools/clippy/src/docs/suspicious_assignment_formatting.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for use of the non-existent `=*`, `=!` and `=-`
+operators.
+
+### Why is this bad?
+This is either a typo of `*=`, `!=` or `-=` or
+confusing.
+
+### Example
+```
+a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_else_formatting.txt b/src/tools/clippy/src/docs/suspicious_else_formatting.txt
new file mode 100644
index 000000000..3cf2f7486
--- /dev/null
+++ b/src/tools/clippy/src/docs/suspicious_else_formatting.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for formatting of `else`. It lints if the `else`
+is followed immediately by a newline or the `else` seems to be missing.
+
+### Why is this bad?
+This is probably some refactoring remnant, even if the
+code is correct, it might look confusing.
+
+### Example
+```
+if foo {
+} { // looks like an `else` is missing here
+}
+
+if foo {
+} if bar { // looks like an `else` is missing here
+}
+
+if foo {
+} else
+
+{ // this is the `else` block of the previous `if`, but should it be?
+}
+
+if foo {
+} else
+
+if bar { // this is the `else` block of the previous `if`, but should it be?
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_map.txt b/src/tools/clippy/src/docs/suspicious_map.txt
new file mode 100644
index 000000000..d8fa52c43
--- /dev/null
+++ b/src/tools/clippy/src/docs/suspicious_map.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for calls to `map` followed by a `count`.
+
+### Why is this bad?
+It looks suspicious. Maybe `map` was confused with `filter`.
+If the `map` call is intentional, this should be rewritten
+using `inspect`. Or, if you intend to drive the iterator to
+completion, you can just use `for_each` instead.
+
+### Example
+```
+let _ = (0..3).map(|x| x + 2).count();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_op_assign_impl.txt b/src/tools/clippy/src/docs/suspicious_op_assign_impl.txt
new file mode 100644
index 000000000..81abfbeca
--- /dev/null
+++ b/src/tools/clippy/src/docs/suspicious_op_assign_impl.txt
@@ -0,0 +1,15 @@
+### What it does
+Lints for suspicious operations in impls of OpAssign, e.g.
+subtracting elements in an AddAssign impl.
+
+### Why is this bad?
+This is probably a typo or copy-and-paste error and not intended.
+
+### Example
+```
+impl AddAssign for Foo {
+ fn add_assign(&mut self, other: Foo) {
+ *self = *self - other;
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_operation_groupings.txt b/src/tools/clippy/src/docs/suspicious_operation_groupings.txt
new file mode 100644
index 000000000..81ede5d3d
--- /dev/null
+++ b/src/tools/clippy/src/docs/suspicious_operation_groupings.txt
@@ -0,0 +1,41 @@
+### What it does
+Checks for unlikely usages of binary operators that are almost
+certainly typos and/or copy/paste errors, given the other usages
+of binary operators nearby.
+
+### Why is this bad?
+They are probably bugs and if they aren't then they look like bugs
+and you should add a comment explaining why you are doing such an
+odd set of operations.
+
+### Known problems
+There may be some false positives if you are trying to do something
+unusual that happens to look like a typo.
+
+### Example
+```
+struct Vec3 {
+ x: f64,
+ y: f64,
+ z: f64,
+}
+
+impl Eq for Vec3 {}
+
+impl PartialEq for Vec3 {
+ fn eq(&self, other: &Self) -> bool {
+ // This should trigger the lint because `self.x` is compared to `other.y`
+ self.x == other.y && self.y == other.y && self.z == other.z
+ }
+}
+```
+Use instead:
+```
+// same as above except:
+impl PartialEq for Vec3 {
+ fn eq(&self, other: &Self) -> bool {
+ // Note we now compare other.x to self.x
+ self.x == other.x && self.y == other.y && self.z == other.z
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_splitn.txt b/src/tools/clippy/src/docs/suspicious_splitn.txt
new file mode 100644
index 000000000..79a3dbfa6
--- /dev/null
+++ b/src/tools/clippy/src/docs/suspicious_splitn.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for calls to [`splitn`]
+(https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and
+related functions with either zero or one splits.
+
+### Why is this bad?
+These calls don't actually split the value and are
+likely to be intended as a different number.
+
+### Example
+```
+for x in s.splitn(1, ":") {
+ // ..
+}
+```
+
+Use instead:
+```
+for x in s.splitn(2, ":") {
+ // ..
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_to_owned.txt b/src/tools/clippy/src/docs/suspicious_to_owned.txt
new file mode 100644
index 000000000..8cbf61dc7
--- /dev/null
+++ b/src/tools/clippy/src/docs/suspicious_to_owned.txt
@@ -0,0 +1,39 @@
+### What it does
+Checks for the usage of `_.to_owned()`, on a `Cow<'_, _>`.
+
+### Why is this bad?
+Calling `to_owned()` on a `Cow` creates a clone of the `Cow`
+itself, without taking ownership of the `Cow` contents (i.e.
+it's equivalent to calling `Cow::clone`).
+The similarly named `into_owned` method, on the other hand,
+clones the `Cow` contents, effectively turning any `Cow::Borrowed`
+into a `Cow::Owned`.
+
+Given the potential ambiguity, consider replacing `to_owned`
+with `clone` for better readability or, if getting a `Cow::Owned`
+was the original intent, using `into_owned` instead.
+
+### Example
+```
+let s = "Hello world!";
+let cow = Cow::Borrowed(s);
+
+let data = cow.to_owned();
+assert!(matches!(data, Cow::Borrowed(_)))
+```
+Use instead:
+```
+let s = "Hello world!";
+let cow = Cow::Borrowed(s);
+
+let data = cow.clone();
+assert!(matches!(data, Cow::Borrowed(_)))
+```
+or
+```
+let s = "Hello world!";
+let cow = Cow::Borrowed(s);
+
+let data = cow.into_owned();
+assert!(matches!(data, String))
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/suspicious_unary_op_formatting.txt b/src/tools/clippy/src/docs/suspicious_unary_op_formatting.txt
new file mode 100644
index 000000000..06fb09db7
--- /dev/null
+++ b/src/tools/clippy/src/docs/suspicious_unary_op_formatting.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks the formatting of a unary operator on the right hand side
+of a binary operator. It lints if there is no space between the binary and unary operators,
+but there is a space between the unary and its operand.
+
+### Why is this bad?
+This is either a typo in the binary operator or confusing.
+
+### Example
+```
+// &&! looks like a different operator
+if foo &&! bar {}
+```
+
+Use instead:
+```
+if foo && !bar {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/swap_ptr_to_ref.txt b/src/tools/clippy/src/docs/swap_ptr_to_ref.txt
new file mode 100644
index 000000000..0215d1e8a
--- /dev/null
+++ b/src/tools/clippy/src/docs/swap_ptr_to_ref.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for calls to `core::mem::swap` where either parameter is derived from a pointer
+
+### Why is this bad?
+When at least one parameter to `swap` is derived from a pointer it may overlap with the
+other. This would then lead to undefined behavior.
+
+### Example
+```
+unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) {
+ for (&x, &y) in x.iter().zip(y) {
+ core::mem::swap(&mut *x, &mut *y);
+ }
+}
+```
+Use instead:
+```
+unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) {
+ for (&x, &y) in x.iter().zip(y) {
+ core::ptr::swap(x, y);
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/tabs_in_doc_comments.txt b/src/tools/clippy/src/docs/tabs_in_doc_comments.txt
new file mode 100644
index 000000000..f83dbe2b7
--- /dev/null
+++ b/src/tools/clippy/src/docs/tabs_in_doc_comments.txt
@@ -0,0 +1,44 @@
+### What it does
+Checks doc comments for usage of tab characters.
+
+### Why is this bad?
+The rust style-guide promotes spaces instead of tabs for indentation.
+To keep a consistent view on the source, also doc comments should not have tabs.
+Also, explaining ascii-diagrams containing tabs can get displayed incorrectly when the
+display settings of the author and reader differ.
+
+### Example
+```
+///
+/// Struct to hold two strings:
+/// - first one
+/// - second one
+pub struct DoubleString {
+ ///
+ /// - First String:
+ /// - needs to be inside here
+ first_string: String,
+ ///
+ /// - Second String:
+ /// - needs to be inside here
+ second_string: String,
+}
+```
+
+Will be converted to:
+```
+///
+/// Struct to hold two strings:
+/// - first one
+/// - second one
+pub struct DoubleString {
+ ///
+ /// - First String:
+ /// - needs to be inside here
+ first_string: String,
+ ///
+ /// - Second String:
+ /// - needs to be inside here
+ second_string: String,
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/temporary_assignment.txt b/src/tools/clippy/src/docs/temporary_assignment.txt
new file mode 100644
index 000000000..195b42cf0
--- /dev/null
+++ b/src/tools/clippy/src/docs/temporary_assignment.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for construction of a structure or tuple just to
+assign a value in it.
+
+### Why is this bad?
+Readability. If the structure is only created to be
+updated, why not write the structure you want in the first place?
+
+### Example
+```
+(0, 0).0 = 1
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/to_digit_is_some.txt b/src/tools/clippy/src/docs/to_digit_is_some.txt
new file mode 100644
index 000000000..eee8375ad
--- /dev/null
+++ b/src/tools/clippy/src/docs/to_digit_is_some.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for `.to_digit(..).is_some()` on `char`s.
+
+### Why is this bad?
+This is a convoluted way of checking if a `char` is a digit. It's
+more straight forward to use the dedicated `is_digit` method.
+
+### Example
+```
+let is_digit = c.to_digit(radix).is_some();
+```
+can be written as:
+```
+let is_digit = c.is_digit(radix);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/to_string_in_format_args.txt b/src/tools/clippy/src/docs/to_string_in_format_args.txt
new file mode 100644
index 000000000..34b205835
--- /dev/null
+++ b/src/tools/clippy/src/docs/to_string_in_format_args.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for [`ToString::to_string`](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string)
+applied to a type that implements [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html)
+in a macro that does formatting.
+
+### Why is this bad?
+Since the type implements `Display`, the use of `to_string` is
+unnecessary.
+
+### Example
+```
+println!("error: something failed at {}", Location::caller().to_string());
+```
+Use instead:
+```
+println!("error: something failed at {}", Location::caller());
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/todo.txt b/src/tools/clippy/src/docs/todo.txt
new file mode 100644
index 000000000..661eb1ac5
--- /dev/null
+++ b/src/tools/clippy/src/docs/todo.txt
@@ -0,0 +1,10 @@
+### What it does
+Checks for usage of `todo!`.
+
+### Why is this bad?
+This macro should not be present in production code
+
+### Example
+```
+todo!();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/too_many_arguments.txt b/src/tools/clippy/src/docs/too_many_arguments.txt
new file mode 100644
index 000000000..4669f9f82
--- /dev/null
+++ b/src/tools/clippy/src/docs/too_many_arguments.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for functions with too many parameters.
+
+### Why is this bad?
+Functions with lots of parameters are considered bad
+style and reduce readability (“what does the 5th parameter mean?”). Consider
+grouping some parameters into a new type.
+
+### Example
+```
+fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
+ // ..
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/too_many_lines.txt b/src/tools/clippy/src/docs/too_many_lines.txt
new file mode 100644
index 000000000..425db348b
--- /dev/null
+++ b/src/tools/clippy/src/docs/too_many_lines.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for functions with a large amount of lines.
+
+### Why is this bad?
+Functions with a lot of lines are harder to understand
+due to having to look at a larger amount of code to understand what the
+function is doing. Consider splitting the body of the function into
+multiple functions.
+
+### Example
+```
+fn im_too_long() {
+ println!("");
+ // ... 100 more LoC
+ println!("");
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/toplevel_ref_arg.txt b/src/tools/clippy/src/docs/toplevel_ref_arg.txt
new file mode 100644
index 000000000..96a9e2db8
--- /dev/null
+++ b/src/tools/clippy/src/docs/toplevel_ref_arg.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for function arguments and let bindings denoted as
+`ref`.
+
+### Why is this bad?
+The `ref` declaration makes the function take an owned
+value, but turns the argument into a reference (which means that the value
+is destroyed when exiting the function). This adds not much value: either
+take a reference type, or take an owned value and create references in the
+body.
+
+For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The
+type of `x` is more obvious with the former.
+
+### Known problems
+If the argument is dereferenced within the function,
+removing the `ref` will lead to errors. This can be fixed by removing the
+dereferences, e.g., changing `*x` to `x` within the function.
+
+### Example
+```
+fn foo(ref _x: u8) {}
+```
+
+Use instead:
+```
+fn foo(_x: &u8) {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/trailing_empty_array.txt b/src/tools/clippy/src/docs/trailing_empty_array.txt
new file mode 100644
index 000000000..db1908cc9
--- /dev/null
+++ b/src/tools/clippy/src/docs/trailing_empty_array.txt
@@ -0,0 +1,22 @@
+### What it does
+Displays a warning when a struct with a trailing zero-sized array is declared without a `repr` attribute.
+
+### Why is this bad?
+Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjunction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed.
+
+### Example
+```
+struct RarelyUseful {
+ some_field: u32,
+ last: [u32; 0],
+}
+```
+
+Use instead:
+```
+#[repr(C)]
+struct MoreOftenUseful {
+ some_field: usize,
+ last: [u32; 0],
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/trait_duplication_in_bounds.txt b/src/tools/clippy/src/docs/trait_duplication_in_bounds.txt
new file mode 100644
index 000000000..509736bb3
--- /dev/null
+++ b/src/tools/clippy/src/docs/trait_duplication_in_bounds.txt
@@ -0,0 +1,37 @@
+### What it does
+Checks for cases where generics are being used and multiple
+syntax specifications for trait bounds are used simultaneously.
+
+### Why is this bad?
+Duplicate bounds makes the code
+less readable than specifying them only once.
+
+### Example
+```
+fn func<T: Clone + Default>(arg: T) where T: Clone + Default {}
+```
+
+Use instead:
+```
+fn func<T: Clone + Default>(arg: T) {}
+
+// or
+
+fn func<T>(arg: T) where T: Clone + Default {}
+```
+
+```
+fn foo<T: Default + Default>(bar: T) {}
+```
+Use instead:
+```
+fn foo<T: Default>(bar: T) {}
+```
+
+```
+fn foo<T>(bar: T) where T: Default + Default {}
+```
+Use instead:
+```
+fn foo<T>(bar: T) where T: Default {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_bytes_to_str.txt b/src/tools/clippy/src/docs/transmute_bytes_to_str.txt
new file mode 100644
index 000000000..75889b9c7
--- /dev/null
+++ b/src/tools/clippy/src/docs/transmute_bytes_to_str.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for transmutes from a `&[u8]` to a `&str`.
+
+### Why is this bad?
+Not every byte slice is a valid UTF-8 string.
+
+### Known problems
+- [`from_utf8`] which this lint suggests using is slower than `transmute`
+as it needs to validate the input.
+If you are certain that the input is always a valid UTF-8,
+use [`from_utf8_unchecked`] which is as fast as `transmute`
+but has a semantically meaningful name.
+- You might want to handle errors returned from [`from_utf8`] instead of calling `unwrap`.
+
+[`from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html
+[`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html
+
+### Example
+```
+let b: &[u8] = &[1_u8, 2_u8];
+unsafe {
+ let _: &str = std::mem::transmute(b); // where b: &[u8]
+}
+
+// should be:
+let _ = std::str::from_utf8(b).unwrap();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_float_to_int.txt b/src/tools/clippy/src/docs/transmute_float_to_int.txt
new file mode 100644
index 000000000..1877e5a46
--- /dev/null
+++ b/src/tools/clippy/src/docs/transmute_float_to_int.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes from a float to an integer.
+
+### Why is this bad?
+Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive
+and safe.
+
+### Example
+```
+unsafe {
+ let _: u32 = std::mem::transmute(1f32);
+}
+
+// should be:
+let _: u32 = 1f32.to_bits();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_int_to_bool.txt b/src/tools/clippy/src/docs/transmute_int_to_bool.txt
new file mode 100644
index 000000000..07c10f8d0
--- /dev/null
+++ b/src/tools/clippy/src/docs/transmute_int_to_bool.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes from an integer to a `bool`.
+
+### Why is this bad?
+This might result in an invalid in-memory representation of a `bool`.
+
+### Example
+```
+let x = 1_u8;
+unsafe {
+ let _: bool = std::mem::transmute(x); // where x: u8
+}
+
+// should be:
+let _: bool = x != 0;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_int_to_char.txt b/src/tools/clippy/src/docs/transmute_int_to_char.txt
new file mode 100644
index 000000000..836d22d3f
--- /dev/null
+++ b/src/tools/clippy/src/docs/transmute_int_to_char.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for transmutes from an integer to a `char`.
+
+### Why is this bad?
+Not every integer is a Unicode scalar value.
+
+### Known problems
+- [`from_u32`] which this lint suggests using is slower than `transmute`
+as it needs to validate the input.
+If you are certain that the input is always a valid Unicode scalar value,
+use [`from_u32_unchecked`] which is as fast as `transmute`
+but has a semantically meaningful name.
+- You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`.
+
+[`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html
+[`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html
+
+### Example
+```
+let x = 1_u32;
+unsafe {
+ let _: char = std::mem::transmute(x); // where x: u32
+}
+
+// should be:
+let _ = std::char::from_u32(x).unwrap();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_int_to_float.txt b/src/tools/clippy/src/docs/transmute_int_to_float.txt
new file mode 100644
index 000000000..75cdc62e9
--- /dev/null
+++ b/src/tools/clippy/src/docs/transmute_int_to_float.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes from an integer to a float.
+
+### Why is this bad?
+Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive
+and safe.
+
+### Example
+```
+unsafe {
+ let _: f32 = std::mem::transmute(1_u32); // where x: u32
+}
+
+// should be:
+let _: f32 = f32::from_bits(1_u32);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_num_to_bytes.txt b/src/tools/clippy/src/docs/transmute_num_to_bytes.txt
new file mode 100644
index 000000000..a2c39a1b9
--- /dev/null
+++ b/src/tools/clippy/src/docs/transmute_num_to_bytes.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes from a number to an array of `u8`
+
+### Why this is bad?
+Transmutes are dangerous and error-prone, whereas `to_ne_bytes`
+is intuitive and safe.
+
+### Example
+```
+unsafe {
+ let x: [u8; 8] = std::mem::transmute(1i64);
+}
+
+// should be
+let x: [u8; 8] = 0i64.to_ne_bytes();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_ptr_to_ptr.txt b/src/tools/clippy/src/docs/transmute_ptr_to_ptr.txt
new file mode 100644
index 000000000..65777db98
--- /dev/null
+++ b/src/tools/clippy/src/docs/transmute_ptr_to_ptr.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for transmutes from a pointer to a pointer, or
+from a reference to a reference.
+
+### Why is this bad?
+Transmutes are dangerous, and these can instead be
+written as casts.
+
+### Example
+```
+let ptr = &1u32 as *const u32;
+unsafe {
+ // pointer-to-pointer transmute
+ let _: *const f32 = std::mem::transmute(ptr);
+ // ref-ref transmute
+ let _: &f32 = std::mem::transmute(&1u32);
+}
+// These can be respectively written:
+let _ = ptr as *const f32;
+let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) };
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_ptr_to_ref.txt b/src/tools/clippy/src/docs/transmute_ptr_to_ref.txt
new file mode 100644
index 000000000..aca550f50
--- /dev/null
+++ b/src/tools/clippy/src/docs/transmute_ptr_to_ref.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for transmutes from a pointer to a reference.
+
+### Why is this bad?
+This can always be rewritten with `&` and `*`.
+
+### Known problems
+- `mem::transmute` in statics and constants is stable from Rust 1.46.0,
+while dereferencing raw pointer is not stable yet.
+If you need to do this in those places,
+you would have to use `transmute` instead.
+
+### Example
+```
+unsafe {
+ let _: &T = std::mem::transmute(p); // where p: *const T
+}
+
+// can be written:
+let _: &T = &*p;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmute_undefined_repr.txt b/src/tools/clippy/src/docs/transmute_undefined_repr.txt
new file mode 100644
index 000000000..5ee6aaf4c
--- /dev/null
+++ b/src/tools/clippy/src/docs/transmute_undefined_repr.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for transmutes between types which do not have a representation defined relative to
+each other.
+
+### Why is this bad?
+The results of such a transmute are not defined.
+
+### Known problems
+This lint has had multiple problems in the past and was moved to `nursery`. See issue
+[#8496](https://github.com/rust-lang/rust-clippy/issues/8496) for more details.
+
+### Example
+```
+struct Foo<T>(u32, T);
+let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
+```
+Use instead:
+```
+#[repr(C)]
+struct Foo<T>(u32, T);
+let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmutes_expressible_as_ptr_casts.txt b/src/tools/clippy/src/docs/transmutes_expressible_as_ptr_casts.txt
new file mode 100644
index 000000000..b68a8cda9
--- /dev/null
+++ b/src/tools/clippy/src/docs/transmutes_expressible_as_ptr_casts.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes that could be a pointer cast.
+
+### Why is this bad?
+Readability. The code tricks people into thinking that
+something complex is going on.
+
+### Example
+
+```
+unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) };
+```
+Use instead:
+```
+p as *const [u16];
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/transmuting_null.txt b/src/tools/clippy/src/docs/transmuting_null.txt
new file mode 100644
index 000000000..f8bacfc0b
--- /dev/null
+++ b/src/tools/clippy/src/docs/transmuting_null.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for transmute calls which would receive a null pointer.
+
+### Why is this bad?
+Transmuting a null pointer is undefined behavior.
+
+### Known problems
+Not all cases can be detected at the moment of this writing.
+For example, variables which hold a null pointer and are then fed to a `transmute`
+call, aren't detectable yet.
+
+### Example
+```
+let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/trim_split_whitespace.txt b/src/tools/clippy/src/docs/trim_split_whitespace.txt
new file mode 100644
index 000000000..f7e3e7858
--- /dev/null
+++ b/src/tools/clippy/src/docs/trim_split_whitespace.txt
@@ -0,0 +1,14 @@
+### What it does
+Warns about calling `str::trim` (or variants) before `str::split_whitespace`.
+
+### Why is this bad?
+`split_whitespace` already ignores leading and trailing whitespace.
+
+### Example
+```
+" A B C ".trim().split_whitespace();
+```
+Use instead:
+```
+" A B C ".split_whitespace();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/trivial_regex.txt b/src/tools/clippy/src/docs/trivial_regex.txt
new file mode 100644
index 000000000..f71d667fd
--- /dev/null
+++ b/src/tools/clippy/src/docs/trivial_regex.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for trivial [regex](https://crates.io/crates/regex)
+creation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`).
+
+### Why is this bad?
+Matching the regex can likely be replaced by `==` or
+`str::starts_with`, `str::ends_with` or `std::contains` or other `str`
+methods.
+
+### Known problems
+If the same regex is going to be applied to multiple
+inputs, the precomputations done by `Regex` construction can give
+significantly better performance than any of the `str`-based methods.
+
+### Example
+```
+Regex::new("^foobar")
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/trivially_copy_pass_by_ref.txt b/src/tools/clippy/src/docs/trivially_copy_pass_by_ref.txt
new file mode 100644
index 000000000..f54cce5e2
--- /dev/null
+++ b/src/tools/clippy/src/docs/trivially_copy_pass_by_ref.txt
@@ -0,0 +1,43 @@
+### What it does
+Checks for functions taking arguments by reference, where
+the argument type is `Copy` and small enough to be more efficient to always
+pass by value.
+
+### Why is this bad?
+In many calling conventions instances of structs will
+be passed through registers if they fit into two or less general purpose
+registers.
+
+### Known problems
+This lint is target register size dependent, it is
+limited to 32-bit to try and reduce portability problems between 32 and
+64-bit, but if you are compiling for 8 or 16-bit targets then the limit
+will be different.
+
+The configuration option `trivial_copy_size_limit` can be set to override
+this limit for a project.
+
+This lint attempts to allow passing arguments by reference if a reference
+to that argument is returned. This is implemented by comparing the lifetime
+of the argument and return value for equality. However, this can cause
+false positives in cases involving multiple lifetimes that are bounded by
+each other.
+
+Also, it does not take account of other similar cases where getting memory addresses
+matters; namely, returning the pointer to the argument in question,
+and passing the argument, as both references and pointers,
+to a function that needs the memory address. For further details, refer to
+[this issue](https://github.com/rust-lang/rust-clippy/issues/5953)
+that explains a real case in which this false positive
+led to an **undefined behavior** introduced with unsafe code.
+
+### Example
+
+```
+fn foo(v: &u32) {}
+```
+
+Use instead:
+```
+fn foo(v: u32) {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/try_err.txt b/src/tools/clippy/src/docs/try_err.txt
new file mode 100644
index 000000000..e3d4ef3a0
--- /dev/null
+++ b/src/tools/clippy/src/docs/try_err.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for usages of `Err(x)?`.
+
+### Why is this bad?
+The `?` operator is designed to allow calls that
+can fail to be easily chained. For example, `foo()?.bar()` or
+`foo(bar()?)`. Because `Err(x)?` can't be used that way (it will
+always return), it is more clear to write `return Err(x)`.
+
+### Example
+```
+fn foo(fail: bool) -> Result<i32, String> {
+ if fail {
+ Err("failed")?;
+ }
+ Ok(0)
+}
+```
+Could be written:
+
+```
+fn foo(fail: bool) -> Result<i32, String> {
+ if fail {
+ return Err("failed".into());
+ }
+ Ok(0)
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/type_complexity.txt b/src/tools/clippy/src/docs/type_complexity.txt
new file mode 100644
index 000000000..69cd87500
--- /dev/null
+++ b/src/tools/clippy/src/docs/type_complexity.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for types used in structs, parameters and `let`
+declarations above a certain complexity threshold.
+
+### Why is this bad?
+Too complex types make the code less readable. Consider
+using a `type` definition to simplify them.
+
+### Example
+```
+struct Foo {
+ inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>,
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/type_repetition_in_bounds.txt b/src/tools/clippy/src/docs/type_repetition_in_bounds.txt
new file mode 100644
index 000000000..18ed372fd
--- /dev/null
+++ b/src/tools/clippy/src/docs/type_repetition_in_bounds.txt
@@ -0,0 +1,16 @@
+### What it does
+This lint warns about unnecessary type repetitions in trait bounds
+
+### Why is this bad?
+Repeating the type for every bound makes the code
+less readable than combining the bounds
+
+### Example
+```
+pub fn foo<T>(t: T) where T: Copy, T: Clone {}
+```
+
+Use instead:
+```
+pub fn foo<T>(t: T) where T: Copy + Clone {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/undocumented_unsafe_blocks.txt b/src/tools/clippy/src/docs/undocumented_unsafe_blocks.txt
new file mode 100644
index 000000000..f3af4753c
--- /dev/null
+++ b/src/tools/clippy/src/docs/undocumented_unsafe_blocks.txt
@@ -0,0 +1,43 @@
+### What it does
+Checks for `unsafe` blocks and impls without a `// SAFETY: ` comment
+explaining why the unsafe operations performed inside
+the block are safe.
+
+Note the comment must appear on the line(s) preceding the unsafe block
+with nothing appearing in between. The following is ok:
+```
+foo(
+ // SAFETY:
+ // This is a valid safety comment
+ unsafe { *x }
+)
+```
+But neither of these are:
+```
+// SAFETY:
+// This is not a valid safety comment
+foo(
+ /* SAFETY: Neither is this */ unsafe { *x },
+);
+```
+
+### Why is this bad?
+Undocumented unsafe blocks and impls can make it difficult to
+read and maintain code, as well as uncover unsoundness
+and bugs.
+
+### Example
+```
+use std::ptr::NonNull;
+let a = &mut 42;
+
+let ptr = unsafe { NonNull::new_unchecked(a) };
+```
+Use instead:
+```
+use std::ptr::NonNull;
+let a = &mut 42;
+
+// SAFETY: references are guaranteed to be non-null.
+let ptr = unsafe { NonNull::new_unchecked(a) };
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/undropped_manually_drops.txt b/src/tools/clippy/src/docs/undropped_manually_drops.txt
new file mode 100644
index 000000000..85e3ec566
--- /dev/null
+++ b/src/tools/clippy/src/docs/undropped_manually_drops.txt
@@ -0,0 +1,22 @@
+### What it does
+Prevents the safe `std::mem::drop` function from being called on `std::mem::ManuallyDrop`.
+
+### Why is this bad?
+The safe `drop` function does not drop the inner value of a `ManuallyDrop`.
+
+### Known problems
+Does not catch cases if the user binds `std::mem::drop`
+to a different name and calls it that way.
+
+### Example
+```
+struct S;
+drop(std::mem::ManuallyDrop::new(S));
+```
+Use instead:
+```
+struct S;
+unsafe {
+ std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(S));
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unicode_not_nfc.txt b/src/tools/clippy/src/docs/unicode_not_nfc.txt
new file mode 100644
index 000000000..c660c51da
--- /dev/null
+++ b/src/tools/clippy/src/docs/unicode_not_nfc.txt
@@ -0,0 +1,12 @@
+### 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}"`. \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unimplemented.txt b/src/tools/clippy/src/docs/unimplemented.txt
new file mode 100644
index 000000000..7095594fb
--- /dev/null
+++ b/src/tools/clippy/src/docs/unimplemented.txt
@@ -0,0 +1,10 @@
+### What it does
+Checks for usage of `unimplemented!`.
+
+### Why is this bad?
+This macro should not be present in production code
+
+### Example
+```
+unimplemented!();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/uninit_assumed_init.txt b/src/tools/clippy/src/docs/uninit_assumed_init.txt
new file mode 100644
index 000000000..cca24093d
--- /dev/null
+++ b/src/tools/clippy/src/docs/uninit_assumed_init.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for `MaybeUninit::uninit().assume_init()`.
+
+### Why is this bad?
+For most types, this is undefined behavior.
+
+### Known problems
+For now, we accept empty tuples and tuples / arrays
+of `MaybeUninit`. There may be other types that allow uninitialized
+data, but those are not yet rigorously defined.
+
+### Example
+```
+// Beware the UB
+use std::mem::MaybeUninit;
+
+let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
+```
+
+Note that the following is OK:
+
+```
+use std::mem::MaybeUninit;
+
+let _: [MaybeUninit<bool>; 5] = unsafe {
+ MaybeUninit::uninit().assume_init()
+};
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/uninit_vec.txt b/src/tools/clippy/src/docs/uninit_vec.txt
new file mode 100644
index 000000000..cd50afe78
--- /dev/null
+++ b/src/tools/clippy/src/docs/uninit_vec.txt
@@ -0,0 +1,41 @@
+### What it does
+Checks for `set_len()` call that creates `Vec` with uninitialized elements.
+This is commonly caused by calling `set_len()` right after allocating or
+reserving a buffer with `new()`, `default()`, `with_capacity()`, or `reserve()`.
+
+### Why is this bad?
+It creates a `Vec` with uninitialized data, which leads to
+undefined behavior with most safe operations. Notably, uninitialized
+`Vec<u8>` must not be used with generic `Read`.
+
+Moreover, calling `set_len()` on a `Vec` created with `new()` or `default()`
+creates out-of-bound values that lead to heap memory corruption when used.
+
+### Known Problems
+This lint only checks directly adjacent statements.
+
+### Example
+```
+let mut vec: Vec<u8> = Vec::with_capacity(1000);
+unsafe { vec.set_len(1000); }
+reader.read(&mut vec); // undefined behavior!
+```
+
+### How to fix?
+1. Use an initialized buffer:
+ ```rust,ignore
+ let mut vec: Vec<u8> = vec![0; 1000];
+ reader.read(&mut vec);
+ ```
+2. Wrap the content in `MaybeUninit`:
+ ```rust,ignore
+ let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000);
+ vec.set_len(1000); // `MaybeUninit` can be uninitialized
+ ```
+3. If you are on 1.60.0 or later, `Vec::spare_capacity_mut()` is available:
+ ```rust,ignore
+ let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ let remaining = vec.spare_capacity_mut(); // `&mut [MaybeUninit<u8>]`
+ // perform initialization with `remaining`
+ vec.set_len(...); // Safe to call `set_len()` on initialized part
+ ``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/uninlined_format_args.txt b/src/tools/clippy/src/docs/uninlined_format_args.txt
new file mode 100644
index 000000000..3d2966c84
--- /dev/null
+++ b/src/tools/clippy/src/docs/uninlined_format_args.txt
@@ -0,0 +1,36 @@
+### What it does
+Detect when a variable is not inlined in a format string,
+and suggests to inline it.
+
+### Why is this bad?
+Non-inlined code is slightly more difficult to read and understand,
+as it requires arguments to be matched against the format string.
+The inlined syntax, where allowed, is simpler.
+
+### Example
+```
+format!("{}", var);
+format!("{v:?}", v = var);
+format!("{0} {0}", var);
+format!("{0:1$}", var, width);
+format!("{:.*}", prec, var);
+```
+Use instead:
+```
+format!("{var}");
+format!("{var:?}");
+format!("{var} {var}");
+format!("{var:width$}");
+format!("{var:.prec$}");
+```
+
+### Known Problems
+
+There may be a false positive if the format string is expanded from certain proc macros:
+
+```
+println!(indoc!("{}"), var);
+```
+
+If a format string contains a numbered argument that cannot be inlined
+nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`. \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unit_arg.txt b/src/tools/clippy/src/docs/unit_arg.txt
new file mode 100644
index 000000000..eb83403bb
--- /dev/null
+++ b/src/tools/clippy/src/docs/unit_arg.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for passing a unit value as an argument to a function without using a
+unit literal (`()`).
+
+### Why is this bad?
+This is likely the result of an accidental semicolon.
+
+### Example
+```
+foo({
+ let a = bar();
+ baz(a);
+})
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unit_cmp.txt b/src/tools/clippy/src/docs/unit_cmp.txt
new file mode 100644
index 000000000..6f3d62010
--- /dev/null
+++ b/src/tools/clippy/src/docs/unit_cmp.txt
@@ -0,0 +1,33 @@
+### What it does
+Checks for comparisons to unit. This includes all binary
+comparisons (like `==` and `<`) and asserts.
+
+### Why is this bad?
+Unit is always equal to itself, and thus is just a
+clumsily written constant. Mostly this happens when someone accidentally
+adds semicolons at the end of the operands.
+
+### Example
+```
+if {
+ foo();
+} == {
+ bar();
+} {
+ baz();
+}
+```
+is equal to
+```
+{
+ foo();
+ bar();
+ baz();
+}
+```
+
+For asserts:
+```
+assert_eq!({ foo(); }, { bar(); });
+```
+will always succeed \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unit_hash.txt b/src/tools/clippy/src/docs/unit_hash.txt
new file mode 100644
index 000000000..a22d29946
--- /dev/null
+++ b/src/tools/clippy/src/docs/unit_hash.txt
@@ -0,0 +1,20 @@
+### 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
+```
+match my_enum {
+ Empty => ().hash(&mut state),
+ WithValue(x) => x.hash(&mut state),
+}
+```
+Use instead:
+```
+match my_enum {
+ Empty => 0_u8.hash(&mut state),
+ WithValue(x) => x.hash(&mut state),
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unit_return_expecting_ord.txt b/src/tools/clippy/src/docs/unit_return_expecting_ord.txt
new file mode 100644
index 000000000..781feac5a
--- /dev/null
+++ b/src/tools/clippy/src/docs/unit_return_expecting_ord.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for functions that expect closures of type
+Fn(...) -> Ord where the implemented closure returns the unit type.
+The lint also suggests to remove the semi-colon at the end of the statement if present.
+
+### Why is this bad?
+Likely, returning the unit type is unintentional, and
+could simply be caused by an extra semi-colon. Since () implements Ord
+it doesn't cause a compilation error.
+This is the same reasoning behind the unit_cmp lint.
+
+### Known problems
+If returning unit is intentional, then there is no
+way of specifying this without triggering needless_return lint
+
+### Example
+```
+let mut twins = vec!((1, 1), (2, 2));
+twins.sort_by_key(|x| { x.1; });
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_cast.txt b/src/tools/clippy/src/docs/unnecessary_cast.txt
new file mode 100644
index 000000000..603f26060
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnecessary_cast.txt
@@ -0,0 +1,19 @@
+### 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
+```
+let _ = 2i32 as i32;
+let _ = 0.5 as f32;
+```
+
+Better:
+
+```
+let _ = 2_i32;
+let _ = 0.5_f32;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_filter_map.txt b/src/tools/clippy/src/docs/unnecessary_filter_map.txt
new file mode 100644
index 000000000..b19341ecf
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnecessary_filter_map.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for `filter_map` calls that could be replaced by `filter` or `map`.
+More specifically it checks if the closure provided is only performing one of the
+filter or map operations and suggests the appropriate option.
+
+### Why is this bad?
+Complexity. The intent is also clearer if only a single
+operation is being performed.
+
+### Example
+```
+let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });
+
+// As there is no transformation of the argument this could be written as:
+let _ = (0..3).filter(|&x| x > 2);
+```
+
+```
+let _ = (0..4).filter_map(|x| Some(x + 1));
+
+// As there is no conditional check on the argument this could be written as:
+let _ = (0..4).map(|x| x + 1);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_find_map.txt b/src/tools/clippy/src/docs/unnecessary_find_map.txt
new file mode 100644
index 000000000..f9444dc48
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnecessary_find_map.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for `find_map` calls that could be replaced by `find` or `map`. More
+specifically it checks if the closure provided is only performing one of the
+find or map operations and suggests the appropriate option.
+
+### Why is this bad?
+Complexity. The intent is also clearer if only a single
+operation is being performed.
+
+### Example
+```
+let _ = (0..3).find_map(|x| if x > 2 { Some(x) } else { None });
+
+// As there is no transformation of the argument this could be written as:
+let _ = (0..3).find(|&x| x > 2);
+```
+
+```
+let _ = (0..4).find_map(|x| Some(x + 1));
+
+// As there is no conditional check on the argument this could be written as:
+let _ = (0..4).map(|x| x + 1).next();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_fold.txt b/src/tools/clippy/src/docs/unnecessary_fold.txt
new file mode 100644
index 000000000..e1b0e65f5
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnecessary_fold.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for using `fold` when a more succinct alternative exists.
+Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
+`sum` or `product`.
+
+### Why is this bad?
+Readability.
+
+### Example
+```
+(0..3).fold(false, |acc, x| acc || x > 2);
+```
+
+Use instead:
+```
+(0..3).any(|x| x > 2);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_join.txt b/src/tools/clippy/src/docs/unnecessary_join.txt
new file mode 100644
index 000000000..ee4e78601
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnecessary_join.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for use of `.collect::<Vec<String>>().join("")` on iterators.
+
+### Why is this bad?
+`.collect::<String>()` is more concise and might be more performant
+
+### Example
+```
+let vector = vec!["hello", "world"];
+let output = vector.iter().map(|item| item.to_uppercase()).collect::<Vec<String>>().join("");
+println!("{}", output);
+```
+The correct use would be:
+```
+let vector = vec!["hello", "world"];
+let output = vector.iter().map(|item| item.to_uppercase()).collect::<String>();
+println!("{}", output);
+```
+### Known problems
+While `.collect::<String>()` is sometimes more performant, there are cases where
+using `.collect::<String>()` over `.collect::<Vec<String>>().join("")`
+will prevent loop unrolling and will result in a negative performance impact.
+
+Additionally, differences have been observed between aarch64 and x86_64 assembly output,
+with aarch64 tending to producing faster assembly in more cases when using `.collect::<String>()` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_lazy_evaluations.txt b/src/tools/clippy/src/docs/unnecessary_lazy_evaluations.txt
new file mode 100644
index 000000000..208188ce9
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnecessary_lazy_evaluations.txt
@@ -0,0 +1,32 @@
+### What it does
+As the counterpart to `or_fun_call`, this lint looks for unnecessary
+lazily evaluated closures on `Option` and `Result`.
+
+This lint suggests changing the following functions, when eager evaluation results in
+simpler code:
+ - `unwrap_or_else` to `unwrap_or`
+ - `and_then` to `and`
+ - `or_else` to `or`
+ - `get_or_insert_with` to `get_or_insert`
+ - `ok_or_else` to `ok_or`
+
+### Why is this bad?
+Using eager evaluation is shorter and simpler in some cases.
+
+### Known problems
+It is possible, but not recommended for `Deref` and `Index` to have
+side effects. Eagerly evaluating them can change the semantics of the program.
+
+### Example
+```
+// example code where clippy issues a warning
+let opt: Option<u32> = None;
+
+opt.unwrap_or_else(|| 42);
+```
+Use instead:
+```
+let opt: Option<u32> = None;
+
+opt.unwrap_or(42);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_mut_passed.txt b/src/tools/clippy/src/docs/unnecessary_mut_passed.txt
new file mode 100644
index 000000000..2f8bdd113
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnecessary_mut_passed.txt
@@ -0,0 +1,17 @@
+### What it does
+Detects passing a mutable reference to a function that only
+requires an immutable reference.
+
+### Why is this bad?
+The mutable reference rules out all other references to
+the value. Also the code misleads about the intent of the call site.
+
+### Example
+```
+vec.push(&mut value);
+```
+
+Use instead:
+```
+vec.push(&value);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_operation.txt b/src/tools/clippy/src/docs/unnecessary_operation.txt
new file mode 100644
index 000000000..7f455e264
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnecessary_operation.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for expression statements that can be reduced to a
+sub-expression.
+
+### Why is this bad?
+Expressions by themselves often have no side-effects.
+Having such expressions reduces readability.
+
+### Example
+```
+compute_array()[0];
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_owned_empty_strings.txt b/src/tools/clippy/src/docs/unnecessary_owned_empty_strings.txt
new file mode 100644
index 000000000..8cd9fba60
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnecessary_owned_empty_strings.txt
@@ -0,0 +1,16 @@
+### What it does
+
+Detects cases of owned empty strings being passed as an argument to a function expecting `&str`
+
+### Why is this bad?
+
+This results in longer and less readable code
+
+### Example
+```
+vec!["1", "2", "3"].join(&String::new());
+```
+Use instead:
+```
+vec!["1", "2", "3"].join("");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_self_imports.txt b/src/tools/clippy/src/docs/unnecessary_self_imports.txt
new file mode 100644
index 000000000..b909cd5a7
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnecessary_self_imports.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for imports ending in `::{self}`.
+
+### Why is this bad?
+In most cases, this can be written much more cleanly by omitting `::{self}`.
+
+### Known problems
+Removing `::{self}` will cause any non-module items at the same path to also be imported.
+This might cause a naming conflict (https://github.com/rust-lang/rustfmt/issues/3568). This lint makes no attempt
+to detect this scenario and that is why it is a restriction lint.
+
+### Example
+```
+use std::io::{self};
+```
+Use instead:
+```
+use std::io;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_sort_by.txt b/src/tools/clippy/src/docs/unnecessary_sort_by.txt
new file mode 100644
index 000000000..6913b62c4
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnecessary_sort_by.txt
@@ -0,0 +1,21 @@
+### What it does
+Detects uses of `Vec::sort_by` passing in a closure
+which compares the two arguments, either directly or indirectly.
+
+### Why is this bad?
+It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if
+possible) than to use `Vec::sort_by` and a more complicated
+closure.
+
+### Known problems
+If the suggested `Vec::sort_by_key` uses Reverse and it isn't already
+imported by a use statement, then it will need to be added manually.
+
+### Example
+```
+vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
+```
+Use instead:
+```
+vec.sort_by_key(|a| a.foo());
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_to_owned.txt b/src/tools/clippy/src/docs/unnecessary_to_owned.txt
new file mode 100644
index 000000000..5d4213bda
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnecessary_to_owned.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for unnecessary calls to [`ToOwned::to_owned`](https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#tymethod.to_owned)
+and other `to_owned`-like functions.
+
+### Why is this bad?
+The unnecessary calls result in useless allocations.
+
+### Known problems
+`unnecessary_to_owned` can falsely trigger if `IntoIterator::into_iter` is applied to an
+owned copy of a resource and the resource is later used mutably. See
+[#8148](https://github.com/rust-lang/rust-clippy/issues/8148).
+
+### Example
+```
+let path = std::path::Path::new("x");
+foo(&path.to_string_lossy().to_string());
+fn foo(s: &str) {}
+```
+Use instead:
+```
+let path = std::path::Path::new("x");
+foo(&path.to_string_lossy());
+fn foo(s: &str) {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_unwrap.txt b/src/tools/clippy/src/docs/unnecessary_unwrap.txt
new file mode 100644
index 000000000..50ae845bb
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnecessary_unwrap.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for calls of `unwrap[_err]()` that cannot fail.
+
+### Why is this bad?
+Using `if let` or `match` is more idiomatic.
+
+### Example
+```
+if option.is_some() {
+ do_something_with(option.unwrap())
+}
+```
+
+Could be written:
+
+```
+if let Some(value) = option {
+ do_something_with(value)
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnecessary_wraps.txt b/src/tools/clippy/src/docs/unnecessary_wraps.txt
new file mode 100644
index 000000000..c0a23d492
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnecessary_wraps.txt
@@ -0,0 +1,36 @@
+### What it does
+Checks for private functions that only return `Ok` or `Some`.
+
+### Why is this bad?
+It is not meaningful to wrap values when no `None` or `Err` is returned.
+
+### Known problems
+There can be false positives if the function signature is designed to
+fit some external requirement.
+
+### Example
+```
+fn get_cool_number(a: bool, b: bool) -> Option<i32> {
+ if a && b {
+ return Some(50);
+ }
+ if a {
+ Some(0)
+ } else {
+ Some(10)
+ }
+}
+```
+Use instead:
+```
+fn get_cool_number(a: bool, b: bool) -> i32 {
+ if a && b {
+ return 50;
+ }
+ if a {
+ 0
+ } else {
+ 10
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unneeded_field_pattern.txt b/src/tools/clippy/src/docs/unneeded_field_pattern.txt
new file mode 100644
index 000000000..3cd00a0f3
--- /dev/null
+++ b/src/tools/clippy/src/docs/unneeded_field_pattern.txt
@@ -0,0 +1,26 @@
+### 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
+```
+let f = Foo { a: 0, b: 0, c: 0 };
+
+match f {
+ Foo { a: _, b: 0, .. } => {},
+ Foo { a: _, b: _, c: _ } => {},
+}
+```
+
+Use instead:
+```
+let f = Foo { a: 0, b: 0, c: 0 };
+
+match f {
+ Foo { b: 0, .. } => {},
+ Foo { .. } => {},
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unneeded_wildcard_pattern.txt b/src/tools/clippy/src/docs/unneeded_wildcard_pattern.txt
new file mode 100644
index 000000000..817061efd
--- /dev/null
+++ b/src/tools/clippy/src/docs/unneeded_wildcard_pattern.txt
@@ -0,0 +1,28 @@
+### 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
+```
+match t {
+ TupleStruct(0, .., _) => (),
+ _ => (),
+}
+```
+
+Use instead:
+```
+match t {
+ TupleStruct(0, ..) => (),
+ _ => (),
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unnested_or_patterns.txt b/src/tools/clippy/src/docs/unnested_or_patterns.txt
new file mode 100644
index 000000000..49c45d4ee
--- /dev/null
+++ b/src/tools/clippy/src/docs/unnested_or_patterns.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for unnested or-patterns, e.g., `Some(0) | Some(2)` and
+suggests replacing the pattern with a nested one, `Some(0 | 2)`.
+
+Another way to think of this is that it rewrites patterns in
+*disjunctive normal form (DNF)* into *conjunctive normal form (CNF)*.
+
+### Why is this bad?
+In the example above, `Some` is repeated, which unnecessarily complicates the pattern.
+
+### Example
+```
+fn main() {
+ if let Some(0) | Some(2) = Some(0) {}
+}
+```
+Use instead:
+```
+fn main() {
+ if let Some(0 | 2) = Some(0) {}
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unreachable.txt b/src/tools/clippy/src/docs/unreachable.txt
new file mode 100644
index 000000000..10469ca77
--- /dev/null
+++ b/src/tools/clippy/src/docs/unreachable.txt
@@ -0,0 +1,10 @@
+### What it does
+Checks for usage of `unreachable!`.
+
+### Why is this bad?
+This macro can cause code to panic
+
+### Example
+```
+unreachable!();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unreadable_literal.txt b/src/tools/clippy/src/docs/unreadable_literal.txt
new file mode 100644
index 000000000..e168f90a8
--- /dev/null
+++ b/src/tools/clippy/src/docs/unreadable_literal.txt
@@ -0,0 +1,16 @@
+### What it does
+Warns if a long integral or floating-point constant does
+not contain underscores.
+
+### Why is this bad?
+Reading long numbers is difficult without separators.
+
+### Example
+```
+61864918973511
+```
+
+Use instead:
+```
+61_864_918_973_511
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unsafe_derive_deserialize.txt b/src/tools/clippy/src/docs/unsafe_derive_deserialize.txt
new file mode 100644
index 000000000..f56c48044
--- /dev/null
+++ b/src/tools/clippy/src/docs/unsafe_derive_deserialize.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for deriving `serde::Deserialize` on a type that
+has methods using `unsafe`.
+
+### Why is this bad?
+Deriving `serde::Deserialize` will create a constructor
+that may violate invariants hold by another constructor.
+
+### Example
+```
+use serde::Deserialize;
+
+#[derive(Deserialize)]
+pub struct Foo {
+ // ..
+}
+
+impl Foo {
+ pub fn new() -> Self {
+ // setup here ..
+ }
+
+ pub unsafe fn parts() -> (&str, &str) {
+ // assumes invariants hold
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unsafe_removed_from_name.txt b/src/tools/clippy/src/docs/unsafe_removed_from_name.txt
new file mode 100644
index 000000000..6f55c1815
--- /dev/null
+++ b/src/tools/clippy/src/docs/unsafe_removed_from_name.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for imports that remove "unsafe" from an item's
+name.
+
+### Why is this bad?
+Renaming makes it less clear which traits and
+structures are unsafe.
+
+### Example
+```
+use std::cell::{UnsafeCell as TotallySafeCell};
+
+extern crate crossbeam;
+use crossbeam::{spawn_unsafe as spawn};
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unseparated_literal_suffix.txt b/src/tools/clippy/src/docs/unseparated_literal_suffix.txt
new file mode 100644
index 000000000..d80248e34
--- /dev/null
+++ b/src/tools/clippy/src/docs/unseparated_literal_suffix.txt
@@ -0,0 +1,18 @@
+### 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?
+Suffix style should be consistent.
+
+### Example
+```
+123832i32
+```
+
+Use instead:
+```
+123832_i32
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unsound_collection_transmute.txt b/src/tools/clippy/src/docs/unsound_collection_transmute.txt
new file mode 100644
index 000000000..29db9258e
--- /dev/null
+++ b/src/tools/clippy/src/docs/unsound_collection_transmute.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for transmutes between collections whose
+types have different ABI, size or alignment.
+
+### Why is this bad?
+This is undefined behavior.
+
+### Known problems
+Currently, we cannot know whether a type is a
+collection, so we just lint the ones that come with `std`.
+
+### Example
+```
+// different size, therefore likely out-of-bounds memory access
+// You absolutely do not want this in your code!
+unsafe {
+ std::mem::transmute::<_, Vec<u32>>(vec![2_u16])
+};
+```
+
+You must always iterate, map and collect the values:
+
+```
+vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unused_async.txt b/src/tools/clippy/src/docs/unused_async.txt
new file mode 100644
index 000000000..26def11aa
--- /dev/null
+++ b/src/tools/clippy/src/docs/unused_async.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for functions that are declared `async` but have no `.await`s inside of them.
+
+### Why is this bad?
+Async functions with no async code create overhead, both mentally and computationally.
+Callers of async methods either need to be calling from an async function themselves or run it on an executor, both of which
+causes runtime overhead and hassle for the caller.
+
+### Example
+```
+async fn get_random_number() -> i64 {
+ 4 // Chosen by fair dice roll. Guaranteed to be random.
+}
+let number_future = get_random_number();
+```
+
+Use instead:
+```
+fn get_random_number_improved() -> i64 {
+ 4 // Chosen by fair dice roll. Guaranteed to be random.
+}
+let number_future = async { get_random_number_improved() };
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unused_format_specs.txt b/src/tools/clippy/src/docs/unused_format_specs.txt
new file mode 100644
index 000000000..77be3a2fb
--- /dev/null
+++ b/src/tools/clippy/src/docs/unused_format_specs.txt
@@ -0,0 +1,24 @@
+### What it does
+Detects [formatting parameters] that have no effect on the output of
+`format!()`, `println!()` or similar macros.
+
+### Why is this bad?
+Shorter format specifiers are easier to read, it may also indicate that
+an expected formatting operation such as adding padding isn't happening.
+
+### Example
+```
+println!("{:.}", 1.0);
+
+println!("not padded: {:5}", format_args!("..."));
+```
+Use instead:
+```
+println!("{}", 1.0);
+
+println!("not padded: {}", format_args!("..."));
+// OR
+println!("padded: {:5}", format!("..."));
+```
+
+[formatting parameters]: https://doc.rust-lang.org/std/fmt/index.html#formatting-parameters \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unused_io_amount.txt b/src/tools/clippy/src/docs/unused_io_amount.txt
new file mode 100644
index 000000000..fbc4c299c
--- /dev/null
+++ b/src/tools/clippy/src/docs/unused_io_amount.txt
@@ -0,0 +1,31 @@
+### What it does
+Checks for unused written/read amount.
+
+### Why is this bad?
+`io::Write::write(_vectored)` and
+`io::Read::read(_vectored)` are not guaranteed to
+process the entire buffer. They return how many bytes were processed, which
+might be smaller
+than a given buffer's length. If you don't need to deal with
+partial-write/read, use
+`write_all`/`read_exact` instead.
+
+When working with asynchronous code (either with the `futures`
+crate or with `tokio`), a similar issue exists for
+`AsyncWriteExt::write()` and `AsyncReadExt::read()` : these
+functions are also not guaranteed to process the entire
+buffer. Your code should either handle partial-writes/reads, or
+call the `write_all`/`read_exact` methods on those traits instead.
+
+### Known problems
+Detects only common patterns.
+
+### Examples
+```
+use std::io;
+fn foo<W: io::Write>(w: &mut W) -> io::Result<()> {
+ // must be `w.write_all(b"foo")?;`
+ w.write(b"foo")?;
+ Ok(())
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unused_peekable.txt b/src/tools/clippy/src/docs/unused_peekable.txt
new file mode 100644
index 000000000..268de1ce3
--- /dev/null
+++ b/src/tools/clippy/src/docs/unused_peekable.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for the creation of a `peekable` iterator that is never `.peek()`ed
+
+### Why is this bad?
+Creating a peekable iterator without using any of its methods is likely a mistake,
+or just a leftover after a refactor.
+
+### Example
+```
+let collection = vec![1, 2, 3];
+let iter = collection.iter().peekable();
+
+for item in iter {
+ // ...
+}
+```
+
+Use instead:
+```
+let collection = vec![1, 2, 3];
+let iter = collection.iter();
+
+for item in iter {
+ // ...
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unused_rounding.txt b/src/tools/clippy/src/docs/unused_rounding.txt
new file mode 100644
index 000000000..70947acee
--- /dev/null
+++ b/src/tools/clippy/src/docs/unused_rounding.txt
@@ -0,0 +1,17 @@
+### What it does
+
+Detects cases where a whole-number literal float is being rounded, using
+the `floor`, `ceil`, or `round` methods.
+
+### Why is this bad?
+
+This is unnecessary and confusing to the reader. Doing this is probably a mistake.
+
+### Example
+```
+let x = 1f32.ceil();
+```
+Use instead:
+```
+let x = 1f32;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unused_self.txt b/src/tools/clippy/src/docs/unused_self.txt
new file mode 100644
index 000000000..a8d0fc759
--- /dev/null
+++ b/src/tools/clippy/src/docs/unused_self.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks methods that contain a `self` argument but don't use it
+
+### Why is this bad?
+It may be clearer to define the method as an associated function instead
+of an instance method if it doesn't require `self`.
+
+### Example
+```
+struct A;
+impl A {
+ fn method(&self) {}
+}
+```
+
+Could be written:
+
+```
+struct A;
+impl A {
+ fn method() {}
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unused_unit.txt b/src/tools/clippy/src/docs/unused_unit.txt
new file mode 100644
index 000000000..48d16ca65
--- /dev/null
+++ b/src/tools/clippy/src/docs/unused_unit.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for unit (`()`) expressions that can be removed.
+
+### Why is this bad?
+Such expressions add no value, but can make the code
+less readable. Depending on formatting they can make a `break` or `return`
+statement look like a function call.
+
+### Example
+```
+fn return_unit() -> () {
+ ()
+}
+```
+is equivalent to
+```
+fn return_unit() {}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unusual_byte_groupings.txt b/src/tools/clippy/src/docs/unusual_byte_groupings.txt
new file mode 100644
index 000000000..9a1f132a6
--- /dev/null
+++ b/src/tools/clippy/src/docs/unusual_byte_groupings.txt
@@ -0,0 +1,12 @@
+### What it does
+Warns if hexadecimal or binary literals are not grouped
+by nibble or byte.
+
+### Why is this bad?
+Negatively impacts readability.
+
+### Example
+```
+let x: u32 = 0xFFF_FFF;
+let y: u8 = 0b01_011_101;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unwrap_in_result.txt b/src/tools/clippy/src/docs/unwrap_in_result.txt
new file mode 100644
index 000000000..7497dd863
--- /dev/null
+++ b/src/tools/clippy/src/docs/unwrap_in_result.txt
@@ -0,0 +1,39 @@
+### 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:
+```
+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:
+```
+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(())
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unwrap_or_else_default.txt b/src/tools/clippy/src/docs/unwrap_or_else_default.txt
new file mode 100644
index 000000000..34b4cf088
--- /dev/null
+++ b/src/tools/clippy/src/docs/unwrap_or_else_default.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and
+`Result` values.
+
+### Why is this bad?
+Readability, these can be written as `_.unwrap_or_default`, which is
+simpler and more concise.
+
+### Examples
+```
+x.unwrap_or_else(Default::default);
+x.unwrap_or_else(u32::default);
+```
+
+Use instead:
+```
+x.unwrap_or_default();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unwrap_used.txt b/src/tools/clippy/src/docs/unwrap_used.txt
new file mode 100644
index 000000000..9b4713df5
--- /dev/null
+++ b/src/tools/clippy/src/docs/unwrap_used.txt
@@ -0,0 +1,37 @@
+### What it does
+Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s.
+
+### Why is this bad?
+It is better to handle the `None` or `Err` case,
+or at least call `.expect(_)` with a more helpful message. Still, for a lot of
+quick-and-dirty code, `unwrap` is a good choice, which is why this lint is
+`Allow` by default.
+
+`result.unwrap()` will let the thread panic on `Err` values.
+Normally, you want to implement more sophisticated error handling,
+and propagate errors upwards with `?` operator.
+
+Even if you want to panic on errors, not all `Error`s implement good
+messages on display. Therefore, it may be beneficial to look at the places
+where they may get displayed. Activate this lint to do just that.
+
+### Examples
+```
+option.unwrap();
+result.unwrap();
+```
+
+Use instead:
+```
+option.expect("more helpful message");
+result.expect("more helpful message");
+```
+
+If [expect_used](#expect_used) is enabled, instead:
+```
+option?;
+
+// or
+
+result?;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/upper_case_acronyms.txt b/src/tools/clippy/src/docs/upper_case_acronyms.txt
new file mode 100644
index 000000000..a1e39c7e1
--- /dev/null
+++ b/src/tools/clippy/src/docs/upper_case_acronyms.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for fully capitalized names and optionally names containing a capitalized acronym.
+
+### Why is this bad?
+In CamelCase, acronyms count as one word.
+See [naming conventions](https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case)
+for more.
+
+By default, the lint only triggers on fully-capitalized names.
+You can use the `upper-case-acronyms-aggressive: true` config option to enable linting
+on all camel case names
+
+### Known problems
+When two acronyms are contiguous, the lint can't tell where
+the first acronym ends and the second starts, so it suggests to lowercase all of
+the letters in the second acronym.
+
+### Example
+```
+struct HTTPResponse;
+```
+Use instead:
+```
+struct HttpResponse;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/use_debug.txt b/src/tools/clippy/src/docs/use_debug.txt
new file mode 100644
index 000000000..94d4a6fd2
--- /dev/null
+++ b/src/tools/clippy/src/docs/use_debug.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for use of `Debug` formatting. The purpose of this
+lint is to catch debugging remnants.
+
+### Why is this bad?
+The purpose of the `Debug` trait is to facilitate
+debugging Rust code. It should not be used in user-facing output.
+
+### Example
+```
+println!("{:?}", foo);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/use_self.txt b/src/tools/clippy/src/docs/use_self.txt
new file mode 100644
index 000000000..bd37ed1e0
--- /dev/null
+++ b/src/tools/clippy/src/docs/use_self.txt
@@ -0,0 +1,31 @@
+### What it does
+Checks for unnecessary repetition of structure name when a
+replacement with `Self` is applicable.
+
+### Why is this bad?
+Unnecessary repetition. Mixed use of `Self` and struct
+name
+feels inconsistent.
+
+### Known problems
+- Unaddressed false negative in fn bodies of trait implementations
+- False positive with associated types in traits (#4140)
+
+### Example
+```
+struct Foo;
+impl Foo {
+ fn new() -> Foo {
+ Foo {}
+ }
+}
+```
+could be
+```
+struct Foo;
+impl Foo {
+ fn new() -> Self {
+ Self {}
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/used_underscore_binding.txt b/src/tools/clippy/src/docs/used_underscore_binding.txt
new file mode 100644
index 000000000..ed67c41eb
--- /dev/null
+++ b/src/tools/clippy/src/docs/used_underscore_binding.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for the use of bindings with a single leading
+underscore.
+
+### Why is this bad?
+A single leading underscore is usually used to indicate
+that a binding will not be used. Using such a binding breaks this
+expectation.
+
+### Known problems
+The lint does not work properly with desugaring and
+macro, it has been allowed in the mean time.
+
+### Example
+```
+let _x = 0;
+let y = _x + 1; // Here we are using `_x`, even though it has a leading
+ // underscore. We should rename `_x` to `x`
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/useless_asref.txt b/src/tools/clippy/src/docs/useless_asref.txt
new file mode 100644
index 000000000..f777cd377
--- /dev/null
+++ b/src/tools/clippy/src/docs/useless_asref.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for usage of `.as_ref()` or `.as_mut()` where the
+types before and after the call are the same.
+
+### Why is this bad?
+The call is unnecessary.
+
+### Example
+```
+let x: &[i32] = &[1, 2, 3, 4, 5];
+do_stuff(x.as_ref());
+```
+The correct use would be:
+```
+let x: &[i32] = &[1, 2, 3, 4, 5];
+do_stuff(x);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/useless_attribute.txt b/src/tools/clippy/src/docs/useless_attribute.txt
new file mode 100644
index 000000000..e02d4c907
--- /dev/null
+++ b/src/tools/clippy/src/docs/useless_attribute.txt
@@ -0,0 +1,36 @@
+### What it does
+Checks for `extern crate` and `use` items annotated with
+lint attributes.
+
+This lint permits lint attributes for lints emitted on the items themself.
+For `use` items these lints are:
+* deprecated
+* unreachable_pub
+* unused_imports
+* clippy::enum_glob_use
+* clippy::macro_use_imports
+* clippy::wildcard_imports
+
+For `extern crate` items these lints are:
+* `unused_imports` on items with `#[macro_use]`
+
+### Why is this bad?
+Lint attributes have no effect on crate imports. Most
+likely a `!` was forgotten.
+
+### Example
+```
+#[deny(dead_code)]
+extern crate foo;
+#[forbid(dead_code)]
+use foo::bar;
+```
+
+Use instead:
+```
+#[allow(unused_imports)]
+use foo::baz;
+#[allow(unused_imports)]
+#[macro_use]
+extern crate baz;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/useless_conversion.txt b/src/tools/clippy/src/docs/useless_conversion.txt
new file mode 100644
index 000000000..06000a7ad
--- /dev/null
+++ b/src/tools/clippy/src/docs/useless_conversion.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls
+which uselessly convert to the same type.
+
+### Why is this bad?
+Redundant code.
+
+### Example
+```
+// format!() returns a `String`
+let s: String = format!("hello").into();
+```
+
+Use instead:
+```
+let s: String = format!("hello");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/useless_format.txt b/src/tools/clippy/src/docs/useless_format.txt
new file mode 100644
index 000000000..eb4819da1
--- /dev/null
+++ b/src/tools/clippy/src/docs/useless_format.txt
@@ -0,0 +1,22 @@
+### 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
+```
+let foo = "foo";
+format!("{}", foo);
+```
+
+Use instead:
+```
+let foo = "foo";
+foo.to_owned();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/useless_let_if_seq.txt b/src/tools/clippy/src/docs/useless_let_if_seq.txt
new file mode 100644
index 000000000..c6dcd57eb
--- /dev/null
+++ b/src/tools/clippy/src/docs/useless_let_if_seq.txt
@@ -0,0 +1,39 @@
+### What it does
+Checks for variable declarations immediately followed by a
+conditional affectation.
+
+### Why is this bad?
+This is not idiomatic Rust.
+
+### Example
+```
+let foo;
+
+if bar() {
+ foo = 42;
+} else {
+ foo = 0;
+}
+
+let mut baz = None;
+
+if bar() {
+ baz = Some(42);
+}
+```
+
+should be written
+
+```
+let foo = if bar() {
+ 42
+} else {
+ 0
+};
+
+let baz = if bar() {
+ Some(42)
+} else {
+ None
+};
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/useless_transmute.txt b/src/tools/clippy/src/docs/useless_transmute.txt
new file mode 100644
index 000000000..1d3a17588
--- /dev/null
+++ b/src/tools/clippy/src/docs/useless_transmute.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for transmutes to the original type of the object
+and transmutes that could be a cast.
+
+### Why is this bad?
+Readability. The code tricks people into thinking that
+something complex is going on.
+
+### Example
+```
+core::intrinsics::transmute(t); // where the result type is the same as `t`'s
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/useless_vec.txt b/src/tools/clippy/src/docs/useless_vec.txt
new file mode 100644
index 000000000..ee5afc99e
--- /dev/null
+++ b/src/tools/clippy/src/docs/useless_vec.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for usage of `&vec![..]` when using `&[..]` would
+be possible.
+
+### Why is this bad?
+This is less efficient.
+
+### Example
+```
+fn foo(_x: &[u8]) {}
+
+foo(&vec![1, 2]);
+```
+
+Use instead:
+```
+foo(&[1, 2]);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/vec_box.txt b/src/tools/clippy/src/docs/vec_box.txt
new file mode 100644
index 000000000..701b1c9ce
--- /dev/null
+++ b/src/tools/clippy/src/docs/vec_box.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code.
+Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
+
+### Why is this bad?
+`Vec` already keeps its contents in a separate area on
+the heap. So if you `Box` its contents, you just add another level of indirection.
+
+### Known problems
+Vec<Box<T: Sized>> makes sense if T is a large type (see [#3530](https://github.com/rust-lang/rust-clippy/issues/3530),
+1st comment).
+
+### Example
+```
+struct X {
+ values: Vec<Box<i32>>,
+}
+```
+
+Better:
+
+```
+struct X {
+ values: Vec<i32>,
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/vec_init_then_push.txt b/src/tools/clippy/src/docs/vec_init_then_push.txt
new file mode 100644
index 000000000..445f28747
--- /dev/null
+++ b/src/tools/clippy/src/docs/vec_init_then_push.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for calls to `push` immediately after creating a new `Vec`.
+
+If the `Vec` is created using `with_capacity` this will only lint if the capacity is a
+constant and the number of pushes is greater than or equal to the initial capacity.
+
+If the `Vec` is extended after the initial sequence of pushes and it was default initialized
+then this will only lint after there were at least four pushes. This number may change in
+the future.
+
+### Why is this bad?
+The `vec![]` macro is both more performant and easier to read than
+multiple `push` calls.
+
+### Example
+```
+let mut v = Vec::new();
+v.push(0);
+```
+Use instead:
+```
+let v = vec![0];
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/vec_resize_to_zero.txt b/src/tools/clippy/src/docs/vec_resize_to_zero.txt
new file mode 100644
index 000000000..0b9268677
--- /dev/null
+++ b/src/tools/clippy/src/docs/vec_resize_to_zero.txt
@@ -0,0 +1,15 @@
+### What it does
+Finds occurrences of `Vec::resize(0, an_int)`
+
+### Why is this bad?
+This is probably an argument inversion mistake.
+
+### Example
+```
+vec!(1, 2, 3, 4, 5).resize(0, 5)
+```
+
+Use instead:
+```
+vec!(1, 2, 3, 4, 5).clear()
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/verbose_bit_mask.txt b/src/tools/clippy/src/docs/verbose_bit_mask.txt
new file mode 100644
index 000000000..87a847029
--- /dev/null
+++ b/src/tools/clippy/src/docs/verbose_bit_mask.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for bit masks that can be replaced by a call
+to `trailing_zeros`
+
+### Why is this bad?
+`x.trailing_zeros() > 4` is much clearer than `x & 15
+== 0`
+
+### Known problems
+llvm generates better code for `x & 15 == 0` on x86
+
+### Example
+```
+if x & 0b1111 == 0 { }
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/verbose_file_reads.txt b/src/tools/clippy/src/docs/verbose_file_reads.txt
new file mode 100644
index 000000000..9703df423
--- /dev/null
+++ b/src/tools/clippy/src/docs/verbose_file_reads.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for use of File::read_to_end and File::read_to_string.
+
+### Why is this bad?
+`fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values.
+See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html)
+
+### Example
+```
+let mut f = File::open("foo.txt").unwrap();
+let mut bytes = Vec::new();
+f.read_to_end(&mut bytes).unwrap();
+```
+Can be written more concisely as
+```
+let mut bytes = fs::read("foo.txt").unwrap();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/vtable_address_comparisons.txt b/src/tools/clippy/src/docs/vtable_address_comparisons.txt
new file mode 100644
index 000000000..4a34e4ba7
--- /dev/null
+++ b/src/tools/clippy/src/docs/vtable_address_comparisons.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for comparisons with an address of a trait vtable.
+
+### Why is this bad?
+Comparing trait objects pointers compares an vtable addresses which
+are not guaranteed to be unique and could vary between different code generation units.
+Furthermore vtables for different types could have the same address after being merged
+together.
+
+### Example
+```
+let a: Rc<dyn Trait> = ...
+let b: Rc<dyn Trait> = ...
+if Rc::ptr_eq(&a, &b) {
+ ...
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/while_immutable_condition.txt b/src/tools/clippy/src/docs/while_immutable_condition.txt
new file mode 100644
index 000000000..71800701f
--- /dev/null
+++ b/src/tools/clippy/src/docs/while_immutable_condition.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks whether variables used within while loop condition
+can be (and are) mutated in the body.
+
+### Why is this bad?
+If the condition is unchanged, entering the body of the loop
+will lead to an infinite loop.
+
+### Known problems
+If the `while`-loop is in a closure, the check for mutation of the
+condition variables in the body can cause false negatives. For example when only `Upvar` `a` is
+in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger.
+
+### Example
+```
+let i = 0;
+while i > 10 {
+ println!("let me loop forever!");
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/while_let_loop.txt b/src/tools/clippy/src/docs/while_let_loop.txt
new file mode 100644
index 000000000..ab7bf6097
--- /dev/null
+++ b/src/tools/clippy/src/docs/while_let_loop.txt
@@ -0,0 +1,25 @@
+### What it does
+Detects `loop + match` combinations that are easier
+written as a `while let` loop.
+
+### Why is this bad?
+The `while let` loop is usually shorter and more
+readable.
+
+### Known problems
+Sometimes the wrong binding is displayed ([#383](https://github.com/rust-lang/rust-clippy/issues/383)).
+
+### Example
+```
+loop {
+ let x = match y {
+ Some(x) => x,
+ None => break,
+ };
+ // .. do something with x
+}
+// is easier written as
+while let Some(x) = y {
+ // .. do something with x
+};
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/while_let_on_iterator.txt b/src/tools/clippy/src/docs/while_let_on_iterator.txt
new file mode 100644
index 000000000..af053c541
--- /dev/null
+++ b/src/tools/clippy/src/docs/while_let_on_iterator.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for `while let` expressions on iterators.
+
+### Why is this bad?
+Readability. A simple `for` loop is shorter and conveys
+the intent better.
+
+### Example
+```
+while let Some(val) = iter.next() {
+ ..
+}
+```
+
+Use instead:
+```
+for val in &mut iter {
+ ..
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/wildcard_dependencies.txt b/src/tools/clippy/src/docs/wildcard_dependencies.txt
new file mode 100644
index 000000000..2affaf974
--- /dev/null
+++ b/src/tools/clippy/src/docs/wildcard_dependencies.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for wildcard dependencies in the `Cargo.toml`.
+
+### Why is this bad?
+[As the edition guide says](https://rust-lang-nursery.github.io/edition-guide/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.html),
+it is highly unlikely that you work with any possible version of your dependency,
+and wildcard dependencies would cause unnecessary breakage in the ecosystem.
+
+### Example
+```
+[dependencies]
+regex = "*"
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/wildcard_enum_match_arm.txt b/src/tools/clippy/src/docs/wildcard_enum_match_arm.txt
new file mode 100644
index 000000000..09807c01c
--- /dev/null
+++ b/src/tools/clippy/src/docs/wildcard_enum_match_arm.txt
@@ -0,0 +1,25 @@
+### 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
+```
+match x {
+ Foo::A(_) => {},
+ _ => {},
+}
+```
+
+Use instead:
+```
+match x {
+ Foo::A(_) => {},
+ Foo::B(_) => {},
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/wildcard_imports.txt b/src/tools/clippy/src/docs/wildcard_imports.txt
new file mode 100644
index 000000000..bd56aa5b0
--- /dev/null
+++ b/src/tools/clippy/src/docs/wildcard_imports.txt
@@ -0,0 +1,45 @@
+### What it does
+Checks for wildcard imports `use _::*`.
+
+### Why is this bad?
+wildcard imports can pollute the namespace. This is especially bad if
+you try to import something through a wildcard, that already has been imported by name from
+a different source:
+
+```
+use crate1::foo; // Imports a function named foo
+use crate2::*; // Has a function named foo
+
+foo(); // Calls crate1::foo
+```
+
+This can lead to confusing error messages at best and to unexpected behavior at worst.
+
+### Exceptions
+Wildcard imports are allowed from modules named `prelude`. Many crates (including the standard library)
+provide modules named "prelude" specifically designed for wildcard import.
+
+`use super::*` is allowed in test modules. This is defined as any module with "test" in the name.
+
+These exceptions can be disabled using the `warn-on-all-wildcard-imports` configuration flag.
+
+### Known problems
+If macros are imported through the wildcard, this macro is not included
+by the suggestion and has to be added by hand.
+
+Applying the suggestion when explicit imports of the things imported with a glob import
+exist, may result in `unused_imports` warnings.
+
+### Example
+```
+use crate1::*;
+
+foo();
+```
+
+Use instead:
+```
+use crate1::foo;
+
+foo();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/wildcard_in_or_patterns.txt b/src/tools/clippy/src/docs/wildcard_in_or_patterns.txt
new file mode 100644
index 000000000..70468ca41
--- /dev/null
+++ b/src/tools/clippy/src/docs/wildcard_in_or_patterns.txt
@@ -0,0 +1,22 @@
+### 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
+```
+match s {
+ "a" => {},
+ "bar" | _ => {},
+}
+```
+
+Use instead:
+```
+match s {
+ "a" => {},
+ _ => {},
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/write_literal.txt b/src/tools/clippy/src/docs/write_literal.txt
new file mode 100644
index 000000000..a7a884d08
--- /dev/null
+++ b/src/tools/clippy/src/docs/write_literal.txt
@@ -0,0 +1,17 @@
+### What it does
+This lint warns about the use of literals as `write!`/`writeln!` args.
+
+### Why is this bad?
+Using literals as `writeln!` args is inefficient
+(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
+(i.e., just put the literal in the format string)
+
+### Example
+```
+writeln!(buf, "{}", "foo");
+```
+
+Use instead:
+```
+writeln!(buf, "foo");
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/write_with_newline.txt b/src/tools/clippy/src/docs/write_with_newline.txt
new file mode 100644
index 000000000..22845fd65
--- /dev/null
+++ b/src/tools/clippy/src/docs/write_with_newline.txt
@@ -0,0 +1,18 @@
+### What it does
+This lint warns when you use `write!()` with a format
+string that
+ends in a newline.
+
+### Why is this bad?
+You should use `writeln!()` instead, which appends the
+newline.
+
+### Example
+```
+write!(buf, "Hello {}!\n", name);
+```
+
+Use instead:
+```
+writeln!(buf, "Hello {}!", name);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/writeln_empty_string.txt b/src/tools/clippy/src/docs/writeln_empty_string.txt
new file mode 100644
index 000000000..3b3aeb79a
--- /dev/null
+++ b/src/tools/clippy/src/docs/writeln_empty_string.txt
@@ -0,0 +1,16 @@
+### What it does
+This lint warns when you use `writeln!(buf, "")` to
+print a newline.
+
+### Why is this bad?
+You should use `writeln!(buf)`, which is simpler.
+
+### Example
+```
+writeln!(buf, "");
+```
+
+Use instead:
+```
+writeln!(buf);
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/wrong_self_convention.txt b/src/tools/clippy/src/docs/wrong_self_convention.txt
new file mode 100644
index 000000000..d6b69ab87
--- /dev/null
+++ b/src/tools/clippy/src/docs/wrong_self_convention.txt
@@ -0,0 +1,39 @@
+### What it does
+Checks for methods with certain name prefixes and which
+doesn't match how self is taken. The actual rules are:
+
+|Prefix |Postfix |`self` taken | `self` type |
+|-------|------------|-------------------------------|--------------|
+|`as_` | none |`&self` or `&mut self` | any |
+|`from_`| none | none | any |
+|`into_`| none |`self` | any |
+|`is_` | none |`&mut self` or `&self` or none | any |
+|`to_` | `_mut` |`&mut self` | any |
+|`to_` | not `_mut` |`self` | `Copy` |
+|`to_` | not `_mut` |`&self` | not `Copy` |
+
+Note: Clippy doesn't trigger methods with `to_` prefix in:
+- Traits definition.
+Clippy can not tell if a type that implements a trait is `Copy` or not.
+- Traits implementation, when `&self` is taken.
+The method signature is controlled by the trait and often `&self` is required for all types that implement the trait
+(see e.g. the `std::string::ToString` trait).
+
+Clippy allows `Pin<&Self>` and `Pin<&mut Self>` if `&self` and `&mut self` is required.
+
+Please find more info here:
+https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
+
+### Why is this bad?
+Consistency breeds readability. If you follow the
+conventions, your users won't be surprised that they, e.g., need to supply a
+mutable reference to a `as_..` function.
+
+### Example
+```
+impl X {
+ fn as_str(self) -> &'static str {
+ // ..
+ }
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/wrong_transmute.txt b/src/tools/clippy/src/docs/wrong_transmute.txt
new file mode 100644
index 000000000..9fc71e0e3
--- /dev/null
+++ b/src/tools/clippy/src/docs/wrong_transmute.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for transmutes that can't ever be correct on any
+architecture.
+
+### Why is this bad?
+It's basically guaranteed to be undefined behavior.
+
+### Known problems
+When accessing C, users might want to store pointer
+sized objects in `extradata` arguments to save an allocation.
+
+### Example
+```
+let ptr: *const T = core::intrinsics::transmute('x')
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/zero_divided_by_zero.txt b/src/tools/clippy/src/docs/zero_divided_by_zero.txt
new file mode 100644
index 000000000..394de20c0
--- /dev/null
+++ b/src/tools/clippy/src/docs/zero_divided_by_zero.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for `0.0 / 0.0`.
+
+### Why is this bad?
+It's less readable than `f32::NAN` or `f64::NAN`.
+
+### Example
+```
+let nan = 0.0f32 / 0.0;
+```
+
+Use instead:
+```
+let nan = f32::NAN;
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/zero_prefixed_literal.txt b/src/tools/clippy/src/docs/zero_prefixed_literal.txt
new file mode 100644
index 000000000..5c5588725
--- /dev/null
+++ b/src/tools/clippy/src/docs/zero_prefixed_literal.txt
@@ -0,0 +1,32 @@
+### 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:
+```
+fn main() {
+ let a = 0123;
+ println!("{}", a);
+}
+```
+
+prints `123`, while in C:
+
+```
+#include <stdio.h>
+
+int main() {
+ int a = 0123;
+ printf("%d\n", a);
+}
+```
+
+prints `83` (as `83 == 0o123` while `123 == 0o173`). \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/zero_ptr.txt b/src/tools/clippy/src/docs/zero_ptr.txt
new file mode 100644
index 000000000..e768a0236
--- /dev/null
+++ b/src/tools/clippy/src/docs/zero_ptr.txt
@@ -0,0 +1,16 @@
+### What it does
+Catch casts from `0` to some pointer type
+
+### Why is this bad?
+This generally means `null` and is better expressed as
+{`std`, `core`}`::ptr::`{`null`, `null_mut`}.
+
+### Example
+```
+let a = 0 as *const u32;
+```
+
+Use instead:
+```
+let a = std::ptr::null::<u32>();
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/zero_sized_map_values.txt b/src/tools/clippy/src/docs/zero_sized_map_values.txt
new file mode 100644
index 000000000..0502bdbf3
--- /dev/null
+++ b/src/tools/clippy/src/docs/zero_sized_map_values.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for maps with zero-sized value types anywhere in the code.
+
+### Why is this bad?
+Since there is only a single value for a zero-sized type, a map
+containing zero sized values is effectively a set. Using a set in that case improves
+readability and communicates intent more clearly.
+
+### Known problems
+* A zero-sized type cannot be recovered later if it contains private fields.
+* This lints the signature of public items
+
+### Example
+```
+fn unique_words(text: &str) -> HashMap<&str, ()> {
+ todo!();
+}
+```
+Use instead:
+```
+fn unique_words(text: &str) -> HashSet<&str> {
+ todo!();
+}
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/docs/zst_offset.txt b/src/tools/clippy/src/docs/zst_offset.txt
new file mode 100644
index 000000000..5810455ee
--- /dev/null
+++ b/src/tools/clippy/src/docs/zst_offset.txt
@@ -0,0 +1,11 @@
+### What it does
+Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to
+zero-sized types
+
+### Why is this bad?
+This is a no-op, and likely unintended
+
+### Example
+```
+unsafe { (&() as *const ()).offset(1) };
+``` \ No newline at end of file
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index c1ec2bd5b..b12208ac6 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -95,7 +95,7 @@ struct ClippyCallbacks {
impl rustc_driver::Callbacks for ClippyCallbacks {
// JUSTIFICATION: necessary in clippy driver to set `mir_opt_level`
- #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))]
+ #[allow(rustc::bad_opt_access)]
fn config(&mut self, config: &mut interface::Config) {
let previous = config.register_lints.take();
let clippy_args_var = self.clippy_args_var.take();
@@ -193,8 +193,8 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
let xs: Vec<Cow<'static, str>> = vec![
"the compiler unexpectedly panicked. this is a bug.".into(),
- format!("we would appreciate a bug report: {}", bug_report_url).into(),
- format!("Clippy version: {}", version_info).into(),
+ format!("we would appreciate a bug report: {bug_report_url}").into(),
+ format!("Clippy version: {version_info}").into(),
];
for note in &xs {
@@ -290,7 +290,7 @@ pub fn main() {
if orig_args.iter().any(|a| a == "--version" || a == "-V") {
let version_info = rustc_tools_util::get_version_info!();
- println!("{}", version_info);
+ println!("{version_info}");
exit(0);
}
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index 9ee4a40cb..fce3cdfc4 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -7,6 +7,8 @@ use std::env;
use std::path::PathBuf;
use std::process::{self, Command};
+mod docs;
+
const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.
Usage:
@@ -17,6 +19,7 @@ Common options:
--fix Automatically apply lint suggestions. This flag implies `--no-deps`
-h, --help Print this message
-V, --version Print version info and exit
+ --explain LINT Print the documentation for a given lint
Other options are the same as `cargo check`.
@@ -34,12 +37,12 @@ You can use tool lints to allow or deny lints from your code, eg.:
"#;
fn show_help() {
- println!("{}", CARGO_CLIPPY_HELP);
+ println!("{CARGO_CLIPPY_HELP}");
}
fn show_version() {
let version_info = rustc_tools_util::get_version_info!();
- println!("{}", version_info);
+ println!("{version_info}");
}
pub fn main() {
@@ -54,6 +57,16 @@ pub fn main() {
return;
}
+ if let Some(pos) = env::args().position(|a| a == "--explain") {
+ if let Some(mut lint) = env::args().nth(pos + 1) {
+ lint.make_ascii_lowercase();
+ docs::explain(&lint.strip_prefix("clippy::").unwrap_or(&lint).replace('-', "_"));
+ } else {
+ show_help();
+ }
+ return;
+ }
+
if let Err(code) = process(env::args().skip(2)) {
process::exit(code);
}
@@ -120,7 +133,7 @@ impl ClippyCmd {
let clippy_args: String = self
.clippy_args
.iter()
- .map(|arg| format!("{}__CLIPPY_HACKERY__", arg))
+ .map(|arg| format!("{arg}__CLIPPY_HACKERY__"))
.collect();
// Currently, `CLIPPY_TERMINAL_WIDTH` is used only to format "unknown field" error messages.
diff --git a/src/tools/clippy/tests/check-fmt.rs b/src/tools/clippy/tests/check-fmt.rs
index 0defd45b6..e106583de 100644
--- a/src/tools/clippy/tests/check-fmt.rs
+++ b/src/tools/clippy/tests/check-fmt.rs
@@ -13,7 +13,7 @@ fn fmt() {
let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let output = Command::new("cargo")
.current_dir(root_dir)
- .args(&["dev", "fmt", "--check"])
+ .args(["dev", "fmt", "--check"])
.output()
.unwrap();
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 92ac1a2be..c10ee969c 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -111,15 +111,14 @@ static EXTERN_FLAGS: LazyLock<String> = LazyLock::new(|| {
.collect();
assert!(
not_found.is_empty(),
- "dependencies not found in depinfo: {:?}\n\
+ "dependencies not found in depinfo: {not_found:?}\n\
help: Make sure the `-Z binary-dep-depinfo` rust flag is enabled\n\
help: Try adding to dev-dependencies in Cargo.toml\n\
help: Be sure to also add `extern crate ...;` to tests/compile-test.rs",
- not_found,
);
crates
.into_iter()
- .map(|(name, path)| format!(" --extern {}={}", name, path))
+ .map(|(name, path)| format!(" --extern {name}={path}"))
.collect()
});
@@ -150,9 +149,8 @@ fn base_config(test_dir: &str) -> compiletest::Config {
.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={}{}{}",
+ "--emit=metadata -Dwarnings -Zui-testing -L dependency={}{host_libs}{}",
deps_path.display(),
- host_libs,
&*EXTERN_FLAGS,
));
@@ -239,7 +237,7 @@ fn run_ui_toml() {
Ok(true) => {},
Ok(false) => panic!("Some tests failed"),
Err(e) => {
- panic!("I/O failure during tests: {:?}", e);
+ panic!("I/O failure during tests: {e:?}");
},
}
}
@@ -285,7 +283,7 @@ fn run_ui_cargo() {
env::set_current_dir(&src_path)?;
let cargo_toml_path = case.path().join("Cargo.toml");
- let cargo_content = fs::read(&cargo_toml_path)?;
+ let cargo_content = fs::read(cargo_toml_path)?;
let cargo_parsed: toml::Value = toml::from_str(
std::str::from_utf8(&cargo_content).expect("`Cargo.toml` is not a valid utf-8 file!"),
)
@@ -348,7 +346,7 @@ fn run_ui_cargo() {
Ok(true) => {},
Ok(false) => panic!("Some tests failed"),
Err(e) => {
- panic!("I/O failure during tests: {:?}", e);
+ panic!("I/O failure during tests: {e:?}");
},
}
}
@@ -393,8 +391,8 @@ const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[
"search_is_some.rs",
"single_component_path_imports_nested_first.rs",
"string_add.rs",
+ "suspicious_to_owned.rs",
"toplevel_ref_arg_non_rustfix.rs",
- "trait_duplication_in_bounds.rs",
"unit_arg.rs",
"unnecessary_clone.rs",
"unnecessary_lazy_eval_unfixable.rs",
@@ -404,24 +402,30 @@ const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[
];
fn check_rustfix_coverage() {
- let missing_coverage_path = Path::new("target/debug/test/ui/rustfix_missing_coverage.txt");
+ let missing_coverage_path = Path::new("debug/test/ui/rustfix_missing_coverage.txt");
+ let missing_coverage_path = if let Ok(target_dir) = std::env::var("CARGO_TARGET_DIR") {
+ PathBuf::from(target_dir).join(missing_coverage_path)
+ } else {
+ missing_coverage_path.to_path_buf()
+ };
if let Ok(missing_coverage_contents) = std::fs::read_to_string(missing_coverage_path) {
assert!(RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS.iter().is_sorted_by_key(Path::new));
- for rs_path in missing_coverage_contents.lines() {
- if Path::new(rs_path).starts_with("tests/ui/crashes") {
+ for rs_file in missing_coverage_contents.lines() {
+ let rs_path = Path::new(rs_file);
+ if rs_path.starts_with("tests/ui/crashes") {
continue;
}
- let filename = Path::new(rs_path).strip_prefix("tests/ui/").unwrap();
+ assert!(rs_path.starts_with("tests/ui/"), "{rs_file:?}");
+ let filename = rs_path.strip_prefix("tests/ui/").unwrap();
assert!(
RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS
.binary_search_by_key(&filename, Path::new)
.is_ok(),
- "`{}` runs `MachineApplicable` diagnostics but is missing a `run-rustfix` annotation. \
+ "`{rs_file}` runs `MachineApplicable` diagnostics but is missing a `run-rustfix` annotation. \
Please either add `// run-rustfix` at the top of the file or add the file to \
`RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS` in `tests/compile-test.rs`.",
- rs_path,
);
}
}
@@ -471,15 +475,13 @@ fn ui_cargo_toml_metadata() {
.map(|component| component.as_os_str().to_string_lossy().replace('-', "_"))
.any(|s| *s == name)
|| path.starts_with(&cargo_common_metadata_path),
- "{:?} has incorrect package name",
- path
+ "{path:?} has incorrect package name"
);
let publish = package.get("publish").and_then(toml::Value::as_bool).unwrap_or(true);
assert!(
!publish || publish_exceptions.contains(&path.parent().unwrap().to_path_buf()),
- "{:?} lacks `publish = false`",
- path
+ "{path:?} lacks `publish = false`"
);
}
}
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index 5697e8680..6d0022f7a 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -20,7 +20,14 @@ fn dogfood_clippy() {
}
// "" is the root package
- for package in &["", "clippy_dev", "clippy_lints", "clippy_utils", "rustc_tools_util"] {
+ for package in &[
+ "",
+ "clippy_dev",
+ "clippy_lints",
+ "clippy_utils",
+ "lintcheck",
+ "rustc_tools_util",
+ ] {
run_clippy_for_package(package, &["-D", "clippy::all", "-D", "clippy::pedantic"]);
}
}
@@ -87,11 +94,11 @@ fn run_clippy_for_package(project: &str, args: &[&str]) {
if cfg!(feature = "internal") {
// internal lints only exist if we build with the internal feature
- command.args(&["-D", "clippy::internal"]);
+ command.args(["-D", "clippy::internal"]);
} else {
// running a clippy built without internal lints on the clippy source
// that contains e.g. `allow(clippy::invalid_paths)`
- command.args(&["-A", "unknown_lints"]);
+ command.args(["-A", "unknown_lints"]);
}
let output = command.output().unwrap();
diff --git a/src/tools/clippy/tests/integration.rs b/src/tools/clippy/tests/integration.rs
index c64425fa0..818ff70b3 100644
--- a/src/tools/clippy/tests/integration.rs
+++ b/src/tools/clippy/tests/integration.rs
@@ -6,10 +6,15 @@ use std::env;
use std::ffi::OsStr;
use std::process::Command;
+#[cfg(not(windows))]
+const CARGO_CLIPPY: &str = "cargo-clippy";
+#[cfg(windows)]
+const CARGO_CLIPPY: &str = "cargo-clippy.exe";
+
#[cfg_attr(feature = "integration", test)]
fn integration_test() {
let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set");
- let repo_url = format!("https://github.com/{}", repo_name);
+ let repo_url = format!("https://github.com/{repo_name}");
let crate_name = repo_name
.split('/')
.nth(1)
@@ -19,7 +24,7 @@ fn integration_test() {
repo_dir.push(crate_name);
let st = Command::new("git")
- .args(&[
+ .args([
OsStr::new("clone"),
OsStr::new("--depth=1"),
OsStr::new(&repo_url),
@@ -31,13 +36,13 @@ fn integration_test() {
let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let target_dir = std::path::Path::new(&root_dir).join("target");
- let clippy_binary = target_dir.join(env!("PROFILE")).join("cargo-clippy");
+ let clippy_binary = target_dir.join(env!("PROFILE")).join(CARGO_CLIPPY);
let output = Command::new(clippy_binary)
.current_dir(repo_dir)
.env("RUST_BACKTRACE", "full")
.env("CARGO_TARGET_DIR", target_dir)
- .args(&[
+ .args([
"clippy",
"--all-targets",
"--all-features",
@@ -51,17 +56,15 @@ fn integration_test() {
.expect("unable to run clippy");
let stderr = String::from_utf8_lossy(&output.stderr);
- if stderr.contains("internal compiler error") {
- let backtrace_start = stderr
- .find("thread 'rustc' panicked at")
- .expect("start of backtrace not found");
- let backtrace_end = stderr
- .rfind("error: internal compiler error")
+ if let Some(backtrace_start) = stderr.find("error: internal compiler error") {
+ static BACKTRACE_END_MSG: &str = "end of query stack";
+ let backtrace_end = stderr[backtrace_start..]
+ .find(BACKTRACE_END_MSG)
.expect("end of backtrace not found");
panic!(
"internal compiler error\nBacktrace:\n\n{}",
- &stderr[backtrace_start..backtrace_end]
+ &stderr[backtrace_start..backtrace_start + backtrace_end + BACKTRACE_END_MSG.len()]
);
} else if stderr.contains("query stack during panic") {
panic!("query stack during panic in the output");
@@ -83,7 +86,7 @@ fn integration_test() {
match output.status.code() {
Some(0) => println!("Compilation successful"),
- Some(code) => eprintln!("Compilation failed. Exit code: {}", code),
+ Some(code) => eprintln!("Compilation failed. Exit code: {code}"),
None => panic!("Process terminated by signal"),
}
}
diff --git a/src/tools/clippy/tests/lint_message_convention.rs b/src/tools/clippy/tests/lint_message_convention.rs
index c3aae1a9a..abd0d1bc5 100644
--- a/src/tools/clippy/tests/lint_message_convention.rs
+++ b/src/tools/clippy/tests/lint_message_convention.rs
@@ -19,7 +19,7 @@ impl Message {
// we don't want the first letter after "error: ", "help: " ... to be capitalized
// also no punctuation (except for "?" ?) at the end of a line
static REGEX_SET: LazyLock<RegexSet> = LazyLock::new(|| {
- RegexSet::new(&[
+ RegexSet::new([
r"error: [A-Z]",
r"help: [A-Z]",
r"warning: [A-Z]",
@@ -37,7 +37,7 @@ impl Message {
// sometimes the first character is capitalized and it is legal (like in "C-like enum variants") or
// we want to ask a question ending in "?"
static EXCEPTIONS_SET: LazyLock<RegexSet> = LazyLock::new(|| {
- RegexSet::new(&[
+ RegexSet::new([
r"\.\.\.$",
r".*C-like enum variant discriminant is not portable to 32-bit targets",
r".*Intel x86 assembly syntax used",
@@ -102,7 +102,7 @@ fn lint_message_convention() {
"error: the test '{}' contained the following nonconforming lines :",
message.path.display()
);
- message.bad_lines.iter().for_each(|line| eprintln!("{}", line));
+ message.bad_lines.iter().for_each(|line| eprintln!("{line}"));
eprintln!("\n\n");
}
diff --git a/src/tools/clippy/tests/missing-test-files.rs b/src/tools/clippy/tests/missing-test-files.rs
index 7d6edc2b1..caedd5d76 100644
--- a/src/tools/clippy/tests/missing-test-files.rs
+++ b/src/tools/clippy/tests/missing-test-files.rs
@@ -17,7 +17,7 @@ fn test_missing_tests() {
"Didn't see a test file for the following files:\n\n{}\n",
missing_files
.iter()
- .map(|s| format!("\t{}", s))
+ .map(|s| format!("\t{s}"))
.collect::<Vec<_>>()
.join("\n")
);
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr
index b450a2b18..3b80d89a6 100644
--- a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr
@@ -7,8 +7,8 @@ LL | / #[path = "b.rs"]
LL | | mod b2;
| |_______^ loaded again here
|
- = note: `-D clippy::duplicate-mod` implied by `-D warnings`
= help: replace all but one `mod` item with `use` items
+ = note: `-D clippy::duplicate-mod` implied by `-D warnings`
error: file is loaded as a module multiple times: `$DIR/c.rs`
--> $DIR/main.rs:9:1
diff --git a/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.stderr b/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.stderr
index b9e6cb49b..c6a11fa93 100644
--- a/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.stderr
+++ b/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.stderr
@@ -1,7 +1,7 @@
error: the "no-" prefix in the feature name "no-qaq" is negative
|
- = note: `-D clippy::negative-feature-names` implied by `-D warnings`
= help: consider renaming the feature to "qaq", but make sure the feature adds functionality
+ = note: `-D clippy::negative-feature-names` implied by `-D warnings`
error: the "no_" prefix in the feature name "no_qaq" is negative
|
@@ -17,8 +17,8 @@ error: the "not_" prefix in the feature name "not_orz" is negative
error: the "-support" suffix in the feature name "qvq-support" is redundant
|
- = note: `-D clippy::redundant-feature-names` implied by `-D warnings`
= help: consider renaming the feature to "qvq"
+ = note: `-D clippy::redundant-feature-names` implied by `-D warnings`
error: the "_support" suffix in the feature name "qvq_support" is redundant
|
diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/main.stderr b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/main.stderr
index e2010e998..697c8b57c 100644
--- a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/main.stderr
+++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod/src/main.stderr
@@ -4,8 +4,8 @@ error: `mod.rs` files are required, found `bad/inner.rs`
LL | pub mod stuff;
| ^
|
- = note: `-D clippy::self-named-module-files` implied by `-D warnings`
= help: move `bad/inner.rs` to `bad/inner/mod.rs`
+ = note: `-D clippy::self-named-module-files` implied by `-D warnings`
error: `mod.rs` files are required, found `bad/inner/stuff.rs`
--> $DIR/bad/inner/stuff.rs:1:1
diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/Cargo.toml b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/Cargo.toml
new file mode 100644
index 000000000..a822fad38
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "fail-mod-remap"
+version = "0.1.0"
+edition = "2018"
+publish = false
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/bad.rs b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/bad.rs
new file mode 100644
index 000000000..509aad186
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/bad.rs
@@ -0,0 +1 @@
+pub mod inner;
diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/bad/inner.rs b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/bad/inner.rs
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/bad/inner.rs
@@ -0,0 +1 @@
+
diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs
new file mode 100644
index 000000000..ba4c8c873
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs
@@ -0,0 +1,7 @@
+// compile-flags: --remap-path-prefix {{src-base}}=/remapped
+
+#![warn(clippy::self_named_module_files)]
+
+mod bad;
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.stderr b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.stderr
new file mode 100644
index 000000000..ea6ea9806
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.stderr
@@ -0,0 +1,11 @@
+error: `mod.rs` files are required, found `bad.rs`
+ --> /remapped/module_style/fail_mod_remap/src/bad.rs:1:1
+ |
+LL | pub mod inner;
+ | ^
+ |
+ = help: move `bad.rs` to `bad/mod.rs`
+ = note: `-D clippy::self-named-module-files` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/main.stderr b/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/main.stderr
index f91940209..f40ceea23 100644
--- a/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/main.stderr
+++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_no_mod/src/main.stderr
@@ -4,8 +4,8 @@ error: `mod.rs` files are not allowed, found `bad/mod.rs`
LL | pub struct Thing;
| ^
|
- = note: `-D clippy::mod-module-files` implied by `-D warnings`
= help: move `bad/mod.rs` to `bad.rs`
+ = note: `-D clippy::mod-module-files` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui-internal/auxiliary/paths.rs b/src/tools/clippy/tests/ui-internal/auxiliary/paths.rs
new file mode 100644
index 000000000..52fcaec4d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/auxiliary/paths.rs
@@ -0,0 +1,2 @@
+pub static OPTION: [&str; 3] = ["core", "option", "Option"];
+pub const RESULT: &[&str] = &["core", "result", "Result"];
diff --git a/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr
index 533107588..fd8c8379f 100644
--- a/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr
+++ b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr
@@ -10,13 +10,13 @@ LL | | report_in_external_macro: true
LL | | }
| |_^
|
+ = help: please use a valid semantic version, see `doc/adding_lints.md`
note: the lint level is defined here
--> $DIR/check_clippy_version_attribute.rs:1:9
|
LL | #![deny(clippy::internal)]
| ^^^^^^^^^^^^^^^^
= note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]`
- = help: please use a valid sematic version, see `doc/adding_lints.md`
= note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this item has an invalid `clippy::version` attribute
@@ -31,7 +31,7 @@ LL | | report_in_external_macro: true
LL | | }
| |_^
|
- = help: please use a valid sematic version, see `doc/adding_lints.md`
+ = help: please use a valid semantic version, see `doc/adding_lints.md`
= note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this lint is missing the `clippy::version` attribute or version value
@@ -46,8 +46,8 @@ LL | | report_in_external_macro: true
LL | | }
| |_^
|
- = note: `#[deny(clippy::missing_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]`
= help: please use a `clippy::version` attribute, see `doc/adding_lints.md`
+ = note: `#[deny(clippy::missing_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]`
= note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this lint is missing the `clippy::version` attribute or version value
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
index a1b8e2ee1..07c594101 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
@@ -1,4 +1,4 @@
-thread 'rustc' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints.rs
+thread 'rustc' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs:28:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: internal compiler error: unexpected panic
diff --git a/src/tools/clippy/tests/ui-internal/if_chain_style.stderr b/src/tools/clippy/tests/ui-internal/if_chain_style.stderr
index 24106510e..d8f1ffb21 100644
--- a/src/tools/clippy/tests/ui-internal/if_chain_style.stderr
+++ b/src/tools/clippy/tests/ui-internal/if_chain_style.stderr
@@ -10,12 +10,12 @@ LL | | }
LL | | }
| |_____^
|
- = note: `-D clippy::if-chain-style` implied by `-D warnings`
help: this `let` statement can also be in the `if_chain!`
--> $DIR/if_chain_style.rs:10:9
|
LL | let x = "";
| ^^^^^^^^^^^
+ = note: `-D clippy::if-chain-style` implied by `-D warnings`
error: `if a && b;` should be `if a; if b;`
--> $DIR/if_chain_style.rs:19:12
diff --git a/src/tools/clippy/tests/ui-internal/invalid_paths.rs b/src/tools/clippy/tests/ui-internal/invalid_paths.rs
index b823ff7fe..9a9790a4b 100644
--- a/src/tools/clippy/tests/ui-internal/invalid_paths.rs
+++ b/src/tools/clippy/tests/ui-internal/invalid_paths.rs
@@ -1,5 +1,5 @@
#![warn(clippy::internal)]
-#![allow(clippy::missing_clippy_version_attribute)]
+#![allow(clippy::missing_clippy_version_attribute, clippy::unnecessary_def_path)]
mod paths {
// Good path
diff --git a/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.rs b/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.rs
deleted file mode 100644
index 4b41ff15e..000000000
--- a/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-#![deny(clippy::internal)]
-#![allow(clippy::missing_clippy_version_attribute)]
-#![feature(rustc_private)]
-
-extern crate clippy_utils;
-extern crate rustc_hir;
-extern crate rustc_lint;
-extern crate rustc_middle;
-
-#[macro_use]
-extern crate rustc_session;
-use clippy_utils::{paths, ty::match_type};
-use rustc_hir::Expr;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::Ty;
-
-declare_lint! {
- pub TEST_LINT,
- Warn,
- ""
-}
-
-declare_lint_pass!(Pass => [TEST_LINT]);
-
-static OPTION: [&str; 3] = ["core", "option", "Option"];
-
-impl<'tcx> LateLintPass<'tcx> for Pass {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr) {
- let ty = cx.typeck_results().expr_ty(expr);
-
- let _ = match_type(cx, ty, &OPTION);
- let _ = match_type(cx, ty, &["core", "result", "Result"]);
-
- let rc_path = &["alloc", "rc", "Rc"];
- let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
- }
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.stderr b/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.stderr
deleted file mode 100644
index e3cb6b6c2..000000000
--- a/src/tools/clippy/tests/ui-internal/match_type_on_diag_item.stderr
+++ /dev/null
@@ -1,27 +0,0 @@
-error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
- --> $DIR/match_type_on_diag_item.rs:31:17
- |
-LL | let _ = match_type(cx, ty, &OPTION);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Option)`
- |
-note: the lint level is defined here
- --> $DIR/match_type_on_diag_item.rs:1:9
- |
-LL | #![deny(clippy::internal)]
- | ^^^^^^^^^^^^^^^^
- = note: `#[deny(clippy::match_type_on_diagnostic_item)]` implied by `#[deny(clippy::internal)]`
-
-error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
- --> $DIR/match_type_on_diag_item.rs:32:17
- |
-LL | let _ = match_type(cx, ty, &["core", "result", "Result"]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Result)`
-
-error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
- --> $DIR/match_type_on_diag_item.rs:35:17
- |
-LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Rc)`
-
-error: aborting due to 3 previous errors
-
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed
new file mode 100644
index 000000000..cbbb46523
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed
@@ -0,0 +1,62 @@
+// run-rustfix
+// aux-build:paths.rs
+#![deny(clippy::internal)]
+#![feature(rustc_private)]
+
+extern crate clippy_utils;
+extern crate paths;
+extern crate rustc_hir;
+extern crate rustc_lint;
+extern crate rustc_middle;
+extern crate rustc_span;
+
+#[allow(unused)]
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type};
+#[allow(unused)]
+use clippy_utils::{
+ is_expr_path_def_path, is_path_diagnostic_item, is_res_diagnostic_ctor, is_res_lang_ctor, is_trait_method,
+ match_def_path, match_trait_method, path_res,
+};
+
+#[allow(unused)]
+use rustc_hir::LangItem;
+#[allow(unused)]
+use rustc_span::sym;
+
+use rustc_hir::def_id::DefId;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+
+#[allow(unused, clippy::unnecessary_def_path)]
+static OPTION: [&str; 3] = ["core", "option", "Option"];
+#[allow(unused, clippy::unnecessary_def_path)]
+const RESULT: &[&str] = &["core", "result", "Result"];
+
+fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) {
+ let _ = is_type_diagnostic_item(cx, ty, sym::Option);
+ let _ = is_type_diagnostic_item(cx, ty, sym::Result);
+ let _ = is_type_diagnostic_item(cx, ty, sym::Result);
+
+ #[allow(unused, clippy::unnecessary_def_path)]
+ let rc_path = &["alloc", "rc", "Rc"];
+ let _ = is_type_diagnostic_item(cx, ty, sym::Rc);
+
+ let _ = is_type_diagnostic_item(cx, ty, sym::Option);
+ let _ = is_type_diagnostic_item(cx, ty, sym::Result);
+
+ let _ = is_type_lang_item(cx, ty, LangItem::OwnedBox);
+ let _ = is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit);
+
+ let _ = cx.tcx.lang_items().require(LangItem::OwnedBox).ok() == Some(did);
+ let _ = cx.tcx.is_diagnostic_item(sym::Option, did);
+ let _ = cx.tcx.lang_items().require(LangItem::OptionSome).ok() == Some(did);
+
+ let _ = is_trait_method(cx, expr, sym::AsRef);
+
+ let _ = is_path_diagnostic_item(cx, expr, sym::Option);
+ let _ = path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().require(LangItem::IteratorNext).ok() == Some(id));
+ let _ = is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome);
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs
new file mode 100644
index 000000000..f17fed6c6
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs
@@ -0,0 +1,62 @@
+// run-rustfix
+// aux-build:paths.rs
+#![deny(clippy::internal)]
+#![feature(rustc_private)]
+
+extern crate clippy_utils;
+extern crate paths;
+extern crate rustc_hir;
+extern crate rustc_lint;
+extern crate rustc_middle;
+extern crate rustc_span;
+
+#[allow(unused)]
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type};
+#[allow(unused)]
+use clippy_utils::{
+ is_expr_path_def_path, is_path_diagnostic_item, is_res_diagnostic_ctor, is_res_lang_ctor, is_trait_method,
+ match_def_path, match_trait_method, path_res,
+};
+
+#[allow(unused)]
+use rustc_hir::LangItem;
+#[allow(unused)]
+use rustc_span::sym;
+
+use rustc_hir::def_id::DefId;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+
+#[allow(unused, clippy::unnecessary_def_path)]
+static OPTION: [&str; 3] = ["core", "option", "Option"];
+#[allow(unused, clippy::unnecessary_def_path)]
+const RESULT: &[&str] = &["core", "result", "Result"];
+
+fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) {
+ let _ = match_type(cx, ty, &OPTION);
+ let _ = match_type(cx, ty, RESULT);
+ let _ = match_type(cx, ty, &["core", "result", "Result"]);
+
+ #[allow(unused, clippy::unnecessary_def_path)]
+ let rc_path = &["alloc", "rc", "Rc"];
+ let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
+
+ let _ = match_type(cx, ty, &paths::OPTION);
+ let _ = match_type(cx, ty, paths::RESULT);
+
+ let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]);
+ let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]);
+
+ let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]);
+ let _ = match_def_path(cx, did, &["core", "option", "Option"]);
+ let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]);
+
+ let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]);
+
+ let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]);
+ let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]);
+ let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]);
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr
new file mode 100644
index 000000000..a99a8f71f
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr
@@ -0,0 +1,101 @@
+error: use of a def path to a diagnostic item
+ --> $DIR/unnecessary_def_path.rs:37:13
+ |
+LL | let _ = match_type(cx, ty, &OPTION);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)`
+ |
+note: the lint level is defined here
+ --> $DIR/unnecessary_def_path.rs:3:9
+ |
+LL | #![deny(clippy::internal)]
+ | ^^^^^^^^^^^^^^^^
+ = note: `#[deny(clippy::unnecessary_def_path)]` implied by `#[deny(clippy::internal)]`
+
+error: use of a def path to a diagnostic item
+ --> $DIR/unnecessary_def_path.rs:38:13
+ |
+LL | let _ = match_type(cx, ty, RESULT);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
+
+error: use of a def path to a diagnostic item
+ --> $DIR/unnecessary_def_path.rs:39:13
+ |
+LL | let _ = match_type(cx, ty, &["core", "result", "Result"]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
+
+error: use of a def path to a diagnostic item
+ --> $DIR/unnecessary_def_path.rs:43:13
+ |
+LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Rc)`
+
+error: use of a def path to a diagnostic item
+ --> $DIR/unnecessary_def_path.rs:45:13
+ |
+LL | let _ = match_type(cx, ty, &paths::OPTION);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)`
+
+error: use of a def path to a diagnostic item
+ --> $DIR/unnecessary_def_path.rs:46:13
+ |
+LL | let _ = match_type(cx, ty, paths::RESULT);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
+
+error: use of a def path to a `LangItem`
+ --> $DIR/unnecessary_def_path.rs:48:13
+ |
+LL | let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_lang_item(cx, ty, LangItem::OwnedBox)`
+
+error: use of a def path to a diagnostic item
+ --> $DIR/unnecessary_def_path.rs:49:13
+ |
+LL | let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit)`
+
+error: use of a def path to a `LangItem`
+ --> $DIR/unnecessary_def_path.rs:51:13
+ |
+LL | let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().require(LangItem::OwnedBox).ok() == Some(did)`
+
+error: use of a def path to a diagnostic item
+ --> $DIR/unnecessary_def_path.rs:52:13
+ |
+LL | let _ = match_def_path(cx, did, &["core", "option", "Option"]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.is_diagnostic_item(sym::Option, did)`
+
+error: use of a def path to a `LangItem`
+ --> $DIR/unnecessary_def_path.rs:53:13
+ |
+LL | let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().require(LangItem::OptionSome).ok() == Some(did)`
+ |
+ = help: if this `DefId` came from a constructor expression or pattern then the parent `DefId` should be used instead
+
+error: use of a def path to a diagnostic item
+ --> $DIR/unnecessary_def_path.rs:55:13
+ |
+LL | let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_trait_method(cx, expr, sym::AsRef)`
+
+error: use of a def path to a diagnostic item
+ --> $DIR/unnecessary_def_path.rs:57:13
+ |
+LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_path_diagnostic_item(cx, expr, sym::Option)`
+
+error: use of a def path to a `LangItem`
+ --> $DIR/unnecessary_def_path.rs:58:13
+ |
+LL | let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().require(LangItem::IteratorNext).ok() == Some(id))`
+
+error: use of a def path to a `LangItem`
+ --> $DIR/unnecessary_def_path.rs:59:13
+ |
+LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome)`
+
+error: aborting due to 15 previous errors
+
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
new file mode 100644
index 000000000..b5ff3a542
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
@@ -0,0 +1,16 @@
+#![feature(rustc_private)]
+#![allow(unused)]
+#![warn(clippy::unnecessary_def_path)]
+
+extern crate rustc_hir;
+
+use rustc_hir::LangItem;
+
+fn main() {
+ const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
+ const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
+ const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
+
+ // Don't lint, not yet a diagnostic or language item
+ const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
+}
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
new file mode 100644
index 000000000..af46d87bf
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
@@ -0,0 +1,27 @@
+error: hardcoded path to a language item
+ --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
+ |
+LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: convert all references to use `LangItem::DerefMut`
+ = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
+
+error: hardcoded path to a diagnostic item
+ --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
+ |
+LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: convert all references to use `sym::deref_method`
+
+error: hardcoded path to a diagnostic item
+ --> $DIR/unnecessary_def_path_hardcoded_path.rs:10:36
+ |
+LL | const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: convert all references to use `sym::Deref`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_allowed/clippy.toml b/src/tools/clippy/tests/ui-toml/arithmetic_allowed/clippy.toml
deleted file mode 100644
index cc40570b1..000000000
--- a/src/tools/clippy/tests/ui-toml/arithmetic_allowed/clippy.toml
+++ /dev/null
@@ -1 +0,0 @@
-arithmetic-allowed = ["Point"]
diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs
index 195fabdbf..1aed09b7c 100644
--- a/src/tools/clippy/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs
+++ b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs
@@ -1,4 +1,4 @@
-#![warn(clippy::arithmetic)]
+#![warn(clippy::arithmetic_side_effects)]
use core::ops::Add;
diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml
new file mode 100644
index 000000000..e736256f2
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml
@@ -0,0 +1 @@
+arithmetic-side-effects-allowed = ["Point"]
diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
index 62c45b546..4c7599843 100644
--- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
+++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
@@ -4,8 +4,8 @@ error: `std::string::String` may not be held across an `await` point per `clippy
LL | let _x = String::from("hello");
| ^^
|
- = note: `-D clippy::await-holding-invalid-type` implied by `-D warnings`
= note: strings are bad
+ = note: `-D clippy::await-holding-invalid-type` implied by `-D warnings`
error: `std::net::Ipv4Addr` may not be held across an `await` point per `clippy.toml`
--> $DIR/await_holding_invalid_type.rs:10:9
diff --git a/src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml b/src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml
index 168675394..d48bab08f 100644
--- a/src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml
@@ -1 +1 @@
-blacklisted-names = 42
+disallowed-names = 42
diff --git a/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr b/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr
index c7bc261de..e3ec60192 100644
--- a/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr
+++ b/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `blacklisted-names`
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `disallowed-names`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr b/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr
deleted file mode 100644
index 9169bb0e8..000000000
--- a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error: use of a blacklisted/placeholder name `foo`
- --> $DIR/blacklisted_names.rs:5:9
- |
-LL | let foo = "bar";
- | ^^^
- |
- = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: use of a blacklisted/placeholder name `ducks`
- --> $DIR/blacklisted_names.rs:7:9
- |
-LL | let ducks = ["quack", "quack"];
- | ^^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml b/src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml
deleted file mode 100644
index 0e052ef50..000000000
--- a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml
+++ /dev/null
@@ -1 +0,0 @@
-blacklisted-names = ["ducks", ".."]
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr b/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr
deleted file mode 100644
index ec6f7f084..000000000
--- a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: use of a blacklisted/placeholder name `ducks`
- --> $DIR/blacklisted_names.rs:7:9
- |
-LL | let ducks = ["quack", "quack"];
- | ^^^^^
- |
- = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: aborting due to previous error
-
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml b/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml
deleted file mode 100644
index 4582f1c06..000000000
--- a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml
+++ /dev/null
@@ -1 +0,0 @@
-blacklisted-names = ["ducks"]
diff --git a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml
index ac47b1950..d79a98d05 100644
--- a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml
@@ -1,5 +1,6 @@
-# that one is an error
-cyclomatic-complexity-threshold = 42
+# Expect errors from these deprecated configs
+cyclomatic-complexity-threshold = 2
+blacklisted-names = [ "..", "wibble" ]
# that one is white-listed
[third-party]
diff --git a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs
index f328e4d9d..7f1c512d7 100644
--- a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs
+++ b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs
@@ -1 +1,13 @@
+#![allow(clippy::uninlined_format_args)]
+
fn main() {}
+
+#[warn(clippy::cognitive_complexity)]
+fn cognitive_complexity() {
+ let x = vec![1, 2, 3];
+ for i in x {
+ if i == 1 {
+ println!("{}", i);
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr
index 90021a034..630bad07c 100644
--- a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr
@@ -1,4 +1,15 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
+warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
-error: aborting due to previous error
+warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `blacklisted-names`. Please use `disallowed-names` instead
+
+error: the function has a cognitive complexity of (3/2)
+ --> $DIR/conf_deprecated_key.rs:6:4
+ |
+LL | fn cognitive_complexity() {
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: you could split it up into multiple smaller functions
+ = note: `-D clippy::cognitive-complexity` implied by `-D warnings`
+
+error: aborting due to previous error; 2 warnings emitted
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_macros/auxiliary/macros.rs b/src/tools/clippy/tests/ui-toml/disallowed_macros/auxiliary/macros.rs
new file mode 100644
index 000000000..fcaeace0e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/disallowed_macros/auxiliary/macros.rs
@@ -0,0 +1,32 @@
+#[macro_export]
+macro_rules! expr {
+ () => {
+ 1
+ };
+}
+
+#[macro_export]
+macro_rules! stmt {
+ () => {
+ let _x = ();
+ };
+}
+
+#[macro_export]
+macro_rules! ty {
+ () => { &'static str };
+}
+
+#[macro_export]
+macro_rules! pat {
+ () => {
+ _
+ };
+}
+
+#[macro_export]
+macro_rules! item {
+ () => {
+ const ITEM: usize = 1;
+ };
+}
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_macros/clippy.toml b/src/tools/clippy/tests/ui-toml/disallowed_macros/clippy.toml
new file mode 100644
index 000000000..c8fe8be9a
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/disallowed_macros/clippy.toml
@@ -0,0 +1,11 @@
+disallowed-macros = [
+ "std::println",
+ "std::vec",
+ { path = "std::cfg" },
+ { path = "serde::Serialize", reason = "no serializing" },
+ "macros::expr",
+ "macros::stmt",
+ "macros::ty",
+ "macros::pat",
+ "macros::item",
+]
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs
new file mode 100644
index 000000000..2bb537607
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs
@@ -0,0 +1,39 @@
+// aux-build:macros.rs
+
+#![allow(unused)]
+
+extern crate macros;
+
+use serde::Serialize;
+
+fn main() {
+ println!("one");
+ println!("two");
+ cfg!(unix);
+ vec![1, 2, 3];
+
+ #[derive(Serialize)]
+ struct Derive;
+
+ let _ = macros::expr!();
+ macros::stmt!();
+ let macros::pat!() = 1;
+ let _: macros::ty!() = "";
+ macros::item!();
+
+ eprintln!("allowed");
+}
+
+struct S;
+
+impl S {
+ macros::item!();
+}
+
+trait Y {
+ macros::item!();
+}
+
+impl Y for S {
+ macros::item!();
+}
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr
new file mode 100644
index 000000000..aed9feb6f
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr
@@ -0,0 +1,84 @@
+error: use of a disallowed macro `std::println`
+ --> $DIR/disallowed_macros.rs:10:5
+ |
+LL | println!("one");
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::disallowed-macros` implied by `-D warnings`
+
+error: use of a disallowed macro `std::println`
+ --> $DIR/disallowed_macros.rs:11:5
+ |
+LL | println!("two");
+ | ^^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `std::cfg`
+ --> $DIR/disallowed_macros.rs:12:5
+ |
+LL | cfg!(unix);
+ | ^^^^^^^^^^
+
+error: use of a disallowed macro `std::vec`
+ --> $DIR/disallowed_macros.rs:13:5
+ |
+LL | vec![1, 2, 3];
+ | ^^^^^^^^^^^^^
+
+error: use of a disallowed macro `serde::Serialize`
+ --> $DIR/disallowed_macros.rs:15:14
+ |
+LL | #[derive(Serialize)]
+ | ^^^^^^^^^
+ |
+ = note: no serializing (from clippy.toml)
+
+error: use of a disallowed macro `macros::expr`
+ --> $DIR/disallowed_macros.rs:18:13
+ |
+LL | let _ = macros::expr!();
+ | ^^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::stmt`
+ --> $DIR/disallowed_macros.rs:19:5
+ |
+LL | macros::stmt!();
+ | ^^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::pat`
+ --> $DIR/disallowed_macros.rs:20:9
+ |
+LL | let macros::pat!() = 1;
+ | ^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::ty`
+ --> $DIR/disallowed_macros.rs:21:12
+ |
+LL | let _: macros::ty!() = "";
+ | ^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::item`
+ --> $DIR/disallowed_macros.rs:22:5
+ |
+LL | macros::item!();
+ | ^^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::item`
+ --> $DIR/disallowed_macros.rs:30:5
+ |
+LL | macros::item!();
+ | ^^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::item`
+ --> $DIR/disallowed_macros.rs:34:5
+ |
+LL | macros::item!();
+ | ^^^^^^^^^^^^^^^
+
+error: use of a disallowed macro `macros::item`
+ --> $DIR/disallowed_macros.rs:38:5
+ |
+LL | macros::item!();
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml b/src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml
new file mode 100644
index 000000000..6df96a3c2
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml
@@ -0,0 +1 @@
+disallowed-names = ["ducks", ".."]
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs
index fb2395cf9..a2e2b46c4 100644
--- a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs
+++ b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs
@@ -1,9 +1,9 @@
-#[warn(clippy::blacklisted_name)]
+#[warn(clippy::disallowed_names)]
fn main() {
// `foo` is part of the default configuration
let foo = "bar";
- // `ducks` was unrightfully blacklisted
+ // `ducks` was unrightfully disallowed
let ducks = ["quack", "quack"];
// `fox` is okay
let fox = ["what", "does", "the", "fox", "say", "?"];
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr
new file mode 100644
index 000000000..23c3e96a8
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr
@@ -0,0 +1,16 @@
+error: use of a disallowed/placeholder name `foo`
+ --> $DIR/disallowed_names.rs:5:9
+ |
+LL | let foo = "bar";
+ | ^^^
+ |
+ = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: use of a disallowed/placeholder name `ducks`
+ --> $DIR/disallowed_names.rs:7:9
+ |
+LL | let ducks = ["quack", "quack"];
+ | ^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml
new file mode 100644
index 000000000..a1c515652
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml
@@ -0,0 +1 @@
+disallowed-names = ["ducks"]
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs
index fb2395cf9..a2e2b46c4 100644
--- a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs
+++ b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs
@@ -1,9 +1,9 @@
-#[warn(clippy::blacklisted_name)]
+#[warn(clippy::disallowed_names)]
fn main() {
// `foo` is part of the default configuration
let foo = "bar";
- // `ducks` was unrightfully blacklisted
+ // `ducks` was unrightfully disallowed
let ducks = ["quack", "quack"];
// `fox` is okay
let fox = ["what", "does", "the", "fox", "say", "?"];
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr
new file mode 100644
index 000000000..d961fa340
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr
@@ -0,0 +1,10 @@
+error: use of a disallowed/placeholder name `ducks`
+ --> $DIR/disallowed_names.rs:7:9
+ |
+LL | let ducks = ["quack", "quack"];
+ | ^^^^^
+ |
+ = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml b/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml
new file mode 100644
index 000000000..63a893cc6
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml
@@ -0,0 +1,5 @@
+cognitive-complexity-threshold = 2
+# This is the deprecated name for the same key
+cyclomatic-complexity-threshold = 3
+# Check we get duplication warning regardless of order
+cognitive-complexity-threshold = 4
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs
new file mode 100644
index 000000000..f328e4d9d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr
new file mode 100644
index 000000000..d99490a24
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr
@@ -0,0 +1,8 @@
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive_complexity_threshold` (provided as `cyclomatic_complexity_threshold`)
+
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive-complexity-threshold`
+
+warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
index 9cb2199ed..28a08599c 100644
--- a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
+++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
@@ -4,8 +4,8 @@ error: used `expect()` on `an Option` value
LL | let _ = opt.expect("");
| ^^^^^^^^^^^^^^
|
+ = help: if this value is `None`, it will panic
= note: `-D clippy::expect-used` implied by `-D warnings`
- = help: if this value is an `None`, it will panic
error: used `expect()` on `a Result` value
--> $DIR/expect_used.rs:11:13
diff --git a/src/tools/clippy/tests/ui-toml/fn_params_excessive_bools/test.stderr b/src/tools/clippy/tests/ui-toml/fn_params_excessive_bools/test.stderr
index d05adc3d3..87bdb61c6 100644
--- a/src/tools/clippy/tests/ui-toml/fn_params_excessive_bools/test.stderr
+++ b/src/tools/clippy/tests/ui-toml/fn_params_excessive_bools/test.stderr
@@ -4,8 +4,8 @@ error: more than 1 bools in function parameters
LL | fn g(_: bool, _: bool) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings`
= help: consider refactoring bools into two-variant enums
+ = note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr
index 6a685a583..7b5fb9e87 100644
--- a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr
+++ b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr
@@ -4,8 +4,8 @@ error: attempted to include a large file
LL | const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::large-include-file` implied by `-D warnings`
= note: the configuration allows a maximum size of 600 bytes
+ = note: `-D clippy::large-include-file` implied by `-D warnings`
= note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: attempted to include a large file
diff --git a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed
new file mode 100644
index 000000000..01d135764
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed
@@ -0,0 +1,62 @@
+// aux-build:proc_macro_derive.rs
+// run-rustfix
+
+#![warn(clippy::nonstandard_macro_braces)]
+
+extern crate proc_macro_derive;
+extern crate quote;
+
+use quote::quote;
+
+#[derive(proc_macro_derive::DeriveSomething)]
+pub struct S;
+
+proc_macro_derive::foo_bar!();
+
+#[rustfmt::skip]
+macro_rules! test {
+ () => {
+ vec![0, 0, 0]
+ };
+}
+
+#[rustfmt::skip]
+macro_rules! test2 {
+ ($($arg:tt)*) => {
+ format_args!($($arg)*)
+ };
+}
+
+macro_rules! type_pos {
+ ($what:ty) => {
+ Vec<$what>
+ };
+}
+
+macro_rules! printlnfoo {
+ ($thing:expr) => {
+ println!("{}", $thing)
+ };
+}
+
+#[rustfmt::skip]
+fn main() {
+ let _ = vec![1, 2, 3];
+ let _ = format!("ugh {} stop being such a good compiler", "hello");
+ let _ = matches!({}, ());
+ let _ = quote!{let x = 1;};
+ let _ = quote::quote!{match match match};
+ let _ = test!(); // trigger when macro def is inside our own crate
+ let _ = vec![1,2,3];
+
+ let _ = quote::quote! {true || false};
+ let _ = vec! [0 ,0 ,0];
+ let _ = format!("fds{}fds", 10);
+ let _ = test2!["{}{}{}", 1, 2, 3];
+
+ let _: type_pos![usize] = vec![];
+
+ eprint!["test if user config overrides defaults"];
+
+ printlnfoo!["test if printlnfoo is triggered by println"];
+}
diff --git a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs
index 5b4adc868..72883e827 100644
--- a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs
+++ b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs
@@ -1,4 +1,5 @@
// aux-build:proc_macro_derive.rs
+// run-rustfix
#![warn(clippy::nonstandard_macro_braces)]
@@ -42,6 +43,7 @@ macro_rules! printlnfoo {
fn main() {
let _ = vec! {1, 2, 3};
let _ = format!["ugh {} stop being such a good compiler", "hello"];
+ let _ = matches!{{}, ()};
let _ = quote!(let x = 1;);
let _ = quote::quote!(match match match);
let _ = test!(); // trigger when macro def is inside our own crate
diff --git a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr
index 039b23b1b..7ae381597 100644
--- a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr
+++ b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr
@@ -1,94 +1,57 @@
error: use of irregular braces for `vec!` macro
- --> $DIR/conf_nonstandard_macro_braces.rs:43:13
+ --> $DIR/conf_nonstandard_macro_braces.rs:44:13
|
LL | let _ = vec! {1, 2, 3};
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ help: consider writing: `vec![1, 2, 3]`
|
= note: `-D clippy::nonstandard-macro-braces` implied by `-D warnings`
-help: consider writing `vec![1, 2, 3]`
- --> $DIR/conf_nonstandard_macro_braces.rs:43:13
- |
-LL | let _ = vec! {1, 2, 3};
- | ^^^^^^^^^^^^^^
error: use of irregular braces for `format!` macro
- --> $DIR/conf_nonstandard_macro_braces.rs:44:13
+ --> $DIR/conf_nonstandard_macro_braces.rs:45:13
|
LL | let _ = format!["ugh {} stop being such a good compiler", "hello"];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider writing `format!("ugh () stop being such a good compiler", "hello")`
- --> $DIR/conf_nonstandard_macro_braces.rs:44:13
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `format!("ugh {} stop being such a good compiler", "hello")`
+
+error: use of irregular braces for `matches!` macro
+ --> $DIR/conf_nonstandard_macro_braces.rs:46:13
|
-LL | let _ = format!["ugh {} stop being such a good compiler", "hello"];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | let _ = matches!{{}, ()};
+ | ^^^^^^^^^^^^^^^^ help: consider writing: `matches!({}, ())`
error: use of irregular braces for `quote!` macro
- --> $DIR/conf_nonstandard_macro_braces.rs:45:13
- |
-LL | let _ = quote!(let x = 1;);
- | ^^^^^^^^^^^^^^^^^^
- |
-help: consider writing `quote! {let x = 1;}`
- --> $DIR/conf_nonstandard_macro_braces.rs:45:13
+ --> $DIR/conf_nonstandard_macro_braces.rs:47:13
|
LL | let _ = quote!(let x = 1;);
- | ^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^ help: consider writing: `quote!{let x = 1;}`
error: use of irregular braces for `quote::quote!` macro
- --> $DIR/conf_nonstandard_macro_braces.rs:46:13
+ --> $DIR/conf_nonstandard_macro_braces.rs:48:13
|
LL | let _ = quote::quote!(match match match);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider writing `quote::quote! {match match match}`
- --> $DIR/conf_nonstandard_macro_braces.rs:46:13
- |
-LL | let _ = quote::quote!(match match match);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `quote::quote!{match match match}`
error: use of irregular braces for `vec!` macro
- --> $DIR/conf_nonstandard_macro_braces.rs:18:9
+ --> $DIR/conf_nonstandard_macro_braces.rs:19:9
|
LL | vec!{0, 0, 0}
- | ^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^ help: consider writing: `vec![0, 0, 0]`
...
LL | let _ = test!(); // trigger when macro def is inside our own crate
| ------- in this macro invocation
|
-help: consider writing `vec![0, 0, 0]`
- --> $DIR/conf_nonstandard_macro_braces.rs:18:9
- |
-LL | vec!{0, 0, 0}
- | ^^^^^^^^^^^^^
-...
-LL | let _ = test!(); // trigger when macro def is inside our own crate
- | ------- in this macro invocation
= note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
error: use of irregular braces for `type_pos!` macro
- --> $DIR/conf_nonstandard_macro_braces.rs:55:12
- |
-LL | let _: type_pos!(usize) = vec![];
- | ^^^^^^^^^^^^^^^^
- |
-help: consider writing `type_pos![usize]`
- --> $DIR/conf_nonstandard_macro_braces.rs:55:12
+ --> $DIR/conf_nonstandard_macro_braces.rs:57:12
|
LL | let _: type_pos!(usize) = vec![];
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^ help: consider writing: `type_pos![usize]`
error: use of irregular braces for `eprint!` macro
- --> $DIR/conf_nonstandard_macro_braces.rs:57:5
- |
-LL | eprint!("test if user config overrides defaults");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider writing `eprint!["test if user config overrides defaults"]`
- --> $DIR/conf_nonstandard_macro_braces.rs:57:5
+ --> $DIR/conf_nonstandard_macro_braces.rs:59:5
|
LL | eprint!("test if user config overrides defaults");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `eprint!["test if user config overrides defaults"]`
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr b/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr
index 49eecf18b..c72f8c648 100644
--- a/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr
+++ b/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr
@@ -4,13 +4,13 @@ error: some fields in `NoGeneric` are not safe to be sent to another thread
LL | unsafe impl Send for NoGeneric {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings`
note: it is not safe to send field `rc_is_not_send` to another thread
--> $DIR/test.rs:8:5
|
LL | rc_is_not_send: Rc<String>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
+ = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings`
error: some fields in `MultiField<T>` are not safe to be sent to another thread
--> $DIR/test.rs:19:1
diff --git a/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.stderr b/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.stderr
index 65861d10d..4e7c70d18 100644
--- a/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.stderr
+++ b/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.stderr
@@ -6,8 +6,8 @@ LL | | a: bool,
LL | | }
| |_^
|
- = note: `-D clippy::struct-excessive-bools` implied by `-D warnings`
= help: consider using a state machine or refactoring bools into two-variant enums
+ = note: `-D clippy::struct-excessive-bools` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml
deleted file mode 100644
index 6abe5a3bb..000000000
--- a/src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml
+++ /dev/null
@@ -1 +0,0 @@
-blacklisted-names = ["toto", "tata", "titi"]
diff --git a/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr b/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr
deleted file mode 100644
index 84ba77851..000000000
--- a/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr
+++ /dev/null
@@ -1,46 +0,0 @@
-error: use of a blacklisted/placeholder name `toto`
- --> $DIR/conf_french_blacklisted_name.rs:6:9
- |
-LL | fn test(toto: ()) {}
- | ^^^^
- |
- = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: use of a blacklisted/placeholder name `toto`
- --> $DIR/conf_french_blacklisted_name.rs:9:9
- |
-LL | let toto = 42;
- | ^^^^
-
-error: use of a blacklisted/placeholder name `tata`
- --> $DIR/conf_french_blacklisted_name.rs:10:9
- |
-LL | let tata = 42;
- | ^^^^
-
-error: use of a blacklisted/placeholder name `titi`
- --> $DIR/conf_french_blacklisted_name.rs:11:9
- |
-LL | let titi = 42;
- | ^^^^
-
-error: use of a blacklisted/placeholder name `toto`
- --> $DIR/conf_french_blacklisted_name.rs:17:10
- |
-LL | (toto, Some(tata), titi @ Some(_)) => (),
- | ^^^^
-
-error: use of a blacklisted/placeholder name `tata`
- --> $DIR/conf_french_blacklisted_name.rs:17:21
- |
-LL | (toto, Some(tata), titi @ Some(_)) => (),
- | ^^^^
-
-error: use of a blacklisted/placeholder name `titi`
- --> $DIR/conf_french_blacklisted_name.rs:17:28
- |
-LL | (toto, Some(tata), titi @ Some(_)) => (),
- | ^^^^
-
-error: aborting due to 7 previous errors
-
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml
new file mode 100644
index 000000000..e4f0cb6df
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml
@@ -0,0 +1 @@
+disallowed-names = ["toto", "tata", "titi"]
diff --git a/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs
index cb35d0e85..2f86b3eda 100644
--- a/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs
+++ b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs
@@ -1,7 +1,7 @@
#![allow(dead_code)]
#![allow(clippy::single_match)]
#![allow(unused_variables)]
-#![warn(clippy::blacklisted_name)]
+#![warn(clippy::disallowed_names)]
fn test(toto: ()) {}
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr
new file mode 100644
index 000000000..9082c1c54
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr
@@ -0,0 +1,46 @@
+error: use of a disallowed/placeholder name `toto`
+ --> $DIR/conf_french_disallowed_name.rs:6:9
+ |
+LL | fn test(toto: ()) {}
+ | ^^^^
+ |
+ = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: use of a disallowed/placeholder name `toto`
+ --> $DIR/conf_french_disallowed_name.rs:9:9
+ |
+LL | let toto = 42;
+ | ^^^^
+
+error: use of a disallowed/placeholder name `tata`
+ --> $DIR/conf_french_disallowed_name.rs:10:9
+ |
+LL | let tata = 42;
+ | ^^^^
+
+error: use of a disallowed/placeholder name `titi`
+ --> $DIR/conf_french_disallowed_name.rs:11:9
+ |
+LL | let titi = 42;
+ | ^^^^
+
+error: use of a disallowed/placeholder name `toto`
+ --> $DIR/conf_french_disallowed_name.rs:17:10
+ |
+LL | (toto, Some(tata), titi @ Some(_)) => (),
+ | ^^^^
+
+error: use of a disallowed/placeholder name `tata`
+ --> $DIR/conf_french_disallowed_name.rs:17:21
+ |
+LL | (toto, Some(tata), titi @ Some(_)) => (),
+ | ^^^^
+
+error: use of a disallowed/placeholder name `titi`
+ --> $DIR/conf_french_disallowed_name.rs:17:28
+ |
+LL | (toto, Some(tata), titi @ Some(_)) => (),
+ | ^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/clippy.toml
index c902d2112..28774db62 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/clippy.toml
@@ -3,6 +3,7 @@ disallowed-methods = [
"std::iter::Iterator::sum",
"f32::clamp",
"slice::sort_unstable",
+ "futures::stream::select_all",
# can give path and reason with an inline table
{ path = "regex::Regex::is_match", reason = "no matching allowed" },
# can use an inline table but omit reason
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
index 3397fa1ec..b483f1600 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
@@ -1,6 +1,9 @@
#![warn(clippy::disallowed_methods)]
+extern crate futures;
extern crate regex;
+
+use futures::stream::{empty, select_all};
use regex::Regex;
fn main() {
@@ -20,4 +23,7 @@ fn main() {
let in_call = Box::new(f32::clamp);
let in_method_call = ["^", "$"].into_iter().map(Regex::new);
+
+ // resolve ambiguity between `futures::stream::select_all` the module and the function
+ let same_name_as_module = select_all(vec![empty::<()>()]);
}
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
index 5cbb56754..6d78c32e1 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
@@ -1,5 +1,5 @@
error: use of a disallowed method `regex::Regex::new`
- --> $DIR/conf_disallowed_methods.rs:7:14
+ --> $DIR/conf_disallowed_methods.rs:10:14
|
LL | let re = Regex::new(r"ab.*c").unwrap();
| ^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | let re = Regex::new(r"ab.*c").unwrap();
= note: `-D clippy::disallowed-methods` implied by `-D warnings`
error: use of a disallowed method `regex::Regex::is_match`
- --> $DIR/conf_disallowed_methods.rs:8:5
+ --> $DIR/conf_disallowed_methods.rs:11:5
|
LL | re.is_match("abc");
| ^^^^^^^^^^^^^^^^^^
@@ -15,40 +15,46 @@ LL | re.is_match("abc");
= note: no matching allowed (from clippy.toml)
error: use of a disallowed method `std::iter::Iterator::sum`
- --> $DIR/conf_disallowed_methods.rs:11:5
+ --> $DIR/conf_disallowed_methods.rs:14:5
|
LL | a.iter().sum::<i32>();
| ^^^^^^^^^^^^^^^^^^^^^
error: use of a disallowed method `slice::sort_unstable`
- --> $DIR/conf_disallowed_methods.rs:13:5
+ --> $DIR/conf_disallowed_methods.rs:16:5
|
LL | a.sort_unstable();
| ^^^^^^^^^^^^^^^^^
error: use of a disallowed method `f32::clamp`
- --> $DIR/conf_disallowed_methods.rs:15:13
+ --> $DIR/conf_disallowed_methods.rs:18:13
|
LL | let _ = 2.0f32.clamp(3.0f32, 4.0f32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of a disallowed method `regex::Regex::new`
- --> $DIR/conf_disallowed_methods.rs:18:61
+ --> $DIR/conf_disallowed_methods.rs:21:61
|
LL | let indirect: fn(&str) -> Result<Regex, regex::Error> = Regex::new;
| ^^^^^^^^^^
error: use of a disallowed method `f32::clamp`
- --> $DIR/conf_disallowed_methods.rs:21:28
+ --> $DIR/conf_disallowed_methods.rs:24:28
|
LL | let in_call = Box::new(f32::clamp);
| ^^^^^^^^^^
error: use of a disallowed method `regex::Regex::new`
- --> $DIR/conf_disallowed_methods.rs:22:53
+ --> $DIR/conf_disallowed_methods.rs:25:53
|
LL | let in_method_call = ["^", "$"].into_iter().map(Regex::new);
| ^^^^^^^^^^
-error: aborting due to 8 previous errors
+error: use of a disallowed method `futures::stream::select_all`
+ --> $DIR/conf_disallowed_methods.rs:28:31
+ |
+LL | let same_name_as_module = select_all(vec![empty::<()>()]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index fe5139c47..82ee80541 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -3,7 +3,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
allow-expect-in-tests
allow-unwrap-in-tests
allowed-scripts
- arithmetic-allowed
+ arithmetic-side-effects-allowed
array-size-threshold
avoid-breaking-exported-api
await-holding-invalid-types
@@ -11,13 +11,16 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
cargo-ignore-publish
cognitive-complexity-threshold
cyclomatic-complexity-threshold
+ disallowed-macros
disallowed-methods
+ disallowed-names
disallowed-types
doc-valid-idents
enable-raw-pointer-heuristic-for-send
enforced-import-renames
enum-variant-name-threshold
enum-variant-size-threshold
+ large-error-threshold
literal-representation-threshold
max-fn-params-bools
max-include-file-size
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
index 6bcfa0a8b..681b5eaf5 100644
--- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
@@ -16,8 +16,8 @@ error: used `unwrap()` on `an Option` value
LL | let _ = boxed_slice.get(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::unwrap-used` implied by `-D warnings`
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: `-D clippy::unwrap-used` implied by `-D warnings`
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:36:17
diff --git a/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr b/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr
index 6de554378..21cb11fa1 100644
--- a/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr
+++ b/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr
@@ -4,8 +4,8 @@ error: this comparison involving the minimum or maximum element for this type co
LL | u <= 0;
| ^^^^^^
|
- = note: `-D clippy::absurd-extreme-comparisons` implied by `-D warnings`
= help: because `0` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `u == 0` instead
+ = note: `-D clippy::absurd-extreme-comparisons` implied by `-D warnings`
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:15:5
diff --git a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr
index cd040a144..23f17e9a7 100644
--- a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr
+++ b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr
@@ -4,12 +4,12 @@ error: `allow` attribute without specifying a reason
LL | #[allow(dead_code)]
| ^^^^^^^^^^^^^^^^^^^
|
+ = help: try adding a reason at the end with `, reason = ".."`
note: the lint level is defined here
--> $DIR/allow_attributes_without_reason.rs:2:9
|
LL | #![deny(clippy::allow_attributes_without_reason)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: try adding a reason at the end with `, reason = ".."`
error: `allow` attribute without specifying a reason
--> $DIR/allow_attributes_without_reason.rs:6:1
diff --git a/src/tools/clippy/tests/ui/almost_complete_letter_range.fixed b/src/tools/clippy/tests/ui/almost_complete_letter_range.fixed
index e69b40f35..079b7c000 100644
--- a/src/tools/clippy/tests/ui/almost_complete_letter_range.fixed
+++ b/src/tools/clippy/tests/ui/almost_complete_letter_range.fixed
@@ -1,5 +1,6 @@
// run-rustfix
// edition:2018
+// aux-build:macro_rules.rs
#![feature(custom_inner_attributes)]
#![feature(exclusive_range_pattern)]
@@ -8,12 +9,21 @@
#![allow(ellipsis_inclusive_range_patterns)]
#![allow(clippy::needless_parens_on_range_literals)]
+#[macro_use]
+extern crate macro_rules;
+
macro_rules! a {
() => {
'a'
};
}
+macro_rules! b {
+ () => {
+ let _ = 'a'..='z';
+ };
+}
+
fn main() {
#[rustfmt::skip]
{
@@ -47,6 +57,9 @@ fn main() {
'B'..'Z' => 4,
_ => 5,
};
+
+ almost_complete_letter_range!();
+ b!();
}
fn _under_msrv() {
diff --git a/src/tools/clippy/tests/ui/almost_complete_letter_range.rs b/src/tools/clippy/tests/ui/almost_complete_letter_range.rs
index f2240981d..a66900a97 100644
--- a/src/tools/clippy/tests/ui/almost_complete_letter_range.rs
+++ b/src/tools/clippy/tests/ui/almost_complete_letter_range.rs
@@ -1,5 +1,6 @@
// run-rustfix
// edition:2018
+// aux-build:macro_rules.rs
#![feature(custom_inner_attributes)]
#![feature(exclusive_range_pattern)]
@@ -8,12 +9,21 @@
#![allow(ellipsis_inclusive_range_patterns)]
#![allow(clippy::needless_parens_on_range_literals)]
+#[macro_use]
+extern crate macro_rules;
+
macro_rules! a {
() => {
'a'
};
}
+macro_rules! b {
+ () => {
+ let _ = 'a'..'z';
+ };
+}
+
fn main() {
#[rustfmt::skip]
{
@@ -47,6 +57,9 @@ fn main() {
'B'..'Z' => 4,
_ => 5,
};
+
+ almost_complete_letter_range!();
+ b!();
}
fn _under_msrv() {
diff --git a/src/tools/clippy/tests/ui/almost_complete_letter_range.stderr b/src/tools/clippy/tests/ui/almost_complete_letter_range.stderr
index 5b5dc40ee..3de44c72c 100644
--- a/src/tools/clippy/tests/ui/almost_complete_letter_range.stderr
+++ b/src/tools/clippy/tests/ui/almost_complete_letter_range.stderr
@@ -1,5 +1,5 @@
error: almost complete ascii letter range
- --> $DIR/almost_complete_letter_range.rs:20:17
+ --> $DIR/almost_complete_letter_range.rs:30:17
|
LL | let _ = ('a') ..'z';
| ^^^^^^--^^^
@@ -9,7 +9,7 @@ LL | let _ = ('a') ..'z';
= note: `-D clippy::almost-complete-letter-range` implied by `-D warnings`
error: almost complete ascii letter range
- --> $DIR/almost_complete_letter_range.rs:21:17
+ --> $DIR/almost_complete_letter_range.rs:31:17
|
LL | let _ = 'A' .. ('Z');
| ^^^^--^^^^^^
@@ -17,7 +17,7 @@ LL | let _ = 'A' .. ('Z');
| help: use an inclusive range: `..=`
error: almost complete ascii letter range
- --> $DIR/almost_complete_letter_range.rs:27:13
+ --> $DIR/almost_complete_letter_range.rs:37:13
|
LL | let _ = (b'a')..(b'z');
| ^^^^^^--^^^^^^
@@ -25,7 +25,7 @@ LL | let _ = (b'a')..(b'z');
| help: use an inclusive range: `..=`
error: almost complete ascii letter range
- --> $DIR/almost_complete_letter_range.rs:28:13
+ --> $DIR/almost_complete_letter_range.rs:38:13
|
LL | let _ = b'A'..b'Z';
| ^^^^--^^^^
@@ -33,7 +33,7 @@ LL | let _ = b'A'..b'Z';
| help: use an inclusive range: `..=`
error: almost complete ascii letter range
- --> $DIR/almost_complete_letter_range.rs:33:13
+ --> $DIR/almost_complete_letter_range.rs:43:13
|
LL | let _ = a!()..'z';
| ^^^^--^^^
@@ -41,7 +41,7 @@ LL | let _ = a!()..'z';
| help: use an inclusive range: `..=`
error: almost complete ascii letter range
- --> $DIR/almost_complete_letter_range.rs:36:9
+ --> $DIR/almost_complete_letter_range.rs:46:9
|
LL | b'a'..b'z' if true => 1,
| ^^^^--^^^^
@@ -49,7 +49,7 @@ LL | b'a'..b'z' if true => 1,
| help: use an inclusive range: `..=`
error: almost complete ascii letter range
- --> $DIR/almost_complete_letter_range.rs:37:9
+ --> $DIR/almost_complete_letter_range.rs:47:9
|
LL | b'A'..b'Z' if true => 2,
| ^^^^--^^^^
@@ -57,7 +57,7 @@ LL | b'A'..b'Z' if true => 2,
| help: use an inclusive range: `..=`
error: almost complete ascii letter range
- --> $DIR/almost_complete_letter_range.rs:44:9
+ --> $DIR/almost_complete_letter_range.rs:54:9
|
LL | 'a'..'z' if true => 1,
| ^^^--^^^
@@ -65,7 +65,7 @@ LL | 'a'..'z' if true => 1,
| help: use an inclusive range: `..=`
error: almost complete ascii letter range
- --> $DIR/almost_complete_letter_range.rs:45:9
+ --> $DIR/almost_complete_letter_range.rs:55:9
|
LL | 'A'..'Z' if true => 2,
| ^^^--^^^
@@ -73,7 +73,20 @@ LL | 'A'..'Z' if true => 2,
| help: use an inclusive range: `..=`
error: almost complete ascii letter range
- --> $DIR/almost_complete_letter_range.rs:55:9
+ --> $DIR/almost_complete_letter_range.rs:23:17
+ |
+LL | let _ = 'a'..'z';
+ | ^^^--^^^
+ | |
+ | help: use an inclusive range: `..=`
+...
+LL | b!();
+ | ---- in this macro invocation
+ |
+ = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: almost complete ascii letter range
+ --> $DIR/almost_complete_letter_range.rs:68:9
|
LL | 'a'..'z' => 1,
| ^^^--^^^
@@ -81,7 +94,7 @@ LL | 'a'..'z' => 1,
| help: use an inclusive range: `...`
error: almost complete ascii letter range
- --> $DIR/almost_complete_letter_range.rs:62:13
+ --> $DIR/almost_complete_letter_range.rs:75:13
|
LL | let _ = 'a'..'z';
| ^^^--^^^
@@ -89,12 +102,12 @@ LL | let _ = 'a'..'z';
| help: use an inclusive range: `..=`
error: almost complete ascii letter range
- --> $DIR/almost_complete_letter_range.rs:64:9
+ --> $DIR/almost_complete_letter_range.rs:77:9
|
LL | 'a'..'z' => 1,
| ^^^--^^^
| |
| help: use an inclusive range: `..=`
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
diff --git a/src/tools/clippy/tests/ui/approx_const.stderr b/src/tools/clippy/tests/ui/approx_const.stderr
index 4da1b8215..0932a2eec 100644
--- a/src/tools/clippy/tests/ui/approx_const.stderr
+++ b/src/tools/clippy/tests/ui/approx_const.stderr
@@ -4,8 +4,8 @@ error: approximate value of `f{32, 64}::consts::E` found
LL | let my_e = 2.7182;
| ^^^^^^
|
- = note: `-D clippy::approx-constant` implied by `-D warnings`
= help: consider using the constant directly
+ = note: `-D clippy::approx-constant` implied by `-D warnings`
error: approximate value of `f{32, 64}::consts::E` found
--> $DIR/approx_const.rs:5:20
diff --git a/src/tools/clippy/tests/ui/arithmetic.fixed b/src/tools/clippy/tests/ui/arithmetic.fixed
deleted file mode 100644
index a2a1c4394..000000000
--- a/src/tools/clippy/tests/ui/arithmetic.fixed
+++ /dev/null
@@ -1,27 +0,0 @@
-// run-rustfix
-
-#![allow(clippy::unnecessary_owned_empty_strings)]
-#![feature(saturating_int_impl)]
-#![warn(clippy::arithmetic)]
-
-use core::num::{Saturating, Wrapping};
-
-pub fn hard_coded_allowed() {
- let _ = Saturating(0u32) + Saturating(0u32);
- let _ = String::new() + "";
- let _ = Wrapping(0u32) + Wrapping(0u32);
-
- let saturating: Saturating<u32> = Saturating(0u32);
- let string: String = String::new();
- let wrapping: Wrapping<u32> = Wrapping(0u32);
-
- let inferred_saturating = saturating + saturating;
- let inferred_string = string + "";
- let inferred_wrapping = wrapping + wrapping;
-
- let _ = inferred_saturating + inferred_saturating;
- let _ = inferred_string + "";
- let _ = inferred_wrapping + inferred_wrapping;
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/arithmetic.rs b/src/tools/clippy/tests/ui/arithmetic.rs
deleted file mode 100644
index a2a1c4394..000000000
--- a/src/tools/clippy/tests/ui/arithmetic.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-// run-rustfix
-
-#![allow(clippy::unnecessary_owned_empty_strings)]
-#![feature(saturating_int_impl)]
-#![warn(clippy::arithmetic)]
-
-use core::num::{Saturating, Wrapping};
-
-pub fn hard_coded_allowed() {
- let _ = Saturating(0u32) + Saturating(0u32);
- let _ = String::new() + "";
- let _ = Wrapping(0u32) + Wrapping(0u32);
-
- let saturating: Saturating<u32> = Saturating(0u32);
- let string: String = String::new();
- let wrapping: Wrapping<u32> = Wrapping(0u32);
-
- let inferred_saturating = saturating + saturating;
- let inferred_string = string + "";
- let inferred_wrapping = wrapping + wrapping;
-
- let _ = inferred_saturating + inferred_saturating;
- let _ = inferred_string + "";
- let _ = inferred_wrapping + inferred_wrapping;
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
new file mode 100644
index 000000000..b25e68f13
--- /dev/null
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
@@ -0,0 +1,224 @@
+#![allow(
+ clippy::assign_op_pattern,
+ clippy::erasing_op,
+ clippy::identity_op,
+ clippy::op_ref,
+ clippy::unnecessary_owned_empty_strings,
+ arithmetic_overflow,
+ unconditional_panic
+)]
+#![feature(const_mut_refs, inline_const, saturating_int_impl)]
+#![warn(clippy::arithmetic_side_effects)]
+
+use core::num::{Saturating, Wrapping};
+
+pub struct Custom;
+
+macro_rules! impl_arith {
+ ( $( $_trait:ident, $ty:ty, $method:ident; )* ) => {
+ $(
+ impl core::ops::$_trait<$ty> for Custom {
+ type Output = Self;
+ fn $method(self, _: $ty) -> Self::Output { Self }
+ }
+ )*
+ }
+}
+
+impl_arith!(
+ Add, i32, add;
+ Div, i32, div;
+ Mul, i32, mul;
+ Sub, i32, sub;
+
+ Add, f64, add;
+ Div, f64, div;
+ Mul, f64, mul;
+ Sub, f64, sub;
+);
+
+pub fn association_with_structures_should_not_trigger_the_lint() {
+ enum Foo {
+ Bar = -2,
+ }
+
+ impl Trait for Foo {
+ const ASSOC: i32 = {
+ let _: [i32; 1 + 1];
+ fn foo() {}
+ 1 + 1
+ };
+ }
+
+ struct Baz([i32; 1 + 1]);
+
+ trait Trait {
+ const ASSOC: i32 = 1 + 1;
+ }
+
+ type Alias = [i32; 1 + 1];
+
+ union Qux {
+ field: [i32; 1 + 1],
+ }
+
+ let _: [i32; 1 + 1] = [0, 0];
+
+ let _: [i32; 1 + 1] = {
+ let a: [i32; 1 + 1] = [0, 0];
+ a
+ };
+}
+
+pub fn hard_coded_allowed() {
+ let _ = 1f32 + 1f32;
+ let _ = 1f64 + 1f64;
+
+ let _ = Saturating(0u32) + Saturating(0u32);
+ let _ = String::new() + "";
+ let _ = Wrapping(0u32) + Wrapping(0u32);
+
+ let saturating: Saturating<u32> = Saturating(0u32);
+ let string: String = String::new();
+ let wrapping: Wrapping<u32> = Wrapping(0u32);
+
+ let inferred_saturating = saturating + saturating;
+ let inferred_string = string + "";
+ let inferred_wrapping = wrapping + wrapping;
+
+ let _ = inferred_saturating + inferred_saturating;
+ let _ = inferred_string + "";
+ let _ = inferred_wrapping + inferred_wrapping;
+}
+
+#[rustfmt::skip]
+pub fn const_ops_should_not_trigger_the_lint() {
+ const _: i32 = { let mut n = 1; n += 1; n };
+ let _ = const { let mut n = 1; n += 1; n };
+
+ const _: i32 = { let mut n = 1; n = n + 1; n };
+ let _ = const { let mut n = 1; n = n + 1; n };
+
+ const _: i32 = { let mut n = 1; n = 1 + n; n };
+ let _ = const { let mut n = 1; n = 1 + n; n };
+
+ const _: i32 = 1 + 1;
+ let _ = const { 1 + 1 };
+
+ const _: i32 = { let mut n = 1; n = -1; n = -(-1); n = -n; n };
+ let _ = const { let mut n = 1; n = -1; n = -(-1); n = -n; n };
+}
+
+pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_trigger_the_lint() {
+ let mut _n = i32::MAX;
+
+ // Assign
+ _n += 0;
+ _n += &0;
+ _n -= 0;
+ _n -= &0;
+ _n /= 99;
+ _n /= &99;
+ _n %= 99;
+ _n %= &99;
+ _n *= 0;
+ _n *= &0;
+ _n *= 1;
+ _n *= &1;
+
+ // Binary
+ _n = _n + 0;
+ _n = _n + &0;
+ _n = 0 + _n;
+ _n = &0 + _n;
+ _n = _n - 0;
+ _n = _n - &0;
+ _n = 0 - _n;
+ _n = &0 - _n;
+ _n = _n / 99;
+ _n = _n / &99;
+ _n = _n % 99;
+ _n = _n % &99;
+ _n = _n * 0;
+ _n = _n * &0;
+ _n = 0 * _n;
+ _n = &0 * _n;
+ _n = _n * 1;
+ _n = _n * &1;
+ _n = 1 * _n;
+ _n = &1 * _n;
+ _n = 23 + 85;
+
+ // Unary
+ _n = -1;
+ _n = -(-1);
+}
+
+pub fn runtime_ops() {
+ let mut _n = i32::MAX;
+
+ // Assign
+ _n += 1;
+ _n += &1;
+ _n -= 1;
+ _n -= &1;
+ _n /= 0;
+ _n /= &0;
+ _n %= 0;
+ _n %= &0;
+ _n *= 2;
+ _n *= &2;
+
+ // Binary
+ _n = _n + 1;
+ _n = _n + &1;
+ _n = 1 + _n;
+ _n = &1 + _n;
+ _n = _n - 1;
+ _n = _n - &1;
+ _n = 1 - _n;
+ _n = &1 - _n;
+ _n = _n / 0;
+ _n = _n / &0;
+ _n = _n % 0;
+ _n = _n % &0;
+ _n = _n * 2;
+ _n = _n * &2;
+ _n = 2 * _n;
+ _n = &2 * _n;
+ _n = 23 + &85;
+ _n = &23 + 85;
+ _n = &23 + &85;
+
+ // Custom
+ let _ = Custom + 0;
+ let _ = Custom + 1;
+ let _ = Custom + 2;
+ let _ = Custom + 0.0;
+ let _ = Custom + 1.0;
+ let _ = Custom + 2.0;
+ let _ = Custom - 0;
+ let _ = Custom - 1;
+ let _ = Custom - 2;
+ let _ = Custom - 0.0;
+ let _ = Custom - 1.0;
+ let _ = Custom - 2.0;
+ let _ = Custom / 0;
+ let _ = Custom / 1;
+ let _ = Custom / 2;
+ let _ = Custom / 0.0;
+ let _ = Custom / 1.0;
+ let _ = Custom / 2.0;
+ let _ = Custom * 0;
+ let _ = Custom * 1;
+ let _ = Custom * 2;
+ let _ = Custom * 0.0;
+ let _ = Custom * 1.0;
+ let _ = Custom * 2.0;
+
+ // Unary
+ _n = -_n;
+ _n = -&_n;
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
new file mode 100644
index 000000000..0f06e22ba
--- /dev/null
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
@@ -0,0 +1,352 @@
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:78:13
+ |
+LL | let _ = String::new() + "";
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:86:27
+ |
+LL | let inferred_string = string + "";
+ | ^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:90:13
+ |
+LL | let _ = inferred_string + "";
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:161:5
+ |
+LL | _n += 1;
+ | ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:162:5
+ |
+LL | _n += &1;
+ | ^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:163:5
+ |
+LL | _n -= 1;
+ | ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:164:5
+ |
+LL | _n -= &1;
+ | ^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:165:5
+ |
+LL | _n /= 0;
+ | ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:166:5
+ |
+LL | _n /= &0;
+ | ^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:167:5
+ |
+LL | _n %= 0;
+ | ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:168:5
+ |
+LL | _n %= &0;
+ | ^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:169:5
+ |
+LL | _n *= 2;
+ | ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:170:5
+ |
+LL | _n *= &2;
+ | ^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:173:10
+ |
+LL | _n = _n + 1;
+ | ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:174:10
+ |
+LL | _n = _n + &1;
+ | ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:175:10
+ |
+LL | _n = 1 + _n;
+ | ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:176:10
+ |
+LL | _n = &1 + _n;
+ | ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:177:10
+ |
+LL | _n = _n - 1;
+ | ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:178:10
+ |
+LL | _n = _n - &1;
+ | ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:179:10
+ |
+LL | _n = 1 - _n;
+ | ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:180:10
+ |
+LL | _n = &1 - _n;
+ | ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:181:10
+ |
+LL | _n = _n / 0;
+ | ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:182:10
+ |
+LL | _n = _n / &0;
+ | ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:183:10
+ |
+LL | _n = _n % 0;
+ | ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:184:10
+ |
+LL | _n = _n % &0;
+ | ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:185:10
+ |
+LL | _n = _n * 2;
+ | ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:186:10
+ |
+LL | _n = _n * &2;
+ | ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:187:10
+ |
+LL | _n = 2 * _n;
+ | ^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:188:10
+ |
+LL | _n = &2 * _n;
+ | ^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:189:10
+ |
+LL | _n = 23 + &85;
+ | ^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:190:10
+ |
+LL | _n = &23 + 85;
+ | ^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:191:10
+ |
+LL | _n = &23 + &85;
+ | ^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:194:13
+ |
+LL | let _ = Custom + 0;
+ | ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:195:13
+ |
+LL | let _ = Custom + 1;
+ | ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:196:13
+ |
+LL | let _ = Custom + 2;
+ | ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:197:13
+ |
+LL | let _ = Custom + 0.0;
+ | ^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:198:13
+ |
+LL | let _ = Custom + 1.0;
+ | ^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:199:13
+ |
+LL | let _ = Custom + 2.0;
+ | ^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:200:13
+ |
+LL | let _ = Custom - 0;
+ | ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:201:13
+ |
+LL | let _ = Custom - 1;
+ | ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:202:13
+ |
+LL | let _ = Custom - 2;
+ | ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:203:13
+ |
+LL | let _ = Custom - 0.0;
+ | ^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:204:13
+ |
+LL | let _ = Custom - 1.0;
+ | ^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:205:13
+ |
+LL | let _ = Custom - 2.0;
+ | ^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:206:13
+ |
+LL | let _ = Custom / 0;
+ | ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:207:13
+ |
+LL | let _ = Custom / 1;
+ | ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:208:13
+ |
+LL | let _ = Custom / 2;
+ | ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:209:13
+ |
+LL | let _ = Custom / 0.0;
+ | ^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:210:13
+ |
+LL | let _ = Custom / 1.0;
+ | ^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:211:13
+ |
+LL | let _ = Custom / 2.0;
+ | ^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:212:13
+ |
+LL | let _ = Custom * 0;
+ | ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:213:13
+ |
+LL | let _ = Custom * 1;
+ | ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:214:13
+ |
+LL | let _ = Custom * 2;
+ | ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:215:13
+ |
+LL | let _ = Custom * 0.0;
+ | ^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:216:13
+ |
+LL | let _ = Custom * 1.0;
+ | ^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:217:13
+ |
+LL | let _ = Custom * 2.0;
+ | ^^^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:220:10
+ |
+LL | _n = -_n;
+ | ^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+ --> $DIR/arithmetic_side_effects.rs:221:10
+ |
+LL | _n = -&_n;
+ | ^^^^
+
+error: aborting due to 58 previous errors
+
diff --git a/src/tools/clippy/tests/ui/as_conversions.stderr b/src/tools/clippy/tests/ui/as_conversions.stderr
index d11b56171..f5d59e1e5 100644
--- a/src/tools/clippy/tests/ui/as_conversions.stderr
+++ b/src/tools/clippy/tests/ui/as_conversions.stderr
@@ -4,8 +4,8 @@ error: using a potentially dangerous silent `as` conversion
LL | let i = 0u32 as u64;
| ^^^^^^^^^^^
|
- = note: `-D clippy::as-conversions` implied by `-D warnings`
= help: consider using a safe wrapper for this conversion
+ = note: `-D clippy::as-conversions` implied by `-D warnings`
error: using a potentially dangerous silent `as` conversion
--> $DIR/as_conversions.rs:17:13
diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs b/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs
new file mode 100644
index 000000000..0d1d92584
--- /dev/null
+++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs
@@ -0,0 +1,37 @@
+#![allow(unused)]
+#![warn(clippy::as_ptr_cast_mut)]
+#![allow(clippy::wrong_self_convention)]
+
+struct MutPtrWrapper(Vec<u8>);
+impl MutPtrWrapper {
+ fn as_ptr(&mut self) -> *const u8 {
+ self.0.as_mut_ptr() as *const u8
+ }
+}
+
+struct Covariant<T>(*const T);
+impl<T> Covariant<T> {
+ fn as_ptr(self) -> *const T {
+ self.0
+ }
+}
+
+fn main() {
+ let mut string = String::new();
+ let _ = string.as_ptr() as *mut u8;
+ let _: *mut i8 = string.as_ptr() as *mut _;
+ let _ = string.as_ptr() as *const i8;
+ let _ = string.as_mut_ptr();
+ let _ = string.as_mut_ptr() as *mut u8;
+ let _ = string.as_mut_ptr() as *const u8;
+
+ let nn = std::ptr::NonNull::new(4 as *mut u8).unwrap();
+ let _ = nn.as_ptr() as *mut u8;
+
+ let mut wrap = MutPtrWrapper(Vec::new());
+ let _ = wrap.as_ptr() as *mut u8;
+
+ let mut local = 4;
+ let ref_with_write_perm = Covariant(std::ptr::addr_of_mut!(local) as *const _);
+ let _ = ref_with_write_perm.as_ptr() as *mut u8;
+}
diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr b/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr
new file mode 100644
index 000000000..2189c3d2f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr
@@ -0,0 +1,16 @@
+error: casting the result of `as_ptr` to *mut u8
+ --> $DIR/as_ptr_cast_mut.rs:21:13
+ |
+LL | let _ = string.as_ptr() as *mut u8;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()`
+ |
+ = note: `-D clippy::as-ptr-cast-mut` implied by `-D warnings`
+
+error: casting the result of `as_ptr` to *mut i8
+ --> $DIR/as_ptr_cast_mut.rs:22:22
+ |
+LL | let _: *mut i8 = string.as_ptr() as *mut _;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/asm_syntax.stderr b/src/tools/clippy/tests/ui/asm_syntax.stderr
index e9b150121..9c7c3ba7d 100644
--- a/src/tools/clippy/tests/ui/asm_syntax.stderr
+++ b/src/tools/clippy/tests/ui/asm_syntax.stderr
@@ -4,8 +4,8 @@ error: Intel x86 assembly syntax used
LL | asm!("");
| ^^^^^^^^
|
- = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings`
= help: use AT&T x86 assembly syntax
+ = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings`
error: Intel x86 assembly syntax used
--> $DIR/asm_syntax.rs:9:9
@@ -29,8 +29,8 @@ error: AT&T x86 assembly syntax used
LL | asm!("", options(att_syntax));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings`
= help: use Intel x86 assembly syntax
+ = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings`
error: AT&T x86 assembly syntax used
--> $DIR/asm_syntax.rs:24:9
diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.stderr b/src/tools/clippy/tests/ui/assertions_on_constants.stderr
index e1f818814..29fe00903 100644
--- a/src/tools/clippy/tests/ui/assertions_on_constants.stderr
+++ b/src/tools/clippy/tests/ui/assertions_on_constants.stderr
@@ -4,8 +4,8 @@ error: `assert!(true)` will be optimized out by the compiler
LL | assert!(true);
| ^^^^^^^^^^^^^
|
- = note: `-D clippy::assertions-on-constants` implied by `-D warnings`
= help: remove it
+ = note: `-D clippy::assertions-on-constants` implied by `-D warnings`
error: `assert!(false)` should probably be replaced
--> $DIR/assertions_on_constants.rs:11:5
diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed
index 7bde72e4b..2bb755290 100644
--- a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed
+++ b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed
@@ -27,6 +27,14 @@ fn main() {
let r: Result<Foo, Foo> = Ok(Foo);
assert!(r.is_ok());
+ // test ok with some messages
+ let r: Result<Foo, DebugFoo> = Ok(Foo);
+ assert!(r.is_ok(), "oops");
+
+ // test ok with unit error
+ let r: Result<Foo, ()> = Ok(Foo);
+ assert!(r.is_ok());
+
// test temporary ok
fn get_ok() -> Result<Foo, DebugFoo> {
Ok(Foo)
@@ -67,3 +75,9 @@ fn main() {
let r: Result<Foo, Foo> = Err(Foo);
assert!(r.is_err());
}
+
+#[allow(dead_code)]
+fn issue9450() {
+ let res: Result<i32, i32> = Ok(1);
+ res.unwrap_err();
+}
diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.rs b/src/tools/clippy/tests/ui/assertions_on_result_states.rs
index 4c5af81ef..d8a9bd2f1 100644
--- a/src/tools/clippy/tests/ui/assertions_on_result_states.rs
+++ b/src/tools/clippy/tests/ui/assertions_on_result_states.rs
@@ -27,6 +27,14 @@ fn main() {
let r: Result<Foo, Foo> = Ok(Foo);
assert!(r.is_ok());
+ // test ok with some messages
+ let r: Result<Foo, DebugFoo> = Ok(Foo);
+ assert!(r.is_ok(), "oops");
+
+ // test ok with unit error
+ let r: Result<Foo, ()> = Ok(Foo);
+ assert!(r.is_ok());
+
// test temporary ok
fn get_ok() -> Result<Foo, DebugFoo> {
Ok(Foo)
@@ -67,3 +75,9 @@ fn main() {
let r: Result<Foo, Foo> = Err(Foo);
assert!(r.is_err());
}
+
+#[allow(dead_code)]
+fn issue9450() {
+ let res: Result<i32, i32> = Ok(1);
+ assert!(res.is_err())
+}
diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr
index 13c2dd877..298d63c9c 100644
--- a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr
+++ b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr
@@ -7,34 +7,40 @@ LL | assert!(r.is_ok());
= note: `-D clippy::assertions-on-result-states` implied by `-D warnings`
error: called `assert!` with `Result::is_ok`
- --> $DIR/assertions_on_result_states.rs:34:5
+ --> $DIR/assertions_on_result_states.rs:42:5
|
LL | assert!(get_ok().is_ok());
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok().unwrap()`
error: called `assert!` with `Result::is_ok`
- --> $DIR/assertions_on_result_states.rs:37:5
+ --> $DIR/assertions_on_result_states.rs:45:5
|
LL | assert!(get_ok_macro!().is_ok());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok_macro!().unwrap()`
error: called `assert!` with `Result::is_ok`
- --> $DIR/assertions_on_result_states.rs:50:5
+ --> $DIR/assertions_on_result_states.rs:58:5
|
LL | assert!(r.is_ok());
| ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()`
error: called `assert!` with `Result::is_ok`
- --> $DIR/assertions_on_result_states.rs:56:9
+ --> $DIR/assertions_on_result_states.rs:64:9
|
LL | assert!(r.is_ok());
| ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()`
error: called `assert!` with `Result::is_err`
- --> $DIR/assertions_on_result_states.rs:64:5
+ --> $DIR/assertions_on_result_states.rs:72:5
|
LL | assert!(r.is_err());
| ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()`
-error: aborting due to 6 previous errors
+error: called `assert!` with `Result::is_err`
+ --> $DIR/assertions_on_result_states.rs:82:5
+ |
+LL | assert!(res.is_err())
+ | ^^^^^^^^^^^^^^^^^^^^^ help: replace with: `res.unwrap_err();`
+
+error: aborting due to 7 previous errors
diff --git a/src/tools/clippy/tests/ui/assign_ops2.rs b/src/tools/clippy/tests/ui/assign_ops2.rs
index f6d3a8fa3..2c876a96c 100644
--- a/src/tools/clippy/tests/ui/assign_ops2.rs
+++ b/src/tools/clippy/tests/ui/assign_ops2.rs
@@ -1,3 +1,5 @@
+#![allow(clippy::uninlined_format_args)]
+
#[allow(unused_assignments)]
#[warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)]
fn main() {
diff --git a/src/tools/clippy/tests/ui/assign_ops2.stderr b/src/tools/clippy/tests/ui/assign_ops2.stderr
index 04b1dc93d..25e746022 100644
--- a/src/tools/clippy/tests/ui/assign_ops2.stderr
+++ b/src/tools/clippy/tests/ui/assign_ops2.stderr
@@ -1,5 +1,5 @@
error: variable appears on both sides of an assignment operation
- --> $DIR/assign_ops2.rs:5:5
+ --> $DIR/assign_ops2.rs:7:5
|
LL | a += a + 1;
| ^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | a = a + a + 1;
| ~~~~~~~~~~~~~
error: variable appears on both sides of an assignment operation
- --> $DIR/assign_ops2.rs:6:5
+ --> $DIR/assign_ops2.rs:8:5
|
LL | a += 1 + a;
| ^^^^^^^^^^
@@ -30,7 +30,7 @@ LL | a = a + 1 + a;
| ~~~~~~~~~~~~~
error: variable appears on both sides of an assignment operation
- --> $DIR/assign_ops2.rs:7:5
+ --> $DIR/assign_ops2.rs:9:5
|
LL | a -= a - 1;
| ^^^^^^^^^^
@@ -45,7 +45,7 @@ LL | a = a - (a - 1);
| ~~~~~~~~~~~~~~~
error: variable appears on both sides of an assignment operation
- --> $DIR/assign_ops2.rs:8:5
+ --> $DIR/assign_ops2.rs:10:5
|
LL | a *= a * 99;
| ^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL | a = a * a * 99;
| ~~~~~~~~~~~~~~
error: variable appears on both sides of an assignment operation
- --> $DIR/assign_ops2.rs:9:5
+ --> $DIR/assign_ops2.rs:11:5
|
LL | a *= 42 * a;
| ^^^^^^^^^^^
@@ -75,7 +75,7 @@ LL | a = a * 42 * a;
| ~~~~~~~~~~~~~~
error: variable appears on both sides of an assignment operation
- --> $DIR/assign_ops2.rs:10:5
+ --> $DIR/assign_ops2.rs:12:5
|
LL | a /= a / 2;
| ^^^^^^^^^^
@@ -90,7 +90,7 @@ LL | a = a / (a / 2);
| ~~~~~~~~~~~~~~~
error: variable appears on both sides of an assignment operation
- --> $DIR/assign_ops2.rs:11:5
+ --> $DIR/assign_ops2.rs:13:5
|
LL | a %= a % 5;
| ^^^^^^^^^^
@@ -105,7 +105,7 @@ LL | a = a % (a % 5);
| ~~~~~~~~~~~~~~~
error: variable appears on both sides of an assignment operation
- --> $DIR/assign_ops2.rs:12:5
+ --> $DIR/assign_ops2.rs:14:5
|
LL | a &= a & 1;
| ^^^^^^^^^^
@@ -120,7 +120,7 @@ LL | a = a & a & 1;
| ~~~~~~~~~~~~~
error: variable appears on both sides of an assignment operation
- --> $DIR/assign_ops2.rs:13:5
+ --> $DIR/assign_ops2.rs:15:5
|
LL | a *= a * a;
| ^^^^^^^^^^
@@ -135,7 +135,7 @@ LL | a = a * a * a;
| ~~~~~~~~~~~~~
error: manual implementation of an assign operation
- --> $DIR/assign_ops2.rs:50:5
+ --> $DIR/assign_ops2.rs:52:5
|
LL | buf = buf + cows.clone();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()`
diff --git a/src/tools/clippy/tests/ui/author.stdout b/src/tools/clippy/tests/ui/author.stdout
index 312586303..27ad538f2 100644
--- a/src/tools/clippy/tests/ui/author.stdout
+++ b/src/tools/clippy/tests/ui/author.stdout
@@ -1,14 +1,12 @@
-if_chain! {
- if let StmtKind::Local(local) = stmt.kind;
- if let Some(init) = local.init;
- if let ExprKind::Cast(expr, cast_ty) = init.kind;
- if let TyKind::Path(ref qpath) = cast_ty.kind;
- if match_qpath(qpath, &["char"]);
- if let ExprKind::Lit(ref lit) = expr.kind;
- if let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node;
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
- if name.as_str() == "x";
- then {
- // report your lint here
- }
+if let StmtKind::Local(local) = stmt.kind
+ && let Some(init) = local.init
+ && let ExprKind::Cast(expr, cast_ty) = init.kind
+ && let TyKind::Path(ref qpath) = cast_ty.kind
+ && match_qpath(qpath, &["char"])
+ && let ExprKind::Lit(ref lit) = expr.kind
+ && let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node
+ && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind
+ && name.as_str() == "x"
+{
+ // report your lint here
}
diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout
index 2fc4a7d1f..9de0550d8 100644
--- a/src/tools/clippy/tests/ui/author/blocks.stdout
+++ b/src/tools/clippy/tests/ui/author/blocks.stdout
@@ -1,64 +1,58 @@
-if_chain! {
- if let ExprKind::Block(block, None) = expr.kind;
- if block.stmts.len() == 3;
- if let StmtKind::Local(local) = block.stmts[0].kind;
- if let Some(init) = local.init;
- if let ExprKind::Lit(ref lit) = init.kind;
- if let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node;
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
- if name.as_str() == "x";
- if let StmtKind::Local(local1) = block.stmts[1].kind;
- if let Some(init1) = local1.init;
- if let ExprKind::Lit(ref lit1) = init1.kind;
- if let LitKind::Float(_, LitFloatType::Suffixed(FloatTy::F32)) = lit1.node;
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local1.pat.kind;
- if name1.as_str() == "_t";
- if let StmtKind::Semi(e) = block.stmts[2].kind;
- if let ExprKind::Unary(UnOp::Neg, inner) = e.kind;
- if let ExprKind::Path(ref qpath) = inner.kind;
- if match_qpath(qpath, &["x"]);
- if block.expr.is_none();
- then {
- // report your lint here
- }
+if let ExprKind::Block(block, None) = expr.kind
+ && block.stmts.len() == 3
+ && let StmtKind::Local(local) = block.stmts[0].kind
+ && let Some(init) = local.init
+ && let ExprKind::Lit(ref lit) = init.kind
+ && let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node
+ && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind
+ && name.as_str() == "x"
+ && let StmtKind::Local(local1) = block.stmts[1].kind
+ && let Some(init1) = local1.init
+ && let ExprKind::Lit(ref lit1) = init1.kind
+ && let LitKind::Float(_, LitFloatType::Suffixed(FloatTy::F32)) = lit1.node
+ && let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local1.pat.kind
+ && name1.as_str() == "_t"
+ && let StmtKind::Semi(e) = block.stmts[2].kind
+ && let ExprKind::Unary(UnOp::Neg, inner) = e.kind
+ && let ExprKind::Path(ref qpath) = inner.kind
+ && match_qpath(qpath, &["x"])
+ && block.expr.is_none()
+{
+ // report your lint here
}
-if_chain! {
- if let ExprKind::Block(block, None) = expr.kind;
- if block.stmts.len() == 1;
- if let StmtKind::Local(local) = block.stmts[0].kind;
- if let Some(init) = local.init;
- if let ExprKind::Call(func, args) = init.kind;
- if let ExprKind::Path(ref qpath) = func.kind;
- if match_qpath(qpath, &["String", "new"]);
- if args.is_empty();
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
- if name.as_str() == "expr";
- if let Some(trailing_expr) = block.expr;
- if let ExprKind::Call(func1, args1) = trailing_expr.kind;
- if let ExprKind::Path(ref qpath1) = func1.kind;
- if match_qpath(qpath1, &["drop"]);
- if args1.len() == 1;
- if let ExprKind::Path(ref qpath2) = args1[0].kind;
- if match_qpath(qpath2, &["expr"]);
- then {
- // report your lint here
- }
+if let ExprKind::Block(block, None) = expr.kind
+ && block.stmts.len() == 1
+ && let StmtKind::Local(local) = block.stmts[0].kind
+ && let Some(init) = local.init
+ && let ExprKind::Call(func, args) = init.kind
+ && let ExprKind::Path(ref qpath) = func.kind
+ && match_qpath(qpath, &["String", "new"])
+ && args.is_empty()
+ && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind
+ && name.as_str() == "expr"
+ && let Some(trailing_expr) = block.expr
+ && let ExprKind::Call(func1, args1) = trailing_expr.kind
+ && let ExprKind::Path(ref qpath1) = func1.kind
+ && match_qpath(qpath1, &["drop"])
+ && args1.len() == 1
+ && let ExprKind::Path(ref qpath2) = args1[0].kind
+ && match_qpath(qpath2, &["expr"])
+{
+ // report your lint here
}
-if_chain! {
- if let ExprKind::Closure(CaptureBy::Value, fn_decl, body_id, _, None) = expr.kind;
- if let FnRetTy::DefaultReturn(_) = fn_decl.output;
- let expr1 = &cx.tcx.hir().body(body_id).value;
- if let ExprKind::Call(func, args) = expr1.kind;
- if let ExprKind::Path(ref qpath) = func.kind;
- if matches!(qpath, QPath::LangItem(LangItem::FromGenerator, _));
- if args.len() == 1;
- if let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = args[0].kind;
- if let FnRetTy::DefaultReturn(_) = fn_decl1.output;
- let expr2 = &cx.tcx.hir().body(body_id1).value;
- if let ExprKind::Block(block, None) = expr2.kind;
- if block.stmts.is_empty();
- if block.expr.is_none();
- then {
- // report your lint here
- }
+if let ExprKind::Closure(CaptureBy::Value, fn_decl, body_id, _, None) = expr.kind
+ && let FnRetTy::DefaultReturn(_) = fn_decl.output
+ && expr1 = &cx.tcx.hir().body(body_id).value
+ && let ExprKind::Call(func, args) = expr1.kind
+ && let ExprKind::Path(ref qpath) = func.kind
+ && matches!(qpath, QPath::LangItem(LangItem::FromGenerator, _))
+ && args.len() == 1
+ && let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = args[0].kind
+ && let FnRetTy::DefaultReturn(_) = fn_decl1.output
+ && expr2 = &cx.tcx.hir().body(body_id1).value
+ && let ExprKind::Block(block, None) = expr2.kind
+ && block.stmts.is_empty()
+ && block.expr.is_none()
+{
+ // report your lint here
}
diff --git a/src/tools/clippy/tests/ui/author/call.stdout b/src/tools/clippy/tests/ui/author/call.stdout
index 266312d63..f040f6330 100644
--- a/src/tools/clippy/tests/ui/author/call.stdout
+++ b/src/tools/clippy/tests/ui/author/call.stdout
@@ -1,16 +1,14 @@
-if_chain! {
- if let StmtKind::Local(local) = stmt.kind;
- if let Some(init) = local.init;
- if let ExprKind::Call(func, args) = init.kind;
- if let ExprKind::Path(ref qpath) = func.kind;
- if match_qpath(qpath, &["{{root}}", "std", "cmp", "min"]);
- if args.len() == 2;
- if let ExprKind::Lit(ref lit) = args[0].kind;
- if let LitKind::Int(3, LitIntType::Unsuffixed) = lit.node;
- if let ExprKind::Lit(ref lit1) = args[1].kind;
- if let LitKind::Int(4, LitIntType::Unsuffixed) = lit1.node;
- if let PatKind::Wild = local.pat.kind;
- then {
- // report your lint here
- }
+if let StmtKind::Local(local) = stmt.kind
+ && let Some(init) = local.init
+ && let ExprKind::Call(func, args) = init.kind
+ && let ExprKind::Path(ref qpath) = func.kind
+ && match_qpath(qpath, &["{{root}}", "std", "cmp", "min"])
+ && args.len() == 2
+ && let ExprKind::Lit(ref lit) = args[0].kind
+ && let LitKind::Int(3, LitIntType::Unsuffixed) = lit.node
+ && let ExprKind::Lit(ref lit1) = args[1].kind
+ && let LitKind::Int(4, LitIntType::Unsuffixed) = lit1.node
+ && let PatKind::Wild = local.pat.kind
+{
+ // report your lint here
}
diff --git a/src/tools/clippy/tests/ui/author/if.stdout b/src/tools/clippy/tests/ui/author/if.stdout
index 8d92849b3..5d7961882 100644
--- a/src/tools/clippy/tests/ui/author/if.stdout
+++ b/src/tools/clippy/tests/ui/author/if.stdout
@@ -1,50 +1,46 @@
-if_chain! {
- if let StmtKind::Local(local) = stmt.kind;
- if let Some(init) = local.init;
- if let ExprKind::If(cond, then, Some(else_expr)) = init.kind;
- if let ExprKind::DropTemps(expr) = cond.kind;
- if let ExprKind::Lit(ref lit) = expr.kind;
- if let LitKind::Bool(true) = lit.node;
- if let ExprKind::Block(block, None) = then.kind;
- if block.stmts.len() == 1;
- if let StmtKind::Semi(e) = block.stmts[0].kind;
- if let ExprKind::Binary(op, left, right) = e.kind;
- if BinOpKind::Eq == op.node;
- if let ExprKind::Lit(ref lit1) = left.kind;
- if let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node;
- if let ExprKind::Lit(ref lit2) = right.kind;
- if let LitKind::Int(1, LitIntType::Unsuffixed) = lit2.node;
- if block.expr.is_none();
- if let ExprKind::Block(block1, None) = else_expr.kind;
- if block1.stmts.len() == 1;
- if let StmtKind::Semi(e1) = block1.stmts[0].kind;
- if let ExprKind::Binary(op1, left1, right1) = e1.kind;
- if BinOpKind::Eq == op1.node;
- if let ExprKind::Lit(ref lit3) = left1.kind;
- if let LitKind::Int(2, LitIntType::Unsuffixed) = lit3.node;
- if let ExprKind::Lit(ref lit4) = right1.kind;
- if let LitKind::Int(2, LitIntType::Unsuffixed) = lit4.node;
- if block1.expr.is_none();
- if let PatKind::Wild = local.pat.kind;
- then {
- // report your lint here
- }
+if let StmtKind::Local(local) = stmt.kind
+ && let Some(init) = local.init
+ && let ExprKind::If(cond, then, Some(else_expr)) = init.kind
+ && let ExprKind::DropTemps(expr) = cond.kind
+ && let ExprKind::Lit(ref lit) = expr.kind
+ && let LitKind::Bool(true) = lit.node
+ && let ExprKind::Block(block, None) = then.kind
+ && block.stmts.len() == 1
+ && let StmtKind::Semi(e) = block.stmts[0].kind
+ && let ExprKind::Binary(op, left, right) = e.kind
+ && BinOpKind::Eq == op.node
+ && let ExprKind::Lit(ref lit1) = left.kind
+ && let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node
+ && let ExprKind::Lit(ref lit2) = right.kind
+ && let LitKind::Int(1, LitIntType::Unsuffixed) = lit2.node
+ && block.expr.is_none()
+ && let ExprKind::Block(block1, None) = else_expr.kind
+ && block1.stmts.len() == 1
+ && let StmtKind::Semi(e1) = block1.stmts[0].kind
+ && let ExprKind::Binary(op1, left1, right1) = e1.kind
+ && BinOpKind::Eq == op1.node
+ && let ExprKind::Lit(ref lit3) = left1.kind
+ && let LitKind::Int(2, LitIntType::Unsuffixed) = lit3.node
+ && let ExprKind::Lit(ref lit4) = right1.kind
+ && let LitKind::Int(2, LitIntType::Unsuffixed) = lit4.node
+ && block1.expr.is_none()
+ && let PatKind::Wild = local.pat.kind
+{
+ // report your lint here
}
-if_chain! {
- if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind;
- if let ExprKind::Let(let_expr) = cond.kind;
- if let PatKind::Lit(lit_expr) = let_expr.pat.kind;
- if let ExprKind::Lit(ref lit) = lit_expr.kind;
- if let LitKind::Bool(true) = lit.node;
- if let ExprKind::Path(ref qpath) = let_expr.init.kind;
- if match_qpath(qpath, &["a"]);
- if let ExprKind::Block(block, None) = then.kind;
- if block.stmts.is_empty();
- if block.expr.is_none();
- if let ExprKind::Block(block1, None) = else_expr.kind;
- if block1.stmts.is_empty();
- if block1.expr.is_none();
- then {
- // report your lint here
- }
+if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind
+ && let ExprKind::Let(let_expr) = cond.kind
+ && let PatKind::Lit(lit_expr) = let_expr.pat.kind
+ && let ExprKind::Lit(ref lit) = lit_expr.kind
+ && let LitKind::Bool(true) = lit.node
+ && let ExprKind::Path(ref qpath) = let_expr.init.kind
+ && match_qpath(qpath, &["a"])
+ && let ExprKind::Block(block, None) = then.kind
+ && block.stmts.is_empty()
+ && block.expr.is_none()
+ && let ExprKind::Block(block1, None) = else_expr.kind
+ && block1.stmts.is_empty()
+ && block1.expr.is_none()
+{
+ // report your lint here
}
diff --git a/src/tools/clippy/tests/ui/author/issue_3849.stdout b/src/tools/clippy/tests/ui/author/issue_3849.stdout
index bce4bc702..32a3127b8 100644
--- a/src/tools/clippy/tests/ui/author/issue_3849.stdout
+++ b/src/tools/clippy/tests/ui/author/issue_3849.stdout
@@ -1,14 +1,12 @@
-if_chain! {
- if let StmtKind::Local(local) = stmt.kind;
- if let Some(init) = local.init;
- if let ExprKind::Call(func, args) = init.kind;
- if let ExprKind::Path(ref qpath) = func.kind;
- if match_qpath(qpath, &["std", "mem", "transmute"]);
- if args.len() == 1;
- if let ExprKind::Path(ref qpath1) = args[0].kind;
- if match_qpath(qpath1, &["ZPTR"]);
- if let PatKind::Wild = local.pat.kind;
- then {
- // report your lint here
- }
+if let StmtKind::Local(local) = stmt.kind
+ && let Some(init) = local.init
+ && let ExprKind::Call(func, args) = init.kind
+ && let ExprKind::Path(ref qpath) = func.kind
+ && match_qpath(qpath, &["std", "mem", "transmute"])
+ && args.len() == 1
+ && let ExprKind::Path(ref qpath1) = args[0].kind
+ && match_qpath(qpath1, &["ZPTR"])
+ && let PatKind::Wild = local.pat.kind
+{
+ // report your lint here
}
diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui/author/loop.stdout
index 3d9560f69..94a6436ed 100644
--- a/src/tools/clippy/tests/ui/author/loop.stdout
+++ b/src/tools/clippy/tests/ui/author/loop.stdout
@@ -1,113 +1,101 @@
-if_chain! {
- if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr);
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = pat.kind;
- if name.as_str() == "y";
- if let ExprKind::Struct(qpath, fields, None) = arg.kind;
- if matches!(qpath, QPath::LangItem(LangItem::Range, _));
- if fields.len() == 2;
- if fields[0].ident.as_str() == "start";
- if let ExprKind::Lit(ref lit) = fields[0].expr.kind;
- if let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node;
- if fields[1].ident.as_str() == "end";
- if let ExprKind::Lit(ref lit1) = fields[1].expr.kind;
- if let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node;
- if let ExprKind::Block(block, None) = body.kind;
- if block.stmts.len() == 1;
- if let StmtKind::Local(local) = block.stmts[0].kind;
- if let Some(init) = local.init;
- if let ExprKind::Path(ref qpath1) = init.kind;
- if match_qpath(qpath1, &["y"]);
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind;
- if name1.as_str() == "z";
- if block.expr.is_none();
- then {
- // report your lint here
- }
+if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr)
+ && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = pat.kind
+ && name.as_str() == "y"
+ && let ExprKind::Struct(qpath, fields, None) = arg.kind
+ && matches!(qpath, QPath::LangItem(LangItem::Range, _))
+ && fields.len() == 2
+ && fields[0].ident.as_str() == "start"
+ && let ExprKind::Lit(ref lit) = fields[0].expr.kind
+ && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
+ && fields[1].ident.as_str() == "end"
+ && let ExprKind::Lit(ref lit1) = fields[1].expr.kind
+ && let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node
+ && let ExprKind::Block(block, None) = body.kind
+ && block.stmts.len() == 1
+ && let StmtKind::Local(local) = block.stmts[0].kind
+ && let Some(init) = local.init
+ && let ExprKind::Path(ref qpath1) = init.kind
+ && match_qpath(qpath1, &["y"])
+ && let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind
+ && name1.as_str() == "z"
+ && block.expr.is_none()
+{
+ // report your lint here
}
-if_chain! {
- if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr);
- if let PatKind::Wild = pat.kind;
- if let ExprKind::Struct(qpath, fields, None) = arg.kind;
- if matches!(qpath, QPath::LangItem(LangItem::Range, _));
- if fields.len() == 2;
- if fields[0].ident.as_str() == "start";
- if let ExprKind::Lit(ref lit) = fields[0].expr.kind;
- if let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node;
- if fields[1].ident.as_str() == "end";
- if let ExprKind::Lit(ref lit1) = fields[1].expr.kind;
- if let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node;
- if let ExprKind::Block(block, None) = body.kind;
- if block.stmts.len() == 1;
- if let StmtKind::Semi(e) = block.stmts[0].kind;
- if let ExprKind::Break(destination, None) = e.kind;
- if destination.label.is_none();
- if block.expr.is_none();
- then {
- // report your lint here
- }
+if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr)
+ && let PatKind::Wild = pat.kind
+ && let ExprKind::Struct(qpath, fields, None) = arg.kind
+ && matches!(qpath, QPath::LangItem(LangItem::Range, _))
+ && fields.len() == 2
+ && fields[0].ident.as_str() == "start"
+ && let ExprKind::Lit(ref lit) = fields[0].expr.kind
+ && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
+ && fields[1].ident.as_str() == "end"
+ && let ExprKind::Lit(ref lit1) = fields[1].expr.kind
+ && let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node
+ && let ExprKind::Block(block, None) = body.kind
+ && block.stmts.len() == 1
+ && let StmtKind::Semi(e) = block.stmts[0].kind
+ && let ExprKind::Break(destination, None) = e.kind
+ && destination.label.is_none()
+ && block.expr.is_none()
+{
+ // report your lint here
}
-if_chain! {
- if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr);
- if let PatKind::Wild = pat.kind;
- if let ExprKind::Struct(qpath, fields, None) = arg.kind;
- if matches!(qpath, QPath::LangItem(LangItem::Range, _));
- if fields.len() == 2;
- if fields[0].ident.as_str() == "start";
- if let ExprKind::Lit(ref lit) = fields[0].expr.kind;
- if let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node;
- if fields[1].ident.as_str() == "end";
- if let ExprKind::Lit(ref lit1) = fields[1].expr.kind;
- if let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node;
- if let ExprKind::Block(block, None) = body.kind;
- if block.stmts.len() == 1;
- if let StmtKind::Semi(e) = block.stmts[0].kind;
- if let ExprKind::Break(destination, None) = e.kind;
- if let Some(label) = destination.label;
- if label.ident.as_str() == "'label";
- if block.expr.is_none();
- then {
- // report your lint here
- }
+if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr)
+ && let PatKind::Wild = pat.kind
+ && let ExprKind::Struct(qpath, fields, None) = arg.kind
+ && matches!(qpath, QPath::LangItem(LangItem::Range, _))
+ && fields.len() == 2
+ && fields[0].ident.as_str() == "start"
+ && let ExprKind::Lit(ref lit) = fields[0].expr.kind
+ && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
+ && fields[1].ident.as_str() == "end"
+ && let ExprKind::Lit(ref lit1) = fields[1].expr.kind
+ && let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node
+ && let ExprKind::Block(block, None) = body.kind
+ && block.stmts.len() == 1
+ && let StmtKind::Semi(e) = block.stmts[0].kind
+ && let ExprKind::Break(destination, None) = e.kind
+ && let Some(label) = destination.label
+ && label.ident.as_str() == "'label"
+ && block.expr.is_none()
+{
+ // report your lint here
}
-if_chain! {
- if let Some(higher::While { condition: condition, body: body }) = higher::While::hir(expr);
- if let ExprKind::Path(ref qpath) = condition.kind;
- if match_qpath(qpath, &["a"]);
- if let ExprKind::Block(block, None) = body.kind;
- if block.stmts.len() == 1;
- if let StmtKind::Semi(e) = block.stmts[0].kind;
- if let ExprKind::Break(destination, None) = e.kind;
- if destination.label.is_none();
- if block.expr.is_none();
- then {
- // report your lint here
- }
+if let Some(higher::While { condition: condition, body: body }) = higher::While::hir(expr)
+ && let ExprKind::Path(ref qpath) = condition.kind
+ && match_qpath(qpath, &["a"])
+ && let ExprKind::Block(block, None) = body.kind
+ && block.stmts.len() == 1
+ && let StmtKind::Semi(e) = block.stmts[0].kind
+ && let ExprKind::Break(destination, None) = e.kind
+ && destination.label.is_none()
+ && block.expr.is_none()
+{
+ // report your lint here
}
-if_chain! {
- if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr);
- if let PatKind::Lit(lit_expr) = let_pat.kind;
- if let ExprKind::Lit(ref lit) = lit_expr.kind;
- if let LitKind::Bool(true) = lit.node;
- if let ExprKind::Path(ref qpath) = let_expr.kind;
- if match_qpath(qpath, &["a"]);
- if let ExprKind::Block(block, None) = if_then.kind;
- if block.stmts.len() == 1;
- if let StmtKind::Semi(e) = block.stmts[0].kind;
- if let ExprKind::Break(destination, None) = e.kind;
- if destination.label.is_none();
- if block.expr.is_none();
- then {
- // report your lint here
- }
+if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr)
+ && let PatKind::Lit(lit_expr) = let_pat.kind
+ && let ExprKind::Lit(ref lit) = lit_expr.kind
+ && let LitKind::Bool(true) = lit.node
+ && let ExprKind::Path(ref qpath) = let_expr.kind
+ && match_qpath(qpath, &["a"])
+ && let ExprKind::Block(block, None) = if_then.kind
+ && block.stmts.len() == 1
+ && let StmtKind::Semi(e) = block.stmts[0].kind
+ && let ExprKind::Break(destination, None) = e.kind
+ && destination.label.is_none()
+ && block.expr.is_none()
+{
+ // report your lint here
}
-if_chain! {
- if let ExprKind::Loop(body, None, LoopSource::Loop, _) = expr.kind;
- if body.stmts.len() == 1;
- if let StmtKind::Semi(e) = body.stmts[0].kind;
- if let ExprKind::Break(destination, None) = e.kind;
- if destination.label.is_none();
- if body.expr.is_none();
- then {
- // report your lint here
- }
+if let ExprKind::Loop(body, None, LoopSource::Loop, _) = expr.kind
+ && body.stmts.len() == 1
+ && let StmtKind::Semi(e) = body.stmts[0].kind
+ && let ExprKind::Break(destination, None) = e.kind
+ && destination.label.is_none()
+ && body.expr.is_none()
+{
+ // report your lint here
}
diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui/author/matches.stdout
index 38444a009..88e2ca656 100644
--- a/src/tools/clippy/tests/ui/author/matches.stdout
+++ b/src/tools/clippy/tests/ui/author/matches.stdout
@@ -1,38 +1,36 @@
-if_chain! {
- if let StmtKind::Local(local) = stmt.kind;
- if let Some(init) = local.init;
- if let ExprKind::Match(scrutinee, arms, MatchSource::Normal) = init.kind;
- if let ExprKind::Lit(ref lit) = scrutinee.kind;
- if let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node;
- if arms.len() == 3;
- if let PatKind::Lit(lit_expr) = arms[0].pat.kind;
- if let ExprKind::Lit(ref lit1) = lit_expr.kind;
- if let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node;
- if arms[0].guard.is_none();
- if let ExprKind::Lit(ref lit2) = arms[0].body.kind;
- if let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node;
- if let PatKind::Lit(lit_expr1) = arms[1].pat.kind;
- if let ExprKind::Lit(ref lit3) = lit_expr1.kind;
- if let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node;
- if arms[1].guard.is_none();
- if let ExprKind::Block(block, None) = arms[1].body.kind;
- if block.stmts.len() == 1;
- if let StmtKind::Local(local1) = block.stmts[0].kind;
- if let Some(init1) = local1.init;
- if let ExprKind::Lit(ref lit4) = init1.kind;
- if let LitKind::Int(3, LitIntType::Unsuffixed) = lit4.node;
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local1.pat.kind;
- if name.as_str() == "x";
- if let Some(trailing_expr) = block.expr;
- if let ExprKind::Path(ref qpath) = trailing_expr.kind;
- if match_qpath(qpath, &["x"]);
- if let PatKind::Wild = arms[2].pat.kind;
- if arms[2].guard.is_none();
- if let ExprKind::Lit(ref lit5) = arms[2].body.kind;
- if let LitKind::Int(1, LitIntType::Unsuffixed) = lit5.node;
- if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind;
- if name1.as_str() == "a";
- then {
- // report your lint here
- }
+if let StmtKind::Local(local) = stmt.kind
+ && let Some(init) = local.init
+ && let ExprKind::Match(scrutinee, arms, MatchSource::Normal) = init.kind
+ && let ExprKind::Lit(ref lit) = scrutinee.kind
+ && let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node
+ && arms.len() == 3
+ && let PatKind::Lit(lit_expr) = arms[0].pat.kind
+ && let ExprKind::Lit(ref lit1) = lit_expr.kind
+ && let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node
+ && arms[0].guard.is_none()
+ && let ExprKind::Lit(ref lit2) = arms[0].body.kind
+ && let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node
+ && let PatKind::Lit(lit_expr1) = arms[1].pat.kind
+ && let ExprKind::Lit(ref lit3) = lit_expr1.kind
+ && let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node
+ && arms[1].guard.is_none()
+ && let ExprKind::Block(block, None) = arms[1].body.kind
+ && block.stmts.len() == 1
+ && let StmtKind::Local(local1) = block.stmts[0].kind
+ && let Some(init1) = local1.init
+ && let ExprKind::Lit(ref lit4) = init1.kind
+ && let LitKind::Int(3, LitIntType::Unsuffixed) = lit4.node
+ && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local1.pat.kind
+ && name.as_str() == "x"
+ && let Some(trailing_expr) = block.expr
+ && let ExprKind::Path(ref qpath) = trailing_expr.kind
+ && match_qpath(qpath, &["x"])
+ && let PatKind::Wild = arms[2].pat.kind
+ && arms[2].guard.is_none()
+ && let ExprKind::Lit(ref lit5) = arms[2].body.kind
+ && let LitKind::Int(1, LitIntType::Unsuffixed) = lit5.node
+ && let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind
+ && name1.as_str() == "a"
+{
+ // report your lint here
}
diff --git a/src/tools/clippy/tests/ui/author/repeat.stdout b/src/tools/clippy/tests/ui/author/repeat.stdout
index 471bbce4f..c2a369610 100644
--- a/src/tools/clippy/tests/ui/author/repeat.stdout
+++ b/src/tools/clippy/tests/ui/author/repeat.stdout
@@ -1,12 +1,10 @@
-if_chain! {
- if let ExprKind::Repeat(value, length) = expr.kind;
- if let ExprKind::Lit(ref lit) = value.kind;
- if let LitKind::Int(1, LitIntType::Unsigned(UintTy::U8)) = lit.node;
- if let ArrayLen::Body(anon_const) = length;
- let expr1 = &cx.tcx.hir().body(anon_const.body).value;
- if let ExprKind::Lit(ref lit1) = expr1.kind;
- if let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node;
- then {
- // report your lint here
- }
+if let ExprKind::Repeat(value, length) = expr.kind
+ && let ExprKind::Lit(ref lit) = value.kind
+ && let LitKind::Int(1, LitIntType::Unsigned(UintTy::U8)) = lit.node
+ && let ArrayLen::Body(anon_const) = length
+ && expr1 = &cx.tcx.hir().body(anon_const.body).value
+ && let ExprKind::Lit(ref lit1) = expr1.kind
+ && let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node
+{
+ // report your lint here
}
diff --git a/src/tools/clippy/tests/ui/author/struct.rs b/src/tools/clippy/tests/ui/author/struct.rs
index 5fdf3433a..a99bdfc13 100644
--- a/src/tools/clippy/tests/ui/author/struct.rs
+++ b/src/tools/clippy/tests/ui/author/struct.rs
@@ -1,4 +1,9 @@
-#[allow(clippy::unnecessary_operation, clippy::single_match)]
+#![allow(
+ clippy::unnecessary_operation,
+ clippy::single_match,
+ clippy::no_effect,
+ clippy::bool_to_int_with_if
+)]
fn main() {
struct Test {
field: u32,
diff --git a/src/tools/clippy/tests/ui/author/struct.stdout b/src/tools/clippy/tests/ui/author/struct.stdout
index 5e78b7c9d..0b332d5e7 100644
--- a/src/tools/clippy/tests/ui/author/struct.stdout
+++ b/src/tools/clippy/tests/ui/author/struct.stdout
@@ -1,64 +1,56 @@
-if_chain! {
- if let ExprKind::Struct(qpath, fields, None) = expr.kind;
- if match_qpath(qpath, &["Test"]);
- if fields.len() == 1;
- if fields[0].ident.as_str() == "field";
- if let ExprKind::If(cond, then, Some(else_expr)) = fields[0].expr.kind;
- if let ExprKind::DropTemps(expr1) = cond.kind;
- if let ExprKind::Lit(ref lit) = expr1.kind;
- if let LitKind::Bool(true) = lit.node;
- if let ExprKind::Block(block, None) = then.kind;
- if block.stmts.is_empty();
- if let Some(trailing_expr) = block.expr;
- if let ExprKind::Lit(ref lit1) = trailing_expr.kind;
- if let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node;
- if let ExprKind::Block(block1, None) = else_expr.kind;
- if block1.stmts.is_empty();
- if let Some(trailing_expr1) = block1.expr;
- if let ExprKind::Lit(ref lit2) = trailing_expr1.kind;
- if let LitKind::Int(0, LitIntType::Unsuffixed) = lit2.node;
- then {
- // report your lint here
- }
+if let ExprKind::Struct(qpath, fields, None) = expr.kind
+ && match_qpath(qpath, &["Test"])
+ && fields.len() == 1
+ && fields[0].ident.as_str() == "field"
+ && let ExprKind::If(cond, then, Some(else_expr)) = fields[0].expr.kind
+ && let ExprKind::DropTemps(expr1) = cond.kind
+ && let ExprKind::Lit(ref lit) = expr1.kind
+ && let LitKind::Bool(true) = lit.node
+ && let ExprKind::Block(block, None) = then.kind
+ && block.stmts.is_empty()
+ && let Some(trailing_expr) = block.expr
+ && let ExprKind::Lit(ref lit1) = trailing_expr.kind
+ && let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node
+ && let ExprKind::Block(block1, None) = else_expr.kind
+ && block1.stmts.is_empty()
+ && let Some(trailing_expr1) = block1.expr
+ && let ExprKind::Lit(ref lit2) = trailing_expr1.kind
+ && let LitKind::Int(0, LitIntType::Unsuffixed) = lit2.node
+{
+ // report your lint here
}
-if_chain! {
- if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind;
- if match_qpath(qpath, &["Test"]);
- if fields.len() == 1;
- if fields[0].ident.as_str() == "field";
- if let PatKind::Lit(lit_expr) = fields[0].pat.kind;
- if let ExprKind::Lit(ref lit) = lit_expr.kind;
- if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
- if arm.guard.is_none();
- if let ExprKind::Block(block, None) = arm.body.kind;
- if block.stmts.is_empty();
- if block.expr.is_none();
- then {
- // report your lint here
- }
+if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind
+ && match_qpath(qpath, &["Test"])
+ && fields.len() == 1
+ && fields[0].ident.as_str() == "field"
+ && let PatKind::Lit(lit_expr) = fields[0].pat.kind
+ && let ExprKind::Lit(ref lit) = lit_expr.kind
+ && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
+ && arm.guard.is_none()
+ && let ExprKind::Block(block, None) = arm.body.kind
+ && block.stmts.is_empty()
+ && block.expr.is_none()
+{
+ // report your lint here
}
-if_chain! {
- if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind;
- if match_qpath(qpath, &["TestTuple"]);
- if fields.len() == 1;
- if let PatKind::Lit(lit_expr) = fields[0].kind;
- if let ExprKind::Lit(ref lit) = lit_expr.kind;
- if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
- if arm.guard.is_none();
- if let ExprKind::Block(block, None) = arm.body.kind;
- if block.stmts.is_empty();
- if block.expr.is_none();
- then {
- // report your lint here
- }
+if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind
+ && match_qpath(qpath, &["TestTuple"])
+ && fields.len() == 1
+ && let PatKind::Lit(lit_expr) = fields[0].kind
+ && let ExprKind::Lit(ref lit) = lit_expr.kind
+ && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
+ && arm.guard.is_none()
+ && let ExprKind::Block(block, None) = arm.body.kind
+ && block.stmts.is_empty()
+ && block.expr.is_none()
+{
+ // report your lint here
}
-if_chain! {
- if let ExprKind::MethodCall(method_name, args, _) = expr.kind;
- if method_name.ident.as_str() == "test";
- if args.len() == 1;
- if let ExprKind::Path(ref qpath) = args[0].kind;
- if match_qpath(qpath, &["test_method_call"]);
- then {
- // report your lint here
- }
+if let ExprKind::MethodCall(method_name, receiver, args, _) = expr.kind
+ && method_name.ident.as_str() == "test"
+ && let ExprKind::Path(ref qpath) = receiver.kind
+ && match_qpath(qpath, &["test_method_call"])
+ && args.is_empty()
+{
+ // report your lint here
}
diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
index 83a0af6b8..ef3ca9aea 100644
--- a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
@@ -140,3 +140,10 @@ macro_rules! manual_rem_euclid {
macro_rules! equatable_if_let {
($a:ident) => {{ if let 2 = $a {} }};
}
+
+#[macro_export]
+macro_rules! almost_complete_letter_range {
+ () => {
+ let _ = 'a'..'z';
+ };
+}
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
index ae2cc2492..4914f14b5 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
@@ -4,7 +4,7 @@
#![crate_type = "proc-macro"]
#![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)]
#![allow(incomplete_features)]
-#![allow(clippy::useless_conversion)]
+#![allow(clippy::useless_conversion, clippy::uninlined_format_args)]
extern crate proc_macro;
extern crate quote;
diff --git a/src/tools/clippy/tests/ui/await_holding_lock.stderr b/src/tools/clippy/tests/ui/await_holding_lock.stderr
index 976da8d92..81a2d0524 100644
--- a/src/tools/clippy/tests/ui/await_holding_lock.stderr
+++ b/src/tools/clippy/tests/ui/await_holding_lock.stderr
@@ -4,7 +4,6 @@ error: this `MutexGuard` is held across an `await` point
LL | let guard = x.lock().unwrap();
| ^^^^^
|
- = note: `-D clippy::await-holding-lock` implied by `-D warnings`
= help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
note: these are all the `await` points this lock is held through
--> $DIR/await_holding_lock.rs:9:9
@@ -13,6 +12,7 @@ LL | / let guard = x.lock().unwrap();
LL | | baz().await
LL | | }
| |_____^
+ = note: `-D clippy::await-holding-lock` implied by `-D warnings`
error: this `MutexGuard` is held across an `await` point
--> $DIR/await_holding_lock.rs:24:13
diff --git a/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr b/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr
index 4339fca73..25c15ab80 100644
--- a/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr
+++ b/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr
@@ -4,7 +4,6 @@ error: this `RefCell` reference is held across an `await` point
LL | let b = x.borrow();
| ^
|
- = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings`
= help: ensure the reference is dropped before calling `await`
note: these are all the `await` points this reference is held through
--> $DIR/await_holding_refcell_ref.rs:6:5
@@ -13,6 +12,7 @@ LL | / let b = x.borrow();
LL | | baz().await
LL | | }
| |_^
+ = note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings`
error: this `RefCell` reference is held across an `await` point
--> $DIR/await_holding_refcell_ref.rs:11:9
diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map.fixed b/src/tools/clippy/tests/ui/bind_instead_of_map.fixed
index 5815550d7..d94e2ac60 100644
--- a/src/tools/clippy/tests/ui/bind_instead_of_map.fixed
+++ b/src/tools/clippy/tests/ui/bind_instead_of_map.fixed
@@ -1,5 +1,6 @@
// run-rustfix
#![deny(clippy::bind_instead_of_map)]
+#![allow(clippy::uninlined_format_args)]
// need a main anyway, use it get rid of unused warnings too
pub fn main() {
diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map.rs b/src/tools/clippy/tests/ui/bind_instead_of_map.rs
index 623b100a4..86f31f582 100644
--- a/src/tools/clippy/tests/ui/bind_instead_of_map.rs
+++ b/src/tools/clippy/tests/ui/bind_instead_of_map.rs
@@ -1,5 +1,6 @@
// run-rustfix
#![deny(clippy::bind_instead_of_map)]
+#![allow(clippy::uninlined_format_args)]
// need a main anyway, use it get rid of unused warnings too
pub fn main() {
diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map.stderr b/src/tools/clippy/tests/ui/bind_instead_of_map.stderr
index 24c6b7f9e..b6a81d21b 100644
--- a/src/tools/clippy/tests/ui/bind_instead_of_map.stderr
+++ b/src/tools/clippy/tests/ui/bind_instead_of_map.stderr
@@ -1,5 +1,5 @@
error: using `Option.and_then(Some)`, which is a no-op
- --> $DIR/bind_instead_of_map.rs:8:13
+ --> $DIR/bind_instead_of_map.rs:9:13
|
LL | let _ = x.and_then(Some);
| ^^^^^^^^^^^^^^^^ help: use the expression directly: `x`
@@ -11,13 +11,13 @@ LL | #![deny(clippy::bind_instead_of_map)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`
- --> $DIR/bind_instead_of_map.rs:9:13
+ --> $DIR/bind_instead_of_map.rs:10:13
|
LL | let _ = x.and_then(|o| Some(o + 1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.map(|o| o + 1)`
error: using `Result.and_then(Ok)`, which is a no-op
- --> $DIR/bind_instead_of_map.rs:15:13
+ --> $DIR/bind_instead_of_map.rs:16:13
|
LL | let _ = x.and_then(Ok);
| ^^^^^^^^^^^^^^ help: use the expression directly: `x`
diff --git a/src/tools/clippy/tests/ui/blacklisted_name.stderr b/src/tools/clippy/tests/ui/blacklisted_name.stderr
deleted file mode 100644
index 70dbdaece..000000000
--- a/src/tools/clippy/tests/ui/blacklisted_name.stderr
+++ /dev/null
@@ -1,88 +0,0 @@
-error: use of a blacklisted/placeholder name `foo`
- --> $DIR/blacklisted_name.rs:11:9
- |
-LL | fn test(foo: ()) {}
- | ^^^
- |
- = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: use of a blacklisted/placeholder name `foo`
- --> $DIR/blacklisted_name.rs:14:9
- |
-LL | let foo = 42;
- | ^^^
-
-error: use of a blacklisted/placeholder name `baz`
- --> $DIR/blacklisted_name.rs:15:9
- |
-LL | let baz = 42;
- | ^^^
-
-error: use of a blacklisted/placeholder name `quux`
- --> $DIR/blacklisted_name.rs:16:9
- |
-LL | let quux = 42;
- | ^^^^
-
-error: use of a blacklisted/placeholder name `foo`
- --> $DIR/blacklisted_name.rs:27:10
- |
-LL | (foo, Some(baz), quux @ Some(_)) => (),
- | ^^^
-
-error: use of a blacklisted/placeholder name `baz`
- --> $DIR/blacklisted_name.rs:27:20
- |
-LL | (foo, Some(baz), quux @ Some(_)) => (),
- | ^^^
-
-error: use of a blacklisted/placeholder name `quux`
- --> $DIR/blacklisted_name.rs:27:26
- |
-LL | (foo, Some(baz), quux @ Some(_)) => (),
- | ^^^^
-
-error: use of a blacklisted/placeholder name `foo`
- --> $DIR/blacklisted_name.rs:32:19
- |
-LL | fn issue_1647(mut foo: u8) {
- | ^^^
-
-error: use of a blacklisted/placeholder name `baz`
- --> $DIR/blacklisted_name.rs:33:13
- |
-LL | let mut baz = 0;
- | ^^^
-
-error: use of a blacklisted/placeholder name `quux`
- --> $DIR/blacklisted_name.rs:34:21
- |
-LL | if let Some(mut quux) = Some(42) {}
- | ^^^^
-
-error: use of a blacklisted/placeholder name `baz`
- --> $DIR/blacklisted_name.rs:38:13
- |
-LL | let ref baz = 0;
- | ^^^
-
-error: use of a blacklisted/placeholder name `quux`
- --> $DIR/blacklisted_name.rs:39:21
- |
-LL | if let Some(ref quux) = Some(42) {}
- | ^^^^
-
-error: use of a blacklisted/placeholder name `baz`
- --> $DIR/blacklisted_name.rs:43:17
- |
-LL | let ref mut baz = 0;
- | ^^^
-
-error: use of a blacklisted/placeholder name `quux`
- --> $DIR/blacklisted_name.rs:44:25
- |
-LL | if let Some(ref mut quux) = Some(42) {}
- | ^^^^
-
-error: aborting due to 14 previous errors
-
diff --git a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr
index 537557f8b..e83eb4d60 100644
--- a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr
+++ b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr
@@ -4,8 +4,8 @@ error: restriction lints are not meant to be all enabled
LL | #![warn(clippy::restriction)]
| ^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
= help: try enabling only the lints you really need
+ = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
error: restriction lints are not meant to be all enabled
--> $DIR/blanket_clippy_restriction_lints.rs:5:9
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
new file mode 100644
index 000000000..2c8339cdd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
@@ -0,0 +1,91 @@
+// run-rustfix
+
+#![warn(clippy::bool_to_int_with_if)]
+#![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
+
+fn main() {
+ let a = true;
+ let b = false;
+
+ let x = 1;
+ let y = 2;
+
+ // Should lint
+ // precedence
+ i32::from(a);
+ i32::from(!a);
+ i32::from(!a);
+ i32::from(a || b);
+ i32::from(cond(a, b));
+ i32::from(x + y < 4);
+
+ // if else if
+ if a {
+ 123
+ } else { i32::from(b) };
+
+ // if else if inverted
+ if a {
+ 123
+ } else { i32::from(!b) };
+
+ // Shouldn't lint
+
+ if a {
+ 1
+ } else if b {
+ 0
+ } else {
+ 3
+ };
+
+ if a {
+ 3
+ } else if b {
+ 1
+ } else {
+ -2
+ };
+
+ if a {
+ 3
+ } else {
+ 0
+ };
+ if a {
+ side_effect();
+ 1
+ } else {
+ 0
+ };
+ if a {
+ 1
+ } else {
+ side_effect();
+ 0
+ };
+
+ // multiple else ifs
+ if a {
+ 123
+ } else if b {
+ 1
+ } else if a | b {
+ 0
+ } else {
+ 123
+ };
+
+ some_fn(a);
+}
+
+// Lint returns and type inference
+fn some_fn(a: bool) -> u8 {
+ u8::from(a)
+}
+
+fn side_effect() {}
+
+fn cond(a: bool, b: bool) -> bool {
+ a || b
+}
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
new file mode 100644
index 000000000..5d9496f01
--- /dev/null
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
@@ -0,0 +1,123 @@
+// run-rustfix
+
+#![warn(clippy::bool_to_int_with_if)]
+#![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
+
+fn main() {
+ let a = true;
+ let b = false;
+
+ let x = 1;
+ let y = 2;
+
+ // Should lint
+ // precedence
+ if a {
+ 1
+ } else {
+ 0
+ };
+ if a {
+ 0
+ } else {
+ 1
+ };
+ if !a {
+ 1
+ } else {
+ 0
+ };
+ if a || b {
+ 1
+ } else {
+ 0
+ };
+ if cond(a, b) {
+ 1
+ } else {
+ 0
+ };
+ if x + y < 4 {
+ 1
+ } else {
+ 0
+ };
+
+ // if else if
+ if a {
+ 123
+ } else if b {
+ 1
+ } else {
+ 0
+ };
+
+ // if else if inverted
+ if a {
+ 123
+ } else if b {
+ 0
+ } else {
+ 1
+ };
+
+ // Shouldn't lint
+
+ if a {
+ 1
+ } else if b {
+ 0
+ } else {
+ 3
+ };
+
+ if a {
+ 3
+ } else if b {
+ 1
+ } else {
+ -2
+ };
+
+ if a {
+ 3
+ } else {
+ 0
+ };
+ if a {
+ side_effect();
+ 1
+ } else {
+ 0
+ };
+ if a {
+ 1
+ } else {
+ side_effect();
+ 0
+ };
+
+ // multiple else ifs
+ if a {
+ 123
+ } else if b {
+ 1
+ } else if a | b {
+ 0
+ } else {
+ 123
+ };
+
+ some_fn(a);
+}
+
+// Lint returns and type inference
+fn some_fn(a: bool) -> u8 {
+ if a { 1 } else { 0 }
+}
+
+fn side_effect() {}
+
+fn cond(a: bool, b: bool) -> bool {
+ a || b
+}
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
new file mode 100644
index 000000000..4cb5531be
--- /dev/null
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
@@ -0,0 +1,109 @@
+error: boolean to int conversion using if
+ --> $DIR/bool_to_int_with_if.rs:15:5
+ |
+LL | / if a {
+LL | | 1
+LL | | } else {
+LL | | 0
+LL | | };
+ | |_____^ help: replace with from: `i32::from(a)`
+ |
+ = note: `a as i32` or `a.into()` can also be valid options
+ = note: `-D clippy::bool-to-int-with-if` implied by `-D warnings`
+
+error: boolean to int conversion using if
+ --> $DIR/bool_to_int_with_if.rs:20:5
+ |
+LL | / if a {
+LL | | 0
+LL | | } else {
+LL | | 1
+LL | | };
+ | |_____^ help: replace with from: `i32::from(!a)`
+ |
+ = note: `!a as i32` or `(!a).into()` can also be valid options
+
+error: boolean to int conversion using if
+ --> $DIR/bool_to_int_with_if.rs:25:5
+ |
+LL | / if !a {
+LL | | 1
+LL | | } else {
+LL | | 0
+LL | | };
+ | |_____^ help: replace with from: `i32::from(!a)`
+ |
+ = note: `!a as i32` or `(!a).into()` can also be valid options
+
+error: boolean to int conversion using if
+ --> $DIR/bool_to_int_with_if.rs:30:5
+ |
+LL | / if a || b {
+LL | | 1
+LL | | } else {
+LL | | 0
+LL | | };
+ | |_____^ help: replace with from: `i32::from(a || b)`
+ |
+ = note: `(a || b) as i32` or `(a || b).into()` can also be valid options
+
+error: boolean to int conversion using if
+ --> $DIR/bool_to_int_with_if.rs:35:5
+ |
+LL | / if cond(a, b) {
+LL | | 1
+LL | | } else {
+LL | | 0
+LL | | };
+ | |_____^ help: replace with from: `i32::from(cond(a, b))`
+ |
+ = note: `cond(a, b) as i32` or `cond(a, b).into()` can also be valid options
+
+error: boolean to int conversion using if
+ --> $DIR/bool_to_int_with_if.rs:40:5
+ |
+LL | / if x + y < 4 {
+LL | | 1
+LL | | } else {
+LL | | 0
+LL | | };
+ | |_____^ help: replace with from: `i32::from(x + y < 4)`
+ |
+ = note: `(x + y < 4) as i32` or `(x + y < 4).into()` can also be valid options
+
+error: boolean to int conversion using if
+ --> $DIR/bool_to_int_with_if.rs:49:12
+ |
+LL | } else if b {
+ | ____________^
+LL | | 1
+LL | | } else {
+LL | | 0
+LL | | };
+ | |_____^ help: replace with from: `{ i32::from(b) }`
+ |
+ = note: `b as i32` or `b.into()` can also be valid options
+
+error: boolean to int conversion using if
+ --> $DIR/bool_to_int_with_if.rs:58:12
+ |
+LL | } else if b {
+ | ____________^
+LL | | 0
+LL | | } else {
+LL | | 1
+LL | | };
+ | |_____^ help: replace with from: `{ i32::from(!b) }`
+ |
+ = note: `!b as i32` or `(!b).into()` can also be valid options
+
+error: boolean to int conversion using if
+ --> $DIR/bool_to_int_with_if.rs:116:5
+ |
+LL | if a { 1 } else { 0 }
+ | ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)`
+ |
+ = note: `a as u8` or `a.into()` can also be valid options
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/borrow_box.rs b/src/tools/clippy/tests/ui/borrow_box.rs
index b606f773c..3b5b6bf4c 100644
--- a/src/tools/clippy/tests/ui/borrow_box.rs
+++ b/src/tools/clippy/tests/ui/borrow_box.rs
@@ -1,7 +1,6 @@
#![deny(clippy::borrowed_box)]
-#![allow(clippy::blacklisted_name)]
-#![allow(unused_variables)]
-#![allow(dead_code)]
+#![allow(dead_code, unused_variables)]
+#![allow(clippy::uninlined_format_args, clippy::disallowed_names)]
use std::fmt::Display;
diff --git a/src/tools/clippy/tests/ui/borrow_box.stderr b/src/tools/clippy/tests/ui/borrow_box.stderr
index 3eac32815..99cb60a1e 100644
--- a/src/tools/clippy/tests/ui/borrow_box.stderr
+++ b/src/tools/clippy/tests/ui/borrow_box.stderr
@@ -1,5 +1,5 @@
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:21:14
+ --> $DIR/borrow_box.rs:20:14
|
LL | let foo: &Box<bool>;
| ^^^^^^^^^^ help: try: `&bool`
@@ -11,55 +11,55 @@ LL | #![deny(clippy::borrowed_box)]
| ^^^^^^^^^^^^^^^^^^^^
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:25:10
+ --> $DIR/borrow_box.rs:24:10
|
LL | foo: &'a Box<bool>,
| ^^^^^^^^^^^^^ help: try: `&'a bool`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:29:17
+ --> $DIR/borrow_box.rs:28:17
|
LL | fn test4(a: &Box<bool>);
| ^^^^^^^^^^ help: try: `&bool`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:95:25
+ --> $DIR/borrow_box.rs:94:25
|
LL | pub fn test14(_display: &Box<dyn Display>) {}
| ^^^^^^^^^^^^^^^^^ help: try: `&dyn Display`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:96:25
+ --> $DIR/borrow_box.rs:95:25
|
LL | pub fn test15(_display: &Box<dyn Display + Send>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:97:29
+ --> $DIR/borrow_box.rs:96:29
|
LL | pub fn test16<'a>(_display: &'a Box<dyn Display + 'a>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (dyn Display + 'a)`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:99:25
+ --> $DIR/borrow_box.rs:98:25
|
LL | pub fn test17(_display: &Box<impl Display>) {}
| ^^^^^^^^^^^^^^^^^^ help: try: `&impl Display`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:100:25
+ --> $DIR/borrow_box.rs:99:25
|
LL | pub fn test18(_display: &Box<impl Display + Send>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(impl Display + Send)`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:101:29
+ --> $DIR/borrow_box.rs:100:29
|
LL | pub fn test19<'a>(_display: &'a Box<impl Display + 'a>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (impl Display + 'a)`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:106:25
+ --> $DIR/borrow_box.rs:105:25
|
LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)`
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr
index 654a1ee7d..b0cab977a 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr
@@ -4,8 +4,8 @@ error: a `const` item with interior mutability should not be borrowed
LL | let _ = &UNFROZEN_VARIANT; //~ ERROR interior mutability
| ^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
= help: assign this const to a local or static variable, and use the variable here
+ = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
error: a `const` item with interior mutability should not be borrowed
--> $DIR/enums.rs:37:18
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
index 9a908cf30..c87ad206c 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
@@ -4,8 +4,8 @@ error: a `const` item with interior mutability should not be borrowed
LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
| ^^^^^^
|
- = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
= help: assign this const to a local or static variable, and use the variable here
+ = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
error: a `const` item with interior mutability should not be borrowed
--> $DIR/others.rs:55:16
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr
index 8f26403ab..f34ae8814 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr
@@ -4,8 +4,8 @@ error: a `const` item with interior mutability should not be borrowed
LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable
| ^^^^^^^^^^^^
|
- = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
= help: assign this const to a local or static variable, and use the variable here
+ = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings`
error: a `const` item with interior mutability should not be borrowed
--> $DIR/traits.rs:26:18
diff --git a/src/tools/clippy/tests/ui/box_collection.rs b/src/tools/clippy/tests/ui/box_collection.rs
index 1a74cdb3f..4c9947b9a 100644
--- a/src/tools/clippy/tests/ui/box_collection.rs
+++ b/src/tools/clippy/tests/ui/box_collection.rs
@@ -2,7 +2,7 @@
#![allow(
clippy::boxed_local,
clippy::needless_pass_by_value,
- clippy::blacklisted_name,
+ clippy::disallowed_names,
unused
)]
@@ -15,7 +15,7 @@ macro_rules! boxit {
}
fn test_macro() {
- boxit!(Vec::new(), Vec<u8>);
+ boxit!(vec![1], Vec<u8>);
}
fn test1(foo: Box<Vec<bool>>) {}
@@ -50,7 +50,7 @@ fn test_local_not_linted() {
pub fn pub_test(foo: Box<Vec<bool>>) {}
pub fn pub_test_ret() -> Box<Vec<bool>> {
- Box::new(Vec::new())
+ Box::default()
}
fn main() {}
diff --git a/src/tools/clippy/tests/ui/box_collection.stderr b/src/tools/clippy/tests/ui/box_collection.stderr
index 2b28598de..40b6f9be6 100644
--- a/src/tools/clippy/tests/ui/box_collection.stderr
+++ b/src/tools/clippy/tests/ui/box_collection.stderr
@@ -4,8 +4,8 @@ error: you seem to be trying to use `Box<Vec<..>>`. Consider using just `Vec<..>
LL | fn test1(foo: Box<Vec<bool>>) {}
| ^^^^^^^^^^^^^^
|
- = note: `-D clippy::box-collection` implied by `-D warnings`
= help: `Vec<..>` is already on the heap, `Box<Vec<..>>` makes an extra allocation
+ = note: `-D clippy::box-collection` implied by `-D warnings`
error: you seem to be trying to use `Box<String>`. Consider using just `String`
--> $DIR/box_collection.rs:28:15
diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed
new file mode 100644
index 000000000..911fa856a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/box_default.fixed
@@ -0,0 +1,57 @@
+// run-rustfix
+#![warn(clippy::box_default)]
+
+#[derive(Default)]
+struct ImplementsDefault;
+
+struct OwnDefault;
+
+impl OwnDefault {
+ fn default() -> Self {
+ Self
+ }
+}
+
+macro_rules! outer {
+ ($e: expr) => {
+ $e
+ };
+}
+
+fn main() {
+ let _string: Box<String> = Box::default();
+ let _byte = Box::<u8>::default();
+ let _vec = Box::<std::vec::Vec<u8>>::default();
+ let _impl = Box::<ImplementsDefault>::default();
+ let _impl2 = Box::<ImplementsDefault>::default();
+ let _impl3: Box<ImplementsDefault> = Box::default();
+ let _own = Box::new(OwnDefault::default()); // should not lint
+ let _in_macro = outer!(Box::<std::string::String>::default());
+ let _string_default = outer!(Box::<std::string::String>::default());
+ let _vec2: Box<Vec<ImplementsDefault>> = Box::default();
+ let _vec3: Box<Vec<bool>> = Box::default();
+ let _vec4: Box<_> = Box::<std::vec::Vec<bool>>::default();
+ let _more = ret_ty_fn();
+ call_ty_fn(Box::default());
+}
+
+fn ret_ty_fn() -> Box<bool> {
+ Box::<bool>::default()
+}
+
+#[allow(clippy::boxed_local)]
+fn call_ty_fn(_b: Box<u8>) {
+ issue_9621_dyn_trait();
+}
+
+use std::io::{Read, Result};
+
+impl Read for ImplementsDefault {
+ fn read(&mut self, _: &mut [u8]) -> Result<usize> {
+ Ok(0)
+ }
+}
+
+fn issue_9621_dyn_trait() {
+ let _: Box<dyn Read> = Box::<ImplementsDefault>::default();
+}
diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs
new file mode 100644
index 000000000..20019c2ee
--- /dev/null
+++ b/src/tools/clippy/tests/ui/box_default.rs
@@ -0,0 +1,57 @@
+// run-rustfix
+#![warn(clippy::box_default)]
+
+#[derive(Default)]
+struct ImplementsDefault;
+
+struct OwnDefault;
+
+impl OwnDefault {
+ fn default() -> Self {
+ Self
+ }
+}
+
+macro_rules! outer {
+ ($e: expr) => {
+ $e
+ };
+}
+
+fn main() {
+ let _string: Box<String> = Box::new(Default::default());
+ let _byte = Box::new(u8::default());
+ let _vec = Box::new(Vec::<u8>::new());
+ let _impl = Box::new(ImplementsDefault::default());
+ let _impl2 = Box::new(<ImplementsDefault as Default>::default());
+ let _impl3: Box<ImplementsDefault> = Box::new(Default::default());
+ let _own = Box::new(OwnDefault::default()); // should not lint
+ let _in_macro = outer!(Box::new(String::new()));
+ let _string_default = outer!(Box::new(String::from("")));
+ let _vec2: Box<Vec<ImplementsDefault>> = Box::new(vec![]);
+ let _vec3: Box<Vec<bool>> = Box::new(Vec::from([]));
+ let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
+ let _more = ret_ty_fn();
+ call_ty_fn(Box::new(u8::default()));
+}
+
+fn ret_ty_fn() -> Box<bool> {
+ Box::new(bool::default())
+}
+
+#[allow(clippy::boxed_local)]
+fn call_ty_fn(_b: Box<u8>) {
+ issue_9621_dyn_trait();
+}
+
+use std::io::{Read, Result};
+
+impl Read for ImplementsDefault {
+ fn read(&mut self, _: &mut [u8]) -> Result<usize> {
+ Ok(0)
+ }
+}
+
+fn issue_9621_dyn_trait() {
+ let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
+}
diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr
new file mode 100644
index 000000000..5ea410331
--- /dev/null
+++ b/src/tools/clippy/tests/ui/box_default.stderr
@@ -0,0 +1,88 @@
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:22:32
+ |
+LL | let _string: Box<String> = Box::new(Default::default());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
+ |
+ = note: `-D clippy::box-default` implied by `-D warnings`
+
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:23:17
+ |
+LL | let _byte = Box::new(u8::default());
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<u8>::default()`
+
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:24:16
+ |
+LL | let _vec = Box::new(Vec::<u8>::new());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::vec::Vec<u8>>::default()`
+
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:25:17
+ |
+LL | let _impl = Box::new(ImplementsDefault::default());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
+
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:26:18
+ |
+LL | let _impl2 = Box::new(<ImplementsDefault as Default>::default());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
+
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:27:42
+ |
+LL | let _impl3: Box<ImplementsDefault> = Box::new(Default::default());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
+
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:29:28
+ |
+LL | let _in_macro = outer!(Box::new(String::new()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::string::String>::default()`
+
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:30:34
+ |
+LL | let _string_default = outer!(Box::new(String::from("")));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::string::String>::default()`
+
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:31:46
+ |
+LL | let _vec2: Box<Vec<ImplementsDefault>> = Box::new(vec![]);
+ | ^^^^^^^^^^^^^^^^ help: try: `Box::default()`
+
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:32:33
+ |
+LL | let _vec3: Box<Vec<bool>> = Box::new(Vec::from([]));
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
+
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:33:25
+ |
+LL | let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::vec::Vec<bool>>::default()`
+
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:35:16
+ |
+LL | call_ty_fn(Box::new(u8::default()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
+
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:39:5
+ |
+LL | Box::new(bool::default())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<bool>::default()`
+
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:56:28
+ |
+LL | let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/box_default_no_std.rs b/src/tools/clippy/tests/ui/box_default_no_std.rs
new file mode 100644
index 000000000..4326abc9a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/box_default_no_std.rs
@@ -0,0 +1,33 @@
+#![feature(lang_items, start, libc)]
+#![warn(clippy::box_default)]
+#![no_std]
+
+pub struct NotBox<T> {
+ _value: T,
+}
+
+impl<T> NotBox<T> {
+ pub fn new(value: T) -> Self {
+ Self { _value: value }
+ }
+}
+
+impl<T: Default> Default for NotBox<T> {
+ fn default() -> Self {
+ Self::new(T::default())
+ }
+}
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+ let _p = NotBox::new(isize::default());
+ 0
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+ loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
index 12f550d9c..6a63008b5 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
@@ -1,5 +1,6 @@
-#![allow(dead_code, clippy::equatable_if_let)]
#![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
+#![allow(dead_code)]
+#![allow(clippy::equatable_if_let, clippy::uninlined_format_args)]
// This tests the branches_sharing_code lint at the end of blocks
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
index 5e1a68d21..b9b113dc0 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
@@ -1,5 +1,5 @@
error: all if blocks contain the same code at the end
- --> $DIR/shared_at_bottom.rs:30:5
+ --> $DIR/shared_at_bottom.rs:31:5
|
LL | / let result = false;
LL | | println!("Block end!");
@@ -7,12 +7,12 @@ LL | | result
LL | | };
| |_____^
|
+ = note: the end suggestion probably needs some adjustments to use the expression result correctly
note: the lint level is defined here
- --> $DIR/shared_at_bottom.rs:2:36
+ --> $DIR/shared_at_bottom.rs:1:36
|
LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: the end suggestion probably needs some adjustments to use the expression result correctly
help: consider moving these statements after the if
|
LL ~ }
@@ -22,7 +22,7 @@ LL ~ result;
|
error: all if blocks contain the same code at the end
- --> $DIR/shared_at_bottom.rs:48:5
+ --> $DIR/shared_at_bottom.rs:49:5
|
LL | / println!("Same end of block");
LL | | }
@@ -35,7 +35,7 @@ LL + println!("Same end of block");
|
error: all if blocks contain the same code at the end
- --> $DIR/shared_at_bottom.rs:65:5
+ --> $DIR/shared_at_bottom.rs:66:5
|
LL | / println!(
LL | | "I'm moveable because I know: `outer_scope_value`: '{}'",
@@ -54,7 +54,7 @@ LL + );
|
error: all if blocks contain the same code at the end
- --> $DIR/shared_at_bottom.rs:77:9
+ --> $DIR/shared_at_bottom.rs:78:9
|
LL | / println!("Hello World");
LL | | }
@@ -67,7 +67,7 @@ LL + println!("Hello World");
|
error: all if blocks contain the same code at the end
- --> $DIR/shared_at_bottom.rs:93:5
+ --> $DIR/shared_at_bottom.rs:94:5
|
LL | / let later_used_value = "A string value";
LL | | println!("{}", later_used_value);
@@ -84,7 +84,7 @@ LL + println!("{}", later_used_value);
|
error: all if blocks contain the same code at the end
- --> $DIR/shared_at_bottom.rs:106:5
+ --> $DIR/shared_at_bottom.rs:107:5
|
LL | / let simple_examples = "I now identify as a &str :)";
LL | | println!("This is the new simple_example: {}", simple_examples);
@@ -100,7 +100,7 @@ LL + println!("This is the new simple_example: {}", simple_examples);
|
error: all if blocks contain the same code at the end
- --> $DIR/shared_at_bottom.rs:171:5
+ --> $DIR/shared_at_bottom.rs:172:5
|
LL | / x << 2
LL | | };
@@ -114,7 +114,7 @@ LL ~ x << 2;
|
error: all if blocks contain the same code at the end
- --> $DIR/shared_at_bottom.rs:178:5
+ --> $DIR/shared_at_bottom.rs:179:5
|
LL | / x * 4
LL | | }
@@ -128,7 +128,7 @@ LL + x * 4
|
error: all if blocks contain the same code at the end
- --> $DIR/shared_at_bottom.rs:190:44
+ --> $DIR/shared_at_bottom.rs:191:44
|
LL | if x == 17 { b = 1; a = 0x99; } else { a = 0x99; }
| ^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs
index bdeb0a395..9e0b99f16 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs
@@ -1,5 +1,6 @@
-#![allow(dead_code, clippy::mixed_read_write_in_expression)]
-#![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
+#![deny(clippy::branches_sharing_code, clippy::if_same_then_else)]
+#![allow(dead_code)]
+#![allow(clippy::mixed_read_write_in_expression, clippy::uninlined_format_args)]
// This tests the branches_sharing_code lint at the start of blocks
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr
index d890b12ec..3e3242a75 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr
@@ -1,15 +1,15 @@
error: all if blocks contain the same code at the start
- --> $DIR/shared_at_top.rs:10:5
+ --> $DIR/shared_at_top.rs:11:5
|
LL | / if true {
LL | | println!("Hello World!");
| |_________________________________^
|
note: the lint level is defined here
- --> $DIR/shared_at_top.rs:2:36
+ --> $DIR/shared_at_top.rs:1:9
|
-LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![deny(clippy::branches_sharing_code, clippy::if_same_then_else)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider moving these statements before the if
|
LL ~ println!("Hello World!");
@@ -17,7 +17,7 @@ LL + if true {
|
error: all if blocks contain the same code at the start
- --> $DIR/shared_at_top.rs:19:5
+ --> $DIR/shared_at_top.rs:20:5
|
LL | / if x == 0 {
LL | | let y = 9;
@@ -35,7 +35,7 @@ LL + if x == 0 {
|
error: all if blocks contain the same code at the start
- --> $DIR/shared_at_top.rs:40:5
+ --> $DIR/shared_at_top.rs:41:5
|
LL | / let _ = if x == 7 {
LL | | let y = 16;
@@ -48,7 +48,7 @@ LL + let _ = if x == 7 {
|
error: all if blocks contain the same code at the start
- --> $DIR/shared_at_top.rs:58:5
+ --> $DIR/shared_at_top.rs:59:5
|
LL | / if x == 10 {
LL | | let used_value_name = "Different type";
@@ -64,7 +64,7 @@ LL + if x == 10 {
|
error: all if blocks contain the same code at the start
- --> $DIR/shared_at_top.rs:72:5
+ --> $DIR/shared_at_top.rs:73:5
|
LL | / if x == 11 {
LL | | let can_be_overridden = "Move me";
@@ -80,7 +80,7 @@ LL + if x == 11 {
|
error: all if blocks contain the same code at the start
- --> $DIR/shared_at_top.rs:88:5
+ --> $DIR/shared_at_top.rs:89:5
|
LL | / if x == 2020 {
LL | | println!("This should trigger the `SHARED_CODE_IN_IF_BLOCKS` lint.");
@@ -95,7 +95,7 @@ LL + if x == 2020 {
|
error: this `if` has identical blocks
- --> $DIR/shared_at_top.rs:96:18
+ --> $DIR/shared_at_top.rs:97:18
|
LL | if x == 2019 {
| __________________^
@@ -103,19 +103,19 @@ LL | | println!("This should trigger `IS_SAME_THAN_ELSE` as usual");
LL | | } else {
| |_____^
|
-note: the lint level is defined here
- --> $DIR/shared_at_top.rs:2:9
- |
-LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
note: same as this
- --> $DIR/shared_at_top.rs:98:12
+ --> $DIR/shared_at_top.rs:99:12
|
LL | } else {
| ____________^
LL | | println!("This should trigger `IS_SAME_THAN_ELSE` as usual");
LL | | }
| |_____^
+note: the lint level is defined here
+ --> $DIR/shared_at_top.rs:1:40
+ |
+LL | #![deny(clippy::branches_sharing_code, clippy::if_same_then_else)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 7 previous errors
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs
index deefdad32..93b8c6e10 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs
@@ -1,5 +1,6 @@
+#![deny(clippy::branches_sharing_code, clippy::if_same_then_else)]
#![allow(dead_code)]
-#![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
+#![allow(clippy::uninlined_format_args)]
// branches_sharing_code at the top and bottom of the if blocks
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr
index a270f637f..ccd697a42 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr
@@ -1,5 +1,5 @@
error: all if blocks contain the same code at both the start and the end
- --> $DIR/shared_at_top_and_bottom.rs:16:5
+ --> $DIR/shared_at_top_and_bottom.rs:17:5
|
LL | / if x == 7 {
LL | | let t = 7;
@@ -7,17 +7,17 @@ LL | | let _overlap_start = t * 2;
LL | | let _overlap_end = 2 * t;
| |_________________________________^
|
-note: the lint level is defined here
- --> $DIR/shared_at_top_and_bottom.rs:2:36
- |
-LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: this code is shared at the end
- --> $DIR/shared_at_top_and_bottom.rs:28:5
+ --> $DIR/shared_at_top_and_bottom.rs:29:5
|
LL | / let _u = 9;
LL | | }
| |_____^
+note: the lint level is defined here
+ --> $DIR/shared_at_top_and_bottom.rs:1:9
+ |
+LL | #![deny(clippy::branches_sharing_code, clippy::if_same_then_else)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider moving these statements before the if
|
LL ~ let t = 7;
@@ -32,7 +32,7 @@ LL + let _u = 9;
|
error: all if blocks contain the same code at both the start and the end
- --> $DIR/shared_at_top_and_bottom.rs:32:5
+ --> $DIR/shared_at_top_and_bottom.rs:33:5
|
LL | / if x == 99 {
LL | | let r = 7;
@@ -41,7 +41,7 @@ LL | | let _overlap_middle = r * r;
| |____________________________________^
|
note: this code is shared at the end
- --> $DIR/shared_at_top_and_bottom.rs:43:5
+ --> $DIR/shared_at_top_and_bottom.rs:44:5
|
LL | / let _overlap_end = r * r * r;
LL | | let z = "end";
@@ -63,7 +63,7 @@ LL + let z = "end";
|
error: all if blocks contain the same code at both the start and the end
- --> $DIR/shared_at_top_and_bottom.rs:61:5
+ --> $DIR/shared_at_top_and_bottom.rs:62:5
|
LL | / if (x > 7 && y < 13) || (x + y) % 2 == 1 {
LL | | let a = 0xcafe;
@@ -72,7 +72,7 @@ LL | | let e_id = gen_id(a, b);
| |________________________________^
|
note: this code is shared at the end
- --> $DIR/shared_at_top_and_bottom.rs:81:5
+ --> $DIR/shared_at_top_and_bottom.rs:82:5
|
LL | / let pack = DataPack {
LL | | id: e_id,
@@ -102,14 +102,14 @@ LL + process_data(pack);
|
error: all if blocks contain the same code at both the start and the end
- --> $DIR/shared_at_top_and_bottom.rs:94:5
+ --> $DIR/shared_at_top_and_bottom.rs:95:5
|
LL | / let _ = if x == 7 {
LL | | let _ = 19;
| |___________________^
|
note: this code is shared at the end
- --> $DIR/shared_at_top_and_bottom.rs:103:5
+ --> $DIR/shared_at_top_and_bottom.rs:104:5
|
LL | / x << 2
LL | | };
@@ -127,14 +127,14 @@ LL ~ x << 2;
|
error: all if blocks contain the same code at both the start and the end
- --> $DIR/shared_at_top_and_bottom.rs:106:5
+ --> $DIR/shared_at_top_and_bottom.rs:107:5
|
LL | / if x == 9 {
LL | | let _ = 17;
| |___________________^
|
note: this code is shared at the end
- --> $DIR/shared_at_top_and_bottom.rs:115:5
+ --> $DIR/shared_at_top_and_bottom.rs:116:5
|
LL | / x * 4
LL | | }
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs
index a26141be2..2d6055eb6 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs
@@ -1,5 +1,6 @@
-#![allow(dead_code, clippy::mixed_read_write_in_expression)]
-#![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
+#![deny(clippy::branches_sharing_code, clippy::if_same_then_else)]
+#![allow(dead_code)]
+#![allow(clippy::mixed_read_write_in_expression, clippy::uninlined_format_args)]
// This tests valid if blocks that shouldn't trigger the lint
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr
index a815995e7..ce7fff012 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.stderr
@@ -1,26 +1,26 @@
error: this `if` has identical blocks
- --> $DIR/valid_if_blocks.rs:104:14
+ --> $DIR/valid_if_blocks.rs:105:14
|
LL | if false {
| ______________^
LL | | } else {
| |_____^
|
-note: the lint level is defined here
- --> $DIR/valid_if_blocks.rs:2:9
- |
-LL | #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
note: same as this
- --> $DIR/valid_if_blocks.rs:105:12
+ --> $DIR/valid_if_blocks.rs:106:12
|
LL | } else {
| ____________^
LL | | }
| |_____^
+note: the lint level is defined here
+ --> $DIR/valid_if_blocks.rs:1:40
+ |
+LL | #![deny(clippy::branches_sharing_code, clippy::if_same_then_else)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `if` has identical blocks
- --> $DIR/valid_if_blocks.rs:115:15
+ --> $DIR/valid_if_blocks.rs:116:15
|
LL | if x == 0 {
| _______________^
@@ -31,7 +31,7 @@ LL | | } else {
| |_____^
|
note: same as this
- --> $DIR/valid_if_blocks.rs:119:12
+ --> $DIR/valid_if_blocks.rs:120:12
|
LL | } else {
| ____________^
@@ -42,19 +42,19 @@ LL | | }
| |_____^
error: this `if` has identical blocks
- --> $DIR/valid_if_blocks.rs:126:23
+ --> $DIR/valid_if_blocks.rs:127:23
|
LL | let _ = if x == 6 { 7 } else { 7 };
| ^^^^^
|
note: same as this
- --> $DIR/valid_if_blocks.rs:126:34
+ --> $DIR/valid_if_blocks.rs:127:34
|
LL | let _ = if x == 6 { 7 } else { 7 };
| ^^^^^
error: this `if` has identical blocks
- --> $DIR/valid_if_blocks.rs:132:23
+ --> $DIR/valid_if_blocks.rs:133:23
|
LL | } else if x == 68 {
| _______________________^
@@ -66,7 +66,7 @@ LL | | } else {
| |_____^
|
note: same as this
- --> $DIR/valid_if_blocks.rs:137:12
+ --> $DIR/valid_if_blocks.rs:138:12
|
LL | } else {
| ____________^
@@ -78,7 +78,7 @@ LL | | };
| |_____^
error: this `if` has identical blocks
- --> $DIR/valid_if_blocks.rs:146:23
+ --> $DIR/valid_if_blocks.rs:147:23
|
LL | } else if x == 68 {
| _______________________^
@@ -88,7 +88,7 @@ LL | | } else {
| |_____^
|
note: same as this
- --> $DIR/valid_if_blocks.rs:149:12
+ --> $DIR/valid_if_blocks.rs:150:12
|
LL | } else {
| ____________^
diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs
index 0d65071af..6f0485b52 100644
--- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs
+++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs
@@ -14,31 +14,31 @@ fn is_rust_file(filename: &str) -> bool {
fn main() {
// std::string::String and &str should trigger the lint failure with .ext12
- let _ = String::from("").ends_with(".ext12");
+ let _ = String::new().ends_with(".ext12");
let _ = "str".ends_with(".ext12");
// The test struct should not trigger the lint failure with .ext12
TestStruct {}.ends_with(".ext12");
// std::string::String and &str should trigger the lint failure with .EXT12
- let _ = String::from("").ends_with(".EXT12");
+ let _ = String::new().ends_with(".EXT12");
let _ = "str".ends_with(".EXT12");
// The test struct should not trigger the lint failure with .EXT12
TestStruct {}.ends_with(".EXT12");
// Should not trigger the lint failure with .eXT12
- let _ = String::from("").ends_with(".eXT12");
+ let _ = String::new().ends_with(".eXT12");
let _ = "str".ends_with(".eXT12");
TestStruct {}.ends_with(".eXT12");
// Should not trigger the lint failure with .EXT123 (too long)
- let _ = String::from("").ends_with(".EXT123");
+ let _ = String::new().ends_with(".EXT123");
let _ = "str".ends_with(".EXT123");
TestStruct {}.ends_with(".EXT123");
// Shouldn't fail if it doesn't start with a dot
- let _ = String::from("").ends_with("a.ext");
+ let _ = String::new().ends_with("a.ext");
let _ = "str".ends_with("a.extA");
TestStruct {}.ends_with("a.ext");
}
diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr
index 05b98169f..a28dd8bd5 100644
--- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr
+++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr
@@ -4,14 +4,14 @@ error: case-sensitive file extension comparison
LL | filename.ends_with(".rs")
| ^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::case-sensitive-file-extension-comparisons` implied by `-D warnings`
= help: consider using a case-insensitive comparison instead
+ = note: `-D clippy::case-sensitive-file-extension-comparisons` implied by `-D warnings`
error: case-sensitive file extension comparison
- --> $DIR/case_sensitive_file_extension_comparisons.rs:17:30
+ --> $DIR/case_sensitive_file_extension_comparisons.rs:17:27
|
-LL | let _ = String::from("").ends_with(".ext12");
- | ^^^^^^^^^^^^^^^^^^^
+LL | let _ = String::new().ends_with(".ext12");
+ | ^^^^^^^^^^^^^^^^^^^
|
= help: consider using a case-insensitive comparison instead
@@ -24,10 +24,10 @@ LL | let _ = "str".ends_with(".ext12");
= help: consider using a case-insensitive comparison instead
error: case-sensitive file extension comparison
- --> $DIR/case_sensitive_file_extension_comparisons.rs:24:30
+ --> $DIR/case_sensitive_file_extension_comparisons.rs:24:27
|
-LL | let _ = String::from("").ends_with(".EXT12");
- | ^^^^^^^^^^^^^^^^^^^
+LL | let _ = String::new().ends_with(".EXT12");
+ | ^^^^^^^^^^^^^^^^^^^
|
= help: consider using a case-insensitive comparison instead
diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed
index a68b32b09..e6bf944c7 100644
--- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed
+++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed
@@ -1,5 +1,8 @@
// run-rustfix
+
+#![feature(custom_inner_attributes)]
#![warn(clippy::cast_abs_to_unsigned)]
+#![allow(clippy::uninlined_format_args, unused)]
fn main() {
let x: i32 = -42;
@@ -26,4 +29,20 @@ fn main() {
let _ = a.unsigned_abs() as u32;
let _ = a.unsigned_abs() as u64;
let _ = a.unsigned_abs() as u128;
+
+ let _ = (x as i64 - y as i64).unsigned_abs() as u32;
+}
+
+fn msrv_1_50() {
+ #![clippy::msrv = "1.50"]
+
+ let x: i32 = 10;
+ assert_eq!(10u32, x.abs() as u32);
+}
+
+fn msrv_1_51() {
+ #![clippy::msrv = "1.51"]
+
+ let x: i32 = 10;
+ assert_eq!(10u32, x.unsigned_abs());
}
diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs
index 110fbc6c2..c87320b52 100644
--- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs
+++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs
@@ -1,5 +1,8 @@
// run-rustfix
+
+#![feature(custom_inner_attributes)]
#![warn(clippy::cast_abs_to_unsigned)]
+#![allow(clippy::uninlined_format_args, unused)]
fn main() {
let x: i32 = -42;
@@ -26,4 +29,20 @@ fn main() {
let _ = a.abs() as u32;
let _ = a.abs() as u64;
let _ = a.abs() as u128;
+
+ let _ = (x as i64 - y as i64).abs() as u32;
+}
+
+fn msrv_1_50() {
+ #![clippy::msrv = "1.50"]
+
+ let x: i32 = 10;
+ assert_eq!(10u32, x.abs() as u32);
+}
+
+fn msrv_1_51() {
+ #![clippy::msrv = "1.51"]
+
+ let x: i32 = 10;
+ assert_eq!(10u32, x.abs() as u32);
}
diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr
index 02c24e106..1b39c554b 100644
--- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr
+++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr
@@ -1,5 +1,5 @@
error: casting the result of `i32::abs()` to u32
- --> $DIR/cast_abs_to_unsigned.rs:6:18
+ --> $DIR/cast_abs_to_unsigned.rs:9:18
|
LL | let y: u32 = x.abs() as u32;
| ^^^^^^^^^^^^^^ help: replace with: `x.unsigned_abs()`
@@ -7,94 +7,106 @@ LL | let y: u32 = x.abs() as u32;
= note: `-D clippy::cast-abs-to-unsigned` implied by `-D warnings`
error: casting the result of `i32::abs()` to usize
- --> $DIR/cast_abs_to_unsigned.rs:10:20
+ --> $DIR/cast_abs_to_unsigned.rs:13:20
|
LL | let _: usize = a.abs() as usize;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
error: casting the result of `i32::abs()` to usize
- --> $DIR/cast_abs_to_unsigned.rs:11:20
+ --> $DIR/cast_abs_to_unsigned.rs:14:20
|
LL | let _: usize = a.abs() as _;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
error: casting the result of `i32::abs()` to usize
- --> $DIR/cast_abs_to_unsigned.rs:12:13
+ --> $DIR/cast_abs_to_unsigned.rs:15:13
|
LL | let _ = a.abs() as usize;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
error: casting the result of `i64::abs()` to usize
- --> $DIR/cast_abs_to_unsigned.rs:15:13
+ --> $DIR/cast_abs_to_unsigned.rs:18:13
|
LL | let _ = a.abs() as usize;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
error: casting the result of `i64::abs()` to u8
- --> $DIR/cast_abs_to_unsigned.rs:16:13
+ --> $DIR/cast_abs_to_unsigned.rs:19:13
|
LL | let _ = a.abs() as u8;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
error: casting the result of `i64::abs()` to u16
- --> $DIR/cast_abs_to_unsigned.rs:17:13
+ --> $DIR/cast_abs_to_unsigned.rs:20:13
|
LL | let _ = a.abs() as u16;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
error: casting the result of `i64::abs()` to u32
- --> $DIR/cast_abs_to_unsigned.rs:18:13
+ --> $DIR/cast_abs_to_unsigned.rs:21:13
|
LL | let _ = a.abs() as u32;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
error: casting the result of `i64::abs()` to u64
- --> $DIR/cast_abs_to_unsigned.rs:19:13
+ --> $DIR/cast_abs_to_unsigned.rs:22:13
|
LL | let _ = a.abs() as u64;
| ^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()`
error: casting the result of `i64::abs()` to u128
- --> $DIR/cast_abs_to_unsigned.rs:20:13
+ --> $DIR/cast_abs_to_unsigned.rs:23:13
|
LL | let _ = a.abs() as u128;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
error: casting the result of `isize::abs()` to usize
- --> $DIR/cast_abs_to_unsigned.rs:23:13
+ --> $DIR/cast_abs_to_unsigned.rs:26:13
|
LL | let _ = a.abs() as usize;
| ^^^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()`
error: casting the result of `isize::abs()` to u8
- --> $DIR/cast_abs_to_unsigned.rs:24:13
+ --> $DIR/cast_abs_to_unsigned.rs:27:13
|
LL | let _ = a.abs() as u8;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
error: casting the result of `isize::abs()` to u16
- --> $DIR/cast_abs_to_unsigned.rs:25:13
+ --> $DIR/cast_abs_to_unsigned.rs:28:13
|
LL | let _ = a.abs() as u16;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
error: casting the result of `isize::abs()` to u32
- --> $DIR/cast_abs_to_unsigned.rs:26:13
+ --> $DIR/cast_abs_to_unsigned.rs:29:13
|
LL | let _ = a.abs() as u32;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
error: casting the result of `isize::abs()` to u64
- --> $DIR/cast_abs_to_unsigned.rs:27:13
+ --> $DIR/cast_abs_to_unsigned.rs:30:13
|
LL | let _ = a.abs() as u64;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
error: casting the result of `isize::abs()` to u128
- --> $DIR/cast_abs_to_unsigned.rs:28:13
+ --> $DIR/cast_abs_to_unsigned.rs:31:13
|
LL | let _ = a.abs() as u128;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
-error: aborting due to 16 previous errors
+error: casting the result of `i64::abs()` to u32
+ --> $DIR/cast_abs_to_unsigned.rs:33:13
+ |
+LL | let _ = (x as i64 - y as i64).abs() as u32;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `(x as i64 - y as i64).unsigned_abs()`
+
+error: casting the result of `i32::abs()` to u32
+ --> $DIR/cast_abs_to_unsigned.rs:47:23
+ |
+LL | assert_eq!(10u32, x.abs() as u32);
+ | ^^^^^^^^^^^^^^ help: replace with: `x.unsigned_abs()`
+
+error: aborting due to 18 previous errors
diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.fixed b/src/tools/clippy/tests/ui/cast_lossless_bool.fixed
index 9e2da45c3..af13b755e 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_bool.fixed
+++ b/src/tools/clippy/tests/ui/cast_lossless_bool.fixed
@@ -1,5 +1,6 @@
// run-rustfix
+#![feature(custom_inner_attributes)]
#![allow(dead_code)]
#![warn(clippy::cast_lossless)]
@@ -40,3 +41,15 @@ mod cast_lossless_in_impl {
}
}
}
+
+fn msrv_1_27() {
+ #![clippy::msrv = "1.27"]
+
+ let _ = true as u8;
+}
+
+fn msrv_1_28() {
+ #![clippy::msrv = "1.28"]
+
+ let _ = u8::from(true);
+}
diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.rs b/src/tools/clippy/tests/ui/cast_lossless_bool.rs
index b6f6c59a0..3b06af899 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_bool.rs
+++ b/src/tools/clippy/tests/ui/cast_lossless_bool.rs
@@ -1,5 +1,6 @@
// run-rustfix
+#![feature(custom_inner_attributes)]
#![allow(dead_code)]
#![warn(clippy::cast_lossless)]
@@ -40,3 +41,15 @@ mod cast_lossless_in_impl {
}
}
}
+
+fn msrv_1_27() {
+ #![clippy::msrv = "1.27"]
+
+ let _ = true as u8;
+}
+
+fn msrv_1_28() {
+ #![clippy::msrv = "1.28"]
+
+ let _ = true as u8;
+}
diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.stderr b/src/tools/clippy/tests/ui/cast_lossless_bool.stderr
index 6b1483360..768b033d1 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_bool.stderr
+++ b/src/tools/clippy/tests/ui/cast_lossless_bool.stderr
@@ -1,5 +1,5 @@
error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)`
- --> $DIR/cast_lossless_bool.rs:8:13
+ --> $DIR/cast_lossless_bool.rs:9:13
|
LL | let _ = true as u8;
| ^^^^^^^^^^ help: try: `u8::from(true)`
@@ -7,76 +7,82 @@ LL | let _ = true as u8;
= note: `-D clippy::cast-lossless` implied by `-D warnings`
error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)`
- --> $DIR/cast_lossless_bool.rs:9:13
+ --> $DIR/cast_lossless_bool.rs:10:13
|
LL | let _ = true as u16;
| ^^^^^^^^^^^ help: try: `u16::from(true)`
error: casting `bool` to `u32` is more cleanly stated with `u32::from(_)`
- --> $DIR/cast_lossless_bool.rs:10:13
+ --> $DIR/cast_lossless_bool.rs:11:13
|
LL | let _ = true as u32;
| ^^^^^^^^^^^ help: try: `u32::from(true)`
error: casting `bool` to `u64` is more cleanly stated with `u64::from(_)`
- --> $DIR/cast_lossless_bool.rs:11:13
+ --> $DIR/cast_lossless_bool.rs:12:13
|
LL | let _ = true as u64;
| ^^^^^^^^^^^ help: try: `u64::from(true)`
error: casting `bool` to `u128` is more cleanly stated with `u128::from(_)`
- --> $DIR/cast_lossless_bool.rs:12:13
+ --> $DIR/cast_lossless_bool.rs:13:13
|
LL | let _ = true as u128;
| ^^^^^^^^^^^^ help: try: `u128::from(true)`
error: casting `bool` to `usize` is more cleanly stated with `usize::from(_)`
- --> $DIR/cast_lossless_bool.rs:13:13
+ --> $DIR/cast_lossless_bool.rs:14:13
|
LL | let _ = true as usize;
| ^^^^^^^^^^^^^ help: try: `usize::from(true)`
error: casting `bool` to `i8` is more cleanly stated with `i8::from(_)`
- --> $DIR/cast_lossless_bool.rs:15:13
+ --> $DIR/cast_lossless_bool.rs:16:13
|
LL | let _ = true as i8;
| ^^^^^^^^^^ help: try: `i8::from(true)`
error: casting `bool` to `i16` is more cleanly stated with `i16::from(_)`
- --> $DIR/cast_lossless_bool.rs:16:13
+ --> $DIR/cast_lossless_bool.rs:17:13
|
LL | let _ = true as i16;
| ^^^^^^^^^^^ help: try: `i16::from(true)`
error: casting `bool` to `i32` is more cleanly stated with `i32::from(_)`
- --> $DIR/cast_lossless_bool.rs:17:13
+ --> $DIR/cast_lossless_bool.rs:18:13
|
LL | let _ = true as i32;
| ^^^^^^^^^^^ help: try: `i32::from(true)`
error: casting `bool` to `i64` is more cleanly stated with `i64::from(_)`
- --> $DIR/cast_lossless_bool.rs:18:13
+ --> $DIR/cast_lossless_bool.rs:19:13
|
LL | let _ = true as i64;
| ^^^^^^^^^^^ help: try: `i64::from(true)`
error: casting `bool` to `i128` is more cleanly stated with `i128::from(_)`
- --> $DIR/cast_lossless_bool.rs:19:13
+ --> $DIR/cast_lossless_bool.rs:20:13
|
LL | let _ = true as i128;
| ^^^^^^^^^^^^ help: try: `i128::from(true)`
error: casting `bool` to `isize` is more cleanly stated with `isize::from(_)`
- --> $DIR/cast_lossless_bool.rs:20:13
+ --> $DIR/cast_lossless_bool.rs:21:13
|
LL | let _ = true as isize;
| ^^^^^^^^^^^^^ help: try: `isize::from(true)`
error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)`
- --> $DIR/cast_lossless_bool.rs:23:13
+ --> $DIR/cast_lossless_bool.rs:24:13
|
LL | let _ = (true | false) as u16;
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::from(true | false)`
-error: aborting due to 13 previous errors
+error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)`
+ --> $DIR/cast_lossless_bool.rs:54:13
+ |
+LL | let _ = true as u8;
+ | ^^^^^^^^^^ help: try: `u8::from(true)`
+
+error: aborting due to 14 previous errors
diff --git a/src/tools/clippy/tests/ui/cast_nan_to_int.rs b/src/tools/clippy/tests/ui/cast_nan_to_int.rs
new file mode 100644
index 000000000..287c5aa21
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_nan_to_int.rs
@@ -0,0 +1,18 @@
+#![warn(clippy::cast_nan_to_int)]
+#![allow(clippy::eq_op)]
+
+fn main() {
+ let _ = (0.0_f32 / -0.0) as usize;
+ let _ = (f64::INFINITY * -0.0) as usize;
+ let _ = (0.0 * f32::INFINITY) as usize;
+
+ let _ = (f64::INFINITY + f64::NEG_INFINITY) as usize;
+ let _ = (f32::INFINITY - f32::INFINITY) as usize;
+ let _ = (f32::INFINITY / f32::NEG_INFINITY) as usize;
+
+ // those won't be linted:
+ let _ = (1.0_f32 / 0.0) as usize;
+ let _ = (f32::INFINITY * f32::NEG_INFINITY) as usize;
+ let _ = (f32::INFINITY - f32::NEG_INFINITY) as usize;
+ let _ = (f64::INFINITY - 0.0) as usize;
+}
diff --git a/src/tools/clippy/tests/ui/cast_nan_to_int.stderr b/src/tools/clippy/tests/ui/cast_nan_to_int.stderr
new file mode 100644
index 000000000..3539be75a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_nan_to_int.stderr
@@ -0,0 +1,51 @@
+error: casting a known NaN to usize
+ --> $DIR/cast_nan_to_int.rs:5:13
+ |
+LL | let _ = (0.0_f32 / -0.0) as usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this always evaluates to 0
+ = note: `-D clippy::cast-nan-to-int` implied by `-D warnings`
+
+error: casting a known NaN to usize
+ --> $DIR/cast_nan_to_int.rs:6:13
+ |
+LL | let _ = (f64::INFINITY * -0.0) as usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this always evaluates to 0
+
+error: casting a known NaN to usize
+ --> $DIR/cast_nan_to_int.rs:7:13
+ |
+LL | let _ = (0.0 * f32::INFINITY) as usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this always evaluates to 0
+
+error: casting a known NaN to usize
+ --> $DIR/cast_nan_to_int.rs:9:13
+ |
+LL | let _ = (f64::INFINITY + f64::NEG_INFINITY) as usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this always evaluates to 0
+
+error: casting a known NaN to usize
+ --> $DIR/cast_nan_to_int.rs:10:13
+ |
+LL | let _ = (f32::INFINITY - f32::INFINITY) as usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this always evaluates to 0
+
+error: casting a known NaN to usize
+ --> $DIR/cast_nan_to_int.rs:11:13
+ |
+LL | let _ = (f32::INFINITY / f32::NEG_INFINITY) as usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this always evaluates to 0
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed
new file mode 100644
index 000000000..b70c19129
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed
@@ -0,0 +1,24 @@
+// run-rustfix
+#![warn(clippy::cast_slice_from_raw_parts)]
+
+#[allow(unused_imports, unused_unsafe)]
+fn main() {
+ let mut vec = vec![0u8; 1];
+ let ptr: *const u8 = vec.as_ptr();
+ let mptr = vec.as_mut_ptr();
+ let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(ptr, 1) };
+ let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(mptr, 1) };
+ let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+ {
+ use core::slice;
+ let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+ use slice as one;
+ let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+ }
+ {
+ use std::slice;
+ let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+ use slice as one;
+ let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+ }
+}
diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs
new file mode 100644
index 000000000..c1b316765
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs
@@ -0,0 +1,24 @@
+// run-rustfix
+#![warn(clippy::cast_slice_from_raw_parts)]
+
+#[allow(unused_imports, unused_unsafe)]
+fn main() {
+ let mut vec = vec![0u8; 1];
+ let ptr: *const u8 = vec.as_ptr();
+ let mptr = vec.as_mut_ptr();
+ let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] };
+ let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] };
+ let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8];
+ {
+ use core::slice;
+ let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+ use slice as one;
+ let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+ }
+ {
+ use std::slice;
+ let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+ use slice as one;
+ let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+ }
+}
diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr
new file mode 100644
index 000000000..f07801c19
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr
@@ -0,0 +1,46 @@
+error: casting the result of `from_raw_parts` to *const [u8]
+ --> $DIR/cast_raw_slice_pointer_cast.rs:9:35
+ |
+LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+ |
+ = note: `-D clippy::cast-slice-from-raw-parts` implied by `-D warnings`
+
+error: casting the result of `from_raw_parts_mut` to *mut [u8]
+ --> $DIR/cast_raw_slice_pointer_cast.rs:10:35
+ |
+LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+ --> $DIR/cast_raw_slice_pointer_cast.rs:11:26
+ |
+LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+ --> $DIR/cast_raw_slice_pointer_cast.rs:14:30
+ |
+LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+ --> $DIR/cast_raw_slice_pointer_cast.rs:16:30
+ |
+LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+ --> $DIR/cast_raw_slice_pointer_cast.rs:20:30
+ |
+LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+ --> $DIR/cast_raw_slice_pointer_cast.rs:22:30
+ |
+LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed
index 061a4ab9b..8a5645b22 100644
--- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed
+++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed
@@ -1,5 +1,5 @@
// run-rustfix
-#![feature(stmt_expr_attributes)]
+#![feature(stmt_expr_attributes, custom_inner_attributes)]
#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
#![warn(clippy::deprecated_cfg_attr)]
@@ -29,3 +29,17 @@ mod foo {
pub fn f() {}
}
+
+fn msrv_1_29() {
+ #![clippy::msrv = "1.29"]
+
+ #[cfg_attr(rustfmt, rustfmt::skip)]
+ 1+29;
+}
+
+fn msrv_1_30() {
+ #![clippy::msrv = "1.30"]
+
+ #[rustfmt::skip]
+ 1+30;
+}
diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs
index 035169fab..2fb140efa 100644
--- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs
+++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs
@@ -1,5 +1,5 @@
// run-rustfix
-#![feature(stmt_expr_attributes)]
+#![feature(stmt_expr_attributes, custom_inner_attributes)]
#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
#![warn(clippy::deprecated_cfg_attr)]
@@ -29,3 +29,17 @@ mod foo {
pub fn f() {}
}
+
+fn msrv_1_29() {
+ #![clippy::msrv = "1.29"]
+
+ #[cfg_attr(rustfmt, rustfmt::skip)]
+ 1+29;
+}
+
+fn msrv_1_30() {
+ #![clippy::msrv = "1.30"]
+
+ #[cfg_attr(rustfmt, rustfmt::skip)]
+ 1+30;
+}
diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr
index c1efd47db..08df7b2b3 100644
--- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr
+++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr
@@ -12,5 +12,11 @@ error: `cfg_attr` is deprecated for rustfmt and got replaced by tool attributes
LL | #[cfg_attr(rustfmt, rustfmt_skip)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]`
-error: aborting due to 2 previous errors
+error: `cfg_attr` is deprecated for rustfmt and got replaced by tool attributes
+ --> $DIR/cfg_attr_rustfmt.rs:43:5
+ |
+LL | #[cfg_attr(rustfmt, rustfmt::skip)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]`
+
+error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8.stderr
index b9836d2f2..39fc9d6dd 100644
--- a/src/tools/clippy/tests/ui/char_lit_as_u8.stderr
+++ b/src/tools/clippy/tests/ui/char_lit_as_u8.stderr
@@ -4,8 +4,8 @@ error: casting a character literal to `u8` truncates
LL | let _ = '❤' as u8; // no suggestion, since a byte literal won't work.
| ^^^^^^^^^
|
- = note: `-D clippy::char-lit-as-u8` implied by `-D warnings`
= note: `char` is four bytes wide, but `u8` is a single byte
+ = note: `-D clippy::char-lit-as-u8` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr
index bf7cb1607..586174c50 100644
--- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr
+++ b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr
@@ -4,8 +4,8 @@ error: casting a character literal to `u8` truncates
LL | let _ = 'a' as u8;
| ^^^^^^^^^ help: use a byte literal instead: `b'a'`
|
- = note: `-D clippy::char-lit-as-u8` implied by `-D warnings`
= note: `char` is four bytes wide, but `u8` is a single byte
+ = note: `-D clippy::char-lit-as-u8` implied by `-D warnings`
error: casting a character literal to `u8` truncates
--> $DIR/char_lit_as_u8_suggestions.rs:7:13
diff --git a/src/tools/clippy/tests/ui/checked_conversions.fixed b/src/tools/clippy/tests/ui/checked_conversions.fixed
index cb7100bc9..f936957cb 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.fixed
+++ b/src/tools/clippy/tests/ui/checked_conversions.fixed
@@ -1,7 +1,9 @@
// run-rustfix
+#![feature(custom_inner_attributes)]
#![allow(
clippy::cast_lossless,
+ unused,
// Int::max_value will be deprecated in the future
deprecated,
)]
@@ -76,4 +78,18 @@ pub const fn issue_8898(i: u32) -> bool {
i <= i32::MAX as u32
}
+fn msrv_1_33() {
+ #![clippy::msrv = "1.33"]
+
+ let value: i64 = 33;
+ let _ = value <= (u32::MAX as i64) && value >= 0;
+}
+
+fn msrv_1_34() {
+ #![clippy::msrv = "1.34"]
+
+ let value: i64 = 34;
+ let _ = u32::try_from(value).is_ok();
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/checked_conversions.rs b/src/tools/clippy/tests/ui/checked_conversions.rs
index ed4e06923..77aec713f 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.rs
+++ b/src/tools/clippy/tests/ui/checked_conversions.rs
@@ -1,7 +1,9 @@
// run-rustfix
+#![feature(custom_inner_attributes)]
#![allow(
clippy::cast_lossless,
+ unused,
// Int::max_value will be deprecated in the future
deprecated,
)]
@@ -76,4 +78,18 @@ pub const fn issue_8898(i: u32) -> bool {
i <= i32::MAX as u32
}
+fn msrv_1_33() {
+ #![clippy::msrv = "1.33"]
+
+ let value: i64 = 33;
+ let _ = value <= (u32::MAX as i64) && value >= 0;
+}
+
+fn msrv_1_34() {
+ #![clippy::msrv = "1.34"]
+
+ let value: i64 = 34;
+ let _ = value <= (u32::MAX as i64) && value >= 0;
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/checked_conversions.stderr b/src/tools/clippy/tests/ui/checked_conversions.stderr
index 2e5180405..b2bf7af8d 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.stderr
+++ b/src/tools/clippy/tests/ui/checked_conversions.stderr
@@ -1,5 +1,5 @@
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:15:13
+ --> $DIR/checked_conversions.rs:17:13
|
LL | let _ = value <= (u32::max_value() as i64) && value >= 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
@@ -7,94 +7,100 @@ LL | let _ = value <= (u32::max_value() as i64) && value >= 0;
= note: `-D clippy::checked-conversions` implied by `-D warnings`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:16:13
+ --> $DIR/checked_conversions.rs:18:13
|
LL | let _ = value <= (u32::MAX as i64) && value >= 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:20:13
+ --> $DIR/checked_conversions.rs:22:13
|
LL | let _ = value <= i64::from(u16::max_value()) && value >= 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:21:13
+ --> $DIR/checked_conversions.rs:23:13
|
LL | let _ = value <= i64::from(u16::MAX) && value >= 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:25:13
+ --> $DIR/checked_conversions.rs:27:13
|
LL | let _ = value <= (u8::max_value() as isize) && value >= 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:26:13
+ --> $DIR/checked_conversions.rs:28:13
|
LL | let _ = value <= (u8::MAX as isize) && value >= 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:32:13
+ --> $DIR/checked_conversions.rs:34:13
|
LL | let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:33:13
+ --> $DIR/checked_conversions.rs:35:13
|
LL | let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:37:13
+ --> $DIR/checked_conversions.rs:39:13
|
LL | let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:38:13
+ --> $DIR/checked_conversions.rs:40:13
|
LL | let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:44:13
+ --> $DIR/checked_conversions.rs:46:13
|
LL | let _ = value <= i32::max_value() as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:45:13
+ --> $DIR/checked_conversions.rs:47:13
|
LL | let _ = value <= i32::MAX as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:49:13
+ --> $DIR/checked_conversions.rs:51:13
|
LL | let _ = value <= isize::max_value() as usize && value as i32 == 5;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:50:13
+ --> $DIR/checked_conversions.rs:52:13
|
LL | let _ = value <= isize::MAX as usize && value as i32 == 5;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:54:13
+ --> $DIR/checked_conversions.rs:56:13
|
LL | let _ = value <= u16::max_value() as u32 && value as i32 == 5;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
error: checked cast can be simplified
- --> $DIR/checked_conversions.rs:55:13
+ --> $DIR/checked_conversions.rs:57:13
|
LL | let _ = value <= u16::MAX as u32 && value as i32 == 5;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
-error: aborting due to 16 previous errors
+error: checked cast can be simplified
+ --> $DIR/checked_conversions.rs:92:13
+ |
+LL | let _ = value <= (u32::MAX as i64) && value >= 0;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
+
+error: aborting due to 17 previous errors
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr
index 46c6f6970..d44d5072e 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr
+++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr
@@ -6,12 +6,12 @@ LL | if x.is_ok() && y.is_err() {
LL | x.unwrap(); // unnecessary
| ^^^^^^^^^^
|
+ = help: try using `if let` or `match`
note: the lint level is defined here
--> $DIR/complex_conditionals.rs:1:35
|
LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: try using `if let` or `match`
error: this call to `unwrap_err()` will always panic
--> $DIR/complex_conditionals.rs:9:9
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.fixed b/src/tools/clippy/tests/ui/clone_on_copy.fixed
index dc0627626..72b122270 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.fixed
+++ b/src/tools/clippy/tests/ui/clone_on_copy.fixed
@@ -21,7 +21,7 @@ fn is_ascii(ch: char) -> bool {
ch.is_ascii()
}
-fn clone_on_copy() {
+fn clone_on_copy() -> Option<(i32)> {
42;
vec![1].clone(); // ok, not a Copy type
@@ -71,4 +71,9 @@ fn clone_on_copy() {
// Issue #5436
let mut vec = Vec::new();
vec.push(42);
+
+ // Issue #9277
+ let opt: &Option<i32> = &None;
+ let value = (*opt)?; // operator precedence needed (*opt)?
+ None
}
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.rs b/src/tools/clippy/tests/ui/clone_on_copy.rs
index 8c39d0d55..03e210eba 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.rs
+++ b/src/tools/clippy/tests/ui/clone_on_copy.rs
@@ -21,7 +21,7 @@ fn is_ascii(ch: char) -> bool {
ch.is_ascii()
}
-fn clone_on_copy() {
+fn clone_on_copy() -> Option<(i32)> {
42.clone();
vec![1].clone(); // ok, not a Copy type
@@ -71,4 +71,9 @@ fn clone_on_copy() {
// Issue #5436
let mut vec = Vec::new();
vec.push(42.clone());
+
+ // Issue #9277
+ let opt: &Option<i32> = &None;
+ let value = opt.clone()?; // operator precedence needed (*opt)?
+ None
}
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.stderr b/src/tools/clippy/tests/ui/clone_on_copy.stderr
index 861543d0a..42ae22777 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.stderr
+++ b/src/tools/clippy/tests/ui/clone_on_copy.stderr
@@ -48,5 +48,11 @@ error: using `clone` on type `i32` which implements the `Copy` trait
LL | vec.push(42.clone());
| ^^^^^^^^^^ help: try removing the `clone` call: `42`
-error: aborting due to 8 previous errors
+error: using `clone` on type `std::option::Option<i32>` which implements the `Copy` trait
+ --> $DIR/clone_on_copy.rs:77:17
+ |
+LL | let value = opt.clone()?; // operator precedence needed (*opt)?
+ | ^^^^^^^^^^^ help: try dereferencing it: `(*opt)`
+
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed b/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed
index 4eb999e18..42ed232d1 100644
--- a/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed
+++ b/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed
@@ -1,5 +1,8 @@
// run-rustfix
+
+#![feature(custom_inner_attributes)]
#![warn(clippy::cloned_instead_of_copied)]
+#![allow(unused)]
fn main() {
// yay
@@ -13,3 +16,24 @@ fn main() {
let _ = [String::new()].iter().cloned();
let _ = Some(&String::new()).cloned();
}
+
+fn msrv_1_34() {
+ #![clippy::msrv = "1.34"]
+
+ let _ = [1].iter().cloned();
+ let _ = Some(&1).cloned();
+}
+
+fn msrv_1_35() {
+ #![clippy::msrv = "1.35"]
+
+ let _ = [1].iter().cloned();
+ let _ = Some(&1).copied(); // Option::copied needs 1.35
+}
+
+fn msrv_1_36() {
+ #![clippy::msrv = "1.36"]
+
+ let _ = [1].iter().copied(); // Iterator::copied needs 1.36
+ let _ = Some(&1).copied();
+}
diff --git a/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs b/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs
index 894496c0e..471bd9654 100644
--- a/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs
+++ b/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs
@@ -1,5 +1,8 @@
// run-rustfix
+
+#![feature(custom_inner_attributes)]
#![warn(clippy::cloned_instead_of_copied)]
+#![allow(unused)]
fn main() {
// yay
@@ -13,3 +16,24 @@ fn main() {
let _ = [String::new()].iter().cloned();
let _ = Some(&String::new()).cloned();
}
+
+fn msrv_1_34() {
+ #![clippy::msrv = "1.34"]
+
+ let _ = [1].iter().cloned();
+ let _ = Some(&1).cloned();
+}
+
+fn msrv_1_35() {
+ #![clippy::msrv = "1.35"]
+
+ let _ = [1].iter().cloned();
+ let _ = Some(&1).cloned(); // Option::copied needs 1.35
+}
+
+fn msrv_1_36() {
+ #![clippy::msrv = "1.36"]
+
+ let _ = [1].iter().cloned(); // Iterator::copied needs 1.36
+ let _ = Some(&1).cloned();
+}
diff --git a/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr b/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr
index e0707d321..914c9a91e 100644
--- a/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr
+++ b/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr
@@ -1,5 +1,5 @@
error: used `cloned` where `copied` could be used instead
- --> $DIR/cloned_instead_of_copied.rs:6:24
+ --> $DIR/cloned_instead_of_copied.rs:9:24
|
LL | let _ = [1].iter().cloned();
| ^^^^^^ help: try: `copied`
@@ -7,28 +7,46 @@ LL | let _ = [1].iter().cloned();
= note: `-D clippy::cloned-instead-of-copied` implied by `-D warnings`
error: used `cloned` where `copied` could be used instead
- --> $DIR/cloned_instead_of_copied.rs:7:31
+ --> $DIR/cloned_instead_of_copied.rs:10:31
|
LL | let _ = vec!["hi"].iter().cloned();
| ^^^^^^ help: try: `copied`
error: used `cloned` where `copied` could be used instead
- --> $DIR/cloned_instead_of_copied.rs:8:22
+ --> $DIR/cloned_instead_of_copied.rs:11:22
|
LL | let _ = Some(&1).cloned();
| ^^^^^^ help: try: `copied`
error: used `cloned` where `copied` could be used instead
- --> $DIR/cloned_instead_of_copied.rs:9:34
+ --> $DIR/cloned_instead_of_copied.rs:12:34
|
LL | let _ = Box::new([1].iter()).cloned();
| ^^^^^^ help: try: `copied`
error: used `cloned` where `copied` could be used instead
- --> $DIR/cloned_instead_of_copied.rs:10:32
+ --> $DIR/cloned_instead_of_copied.rs:13:32
|
LL | let _ = Box::new(Some(&1)).cloned();
| ^^^^^^ help: try: `copied`
-error: aborting due to 5 previous errors
+error: used `cloned` where `copied` could be used instead
+ --> $DIR/cloned_instead_of_copied.rs:31:22
+ |
+LL | let _ = Some(&1).cloned(); // Option::copied needs 1.35
+ | ^^^^^^ help: try: `copied`
+
+error: used `cloned` where `copied` could be used instead
+ --> $DIR/cloned_instead_of_copied.rs:37:24
+ |
+LL | let _ = [1].iter().cloned(); // Iterator::copied needs 1.36
+ | ^^^^^^ help: try: `copied`
+
+error: used `cloned` where `copied` could be used instead
+ --> $DIR/cloned_instead_of_copied.rs:38:22
+ |
+LL | let _ = Some(&1).cloned();
+ | ^^^^^^ help: try: `copied`
+
+error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/cognitive_complexity.stderr b/src/tools/clippy/tests/ui/cognitive_complexity.stderr
index a0ddc673a..d7f2f24e5 100644
--- a/src/tools/clippy/tests/ui/cognitive_complexity.stderr
+++ b/src/tools/clippy/tests/ui/cognitive_complexity.stderr
@@ -4,8 +4,8 @@ error: the function has a cognitive complexity of (28/25)
LL | fn main() {
| ^^^^
|
- = note: `-D clippy::cognitive-complexity` implied by `-D warnings`
= help: you could split it up into multiple smaller functions
+ = note: `-D clippy::cognitive-complexity` implied by `-D warnings`
error: the function has a cognitive complexity of (7/1)
--> $DIR/cognitive_complexity.rs:91:4
diff --git a/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.stderr b/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.stderr
index f5ff53dda..bb48f3297 100644
--- a/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.stderr
+++ b/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.stderr
@@ -4,8 +4,8 @@ error: the function has a cognitive complexity of (3/0)
LL | fn kaboom() {
| ^^^^^^
|
- = note: `-D clippy::cognitive-complexity` implied by `-D warnings`
= help: you could split it up into multiple smaller functions
+ = note: `-D clippy::cognitive-complexity` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/collapsible_if.fixed b/src/tools/clippy/tests/ui/collapsible_if.fixed
index 5b0e4a473..6bb7682ba 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.fixed
+++ b/src/tools/clippy/tests/ui/collapsible_if.fixed
@@ -139,6 +139,9 @@ fn main() {
// Fix #5962
if matches!(true, true) && matches!(true, true) {}
+ // Issue #9375
+ if matches!(true, true) && truth() && matches!(true, true) {}
+
if true {
#[cfg(not(teehee))]
if true {
diff --git a/src/tools/clippy/tests/ui/collapsible_if.rs b/src/tools/clippy/tests/ui/collapsible_if.rs
index cd231a5d7..e216a9ee5 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.rs
+++ b/src/tools/clippy/tests/ui/collapsible_if.rs
@@ -155,6 +155,11 @@ fn main() {
if matches!(true, true) {}
}
+ // Issue #9375
+ if matches!(true, true) && truth() {
+ if matches!(true, true) {}
+ }
+
if true {
#[cfg(not(teehee))]
if true {
diff --git a/src/tools/clippy/tests/ui/collapsible_if.stderr b/src/tools/clippy/tests/ui/collapsible_if.stderr
index 674961238..6327444df 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_if.stderr
@@ -126,5 +126,13 @@ LL | | if matches!(true, true) {}
LL | | }
| |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}`
-error: aborting due to 8 previous errors
+error: this `if` statement can be collapsed
+ --> $DIR/collapsible_if.rs:159:5
+ |
+LL | / if matches!(true, true) && truth() {
+LL | | if matches!(true, true) {}
+LL | | }
+ | |_____^ help: collapse nested if block: `if matches!(true, true) && truth() && matches!(true, true) {}`
+
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/collapsible_match.rs b/src/tools/clippy/tests/ui/collapsible_match.rs
index 603ae7dc9..1d7a72846 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.rs
+++ b/src/tools/clippy/tests/ui/collapsible_match.rs
@@ -1,9 +1,10 @@
#![warn(clippy::collapsible_match)]
#![allow(
+ clippy::equatable_if_let,
clippy::needless_return,
clippy::no_effect,
clippy::single_match,
- clippy::equatable_if_let
+ clippy::uninlined_format_args
)]
fn lint_cases(opt_opt: Option<Option<u32>>, res_opt: Result<Option<u32>, String>) {
@@ -252,6 +253,27 @@ fn negative_cases(res_opt: Result<Option<u32>, String>, res_res: Result<Result<u
};
}
+pub enum Issue9647 {
+ A { a: Option<Option<u8>>, b: () },
+ B,
+}
+
+pub fn test_1(x: Issue9647) {
+ if let Issue9647::A { a, .. } = x {
+ if let Some(u) = a {
+ println!("{u:?}")
+ }
+ }
+}
+
+pub fn test_2(x: Issue9647) {
+ if let Issue9647::A { a: Some(a), .. } = x {
+ if let Some(u) = a {
+ println!("{u}")
+ }
+ }
+}
+
fn make<T>() -> T {
unimplemented!()
}
diff --git a/src/tools/clippy/tests/ui/collapsible_match.stderr b/src/tools/clippy/tests/ui/collapsible_match.stderr
index 5f18b6935..0294be60b 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_match.stderr
@@ -1,5 +1,5 @@
error: this `match` can be collapsed into the outer `match`
- --> $DIR/collapsible_match.rs:12:20
+ --> $DIR/collapsible_match.rs:13:20
|
LL | Ok(val) => match val {
| ____________________^
@@ -8,17 +8,17 @@ LL | | _ => return,
LL | | },
| |_________^
|
- = note: `-D clippy::collapsible-match` implied by `-D warnings`
help: the outer pattern can be modified to include the inner pattern
- --> $DIR/collapsible_match.rs:12:12
+ --> $DIR/collapsible_match.rs:13:12
|
LL | Ok(val) => match val {
| ^^^ replace this binding
LL | Some(n) => foo(n),
| ^^^^^^^ with this pattern
+ = note: `-D clippy::collapsible-match` implied by `-D warnings`
error: this `match` can be collapsed into the outer `match`
- --> $DIR/collapsible_match.rs:21:20
+ --> $DIR/collapsible_match.rs:22:20
|
LL | Ok(val) => match val {
| ____________________^
@@ -28,7 +28,7 @@ LL | | },
| |_________^
|
help: the outer pattern can be modified to include the inner pattern
- --> $DIR/collapsible_match.rs:21:12
+ --> $DIR/collapsible_match.rs:22:12
|
LL | Ok(val) => match val {
| ^^^ replace this binding
@@ -36,7 +36,7 @@ LL | Some(n) => foo(n),
| ^^^^^^^ with this pattern
error: this `if let` can be collapsed into the outer `if let`
- --> $DIR/collapsible_match.rs:30:9
+ --> $DIR/collapsible_match.rs:31:9
|
LL | / if let Some(n) = val {
LL | | take(n);
@@ -44,7 +44,7 @@ LL | | }
| |_________^
|
help: the outer pattern can be modified to include the inner pattern
- --> $DIR/collapsible_match.rs:29:15
+ --> $DIR/collapsible_match.rs:30:15
|
LL | if let Ok(val) = res_opt {
| ^^^ replace this binding
@@ -52,7 +52,7 @@ LL | if let Some(n) = val {
| ^^^^^^^ with this pattern
error: this `if let` can be collapsed into the outer `if let`
- --> $DIR/collapsible_match.rs:37:9
+ --> $DIR/collapsible_match.rs:38:9
|
LL | / if let Some(n) = val {
LL | | take(n);
@@ -62,7 +62,7 @@ LL | | }
| |_________^
|
help: the outer pattern can be modified to include the inner pattern
- --> $DIR/collapsible_match.rs:36:15
+ --> $DIR/collapsible_match.rs:37:15
|
LL | if let Ok(val) = res_opt {
| ^^^ replace this binding
@@ -70,7 +70,7 @@ LL | if let Some(n) = val {
| ^^^^^^^ with this pattern
error: this `match` can be collapsed into the outer `if let`
- --> $DIR/collapsible_match.rs:48:9
+ --> $DIR/collapsible_match.rs:49:9
|
LL | / match val {
LL | | Some(n) => foo(n),
@@ -79,7 +79,7 @@ LL | | }
| |_________^
|
help: the outer pattern can be modified to include the inner pattern
- --> $DIR/collapsible_match.rs:47:15
+ --> $DIR/collapsible_match.rs:48:15
|
LL | if let Ok(val) = res_opt {
| ^^^ replace this binding
@@ -88,7 +88,7 @@ LL | Some(n) => foo(n),
| ^^^^^^^ with this pattern
error: this `if let` can be collapsed into the outer `match`
- --> $DIR/collapsible_match.rs:57:13
+ --> $DIR/collapsible_match.rs:58:13
|
LL | / if let Some(n) = val {
LL | | take(n);
@@ -96,7 +96,7 @@ LL | | }
| |_____________^
|
help: the outer pattern can be modified to include the inner pattern
- --> $DIR/collapsible_match.rs:56:12
+ --> $DIR/collapsible_match.rs:57:12
|
LL | Ok(val) => {
| ^^^ replace this binding
@@ -104,7 +104,7 @@ LL | if let Some(n) = val {
| ^^^^^^^ with this pattern
error: this `match` can be collapsed into the outer `if let`
- --> $DIR/collapsible_match.rs:66:9
+ --> $DIR/collapsible_match.rs:67:9
|
LL | / match val {
LL | | Some(n) => foo(n),
@@ -113,7 +113,7 @@ LL | | }
| |_________^
|
help: the outer pattern can be modified to include the inner pattern
- --> $DIR/collapsible_match.rs:65:15
+ --> $DIR/collapsible_match.rs:66:15
|
LL | if let Ok(val) = res_opt {
| ^^^ replace this binding
@@ -122,7 +122,7 @@ LL | Some(n) => foo(n),
| ^^^^^^^ with this pattern
error: this `if let` can be collapsed into the outer `match`
- --> $DIR/collapsible_match.rs:77:13
+ --> $DIR/collapsible_match.rs:78:13
|
LL | / if let Some(n) = val {
LL | | take(n);
@@ -132,7 +132,7 @@ LL | | }
| |_____________^
|
help: the outer pattern can be modified to include the inner pattern
- --> $DIR/collapsible_match.rs:76:12
+ --> $DIR/collapsible_match.rs:77:12
|
LL | Ok(val) => {
| ^^^ replace this binding
@@ -140,7 +140,7 @@ LL | if let Some(n) = val {
| ^^^^^^^ with this pattern
error: this `match` can be collapsed into the outer `match`
- --> $DIR/collapsible_match.rs:88:20
+ --> $DIR/collapsible_match.rs:89:20
|
LL | Ok(val) => match val {
| ____________________^
@@ -150,7 +150,7 @@ LL | | },
| |_________^
|
help: the outer pattern can be modified to include the inner pattern
- --> $DIR/collapsible_match.rs:88:12
+ --> $DIR/collapsible_match.rs:89:12
|
LL | Ok(val) => match val {
| ^^^ replace this binding
@@ -158,7 +158,7 @@ LL | Some(n) => foo(n),
| ^^^^^^^ with this pattern
error: this `match` can be collapsed into the outer `match`
- --> $DIR/collapsible_match.rs:97:22
+ --> $DIR/collapsible_match.rs:98:22
|
LL | Some(val) => match val {
| ______________________^
@@ -168,12 +168,44 @@ LL | | },
| |_________^
|
help: the outer pattern can be modified to include the inner pattern
- --> $DIR/collapsible_match.rs:97:14
+ --> $DIR/collapsible_match.rs:98:14
|
LL | Some(val) => match val {
| ^^^ replace this binding
LL | Some(n) => foo(n),
| ^^^^^^^ with this pattern
-error: aborting due to 10 previous errors
+error: this `if let` can be collapsed into the outer `if let`
+ --> $DIR/collapsible_match.rs:263:9
+ |
+LL | / if let Some(u) = a {
+LL | | println!("{u:?}")
+LL | | }
+ | |_________^
+ |
+help: the outer pattern can be modified to include the inner pattern
+ --> $DIR/collapsible_match.rs:262:27
+ |
+LL | if let Issue9647::A { a, .. } = x {
+ | ^ replace this binding
+LL | if let Some(u) = a {
+ | ^^^^^^^ with this pattern, prefixed by a:
+
+error: this `if let` can be collapsed into the outer `if let`
+ --> $DIR/collapsible_match.rs:271:9
+ |
+LL | / if let Some(u) = a {
+LL | | println!("{u}")
+LL | | }
+ | |_________^
+ |
+help: the outer pattern can be modified to include the inner pattern
+ --> $DIR/collapsible_match.rs:270:35
+ |
+LL | if let Issue9647::A { a: Some(a), .. } = x {
+ | ^ replace this binding
+LL | if let Some(u) = a {
+ | ^^^^^^^ with this pattern
+
+error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/collapsible_match2.stderr b/src/tools/clippy/tests/ui/collapsible_match2.stderr
index fe64e4693..144dbe40a 100644
--- a/src/tools/clippy/tests/ui/collapsible_match2.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_match2.stderr
@@ -8,7 +8,6 @@ LL | | _ => return,
LL | | },
| |_____________^
|
- = note: `-D clippy::collapsible-match` implied by `-D warnings`
help: the outer pattern can be modified to include the inner pattern
--> $DIR/collapsible_match2.rs:13:16
|
@@ -16,6 +15,7 @@ LL | Ok(val) if make() => match val {
| ^^^ replace this binding
LL | Some(n) => foo(n),
| ^^^^^^^ with this pattern
+ = note: `-D clippy::collapsible-match` implied by `-D warnings`
error: this `match` can be collapsed into the outer `match`
--> $DIR/collapsible_match2.rs:20:24
diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.fixed b/src/tools/clippy/tests/ui/collapsible_str_replace.fixed
new file mode 100644
index 000000000..49fc9a962
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_str_replace.fixed
@@ -0,0 +1,73 @@
+// run-rustfix
+
+#![warn(clippy::collapsible_str_replace)]
+
+fn get_filter() -> char {
+ 'u'
+}
+
+fn main() {
+ let d = 'd';
+ let p = 'p';
+ let s = 's';
+ let u = 'u';
+ let l = "l";
+
+ let mut iter = ["l", "z"].iter();
+
+ // LINT CASES
+ let _ = "hesuo worpd".replace(['s', 'u'], "l");
+
+ let _ = "hesuo worpd".replace(['s', 'u'], l);
+
+ let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l");
+
+ let _ = "hesuo worpd"
+ .replace(['s', 'u', 'p', 'd'], "l");
+
+ let _ = "hesuo world".replace([s, 'u'], "l");
+
+ let _ = "hesuo worpd".replace([s, 'u', 'p'], "l");
+
+ let _ = "hesuo worpd".replace([s, u, 'p'], "l");
+
+ let _ = "hesuo worpd".replace([s, u, p], "l");
+
+ let _ = "hesuo worlp".replace(['s', 'u'], "l").replace('p', "d");
+
+ let _ = "hesuo worpd".replace('s', "x").replace(['u', 'p'], "l");
+
+ // Note: Future iterations could lint `replace(|c| matches!(c, "su" | 'd' | 'p'), "l")`
+ let _ = "hesudo worpd".replace("su", "l").replace(['d', 'p'], "l");
+
+ let _ = "hesudo worpd".replace([d, 'p'], "l").replace("su", "l");
+
+ let _ = "hesuo world".replace([get_filter(), 's'], "l");
+
+ // NO LINT CASES
+ let _ = "hesuo world".replace('s', "l").replace('u', "p");
+
+ let _ = "hesuo worpd".replace('s', "l").replace('p', l);
+
+ let _ = "hesudo worpd".replace('d', "l").replace("su", "l").replace('p', "l");
+
+ // Note: Future iterations of `collapsible_str_replace` might lint this and combine to `[s, u, p]`
+ let _ = "hesuo worpd".replace([s, u], "l").replace([u, p], "l");
+
+ let _ = "hesuo worpd".replace(['s', 'u'], "l").replace(['u', 'p'], "l");
+
+ let _ = "hesuo worpd".replace('s', "l").replace(['u', 'p'], "l");
+
+ let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l").replace('r', "l");
+
+ let _ = "hesuo worpd".replace(['s', 'u', 'p'], l).replace('r', l);
+
+ let _ = "hesuo worpd".replace(['s', u, 'p'], "l").replace('r', "l");
+
+ let _ = "hesuo worpd".replace([s, u], "l").replace(p, "l");
+
+ // Regression test
+ let _ = "hesuo worpd"
+ .replace('u', iter.next().unwrap())
+ .replace('s', iter.next().unwrap());
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.rs b/src/tools/clippy/tests/ui/collapsible_str_replace.rs
new file mode 100644
index 000000000..e3e25c414
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_str_replace.rs
@@ -0,0 +1,76 @@
+// run-rustfix
+
+#![warn(clippy::collapsible_str_replace)]
+
+fn get_filter() -> char {
+ 'u'
+}
+
+fn main() {
+ let d = 'd';
+ let p = 'p';
+ let s = 's';
+ let u = 'u';
+ let l = "l";
+
+ let mut iter = ["l", "z"].iter();
+
+ // LINT CASES
+ let _ = "hesuo worpd".replace('s', "l").replace('u', "l");
+
+ let _ = "hesuo worpd".replace('s', l).replace('u', l);
+
+ let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l");
+
+ let _ = "hesuo worpd"
+ .replace('s', "l")
+ .replace('u', "l")
+ .replace('p', "l")
+ .replace('d', "l");
+
+ let _ = "hesuo world".replace(s, "l").replace('u', "l");
+
+ let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l");
+
+ let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l");
+
+ let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l");
+
+ let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d");
+
+ let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l");
+
+ // Note: Future iterations could lint `replace(|c| matches!(c, "su" | 'd' | 'p'), "l")`
+ let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l");
+
+ let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l");
+
+ let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l");
+
+ // NO LINT CASES
+ let _ = "hesuo world".replace('s', "l").replace('u', "p");
+
+ let _ = "hesuo worpd".replace('s', "l").replace('p', l);
+
+ let _ = "hesudo worpd".replace('d', "l").replace("su", "l").replace('p', "l");
+
+ // Note: Future iterations of `collapsible_str_replace` might lint this and combine to `[s, u, p]`
+ let _ = "hesuo worpd".replace([s, u], "l").replace([u, p], "l");
+
+ let _ = "hesuo worpd".replace(['s', 'u'], "l").replace(['u', 'p'], "l");
+
+ let _ = "hesuo worpd".replace('s', "l").replace(['u', 'p'], "l");
+
+ let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l").replace('r', "l");
+
+ let _ = "hesuo worpd".replace(['s', 'u', 'p'], l).replace('r', l);
+
+ let _ = "hesuo worpd".replace(['s', u, 'p'], "l").replace('r', "l");
+
+ let _ = "hesuo worpd".replace([s, u], "l").replace(p, "l");
+
+ // Regression test
+ let _ = "hesuo worpd"
+ .replace('u', iter.next().unwrap())
+ .replace('s', iter.next().unwrap());
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.stderr b/src/tools/clippy/tests/ui/collapsible_str_replace.stderr
new file mode 100644
index 000000000..8e3daf3b8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_str_replace.stderr
@@ -0,0 +1,86 @@
+error: used consecutive `str::replace` call
+ --> $DIR/collapsible_str_replace.rs:19:27
+ |
+LL | let _ = "hesuo worpd".replace('s', "l").replace('u', "l");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")`
+ |
+ = note: `-D clippy::collapsible-str-replace` implied by `-D warnings`
+
+error: used consecutive `str::replace` call
+ --> $DIR/collapsible_str_replace.rs:21:27
+ |
+LL | let _ = "hesuo worpd".replace('s', l).replace('u', l);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], l)`
+
+error: used consecutive `str::replace` call
+ --> $DIR/collapsible_str_replace.rs:23:27
+ |
+LL | let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u', 'p'], "l")`
+
+error: used consecutive `str::replace` call
+ --> $DIR/collapsible_str_replace.rs:26:10
+ |
+LL | .replace('s', "l")
+ | __________^
+LL | | .replace('u', "l")
+LL | | .replace('p', "l")
+LL | | .replace('d', "l");
+ | |__________________________^ help: replace with: `replace(['s', 'u', 'p', 'd'], "l")`
+
+error: used consecutive `str::replace` call
+ --> $DIR/collapsible_str_replace.rs:31:27
+ |
+LL | let _ = "hesuo world".replace(s, "l").replace('u', "l");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u'], "l")`
+
+error: used consecutive `str::replace` call
+ --> $DIR/collapsible_str_replace.rs:33:27
+ |
+LL | let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u', 'p'], "l")`
+
+error: used consecutive `str::replace` call
+ --> $DIR/collapsible_str_replace.rs:35:27
+ |
+LL | let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, 'p'], "l")`
+
+error: used consecutive `str::replace` call
+ --> $DIR/collapsible_str_replace.rs:37:27
+ |
+LL | let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, p], "l")`
+
+error: used consecutive `str::replace` call
+ --> $DIR/collapsible_str_replace.rs:39:27
+ |
+LL | let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")`
+
+error: used consecutive `str::replace` call
+ --> $DIR/collapsible_str_replace.rs:41:45
+ |
+LL | let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['u', 'p'], "l")`
+
+error: used consecutive `str::replace` call
+ --> $DIR/collapsible_str_replace.rs:44:47
+ |
+LL | let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['d', 'p'], "l")`
+
+error: used consecutive `str::replace` call
+ --> $DIR/collapsible_str_replace.rs:46:28
+ |
+LL | let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([d, 'p'], "l")`
+
+error: used consecutive `str::replace` call
+ --> $DIR/collapsible_str_replace.rs:48:27
+ |
+LL | let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([get_filter(), 's'], "l")`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/comparison_chain.stderr b/src/tools/clippy/tests/ui/comparison_chain.stderr
index be25a80dd..2eeb50202 100644
--- a/src/tools/clippy/tests/ui/comparison_chain.stderr
+++ b/src/tools/clippy/tests/ui/comparison_chain.stderr
@@ -8,8 +8,8 @@ LL | | b()
LL | | }
| |_____^
|
- = note: `-D clippy::comparison-chain` implied by `-D warnings`
= help: consider rewriting the `if` chain to use `cmp` and `match`
+ = note: `-D clippy::comparison-chain` implied by `-D warnings`
error: `if` chain can be rewritten with `match`
--> $DIR/comparison_chain.rs:27:5
diff --git a/src/tools/clippy/tests/ui/copy_iterator.stderr b/src/tools/clippy/tests/ui/copy_iterator.stderr
index f8ce6af79..6bc6fd6b6 100644
--- a/src/tools/clippy/tests/ui/copy_iterator.stderr
+++ b/src/tools/clippy/tests/ui/copy_iterator.stderr
@@ -10,8 +10,8 @@ LL | | }
LL | | }
| |_^
|
- = note: `-D clippy::copy-iterator` implied by `-D warnings`
= note: consider implementing `IntoIterator` instead
+ = note: `-D clippy::copy-iterator` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2760.rs b/src/tools/clippy/tests/ui/crashes/ice-2760.rs
index f1a229f3f..61ef24804 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2760.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2760.rs
@@ -1,6 +1,6 @@
#![allow(
unused_variables,
- clippy::blacklisted_name,
+ clippy::disallowed_names,
clippy::needless_pass_by_value,
dead_code
)]
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3462.rs b/src/tools/clippy/tests/ui/crashes/ice-3462.rs
index 02c49aa0d..b40205288 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-3462.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-3462.rs
@@ -1,5 +1,5 @@
#![warn(clippy::all)]
-#![allow(clippy::blacklisted_name, clippy::equatable_if_let)]
+#![allow(clippy::disallowed_names, clippy::equatable_if_let)]
#![allow(unused)]
/// Test for https://github.com/rust-lang/rust-clippy/issues/3462
diff --git a/src/tools/clippy/tests/ui/crashes/ice-360.stderr b/src/tools/clippy/tests/ui/crashes/ice-360.stderr
index 0eb7bb12b..a2e2ab8fd 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-360.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-360.stderr
@@ -18,8 +18,8 @@ error: empty `loop {}` wastes CPU cycles
LL | loop {}
| ^^^^^^^
|
- = note: `-D clippy::empty-loop` implied by `-D warnings`
= help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
+ = note: `-D clippy::empty-loop` implied by `-D warnings`
error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/crashes/ice-4775.rs b/src/tools/clippy/tests/ui/crashes/ice-4775.rs
index 405e3039e..f693aafd1 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-4775.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-4775.rs
@@ -1,3 +1,5 @@
+#![allow(clippy::uninlined_format_args)]
+
pub struct ArrayWrapper<const N: usize>([usize; N]);
impl<const N: usize> ArrayWrapper<{ N }> {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.stderr b/src/tools/clippy/tests/ui/crashes/ice-6254.stderr
index f37ab2e9b..22d82a30c 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6254.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6254.stderr
@@ -4,9 +4,9 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated wit
LL | FOO_REF_REF => {},
| ^^^^^^^^^^^
|
- = note: `-D indirect-structural-match` implied by `-D warnings`
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+ = note: `-D indirect-structural-match` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7126.rs b/src/tools/clippy/tests/ui/crashes/ice-7126.rs
index ca563ba09..b2dc2248b 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-7126.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-7126.rs
@@ -1,13 +1,13 @@
// This test requires a feature gated const fn and will stop working in the future.
-#![feature(const_btree_new)]
+#![feature(const_btree_len)]
use std::collections::BTreeMap;
-struct Foo(BTreeMap<i32, i32>);
+struct Foo(usize);
impl Foo {
fn new() -> Self {
- Self(BTreeMap::new())
+ Self(BTreeMap::len(&BTreeMap::<u8, u8>::new()))
}
}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7868.stderr b/src/tools/clippy/tests/ui/crashes/ice-7868.stderr
index 1a33e6475..1d8314e88 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-7868.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-7868.stderr
@@ -4,8 +4,8 @@ error: unsafe block missing a safety comment
LL | unsafe { 0 };
| ^^^^^^^^^^^^
|
- = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
= help: consider adding a safety comment on the preceding line
+ = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7869.stderr b/src/tools/clippy/tests/ui/crashes/ice-7869.stderr
index 4fa9fb27e..35d1e8fd2 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-7869.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-7869.stderr
@@ -8,8 +8,8 @@ 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
+ = note: `-D clippy::enum-variant-names` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9405.rs b/src/tools/clippy/tests/ui/crashes/ice-9405.rs
new file mode 100644
index 000000000..e2d274aeb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-9405.rs
@@ -0,0 +1,11 @@
+#![warn(clippy::useless_format)]
+#![allow(clippy::print_literal)]
+
+fn main() {
+ println!(
+ "\
+
+ {}",
+ "multiple skipped lines"
+ );
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9405.stderr b/src/tools/clippy/tests/ui/crashes/ice-9405.stderr
new file mode 100644
index 000000000..9a6e410f2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-9405.stderr
@@ -0,0 +1,11 @@
+warning: multiple lines skipped by escaped newline
+ --> $DIR/ice-9405.rs:6:10
+ |
+LL | "/
+ | __________^
+LL | |
+LL | | {}",
+ | |____________^ skipping everything up to and including this point
+
+warning: 1 warning emitted
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9414.rs b/src/tools/clippy/tests/ui/crashes/ice-9414.rs
new file mode 100644
index 000000000..02cf5d5c2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-9414.rs
@@ -0,0 +1,8 @@
+#![warn(clippy::result_large_err)]
+
+trait T {}
+fn f(_: &u32) -> Result<(), *const (dyn '_ + T)> {
+ Ok(())
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9445.rs b/src/tools/clippy/tests/ui/crashes/ice-9445.rs
new file mode 100644
index 000000000..c67b22f6f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-9445.rs
@@ -0,0 +1,3 @@
+const UNINIT: core::mem::MaybeUninit<core::cell::Cell<&'static ()>> = core::mem::MaybeUninit::uninit();
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9459.rs b/src/tools/clippy/tests/ui/crashes/ice-9459.rs
new file mode 100644
index 000000000..55615124f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-9459.rs
@@ -0,0 +1,5 @@
+#![feature(unsized_fn_params)]
+
+pub fn f0(_f: dyn FnOnce()) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9463.rs b/src/tools/clippy/tests/ui/crashes/ice-9463.rs
new file mode 100644
index 000000000..9564e77c2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-9463.rs
@@ -0,0 +1,5 @@
+#![deny(arithmetic_overflow)]
+fn main() {
+ let _x = -1_i32 >> -1;
+ let _y = 1u32 >> 10000000000000u32;
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9463.stderr b/src/tools/clippy/tests/ui/crashes/ice-9463.stderr
new file mode 100644
index 000000000..2b425e85a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-9463.stderr
@@ -0,0 +1,29 @@
+error: this arithmetic operation will overflow
+ --> $DIR/ice-9463.rs:3:14
+ |
+LL | let _x = -1_i32 >> -1;
+ | ^^^^^^^^^^^^ attempt to shift right by `-1_i32`, which would overflow
+ |
+note: the lint level is defined here
+ --> $DIR/ice-9463.rs:1:9
+ |
+LL | #![deny(arithmetic_overflow)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: this arithmetic operation will overflow
+ --> $DIR/ice-9463.rs:4:14
+ |
+LL | let _y = 1u32 >> 10000000000000u32;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift right by `1316134912_u32`, which would overflow
+
+error: literal out of range for `u32`
+ --> $DIR/ice-9463.rs:4:22
+ |
+LL | let _y = 1u32 >> 10000000000000u32;
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: the literal `10000000000000u32` does not fit into the type `u32` whose range is `0..=4294967295`
+ = note: `#[deny(overflowing_literals)]` on by default
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9625.rs b/src/tools/clippy/tests/ui/crashes/ice-9625.rs
new file mode 100644
index 000000000..a765882b5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-9625.rs
@@ -0,0 +1,4 @@
+fn main() {
+ let x = &1;
+ let _ = &1 < x && x < &10;
+}
diff --git a/src/tools/clippy/tests/ui/crashes/regressions.rs b/src/tools/clippy/tests/ui/crashes/regressions.rs
index 6f9d98bbf..b34997d4e 100644
--- a/src/tools/clippy/tests/ui/crashes/regressions.rs
+++ b/src/tools/clippy/tests/ui/crashes/regressions.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names, clippy::uninlined_format_args)]
pub fn foo(bar: *const u8) {
println!("{:#p}", bar);
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.stderr b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.stderr
index 459cf12a1..3d79a115c 100644
--- a/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.stderr
+++ b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.stderr
@@ -4,8 +4,8 @@ error: recursing into entrypoint `a`
LL | a();
| ^
|
- = note: `-D clippy::main-recursion` implied by `-D warnings`
= help: consider using another function for this recursion
+ = note: `-D clippy::main-recursion` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr
index 48152d8ad..7d8ea3f76 100644
--- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr
+++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr
@@ -5,8 +5,8 @@ LL | / a = b;
LL | | b = a;
| |_________^ help: try: `core::mem::swap(&mut a, &mut b)`
|
- = note: `-D clippy::almost-swapped` implied by `-D warnings`
= note: or maybe you should use `core::mem::replace`?
+ = note: `-D clippy::almost-swapped` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.stderr b/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.stderr
index 0a260f9d2..82c68bd1c 100644
--- a/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.stderr
+++ b/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.stderr
@@ -4,8 +4,8 @@ error: recursing into entrypoint `main`
LL | main();
| ^^^^
|
- = note: `-D clippy::main-recursion` implied by `-D warnings`
= help: consider using another function for this recursion
+ = note: `-D clippy::main-recursion` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs
index 156c88e2e..a7da8f89a 100644
--- a/src/tools/clippy/tests/ui/def_id_nocore.rs
+++ b/src/tools/clippy/tests/ui/def_id_nocore.rs
@@ -1,4 +1,3 @@
-// ignore-windows
// ignore-macos
#![feature(no_core, lang_items, start)]
diff --git a/src/tools/clippy/tests/ui/def_id_nocore.stderr b/src/tools/clippy/tests/ui/def_id_nocore.stderr
index 40d355e9a..f8fc17e87 100644
--- a/src/tools/clippy/tests/ui/def_id_nocore.stderr
+++ b/src/tools/clippy/tests/ui/def_id_nocore.stderr
@@ -1,11 +1,11 @@
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
- --> $DIR/def_id_nocore.rs:28:19
+ --> $DIR/def_id_nocore.rs:27:19
|
LL | pub fn as_ref(self) -> &'static str {
| ^^^^
|
- = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
= help: consider choosing a less ambiguous name
+ = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed
index a28bff767..a370ccc76 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed
@@ -33,6 +33,7 @@ mod basic_expr {
let x: [f64; 3] = [1., 2., 3.];
let x: (f64, f64) = if true { (1., 2.) } else { (3., 4.) };
let x: _ = 1.;
+ const X: f32 = 1.;
}
}
@@ -59,6 +60,14 @@ mod nested_local {
// Should NOT lint this because this literal is bound to `_` of outer `Local`.
2.
};
+
+ const X: f32 = {
+ // Should lint this because this literal is not bound to any types.
+ let y = 1.0_f64;
+
+ // Should NOT lint this because this literal is bound to `_` of outer `Local`.
+ 1.
+ };
}
}
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs
index b48435cc7..2476fe951 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs
@@ -33,6 +33,7 @@ mod basic_expr {
let x: [f64; 3] = [1., 2., 3.];
let x: (f64, f64) = if true { (1., 2.) } else { (3., 4.) };
let x: _ = 1.;
+ const X: f32 = 1.;
}
}
@@ -59,6 +60,14 @@ mod nested_local {
// Should NOT lint this because this literal is bound to `_` of outer `Local`.
2.
};
+
+ const X: f32 = {
+ // Should lint this because this literal is not bound to any types.
+ let y = 1.;
+
+ // Should NOT lint this because this literal is bound to `_` of outer `Local`.
+ 1.
+ };
}
}
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr
index f8b6c7746..5df2f6423 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr
@@ -61,79 +61,85 @@ LL | _ => 1.,
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_f64.rs:43:21
+ --> $DIR/default_numeric_fallback_f64.rs:44:21
|
LL | let y = 1.;
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_f64.rs:51:21
+ --> $DIR/default_numeric_fallback_f64.rs:52:21
|
LL | let y = 1.;
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_f64.rs:57:21
+ --> $DIR/default_numeric_fallback_f64.rs:58:21
|
LL | let y = 1.;
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_f64.rs:69:9
+ --> $DIR/default_numeric_fallback_f64.rs:66:21
+ |
+LL | let y = 1.;
+ | ^^ help: consider adding suffix: `1.0_f64`
+
+error: default numeric fallback might occur
+ --> $DIR/default_numeric_fallback_f64.rs:78:9
|
LL | 1.
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_f64.rs:75:27
+ --> $DIR/default_numeric_fallback_f64.rs:84:27
|
LL | let f = || -> _ { 1. };
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_f64.rs:79:29
+ --> $DIR/default_numeric_fallback_f64.rs:88:29
|
LL | let f = || -> f64 { 1. };
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_f64.rs:93:21
+ --> $DIR/default_numeric_fallback_f64.rs:102:21
|
LL | generic_arg(1.);
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_f64.rs:96:32
+ --> $DIR/default_numeric_fallback_f64.rs:105:32
|
LL | let x: _ = generic_arg(1.);
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_f64.rs:114:28
+ --> $DIR/default_numeric_fallback_f64.rs:123:28
|
LL | GenericStruct { x: 1. };
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_f64.rs:117:36
+ --> $DIR/default_numeric_fallback_f64.rs:126:36
|
LL | let _ = GenericStruct { x: 1. };
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_f64.rs:135:24
+ --> $DIR/default_numeric_fallback_f64.rs:144:24
|
LL | GenericEnum::X(1.);
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_f64.rs:155:23
+ --> $DIR/default_numeric_fallback_f64.rs:164:23
|
LL | s.generic_arg(1.);
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_f64.rs:162:21
+ --> $DIR/default_numeric_fallback_f64.rs:171:21
|
LL | let x = 22.;
| ^^^ help: consider adding suffix: `22.0_f64`
@@ -143,5 +149,5 @@ LL | internal_macro!();
|
= note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 23 previous errors
+error: aborting due to 24 previous errors
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed
index 55451cf2f..3f4994f04 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed
@@ -33,6 +33,8 @@ mod basic_expr {
let x: [i32; 3] = [1, 2, 3];
let x: (i32, i32) = if true { (1, 2) } else { (3, 4) };
let x: _ = 1;
+ let x: u64 = 1;
+ const CONST_X: i8 = 1;
}
}
@@ -59,6 +61,14 @@ mod nested_local {
// Should NOT lint this because this literal is bound to `_` of outer `Local`.
2
};
+
+ const CONST_X: i32 = {
+ // Should lint this because this literal is not bound to any types.
+ let y = 1_i32;
+
+ // Should NOT lint this because this literal is bound to `_` of outer `Local`.
+ 1
+ };
}
}
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs
index 62d72f2fe..2df0e0978 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs
@@ -33,6 +33,8 @@ mod basic_expr {
let x: [i32; 3] = [1, 2, 3];
let x: (i32, i32) = if true { (1, 2) } else { (3, 4) };
let x: _ = 1;
+ let x: u64 = 1;
+ const CONST_X: i8 = 1;
}
}
@@ -59,6 +61,14 @@ mod nested_local {
// Should NOT lint this because this literal is bound to `_` of outer `Local`.
2
};
+
+ const CONST_X: i32 = {
+ // Should lint this because this literal is not bound to any types.
+ let y = 1;
+
+ // Should NOT lint this because this literal is bound to `_` of outer `Local`.
+ 1
+ };
}
}
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr
index f7c5e724c..6f219c3fc 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr
@@ -73,79 +73,85 @@ LL | _ => 2,
| ^ help: consider adding suffix: `2_i32`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_i32.rs:43:21
+ --> $DIR/default_numeric_fallback_i32.rs:45:21
|
LL | let y = 1;
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_i32.rs:51:21
+ --> $DIR/default_numeric_fallback_i32.rs:53:21
|
LL | let y = 1;
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_i32.rs:57:21
+ --> $DIR/default_numeric_fallback_i32.rs:59:21
|
LL | let y = 1;
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_i32.rs:69:9
+ --> $DIR/default_numeric_fallback_i32.rs:67:21
+ |
+LL | let y = 1;
+ | ^ help: consider adding suffix: `1_i32`
+
+error: default numeric fallback might occur
+ --> $DIR/default_numeric_fallback_i32.rs:79:9
|
LL | 1
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_i32.rs:75:27
+ --> $DIR/default_numeric_fallback_i32.rs:85:27
|
LL | let f = || -> _ { 1 };
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_i32.rs:79:29
+ --> $DIR/default_numeric_fallback_i32.rs:89:29
|
LL | let f = || -> i32 { 1 };
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_i32.rs:93:21
+ --> $DIR/default_numeric_fallback_i32.rs:103:21
|
LL | generic_arg(1);
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_i32.rs:96:32
+ --> $DIR/default_numeric_fallback_i32.rs:106:32
|
LL | let x: _ = generic_arg(1);
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_i32.rs:114:28
+ --> $DIR/default_numeric_fallback_i32.rs:124:28
|
LL | GenericStruct { x: 1 };
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_i32.rs:117:36
+ --> $DIR/default_numeric_fallback_i32.rs:127:36
|
LL | let _ = GenericStruct { x: 1 };
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_i32.rs:135:24
+ --> $DIR/default_numeric_fallback_i32.rs:145:24
|
LL | GenericEnum::X(1);
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_i32.rs:155:23
+ --> $DIR/default_numeric_fallback_i32.rs:165:23
|
LL | s.generic_arg(1);
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
- --> $DIR/default_numeric_fallback_i32.rs:162:21
+ --> $DIR/default_numeric_fallback_i32.rs:172:21
|
LL | let x = 22;
| ^^ help: consider adding suffix: `22_i32`
@@ -155,5 +161,5 @@ LL | internal_macro!();
|
= note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 25 previous errors
+error: aborting due to 26 previous errors
diff --git a/src/tools/clippy/tests/ui/default_trait_access.fixed b/src/tools/clippy/tests/ui/default_trait_access.fixed
index 264dd4efa..eedd43619 100644
--- a/src/tools/clippy/tests/ui/default_trait_access.fixed
+++ b/src/tools/clippy/tests/ui/default_trait_access.fixed
@@ -1,8 +1,12 @@
// run-rustfix
-
-#![allow(unused_imports, dead_code)]
+// aux-build: proc_macro_with_span.rs
#![deny(clippy::default_trait_access)]
+#![allow(dead_code, unused_imports)]
+#![allow(clippy::uninlined_format_args)]
+
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
use std::default;
use std::default::Default as D2;
use std::string;
@@ -51,6 +55,8 @@ fn main() {
..Default::default()
};
+ let _s21: String = with_span!(s Default::default());
+
println!(
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]",
s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20,
diff --git a/src/tools/clippy/tests/ui/default_trait_access.rs b/src/tools/clippy/tests/ui/default_trait_access.rs
index a0930fab8..11d4bc5c5 100644
--- a/src/tools/clippy/tests/ui/default_trait_access.rs
+++ b/src/tools/clippy/tests/ui/default_trait_access.rs
@@ -1,8 +1,12 @@
// run-rustfix
-
-#![allow(unused_imports, dead_code)]
+// aux-build: proc_macro_with_span.rs
#![deny(clippy::default_trait_access)]
+#![allow(dead_code, unused_imports)]
+#![allow(clippy::uninlined_format_args)]
+
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
use std::default;
use std::default::Default as D2;
use std::string;
@@ -51,6 +55,8 @@ fn main() {
..Default::default()
};
+ let _s21: String = with_span!(s Default::default());
+
println!(
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]",
s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20,
diff --git a/src/tools/clippy/tests/ui/default_trait_access.stderr b/src/tools/clippy/tests/ui/default_trait_access.stderr
index df8a5b94d..49b2dde3f 100644
--- a/src/tools/clippy/tests/ui/default_trait_access.stderr
+++ b/src/tools/clippy/tests/ui/default_trait_access.stderr
@@ -1,53 +1,53 @@
error: calling `std::string::String::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:11:22
+ --> $DIR/default_trait_access.rs:15:22
|
LL | let s1: String = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
|
note: the lint level is defined here
- --> $DIR/default_trait_access.rs:4:9
+ --> $DIR/default_trait_access.rs:3:9
|
LL | #![deny(clippy::default_trait_access)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: calling `std::string::String::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:15:22
+ --> $DIR/default_trait_access.rs:19:22
|
LL | let s3: String = D2::default();
| ^^^^^^^^^^^^^ help: try: `std::string::String::default()`
error: calling `std::string::String::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:17:22
+ --> $DIR/default_trait_access.rs:21:22
|
LL | let s4: String = std::default::Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
error: calling `std::string::String::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:21:22
+ --> $DIR/default_trait_access.rs:25:22
|
LL | let s6: String = default::Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
error: calling `GenericDerivedDefault::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:31:46
+ --> $DIR/default_trait_access.rs:35:46
|
LL | let s11: GenericDerivedDefault<String> = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()`
error: calling `TupleDerivedDefault::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:37:36
+ --> $DIR/default_trait_access.rs:41:36
|
LL | let s14: TupleDerivedDefault = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()`
error: calling `ArrayDerivedDefault::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:39:36
+ --> $DIR/default_trait_access.rs:43:36
|
LL | let s15: ArrayDerivedDefault = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()`
error: calling `TupleStructDerivedDefault::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:43:42
+ --> $DIR/default_trait_access.rs:47:42
|
LL | let s17: TupleStructDerivedDefault = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()`
diff --git a/src/tools/clippy/tests/ui/default_union_representation.stderr b/src/tools/clippy/tests/ui/default_union_representation.stderr
index 138884af8..8b7ed94cb 100644
--- a/src/tools/clippy/tests/ui/default_union_representation.stderr
+++ b/src/tools/clippy/tests/ui/default_union_representation.stderr
@@ -7,8 +7,8 @@ LL | | b: u32,
LL | | }
| |_^
|
- = note: `-D clippy::default-union-representation` implied by `-D warnings`
= help: consider annotating `NoAttribute` with `#[repr(C)]` to explicitly specify memory layout
+ = note: `-D clippy::default-union-representation` implied by `-D warnings`
error: this union has the default representation
--> $DIR/default_union_representation.rs:16:1
diff --git a/src/tools/clippy/tests/ui/derivable_impls.fixed b/src/tools/clippy/tests/ui/derivable_impls.fixed
new file mode 100644
index 000000000..7dcdfb093
--- /dev/null
+++ b/src/tools/clippy/tests/ui/derivable_impls.fixed
@@ -0,0 +1,213 @@
+// run-rustfix
+
+#![allow(dead_code)]
+
+use std::collections::HashMap;
+
+#[derive(Default)]
+struct FooDefault<'a> {
+ a: bool,
+ b: i32,
+ c: u64,
+ d: Vec<i32>,
+ e: FooND1,
+ f: FooND2,
+ g: HashMap<i32, i32>,
+ h: (i32, Vec<i32>),
+ i: [Vec<i32>; 3],
+ j: [i32; 5],
+ k: Option<i32>,
+ l: &'a [i32],
+}
+
+
+
+#[derive(Default)]
+struct TupleDefault(bool, i32, u64);
+
+
+
+struct FooND1 {
+ a: bool,
+}
+
+impl std::default::Default for FooND1 {
+ fn default() -> Self {
+ Self { a: true }
+ }
+}
+
+struct FooND2 {
+ a: i32,
+}
+
+impl std::default::Default for FooND2 {
+ fn default() -> Self {
+ Self { a: 5 }
+ }
+}
+
+struct FooNDNew {
+ a: bool,
+}
+
+impl FooNDNew {
+ fn new() -> Self {
+ Self { a: true }
+ }
+}
+
+impl Default for FooNDNew {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+struct FooNDVec(Vec<i32>);
+
+impl Default for FooNDVec {
+ fn default() -> Self {
+ Self(vec![5, 12])
+ }
+}
+
+#[derive(Default)]
+struct StrDefault<'a>(&'a str);
+
+
+
+#[derive(Default)]
+struct AlreadyDerived(i32, bool);
+
+macro_rules! mac {
+ () => {
+ 0
+ };
+ ($e:expr) => {
+ struct X(u32);
+ impl Default for X {
+ fn default() -> Self {
+ Self($e)
+ }
+ }
+ };
+}
+
+mac!(0);
+
+#[derive(Default)]
+struct Y(u32);
+
+
+struct RustIssue26925<T> {
+ a: Option<T>,
+}
+
+// We should watch out for cases where a manual impl is needed because a
+// derive adds different type bounds (https://github.com/rust-lang/rust/issues/26925).
+// For example, a struct with Option<T> does not require T: Default, but a derive adds
+// that type bound anyways. So until #26925 get fixed we should disable lint
+// for the following case
+impl<T> Default for RustIssue26925<T> {
+ fn default() -> Self {
+ Self { a: None }
+ }
+}
+
+struct SpecializedImpl<A, B> {
+ a: A,
+ b: B,
+}
+
+impl<T: Default> Default for SpecializedImpl<T, T> {
+ fn default() -> Self {
+ Self {
+ a: T::default(),
+ b: T::default(),
+ }
+ }
+}
+
+#[derive(Default)]
+struct WithoutSelfCurly {
+ a: bool,
+}
+
+
+
+#[derive(Default)]
+struct WithoutSelfParan(bool);
+
+
+
+// https://github.com/rust-lang/rust-clippy/issues/7655
+
+pub struct SpecializedImpl2<T> {
+ v: Vec<T>,
+}
+
+impl Default for SpecializedImpl2<String> {
+ fn default() -> Self {
+ Self { v: Vec::new() }
+ }
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/7654
+
+pub struct Color {
+ pub r: u8,
+ pub g: u8,
+ pub b: u8,
+}
+
+/// `#000000`
+impl Default for Color {
+ fn default() -> Self {
+ Color { r: 0, g: 0, b: 0 }
+ }
+}
+
+pub struct Color2 {
+ pub r: u8,
+ pub g: u8,
+ pub b: u8,
+}
+
+impl Default for Color2 {
+ /// `#000000`
+ fn default() -> Self {
+ Self { r: 0, g: 0, b: 0 }
+ }
+}
+
+#[derive(Default)]
+pub struct RepeatDefault1 {
+ a: [i8; 32],
+}
+
+
+
+pub struct RepeatDefault2 {
+ a: [i8; 33],
+}
+
+impl Default for RepeatDefault2 {
+ fn default() -> Self {
+ RepeatDefault2 { a: [0; 33] }
+ }
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/7753
+
+pub enum IntOrString {
+ Int(i32),
+ String(String),
+}
+
+impl Default for IntOrString {
+ fn default() -> Self {
+ IntOrString::Int(0)
+ }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/derivable_impls.rs b/src/tools/clippy/tests/ui/derivable_impls.rs
index a64120047..625cbcdde 100644
--- a/src/tools/clippy/tests/ui/derivable_impls.rs
+++ b/src/tools/clippy/tests/ui/derivable_impls.rs
@@ -1,3 +1,7 @@
+// run-rustfix
+
+#![allow(dead_code)]
+
use std::collections::HashMap;
struct FooDefault<'a> {
diff --git a/src/tools/clippy/tests/ui/derivable_impls.stderr b/src/tools/clippy/tests/ui/derivable_impls.stderr
index 49fb471a2..c1db5a58b 100644
--- a/src/tools/clippy/tests/ui/derivable_impls.stderr
+++ b/src/tools/clippy/tests/ui/derivable_impls.stderr
@@ -1,5 +1,5 @@
error: this `impl` can be derived
- --> $DIR/derivable_impls.rs:18:1
+ --> $DIR/derivable_impls.rs:22:1
|
LL | / impl std::default::Default for FooDefault<'_> {
LL | | fn default() -> Self {
@@ -11,10 +11,14 @@ LL | | }
| |_^
|
= note: `-D clippy::derivable-impls` implied by `-D warnings`
- = help: try annotating `FooDefault` with `#[derive(Default)]`
+ = help: remove the manual implementation...
+help: ...and instead derive it
+ |
+LL | #[derive(Default)]
+ |
error: this `impl` can be derived
- --> $DIR/derivable_impls.rs:39:1
+ --> $DIR/derivable_impls.rs:43:1
|
LL | / impl std::default::Default for TupleDefault {
LL | | fn default() -> Self {
@@ -23,10 +27,14 @@ LL | | }
LL | | }
| |_^
|
- = help: try annotating `TupleDefault` with `#[derive(Default)]`
+ = help: remove the manual implementation...
+help: ...and instead derive it
+ |
+LL | #[derive(Default)]
+ |
error: this `impl` can be derived
- --> $DIR/derivable_impls.rs:91:1
+ --> $DIR/derivable_impls.rs:95:1
|
LL | / impl Default for StrDefault<'_> {
LL | | fn default() -> Self {
@@ -35,10 +43,14 @@ LL | | }
LL | | }
| |_^
|
- = help: try annotating `StrDefault` with `#[derive(Default)]`
+ = help: remove the manual implementation...
+help: ...and instead derive it
+ |
+LL | #[derive(Default)]
+ |
error: this `impl` can be derived
- --> $DIR/derivable_impls.rs:117:1
+ --> $DIR/derivable_impls.rs:121:1
|
LL | / impl Default for Y {
LL | | fn default() -> Self {
@@ -47,10 +59,14 @@ LL | | }
LL | | }
| |_^
|
- = help: try annotating `Y` with `#[derive(Default)]`
+ = help: remove the manual implementation...
+help: ...and instead derive it
+ |
+LL | #[derive(Default)]
+ |
error: this `impl` can be derived
- --> $DIR/derivable_impls.rs:156:1
+ --> $DIR/derivable_impls.rs:160:1
|
LL | / impl Default for WithoutSelfCurly {
LL | | fn default() -> Self {
@@ -59,10 +75,14 @@ LL | | }
LL | | }
| |_^
|
- = help: try annotating `WithoutSelfCurly` with `#[derive(Default)]`
+ = help: remove the manual implementation...
+help: ...and instead derive it
+ |
+LL | #[derive(Default)]
+ |
error: this `impl` can be derived
- --> $DIR/derivable_impls.rs:164:1
+ --> $DIR/derivable_impls.rs:168:1
|
LL | / impl Default for WithoutSelfParan {
LL | | fn default() -> Self {
@@ -71,10 +91,14 @@ LL | | }
LL | | }
| |_^
|
- = help: try annotating `WithoutSelfParan` with `#[derive(Default)]`
+ = help: remove the manual implementation...
+help: ...and instead derive it
+ |
+LL | #[derive(Default)]
+ |
error: this `impl` can be derived
- --> $DIR/derivable_impls.rs:214:1
+ --> $DIR/derivable_impls.rs:218:1
|
LL | / impl Default for RepeatDefault1 {
LL | | fn default() -> Self {
@@ -83,7 +107,11 @@ LL | | }
LL | | }
| |_^
|
- = help: try annotating `RepeatDefault1` with `#[derive(Default)]`
+ = help: remove the manual implementation...
+help: ...and instead derive it
+ |
+LL | #[derive(Default)]
+ |
error: aborting due to 7 previous errors
diff --git a/src/tools/clippy/tests/ui/derive.stderr b/src/tools/clippy/tests/ui/derive.stderr
index 82a70ceec..e1fbb8dcd 100644
--- a/src/tools/clippy/tests/ui/derive.stderr
+++ b/src/tools/clippy/tests/ui/derive.stderr
@@ -8,7 +8,6 @@ LL | | }
LL | | }
| |_^
|
- = note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings`
note: consider deriving `Clone` or removing `Copy`
--> $DIR/derive.rs:8:1
|
@@ -18,6 +17,7 @@ LL | | Qux
LL | | }
LL | | }
| |_^
+ = note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings`
error: you are implementing `Clone` explicitly on a `Copy` type
--> $DIR/derive.rs:32:1
diff --git a/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr b/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr
index 2a4abb0c5..16c923978 100644
--- a/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr
+++ b/src/tools/clippy/tests/ui/derive_hash_xor_eq.stderr
@@ -4,12 +4,12 @@ error: you are deriving `Hash` but have implemented `PartialEq` explicitly
LL | #[derive(Hash)]
| ^^^^
|
- = note: `#[deny(clippy::derive_hash_xor_eq)]` on by default
note: `PartialEq` implemented here
--> $DIR/derive_hash_xor_eq.rs:15:1
|
LL | impl PartialEq for Bar {
| ^^^^^^^^^^^^^^^^^^^^^^
+ = note: `#[deny(clippy::derive_hash_xor_eq)]` on by default
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are deriving `Hash` but have implemented `PartialEq` explicitly
diff --git a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr
index baf8341ab..58efbb854 100644
--- a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr
+++ b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr
@@ -4,12 +4,12 @@ error: you are deriving `Ord` but have implemented `PartialOrd` explicitly
LL | #[derive(Ord, PartialEq, Eq)]
| ^^^
|
- = note: `-D clippy::derive-ord-xor-partial-ord` implied by `-D warnings`
note: `PartialOrd` implemented here
--> $DIR/derive_ord_xor_partial_ord.rs:24:1
|
LL | impl PartialOrd for DeriveOrd {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: `-D clippy::derive-ord-xor-partial-ord` implied by `-D warnings`
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are deriving `Ord` but have implemented `PartialOrd` explicitly
diff --git a/src/tools/clippy/tests/ui/blacklisted_name.rs b/src/tools/clippy/tests/ui/disallowed_names.rs
index 27df732a0..e937c49f3 100644
--- a/src/tools/clippy/tests/ui/blacklisted_name.rs
+++ b/src/tools/clippy/tests/ui/disallowed_names.rs
@@ -6,7 +6,7 @@
unused_mut,
unused_variables
)]
-#![warn(clippy::blacklisted_name)]
+#![warn(clippy::disallowed_names)]
fn test(foo: ()) {}
@@ -46,7 +46,7 @@ fn issue_1647_ref_mut() {
mod tests {
fn issue_7305() {
- // `blacklisted_name` lint should not be triggered inside of the test code.
+ // `disallowed_names` lint should not be triggered inside of the test code.
let foo = 0;
// Check that even in nested functions warning is still not triggered.
diff --git a/src/tools/clippy/tests/ui/disallowed_names.stderr b/src/tools/clippy/tests/ui/disallowed_names.stderr
new file mode 100644
index 000000000..78cb55096
--- /dev/null
+++ b/src/tools/clippy/tests/ui/disallowed_names.stderr
@@ -0,0 +1,88 @@
+error: use of a disallowed/placeholder name `foo`
+ --> $DIR/disallowed_names.rs:11:9
+ |
+LL | fn test(foo: ()) {}
+ | ^^^
+ |
+ = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: use of a disallowed/placeholder name `foo`
+ --> $DIR/disallowed_names.rs:14:9
+ |
+LL | let foo = 42;
+ | ^^^
+
+error: use of a disallowed/placeholder name `baz`
+ --> $DIR/disallowed_names.rs:15:9
+ |
+LL | let baz = 42;
+ | ^^^
+
+error: use of a disallowed/placeholder name `quux`
+ --> $DIR/disallowed_names.rs:16:9
+ |
+LL | let quux = 42;
+ | ^^^^
+
+error: use of a disallowed/placeholder name `foo`
+ --> $DIR/disallowed_names.rs:27:10
+ |
+LL | (foo, Some(baz), quux @ Some(_)) => (),
+ | ^^^
+
+error: use of a disallowed/placeholder name `baz`
+ --> $DIR/disallowed_names.rs:27:20
+ |
+LL | (foo, Some(baz), quux @ Some(_)) => (),
+ | ^^^
+
+error: use of a disallowed/placeholder name `quux`
+ --> $DIR/disallowed_names.rs:27:26
+ |
+LL | (foo, Some(baz), quux @ Some(_)) => (),
+ | ^^^^
+
+error: use of a disallowed/placeholder name `foo`
+ --> $DIR/disallowed_names.rs:32:19
+ |
+LL | fn issue_1647(mut foo: u8) {
+ | ^^^
+
+error: use of a disallowed/placeholder name `baz`
+ --> $DIR/disallowed_names.rs:33:13
+ |
+LL | let mut baz = 0;
+ | ^^^
+
+error: use of a disallowed/placeholder name `quux`
+ --> $DIR/disallowed_names.rs:34:21
+ |
+LL | if let Some(mut quux) = Some(42) {}
+ | ^^^^
+
+error: use of a disallowed/placeholder name `baz`
+ --> $DIR/disallowed_names.rs:38:13
+ |
+LL | let ref baz = 0;
+ | ^^^
+
+error: use of a disallowed/placeholder name `quux`
+ --> $DIR/disallowed_names.rs:39:21
+ |
+LL | if let Some(ref quux) = Some(42) {}
+ | ^^^^
+
+error: use of a disallowed/placeholder name `baz`
+ --> $DIR/disallowed_names.rs:43:17
+ |
+LL | let ref mut baz = 0;
+ | ^^^
+
+error: use of a disallowed/placeholder name `quux`
+ --> $DIR/disallowed_names.rs:44:25
+ |
+LL | if let Some(ref mut quux) = Some(42) {}
+ | ^^^^
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/diverging_sub_expression.rs b/src/tools/clippy/tests/ui/diverging_sub_expression.rs
index e27f9fea7..e8f992e6d 100644
--- a/src/tools/clippy/tests/ui/diverging_sub_expression.rs
+++ b/src/tools/clippy/tests/ui/diverging_sub_expression.rs
@@ -1,5 +1,5 @@
#![warn(clippy::diverging_sub_expression)]
-#![allow(clippy::match_same_arms, clippy::logic_bug)]
+#![allow(clippy::match_same_arms, clippy::overly_complex_bool_expr)]
#[allow(clippy::empty_loop)]
fn diverge() -> ! {
loop {}
diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
index a462b9887..f2ac6bc32 100644
--- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
+++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
@@ -7,8 +7,8 @@ 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
+ = note: `-D clippy::doc-markdown` implied by `-D warnings`
error: backticks are unbalanced
--> $DIR/unbalanced_ticks.rs:13:1
diff --git a/src/tools/clippy/tests/ui/doc_link_with_quotes.rs b/src/tools/clippy/tests/ui/doc_link_with_quotes.rs
index ab52fb1a4..17c04c34e 100644
--- a/src/tools/clippy/tests/ui/doc_link_with_quotes.rs
+++ b/src/tools/clippy/tests/ui/doc_link_with_quotes.rs
@@ -4,9 +4,14 @@ fn main() {
foo()
}
-/// Calls ['bar']
+/// Calls ['bar'] uselessly
pub fn foo() {
bar()
}
+/// # Examples
+/// This demonstrates issue \#8961
+/// ```
+/// let _ = vec!['w', 'a', 't'];
+/// ```
pub fn bar() {}
diff --git a/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr b/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr
index bf6d57d8a..ea730e667 100644
--- a/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr
+++ b/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr
@@ -1,8 +1,8 @@
error: possible intra-doc link using quotes instead of backticks
- --> $DIR/doc_link_with_quotes.rs:7:1
+ --> $DIR/doc_link_with_quotes.rs:7:12
|
-LL | /// Calls ['bar']
- | ^^^^^^^^^^^^^^^^^
+LL | /// Calls ['bar'] uselessly
+ | ^^^^^
|
= note: `-D clippy::doc-link-with-quotes` implied by `-D warnings`
diff --git a/src/tools/clippy/tests/ui/double_must_use.stderr b/src/tools/clippy/tests/ui/double_must_use.stderr
index 8290ece1c..3d34557a8 100644
--- a/src/tools/clippy/tests/ui/double_must_use.stderr
+++ b/src/tools/clippy/tests/ui/double_must_use.stderr
@@ -4,8 +4,8 @@ error: this function has an empty `#[must_use]` attribute, but returns a type al
LL | pub fn must_use_result() -> Result<(), ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::double-must-use` implied by `-D warnings`
= help: either add some descriptive text or remove the attribute
+ = note: `-D clippy::double-must-use` implied by `-D warnings`
error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`
--> $DIR/double_must_use.rs:10:1
diff --git a/src/tools/clippy/tests/ui/drop_forget_copy.rs b/src/tools/clippy/tests/ui/drop_forget_copy.rs
index 7c7a9ecff..a7276dd59 100644
--- a/src/tools/clippy/tests/ui/drop_forget_copy.rs
+++ b/src/tools/clippy/tests/ui/drop_forget_copy.rs
@@ -64,3 +64,23 @@ fn main() {
let a5 = a1.clone();
forget(a5);
}
+
+#[allow(unused)]
+#[allow(clippy::unit_cmp)]
+fn issue9482(x: u8) {
+ fn println_and<T>(t: T) -> T {
+ println!("foo");
+ t
+ }
+
+ match x {
+ 0 => drop(println_and(12)), // Don't lint (copy type), we only care about side-effects
+ 1 => drop(println_and(String::new())), // Don't lint (no copy type), we only care about side-effects
+ 2 => {
+ drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block
+ },
+ 3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
+ 4 => drop(2), // Lint, not a fn/method call
+ _ => (),
+ }
+}
diff --git a/src/tools/clippy/tests/ui/drop_forget_copy.stderr b/src/tools/clippy/tests/ui/drop_forget_copy.stderr
index 88228afae..90bef1c3c 100644
--- a/src/tools/clippy/tests/ui/drop_forget_copy.stderr
+++ b/src/tools/clippy/tests/ui/drop_forget_copy.stderr
@@ -4,12 +4,12 @@ error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a
LL | drop(s1);
| ^^^^^^^^
|
- = note: `-D clippy::drop-copy` implied by `-D warnings`
note: argument has type `SomeStruct`
--> $DIR/drop_forget_copy.rs:33:10
|
LL | drop(s1);
| ^^
+ = note: `-D clippy::drop-copy` implied by `-D warnings`
error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact
--> $DIR/drop_forget_copy.rs:34:5
@@ -41,12 +41,12 @@ error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetti
LL | forget(s1);
| ^^^^^^^^^^
|
- = note: `-D clippy::forget-copy` implied by `-D warnings`
note: argument has type `SomeStruct`
--> $DIR/drop_forget_copy.rs:39:12
|
LL | forget(s1);
| ^^
+ = note: `-D clippy::forget-copy` implied by `-D warnings`
error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact
--> $DIR/drop_forget_copy.rs:40:5
@@ -72,5 +72,41 @@ note: argument has type `SomeStruct`
LL | forget(s4);
| ^^
-error: aborting due to 6 previous errors
+error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact
+ --> $DIR/drop_forget_copy.rs:80:13
+ |
+LL | drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+note: argument has type `i32`
+ --> $DIR/drop_forget_copy.rs:80:18
+ |
+LL | drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block
+ | ^^^^^^^^^^^^^^^
+
+error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact
+ --> $DIR/drop_forget_copy.rs:82:14
+ |
+LL | 3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+note: argument has type `i32`
+ --> $DIR/drop_forget_copy.rs:82:19
+ |
+LL | 3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
+ | ^^^^^^^^^^^^^^^
+
+error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact
+ --> $DIR/drop_forget_copy.rs:83:14
+ |
+LL | 4 => drop(2), // Lint, not a fn/method call
+ | ^^^^^^^
+ |
+note: argument has type `i32`
+ --> $DIR/drop_forget_copy.rs:83:19
+ |
+LL | 4 => drop(2), // Lint, not a fn/method call
+ | ^
+
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/drop_non_drop.stderr b/src/tools/clippy/tests/ui/drop_non_drop.stderr
index 30121033d..b86057c0c 100644
--- a/src/tools/clippy/tests/ui/drop_non_drop.stderr
+++ b/src/tools/clippy/tests/ui/drop_non_drop.stderr
@@ -4,12 +4,12 @@ error: call to `std::mem::drop` with a value that does not implement `Drop`. Dro
LL | drop(Foo);
| ^^^^^^^^^
|
- = note: `-D clippy::drop-non-drop` implied by `-D warnings`
note: argument has type `main::Foo`
--> $DIR/drop_non_drop.rs:22:10
|
LL | drop(Foo);
| ^^^
+ = note: `-D clippy::drop-non-drop` implied by `-D warnings`
error: call to `std::mem::drop` with a value that does not implement `Drop`. Dropping such a type only extends its contained lifetimes
--> $DIR/drop_non_drop.rs:37:5
diff --git a/src/tools/clippy/tests/ui/drop_ref.stderr b/src/tools/clippy/tests/ui/drop_ref.stderr
index 531849f06..4743cf79b 100644
--- a/src/tools/clippy/tests/ui/drop_ref.stderr
+++ b/src/tools/clippy/tests/ui/drop_ref.stderr
@@ -4,12 +4,12 @@ error: calls to `std::mem::drop` with a reference instead of an owned value. Dro
LL | drop(&SomeStruct);
| ^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::drop-ref` implied by `-D warnings`
note: argument has type `&SomeStruct`
--> $DIR/drop_ref.rs:11:10
|
LL | drop(&SomeStruct);
| ^^^^^^^^^^^
+ = note: `-D clippy::drop-ref` implied by `-D warnings`
error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
--> $DIR/drop_ref.rs:14:5
diff --git a/src/tools/clippy/tests/ui/else_if_without_else.stderr b/src/tools/clippy/tests/ui/else_if_without_else.stderr
index 6f47658cf..90ccfb4fa 100644
--- a/src/tools/clippy/tests/ui/else_if_without_else.stderr
+++ b/src/tools/clippy/tests/ui/else_if_without_else.stderr
@@ -8,8 +8,8 @@ LL | | println!("else if");
LL | | }
| |_____^
|
- = note: `-D clippy::else-if-without-else` implied by `-D warnings`
= help: add an `else` block here
+ = note: `-D clippy::else-if-without-else` implied by `-D warnings`
error: `if` expression with an `else if`, but without a final `else`
--> $DIR/else_if_without_else.rs:54:12
diff --git a/src/tools/clippy/tests/ui/empty_enum.stderr b/src/tools/clippy/tests/ui/empty_enum.stderr
index 7125e5f60..0d9aa5818 100644
--- a/src/tools/clippy/tests/ui/empty_enum.stderr
+++ b/src/tools/clippy/tests/ui/empty_enum.stderr
@@ -4,8 +4,8 @@ error: enum with no variants
LL | enum Empty {}
| ^^^^^^^^^^^^^
|
- = note: `-D clippy::empty-enum` implied by `-D warnings`
= help: consider using the uninhabited type `!` (never type) or a wrapper around it to introduce a type which can't be instantiated
+ = note: `-D clippy::empty-enum` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/empty_loop.stderr b/src/tools/clippy/tests/ui/empty_loop.stderr
index 555f3d3d8..760241233 100644
--- a/src/tools/clippy/tests/ui/empty_loop.stderr
+++ b/src/tools/clippy/tests/ui/empty_loop.stderr
@@ -4,8 +4,8 @@ error: empty `loop {}` wastes CPU cycles
LL | loop {}
| ^^^^^^^
|
- = note: `-D clippy::empty-loop` implied by `-D warnings`
= help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
+ = note: `-D clippy::empty-loop` implied by `-D warnings`
error: empty `loop {}` wastes CPU cycles
--> $DIR/empty_loop.rs:11:9
diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.rs b/src/tools/clippy/tests/ui/empty_loop_no_std.rs
index 235e0fc51..e742b396f 100644
--- a/src/tools/clippy/tests/ui/empty_loop_no_std.rs
+++ b/src/tools/clippy/tests/ui/empty_loop_no_std.rs
@@ -1,6 +1,5 @@
// compile-flags: -Clink-arg=-nostartfiles
// ignore-macos
-// ignore-windows
#![warn(clippy::empty_loop)]
#![feature(lang_items, start, libc)]
diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr
index 520248fcb..71af64f49 100644
--- a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr
+++ b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr
@@ -1,14 +1,14 @@
error: empty `loop {}` wastes CPU cycles
- --> $DIR/empty_loop_no_std.rs:14:5
+ --> $DIR/empty_loop_no_std.rs:13:5
|
LL | loop {}
| ^^^^^^^
|
- = note: `-D clippy::empty-loop` implied by `-D warnings`
= help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body
+ = note: `-D clippy::empty-loop` implied by `-D warnings`
error: empty `loop {}` wastes CPU cycles
- --> $DIR/empty_loop_no_std.rs:26:5
+ --> $DIR/empty_loop_no_std.rs:25:5
|
LL | loop {}
| ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/entry.fixed b/src/tools/clippy/tests/ui/entry.fixed
index e43635abc..79c29c04e 100644
--- a/src/tools/clippy/tests/ui/entry.fixed
+++ b/src/tools/clippy/tests/ui/entry.fixed
@@ -1,3 +1,4 @@
+// needs-asm-support
// run-rustfix
#![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
diff --git a/src/tools/clippy/tests/ui/entry.rs b/src/tools/clippy/tests/ui/entry.rs
index d999b3b7d..2d7985457 100644
--- a/src/tools/clippy/tests/ui/entry.rs
+++ b/src/tools/clippy/tests/ui/entry.rs
@@ -1,3 +1,4 @@
+// needs-asm-support
// run-rustfix
#![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
diff --git a/src/tools/clippy/tests/ui/entry.stderr b/src/tools/clippy/tests/ui/entry.stderr
index 2ef996652..2c4c49d25 100644
--- a/src/tools/clippy/tests/ui/entry.stderr
+++ b/src/tools/clippy/tests/ui/entry.stderr
@@ -1,5 +1,5 @@
error: usage of `contains_key` followed by `insert` on a `HashMap`
- --> $DIR/entry.rs:24:5
+ --> $DIR/entry.rs:25:5
|
LL | / if !m.contains_key(&k) {
LL | | m.insert(k, v);
@@ -9,7 +9,7 @@ LL | | }
= note: `-D clippy::map-entry` implied by `-D warnings`
error: usage of `contains_key` followed by `insert` on a `HashMap`
- --> $DIR/entry.rs:29:5
+ --> $DIR/entry.rs:30:5
|
LL | / if !m.contains_key(&k) {
LL | | if true {
@@ -32,7 +32,7 @@ LL + });
|
error: usage of `contains_key` followed by `insert` on a `HashMap`
- --> $DIR/entry.rs:38:5
+ --> $DIR/entry.rs:39:5
|
LL | / if !m.contains_key(&k) {
LL | | if true {
@@ -55,7 +55,7 @@ LL + });
|
error: usage of `contains_key` followed by `insert` on a `HashMap`
- --> $DIR/entry.rs:47:5
+ --> $DIR/entry.rs:48:5
|
LL | / if !m.contains_key(&k) {
LL | | if true {
@@ -79,7 +79,7 @@ LL + }
|
error: usage of `contains_key` followed by `insert` on a `HashMap`
- --> $DIR/entry.rs:57:5
+ --> $DIR/entry.rs:58:5
|
LL | / if !m.contains_key(&k) {
LL | | foo();
@@ -96,7 +96,7 @@ LL + });
|
error: usage of `contains_key` followed by `insert` on a `HashMap`
- --> $DIR/entry.rs:63:5
+ --> $DIR/entry.rs:64:5
|
LL | / if !m.contains_key(&k) {
LL | | match 0 {
@@ -122,7 +122,7 @@ LL + });
|
error: usage of `contains_key` followed by `insert` on a `HashMap`
- --> $DIR/entry.rs:75:5
+ --> $DIR/entry.rs:76:5
|
LL | / if !m.contains_key(&k) {
LL | | match 0 {
@@ -146,7 +146,7 @@ LL + }
|
error: usage of `contains_key` followed by `insert` on a `HashMap`
- --> $DIR/entry.rs:85:5
+ --> $DIR/entry.rs:86:5
|
LL | / if !m.contains_key(&k) {
LL | | foo();
@@ -187,7 +187,7 @@ LL + });
|
error: usage of `contains_key` followed by `insert` on a `HashMap`
- --> $DIR/entry.rs:119:5
+ --> $DIR/entry.rs:120:5
|
LL | / if !m.contains_key(&m!(k)) {
LL | | m.insert(m!(k), m!(v));
@@ -195,7 +195,7 @@ LL | | }
| |_____^ help: try this: `m.entry(m!(k)).or_insert_with(|| m!(v));`
error: usage of `contains_key` followed by `insert` on a `HashMap`
- --> $DIR/entry.rs:151:5
+ --> $DIR/entry.rs:152:5
|
LL | / if !m.contains_key(&k) {
LL | | let x = (String::new(), String::new());
diff --git a/src/tools/clippy/tests/ui/eprint_with_newline.rs b/src/tools/clippy/tests/ui/eprint_with_newline.rs
index 8df32649a..de5e121be 100644
--- a/src/tools/clippy/tests/ui/eprint_with_newline.rs
+++ b/src/tools/clippy/tests/ui/eprint_with_newline.rs
@@ -45,5 +45,13 @@ fn main() {
eprint!("\r\n");
eprint!("foo\r\n");
eprint!("\\r\n"); //~ ERROR
- eprint!("foo\rbar\n") // ~ ERROR
+ eprint!("foo\rbar\n");
+
+ // Ignore expanded format strings
+ macro_rules! newline {
+ () => {
+ "\n"
+ };
+ }
+ eprint!(newline!());
}
diff --git a/src/tools/clippy/tests/ui/eprint_with_newline.stderr b/src/tools/clippy/tests/ui/eprint_with_newline.stderr
index f137787bf..0eefb9f0c 100644
--- a/src/tools/clippy/tests/ui/eprint_with_newline.stderr
+++ b/src/tools/clippy/tests/ui/eprint_with_newline.stderr
@@ -83,7 +83,7 @@ LL | | );
help: use `eprintln!` instead
|
LL ~ eprintln!(
-LL ~ ""
+LL ~
|
error: using `eprint!()` with a format string that ends in a single newline
@@ -98,7 +98,7 @@ LL | | );
help: use `eprintln!` instead
|
LL ~ eprintln!(
-LL ~ r""
+LL ~
|
error: using `eprint!()` with a format string that ends in a single newline
@@ -113,17 +113,5 @@ LL - eprint!("/r/n"); //~ ERROR
LL + eprintln!("/r"); //~ ERROR
|
-error: using `eprint!()` with a format string that ends in a single newline
- --> $DIR/eprint_with_newline.rs:48:5
- |
-LL | eprint!("foo/rbar/n") // ~ ERROR
- | ^^^^^^^^^^^^^^^^^^^^^
- |
-help: use `eprintln!` instead
- |
-LL - eprint!("foo/rbar/n") // ~ ERROR
-LL + eprintln!("foo/rbar") // ~ ERROR
- |
-
-error: aborting due to 10 previous errors
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/err_expect.fixed b/src/tools/clippy/tests/ui/err_expect.fixed
index 7e18d70ba..3bac738ac 100644
--- a/src/tools/clippy/tests/ui/err_expect.fixed
+++ b/src/tools/clippy/tests/ui/err_expect.fixed
@@ -1,5 +1,8 @@
// run-rustfix
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
+
struct MyTypeNonDebug;
#[derive(Debug)]
@@ -12,3 +15,17 @@ fn main() {
let test_non_debug: Result<MyTypeNonDebug, u32> = Ok(MyTypeNonDebug);
test_non_debug.err().expect("Testing non debug type");
}
+
+fn msrv_1_16() {
+ #![clippy::msrv = "1.16"]
+
+ let x: Result<u32, &str> = Ok(16);
+ x.err().expect("16");
+}
+
+fn msrv_1_17() {
+ #![clippy::msrv = "1.17"]
+
+ let x: Result<u32, &str> = Ok(17);
+ x.expect_err("17");
+}
diff --git a/src/tools/clippy/tests/ui/err_expect.rs b/src/tools/clippy/tests/ui/err_expect.rs
index bf8c3c9fb..6e7c47d9a 100644
--- a/src/tools/clippy/tests/ui/err_expect.rs
+++ b/src/tools/clippy/tests/ui/err_expect.rs
@@ -1,5 +1,8 @@
// run-rustfix
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
+
struct MyTypeNonDebug;
#[derive(Debug)]
@@ -12,3 +15,17 @@ fn main() {
let test_non_debug: Result<MyTypeNonDebug, u32> = Ok(MyTypeNonDebug);
test_non_debug.err().expect("Testing non debug type");
}
+
+fn msrv_1_16() {
+ #![clippy::msrv = "1.16"]
+
+ let x: Result<u32, &str> = Ok(16);
+ x.err().expect("16");
+}
+
+fn msrv_1_17() {
+ #![clippy::msrv = "1.17"]
+
+ let x: Result<u32, &str> = Ok(17);
+ x.err().expect("17");
+}
diff --git a/src/tools/clippy/tests/ui/err_expect.stderr b/src/tools/clippy/tests/ui/err_expect.stderr
index ffd97e00a..91a6cf8de 100644
--- a/src/tools/clippy/tests/ui/err_expect.stderr
+++ b/src/tools/clippy/tests/ui/err_expect.stderr
@@ -1,10 +1,16 @@
error: called `.err().expect()` on a `Result` value
- --> $DIR/err_expect.rs:10:16
+ --> $DIR/err_expect.rs:13:16
|
LL | test_debug.err().expect("Testing debug type");
| ^^^^^^^^^^^^ help: try: `expect_err`
|
= note: `-D clippy::err-expect` implied by `-D warnings`
-error: aborting due to previous error
+error: called `.err().expect()` on a `Result` value
+ --> $DIR/err_expect.rs:30:7
+ |
+LL | x.err().expect("17");
+ | ^^^^^^^^^^^^ help: try: `expect_err`
+
+error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index f8d559bf2..a9cc80aaa 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -1,14 +1,14 @@
// run-rustfix
-
+#![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)]
+#![allow(unused)]
#![allow(
- unused,
- clippy::no_effect,
- clippy::redundant_closure_call,
+ clippy::needless_borrow,
clippy::needless_pass_by_value,
+ clippy::no_effect,
clippy::option_map_unit_fn,
- clippy::needless_borrow
+ clippy::redundant_closure_call,
+ clippy::uninlined_format_args
)]
-#![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)]
use std::path::{Path, PathBuf};
@@ -303,3 +303,16 @@ fn not_general_enough() {
fn f(_: impl FnMut(&Path) -> std::io::Result<()>) {}
f(|path| std::fs::remove_file(path));
}
+
+// https://github.com/rust-lang/rust-clippy/issues/9369
+pub fn mutable_impl_fn_mut(mut f: impl FnMut(), mut f_used_once: impl FnMut()) -> impl FnMut() {
+ fn takes_fn_mut(_: impl FnMut()) {}
+ takes_fn_mut(&mut f);
+
+ fn takes_fn_once(_: impl FnOnce()) {}
+ takes_fn_once(&mut f);
+
+ f();
+
+ move || takes_fn_mut(&mut f_used_once)
+}
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index f0fb55a1e..cc99906cc 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -1,14 +1,14 @@
// run-rustfix
-
+#![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)]
+#![allow(unused)]
#![allow(
- unused,
- clippy::no_effect,
- clippy::redundant_closure_call,
+ clippy::needless_borrow,
clippy::needless_pass_by_value,
+ clippy::no_effect,
clippy::option_map_unit_fn,
- clippy::needless_borrow
+ clippy::redundant_closure_call,
+ clippy::uninlined_format_args
)]
-#![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)]
use std::path::{Path, PathBuf};
@@ -303,3 +303,16 @@ fn not_general_enough() {
fn f(_: impl FnMut(&Path) -> std::io::Result<()>) {}
f(|path| std::fs::remove_file(path));
}
+
+// https://github.com/rust-lang/rust-clippy/issues/9369
+pub fn mutable_impl_fn_mut(mut f: impl FnMut(), mut f_used_once: impl FnMut()) -> impl FnMut() {
+ fn takes_fn_mut(_: impl FnMut()) {}
+ takes_fn_mut(|| f());
+
+ fn takes_fn_once(_: impl FnOnce()) {}
+ takes_fn_once(|| f());
+
+ f();
+
+ move || takes_fn_mut(|| f_used_once())
+}
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index bf2e97e74..434706b7e 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -116,5 +116,23 @@ error: redundant closure
LL | Some(1).map(|n| in_loop(n));
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop`
-error: aborting due to 19 previous errors
+error: redundant closure
+ --> $DIR/eta.rs:310:18
+ |
+LL | takes_fn_mut(|| f());
+ | ^^^^^^ help: replace the closure with the function itself: `&mut f`
+
+error: redundant closure
+ --> $DIR/eta.rs:313:19
+ |
+LL | takes_fn_once(|| f());
+ | ^^^^^^ help: replace the closure with the function itself: `&mut f`
+
+error: redundant closure
+ --> $DIR/eta.rs:317:26
+ |
+LL | move || takes_fn_mut(|| f_used_once())
+ | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once`
+
+error: aborting due to 22 previous errors
diff --git a/src/tools/clippy/tests/ui/expect.rs b/src/tools/clippy/tests/ui/expect.rs
index 1073acf6f..d742595e1 100644
--- a/src/tools/clippy/tests/ui/expect.rs
+++ b/src/tools/clippy/tests/ui/expect.rs
@@ -6,8 +6,9 @@ fn expect_option() {
}
fn expect_result() {
- let res: Result<u8, ()> = Ok(0);
+ let res: Result<u8, u8> = Ok(0);
let _ = res.expect("");
+ let _ = res.expect_err("");
}
fn main() {
diff --git a/src/tools/clippy/tests/ui/expect.stderr b/src/tools/clippy/tests/ui/expect.stderr
index 9d3fc7df1..f6738865c 100644
--- a/src/tools/clippy/tests/ui/expect.stderr
+++ b/src/tools/clippy/tests/ui/expect.stderr
@@ -4,8 +4,8 @@ error: used `expect()` on `an Option` value
LL | let _ = opt.expect("");
| ^^^^^^^^^^^^^^
|
+ = help: if this value is `None`, it will panic
= note: `-D clippy::expect-used` implied by `-D warnings`
- = help: if this value is an `None`, it will panic
error: used `expect()` on `a Result` value
--> $DIR/expect.rs:10:13
@@ -15,5 +15,13 @@ LL | let _ = res.expect("");
|
= help: if this value is an `Err`, it will panic
-error: aborting due to 2 previous errors
+error: used `expect_err()` on `a Result` value
+ --> $DIR/expect.rs:11:13
+ |
+LL | let _ = res.expect_err("");
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = help: if this value is an `Ok`, it will panic
+
+error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/expect_fun_call.fixed b/src/tools/clippy/tests/ui/expect_fun_call.fixed
index 53e45d28b..15172ae34 100644
--- a/src/tools/clippy/tests/ui/expect_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/expect_fun_call.fixed
@@ -1,7 +1,6 @@
// run-rustfix
-
#![warn(clippy::expect_fun_call)]
-#![allow(clippy::to_string_in_format_args)]
+#![allow(clippy::to_string_in_format_args, clippy::uninlined_format_args)]
/// Checks implementation of the `EXPECT_FUN_CALL` lint
@@ -101,4 +100,10 @@ fn main() {
let opt_ref = &opt;
opt_ref.unwrap_or_else(|| panic!("{:?}", opt_ref));
}
+
+ let format_capture: Option<i32> = None;
+ format_capture.unwrap_or_else(|| panic!("{error_code}"));
+
+ let format_capture_and_value: Option<i32> = None;
+ format_capture_and_value.unwrap_or_else(|| panic!("{error_code}, {}", 1));
}
diff --git a/src/tools/clippy/tests/ui/expect_fun_call.rs b/src/tools/clippy/tests/ui/expect_fun_call.rs
index 22e530b80..0f448d004 100644
--- a/src/tools/clippy/tests/ui/expect_fun_call.rs
+++ b/src/tools/clippy/tests/ui/expect_fun_call.rs
@@ -1,7 +1,6 @@
// run-rustfix
-
#![warn(clippy::expect_fun_call)]
-#![allow(clippy::to_string_in_format_args)]
+#![allow(clippy::to_string_in_format_args, clippy::uninlined_format_args)]
/// Checks implementation of the `EXPECT_FUN_CALL` lint
@@ -101,4 +100,10 @@ fn main() {
let opt_ref = &opt;
opt_ref.expect(&format!("{:?}", opt_ref));
}
+
+ let format_capture: Option<i32> = None;
+ format_capture.expect(&format!("{error_code}"));
+
+ let format_capture_and_value: Option<i32> = None;
+ format_capture_and_value.expect(&format!("{error_code}, {}", 1));
}
diff --git a/src/tools/clippy/tests/ui/expect_fun_call.stderr b/src/tools/clippy/tests/ui/expect_fun_call.stderr
index aca15935f..cb55e32ae 100644
--- a/src/tools/clippy/tests/ui/expect_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/expect_fun_call.stderr
@@ -1,5 +1,5 @@
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:35:26
+ --> $DIR/expect_fun_call.rs:34:26
|
LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
@@ -7,76 +7,88 @@ LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code
= note: `-D clippy::expect-fun-call` implied by `-D warnings`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:38:26
+ --> $DIR/expect_fun_call.rs:37:26
|
LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:41:37
+ --> $DIR/expect_fun_call.rs:40:37
|
LL | with_none_and_format_with_macro.expect(format!("Error {}: fake error", one!()).as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", one!()))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:51:25
+ --> $DIR/expect_fun_call.rs:50:25
|
LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:54:25
+ --> $DIR/expect_fun_call.rs:53:25
|
LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:66:17
+ --> $DIR/expect_fun_call.rs:65:17
|
LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{} {}", 1, 2))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:87:21
+ --> $DIR/expect_fun_call.rs:86:21
|
LL | Some("foo").expect(&get_string());
| ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:88:21
+ --> $DIR/expect_fun_call.rs:87:21
|
LL | Some("foo").expect(get_string().as_ref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:89:21
+ --> $DIR/expect_fun_call.rs:88:21
|
LL | Some("foo").expect(get_string().as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:91:21
+ --> $DIR/expect_fun_call.rs:90:21
|
LL | Some("foo").expect(get_static_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_static_str()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:92:21
+ --> $DIR/expect_fun_call.rs:91:21
|
LL | Some("foo").expect(get_non_static_str(&0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:96:16
+ --> $DIR/expect_fun_call.rs:95:16
|
LL | Some(true).expect(&format!("key {}, {}", 1, 2));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:102:17
+ --> $DIR/expect_fun_call.rs:101:17
|
LL | opt_ref.expect(&format!("{:?}", opt_ref));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{:?}", opt_ref))`
-error: aborting due to 13 previous errors
+error: use of `expect` followed by a function call
+ --> $DIR/expect_fun_call.rs:105:20
+ |
+LL | format_capture.expect(&format!("{error_code}"));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{error_code}"))`
+
+error: use of `expect` followed by a function call
+ --> $DIR/expect_fun_call.rs:108:30
+ |
+LL | format_capture_and_value.expect(&format!("{error_code}, {}", 1));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{error_code}, {}", 1))`
+
+error: aborting due to 15 previous errors
diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
index 28b37f96e..0415e33b3 100644
--- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
+++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
@@ -98,7 +98,7 @@ mod clippy_ok {
let _ = if true { 42 } else { 42 };
}
- #[expect(clippy::logic_bug)]
+ #[expect(clippy::overly_complex_bool_expr)]
fn burger() {
let a = false;
let b = true;
@@ -127,7 +127,7 @@ mod clippy_warn {
let _ = if true { 33 } else { 42 };
}
- #[expect(clippy::logic_bug)]
+ #[expect(clippy::overly_complex_bool_expr)]
fn burger() {
let a = false;
let b = true;
diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
index db29e85a8..7ce9e855b 100644
--- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
+++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
@@ -33,8 +33,8 @@ LL | #[expect(clippy::if_same_then_else)]
error: this lint expectation is unfulfilled
--> $DIR/expect_tool_lint_rfc_2383.rs:130:14
|
-LL | #[expect(clippy::logic_bug)]
- | ^^^^^^^^^^^^^^^^^
+LL | #[expect(clippy::overly_complex_bool_expr)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 6 previous errors
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
index a650fdc1f..d1d35e5c0 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
@@ -1,5 +1,6 @@
// run-rustfix
+#![feature(closure_lifetime_binder)]
#![warn(clippy::explicit_auto_deref)]
#![allow(
dead_code,
@@ -67,6 +68,8 @@ fn main() {
let s = String::new();
let _: &str = &s;
+ let _: &str = &{ String::new() };
+ let _: &str = &mut { String::new() };
let _ = &*s; // Don't lint. Inferred type would change.
let _: &_ = &*s; // Don't lint. Inferred type would change.
@@ -215,4 +218,52 @@ fn main() {
let s = &"str";
let _ = || return *s;
let _ = || -> &'static str { return s };
+
+ struct X;
+ struct Y(X);
+ impl core::ops::Deref for Y {
+ type Target = X;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+ let _: &X = &*{ Y(X) };
+ let _: &X = &*match 0 {
+ #[rustfmt::skip]
+ 0 => { Y(X) },
+ _ => panic!(),
+ };
+ let _: &X = &*if true { Y(X) } else { panic!() };
+
+ fn deref_to_u<U, T: core::ops::Deref<Target = U>>(x: &T) -> &U {
+ x
+ }
+
+ let _ = |x: &'static Box<dyn Iterator<Item = u32>>| -> &'static dyn Iterator<Item = u32> { &**x };
+ fn ret_any(x: &Box<dyn std::any::Any>) -> &dyn std::any::Any {
+ &**x
+ }
+
+ let x = String::new();
+ let _: *const str = &*x;
+
+ struct S7([u32; 1]);
+ impl core::ops::Deref for S7 {
+ type Target = [u32; 1];
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+ let x = S7([0]);
+ let _: &[u32] = &*x;
+
+ let c1 = |_: &Vec<&u32>| {};
+ let x = &&vec![&1u32];
+ c1(x);
+ let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> {
+ if b {
+ return x;
+ }
+ x
+ };
}
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.rs b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
index 8f4f35257..deedafad1 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.rs
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
@@ -1,5 +1,6 @@
// run-rustfix
+#![feature(closure_lifetime_binder)]
#![warn(clippy::explicit_auto_deref)]
#![allow(
dead_code,
@@ -67,6 +68,8 @@ fn main() {
let s = String::new();
let _: &str = &*s;
+ let _: &str = &*{ String::new() };
+ let _: &str = &mut *{ String::new() };
let _ = &*s; // Don't lint. Inferred type would change.
let _: &_ = &*s; // Don't lint. Inferred type would change.
@@ -215,4 +218,52 @@ fn main() {
let s = &"str";
let _ = || return *s;
let _ = || -> &'static str { return *s };
+
+ struct X;
+ struct Y(X);
+ impl core::ops::Deref for Y {
+ type Target = X;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+ let _: &X = &*{ Y(X) };
+ let _: &X = &*match 0 {
+ #[rustfmt::skip]
+ 0 => { Y(X) },
+ _ => panic!(),
+ };
+ let _: &X = &*if true { Y(X) } else { panic!() };
+
+ fn deref_to_u<U, T: core::ops::Deref<Target = U>>(x: &T) -> &U {
+ &**x
+ }
+
+ let _ = |x: &'static Box<dyn Iterator<Item = u32>>| -> &'static dyn Iterator<Item = u32> { &**x };
+ fn ret_any(x: &Box<dyn std::any::Any>) -> &dyn std::any::Any {
+ &**x
+ }
+
+ let x = String::new();
+ let _: *const str = &*x;
+
+ struct S7([u32; 1]);
+ impl core::ops::Deref for S7 {
+ type Target = [u32; 1];
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+ let x = S7([0]);
+ let _: &[u32] = &*x;
+
+ let c1 = |_: &Vec<&u32>| {};
+ let x = &&vec![&1u32];
+ c1(*x);
+ let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> {
+ if b {
+ return *x;
+ }
+ *x
+ };
}
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
index 92765307e..91863abcc 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
@@ -1,202 +1,238 @@
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:69:20
+ --> $DIR/explicit_auto_deref.rs:70:19
|
LL | let _: &str = &*s;
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
|
= note: `-D clippy::explicit-auto-deref` implied by `-D warnings`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:73:12
+ --> $DIR/explicit_auto_deref.rs:71:19
+ |
+LL | let _: &str = &*{ String::new() };
+ | ^^^^^^^^^^^^^^^^^^^ help: try this: `&{ String::new() }`
+
+error: deref which would be done by auto-deref
+ --> $DIR/explicit_auto_deref.rs:72:19
+ |
+LL | let _: &str = &mut *{ String::new() };
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut { String::new() }`
+
+error: deref which would be done by auto-deref
+ --> $DIR/explicit_auto_deref.rs:76:11
|
LL | f_str(&*s);
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:77:14
+ --> $DIR/explicit_auto_deref.rs:80:13
|
LL | f_str_t(&*s, &*s); // Don't lint second param.
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:80:25
+ --> $DIR/explicit_auto_deref.rs:83:24
|
LL | let _: &Box<i32> = &**b;
- | ^^^ help: try this: `b`
+ | ^^^^ help: try this: `&b`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:86:8
+ --> $DIR/explicit_auto_deref.rs:89:7
|
LL | c(&*s);
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:92:9
+ --> $DIR/explicit_auto_deref.rs:95:9
|
LL | &**x
| ^^^^ help: try this: `x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:96:11
+ --> $DIR/explicit_auto_deref.rs:99:11
|
LL | { &**x }
| ^^^^ help: try this: `x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:100:9
+ --> $DIR/explicit_auto_deref.rs:103:9
|
LL | &**{ x }
| ^^^^^^^^ help: try this: `{ x }`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:104:9
+ --> $DIR/explicit_auto_deref.rs:107:9
|
LL | &***x
| ^^^^^ help: try this: `x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:121:13
+ --> $DIR/explicit_auto_deref.rs:124:12
|
LL | f1(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:122:13
+ --> $DIR/explicit_auto_deref.rs:125:12
|
LL | f2(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:123:13
+ --> $DIR/explicit_auto_deref.rs:126:12
|
LL | f3(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:124:28
+ --> $DIR/explicit_auto_deref.rs:127:27
|
LL | f4.callable_str()(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:125:13
+ --> $DIR/explicit_auto_deref.rs:128:12
|
LL | f5(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:126:13
+ --> $DIR/explicit_auto_deref.rs:129:12
|
LL | f6(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:127:28
+ --> $DIR/explicit_auto_deref.rs:130:27
|
LL | f7.callable_str()(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:128:26
+ --> $DIR/explicit_auto_deref.rs:131:25
|
LL | f8.callable_t()(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:129:13
+ --> $DIR/explicit_auto_deref.rs:132:12
|
LL | f9(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:130:14
+ --> $DIR/explicit_auto_deref.rs:133:13
|
LL | f10(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:131:27
+ --> $DIR/explicit_auto_deref.rs:134:26
|
LL | f11.callable_t()(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:135:17
+ --> $DIR/explicit_auto_deref.rs:138:16
|
LL | let _ = S1(&*s);
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:140:22
+ --> $DIR/explicit_auto_deref.rs:143:21
|
LL | let _ = S2 { s: &*s };
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:156:30
+ --> $DIR/explicit_auto_deref.rs:159:30
|
LL | let _ = Self::S1(&**s);
| ^^^^ help: try this: `s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:157:35
+ --> $DIR/explicit_auto_deref.rs:160:35
|
LL | let _ = Self::S2 { s: &**s };
| ^^^^ help: try this: `s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:160:21
+ --> $DIR/explicit_auto_deref.rs:163:20
|
LL | let _ = E1::S1(&*s);
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:161:26
+ --> $DIR/explicit_auto_deref.rs:164:25
|
LL | let _ = E1::S2 { s: &*s };
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:179:13
+ --> $DIR/explicit_auto_deref.rs:182:13
|
LL | let _ = (*b).foo;
| ^^^^ help: try this: `b`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:180:13
+ --> $DIR/explicit_auto_deref.rs:183:13
|
LL | let _ = (**b).foo;
| ^^^^^ help: try this: `b`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:195:19
+ --> $DIR/explicit_auto_deref.rs:198:19
|
LL | let _ = f_str(*ref_str);
| ^^^^^^^^ help: try this: `ref_str`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:197:19
+ --> $DIR/explicit_auto_deref.rs:200:19
|
LL | let _ = f_str(**ref_ref_str);
| ^^^^^^^^^^^^^ help: try this: `ref_ref_str`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:207:13
+ --> $DIR/explicit_auto_deref.rs:210:13
|
LL | f_str(&&*ref_str); // `needless_borrow` will suggest removing both references
| ^^^^^^^^ help: try this: `ref_str`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:208:12
+ --> $DIR/explicit_auto_deref.rs:211:12
|
LL | f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference
| ^^^^^^^^^^ help: try this: `ref_str`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:217:41
+ --> $DIR/explicit_auto_deref.rs:220:41
|
LL | let _ = || -> &'static str { return *s };
| ^^ help: try this: `s`
-error: aborting due to 33 previous errors
+error: deref which would be done by auto-deref
+ --> $DIR/explicit_auto_deref.rs:239:9
+ |
+LL | &**x
+ | ^^^^ help: try this: `x`
+
+error: deref which would be done by auto-deref
+ --> $DIR/explicit_auto_deref.rs:262:8
+ |
+LL | c1(*x);
+ | ^^ help: try this: `x`
+
+error: deref which would be done by auto-deref
+ --> $DIR/explicit_auto_deref.rs:265:20
+ |
+LL | return *x;
+ | ^^ help: try this: `x`
+
+error: deref which would be done by auto-deref
+ --> $DIR/explicit_auto_deref.rs:267:9
+ |
+LL | *x
+ | ^^ help: try this: `x`
+
+error: aborting due to 39 previous errors
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.rs b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
index aa966761f..6eddc01e2 100644
--- a/src/tools/clippy/tests/ui/explicit_counter_loop.rs
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
@@ -1,4 +1,5 @@
#![warn(clippy::explicit_counter_loop)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
let mut vec = vec![1, 2, 3, 4];
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr
index f9f8407d5..d3f3c626b 100644
--- a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr
@@ -1,5 +1,5 @@
error: the variable `_index` is used as a loop counter
- --> $DIR/explicit_counter_loop.rs:6:5
+ --> $DIR/explicit_counter_loop.rs:7:5
|
LL | for _v in &vec {
| ^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.iter().enumerate()`
@@ -7,49 +7,49 @@ LL | for _v in &vec {
= note: `-D clippy::explicit-counter-loop` implied by `-D warnings`
error: the variable `_index` is used as a loop counter
- --> $DIR/explicit_counter_loop.rs:12:5
+ --> $DIR/explicit_counter_loop.rs:13:5
|
LL | for _v in &vec {
| ^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.iter().enumerate()`
error: the variable `_index` is used as a loop counter
- --> $DIR/explicit_counter_loop.rs:17:5
+ --> $DIR/explicit_counter_loop.rs:18:5
|
LL | for _v in &mut vec {
| ^^^^^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.iter_mut().enumerate()`
error: the variable `_index` is used as a loop counter
- --> $DIR/explicit_counter_loop.rs:22:5
+ --> $DIR/explicit_counter_loop.rs:23:5
|
LL | for _v in vec {
| ^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.into_iter().enumerate()`
error: the variable `count` is used as a loop counter
- --> $DIR/explicit_counter_loop.rs:61:9
+ --> $DIR/explicit_counter_loop.rs:62:9
|
LL | for ch in text.chars() {
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `for (count, ch) in text.chars().enumerate()`
error: the variable `count` is used as a loop counter
- --> $DIR/explicit_counter_loop.rs:72:9
+ --> $DIR/explicit_counter_loop.rs:73:9
|
LL | for ch in text.chars() {
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `for (count, ch) in text.chars().enumerate()`
error: the variable `count` is used as a loop counter
- --> $DIR/explicit_counter_loop.rs:130:9
+ --> $DIR/explicit_counter_loop.rs:131:9
|
LL | for _i in 3..10 {
| ^^^^^^^^^^^^^^^ help: consider using: `for (count, _i) in (3..10).enumerate()`
error: the variable `idx_usize` is used as a loop counter
- --> $DIR/explicit_counter_loop.rs:170:9
+ --> $DIR/explicit_counter_loop.rs:171:9
|
LL | for _item in slice {
| ^^^^^^^^^^^^^^^^^^ help: consider using: `for (idx_usize, _item) in slice.iter().enumerate()`
error: the variable `idx_u32` is used as a loop counter
- --> $DIR/explicit_counter_loop.rs:182:9
+ --> $DIR/explicit_counter_loop.rs:183:9
|
LL | for _item in slice {
| ^^^^^^^^^^^^^^^^^^ help: consider using: `for (idx_u32, _item) in (0_u32..).zip(slice.iter())`
diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
index 523cae183..6d32bbece 100644
--- a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
+++ b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
@@ -1,13 +1,13 @@
// run-rustfix
-
+#![warn(clippy::explicit_deref_methods)]
+#![allow(unused_variables)]
#![allow(
- unused_variables,
+ clippy::borrow_deref_ref,
clippy::clone_double_ref,
+ clippy::explicit_auto_deref,
clippy::needless_borrow,
- clippy::borrow_deref_ref,
- clippy::explicit_auto_deref
+ clippy::uninlined_format_args
)]
-#![warn(clippy::explicit_deref_methods)]
use std::ops::{Deref, DerefMut};
diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.rs b/src/tools/clippy/tests/ui/explicit_deref_methods.rs
index 0bbc1ae57..779909e42 100644
--- a/src/tools/clippy/tests/ui/explicit_deref_methods.rs
+++ b/src/tools/clippy/tests/ui/explicit_deref_methods.rs
@@ -1,13 +1,13 @@
// run-rustfix
-
+#![warn(clippy::explicit_deref_methods)]
+#![allow(unused_variables)]
#![allow(
- unused_variables,
+ clippy::borrow_deref_ref,
clippy::clone_double_ref,
+ clippy::explicit_auto_deref,
clippy::needless_borrow,
- clippy::borrow_deref_ref,
- clippy::explicit_auto_deref
+ clippy::uninlined_format_args
)]
-#![warn(clippy::explicit_deref_methods)]
use std::ops::{Deref, DerefMut};
diff --git a/src/tools/clippy/tests/ui/explicit_write.fixed b/src/tools/clippy/tests/ui/explicit_write.fixed
index 74d0e5290..862c3fea9 100644
--- a/src/tools/clippy/tests/ui/explicit_write.fixed
+++ b/src/tools/clippy/tests/ui/explicit_write.fixed
@@ -1,6 +1,7 @@
// run-rustfix
-#![allow(unused_imports)]
#![warn(clippy::explicit_write)]
+#![allow(unused_imports)]
+#![allow(clippy::uninlined_format_args)]
fn stdout() -> String {
String::new()
@@ -36,6 +37,8 @@ fn main() {
eprintln!("with {} {}", 2, value);
eprintln!("with {value}");
eprintln!("macro arg {}", one!());
+ let width = 2;
+ eprintln!("{:w$}", value, w = width);
}
// these should not warn, different destination
{
diff --git a/src/tools/clippy/tests/ui/explicit_write.rs b/src/tools/clippy/tests/ui/explicit_write.rs
index e7a698d3e..41d7c2255 100644
--- a/src/tools/clippy/tests/ui/explicit_write.rs
+++ b/src/tools/clippy/tests/ui/explicit_write.rs
@@ -1,6 +1,7 @@
// run-rustfix
-#![allow(unused_imports)]
#![warn(clippy::explicit_write)]
+#![allow(unused_imports)]
+#![allow(clippy::uninlined_format_args)]
fn stdout() -> String {
String::new()
@@ -36,6 +37,8 @@ fn main() {
writeln!(std::io::stderr(), "with {} {}", 2, value).unwrap();
writeln!(std::io::stderr(), "with {value}").unwrap();
writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap();
+ let width = 2;
+ writeln!(std::io::stderr(), "{:w$}", value, w = width).unwrap();
}
// these should not warn, different destination
{
diff --git a/src/tools/clippy/tests/ui/explicit_write.stderr b/src/tools/clippy/tests/ui/explicit_write.stderr
index 29ae0cdec..457e9c627 100644
--- a/src/tools/clippy/tests/ui/explicit_write.stderr
+++ b/src/tools/clippy/tests/ui/explicit_write.stderr
@@ -1,5 +1,5 @@
error: use of `write!(stdout(), ...).unwrap()`
- --> $DIR/explicit_write.rs:23:9
+ --> $DIR/explicit_write.rs:24:9
|
LL | write!(std::io::stdout(), "test").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")`
@@ -7,70 +7,76 @@ LL | write!(std::io::stdout(), "test").unwrap();
= note: `-D clippy::explicit-write` implied by `-D warnings`
error: use of `write!(stderr(), ...).unwrap()`
- --> $DIR/explicit_write.rs:24:9
+ --> $DIR/explicit_write.rs:25:9
|
LL | write!(std::io::stderr(), "test").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")`
error: use of `writeln!(stdout(), ...).unwrap()`
- --> $DIR/explicit_write.rs:25:9
+ --> $DIR/explicit_write.rs:26:9
|
LL | writeln!(std::io::stdout(), "test").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test")`
error: use of `writeln!(stderr(), ...).unwrap()`
- --> $DIR/explicit_write.rs:26:9
+ --> $DIR/explicit_write.rs:27:9
|
LL | writeln!(std::io::stderr(), "test").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test")`
error: use of `stdout().write_fmt(...).unwrap()`
- --> $DIR/explicit_write.rs:27:9
+ --> $DIR/explicit_write.rs:28:9
|
LL | std::io::stdout().write_fmt(format_args!("test")).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")`
error: use of `stderr().write_fmt(...).unwrap()`
- --> $DIR/explicit_write.rs:28:9
+ --> $DIR/explicit_write.rs:29:9
|
LL | std::io::stderr().write_fmt(format_args!("test")).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")`
error: use of `writeln!(stdout(), ...).unwrap()`
- --> $DIR/explicit_write.rs:31:9
+ --> $DIR/explicit_write.rs:32:9
|
LL | writeln!(std::io::stdout(), "test/ntest").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test/ntest")`
error: use of `writeln!(stderr(), ...).unwrap()`
- --> $DIR/explicit_write.rs:32:9
+ --> $DIR/explicit_write.rs:33:9
|
LL | writeln!(std::io::stderr(), "test/ntest").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test/ntest")`
error: use of `writeln!(stderr(), ...).unwrap()`
- --> $DIR/explicit_write.rs:35:9
+ --> $DIR/explicit_write.rs:36:9
|
LL | writeln!(std::io::stderr(), "with {}", value).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {}", value)`
error: use of `writeln!(stderr(), ...).unwrap()`
- --> $DIR/explicit_write.rs:36:9
+ --> $DIR/explicit_write.rs:37:9
|
LL | writeln!(std::io::stderr(), "with {} {}", 2, value).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {} {}", 2, value)`
error: use of `writeln!(stderr(), ...).unwrap()`
- --> $DIR/explicit_write.rs:37:9
+ --> $DIR/explicit_write.rs:38:9
|
LL | writeln!(std::io::stderr(), "with {value}").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {value}")`
error: use of `writeln!(stderr(), ...).unwrap()`
- --> $DIR/explicit_write.rs:38:9
+ --> $DIR/explicit_write.rs:39:9
|
LL | writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("macro arg {}", one!())`
-error: aborting due to 12 previous errors
+error: use of `writeln!(stderr(), ...).unwrap()`
+ --> $DIR/explicit_write.rs:41:9
+ |
+LL | writeln!(std::io::stderr(), "{:w$}", value, w = width).unwrap();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("{:w$}", value, w = width)`
+
+error: aborting due to 13 previous errors
diff --git a/src/tools/clippy/tests/ui/fallible_impl_from.rs b/src/tools/clippy/tests/ui/fallible_impl_from.rs
index 5d5af4e46..fb6e8ec70 100644
--- a/src/tools/clippy/tests/ui/fallible_impl_from.rs
+++ b/src/tools/clippy/tests/ui/fallible_impl_from.rs
@@ -1,4 +1,5 @@
#![deny(clippy::fallible_impl_from)]
+#![allow(clippy::uninlined_format_args)]
// docs example
struct Foo(i32);
diff --git a/src/tools/clippy/tests/ui/fallible_impl_from.stderr b/src/tools/clippy/tests/ui/fallible_impl_from.stderr
index d637dbce5..21761484f 100644
--- a/src/tools/clippy/tests/ui/fallible_impl_from.stderr
+++ b/src/tools/clippy/tests/ui/fallible_impl_from.stderr
@@ -1,5 +1,5 @@
error: consider implementing `TryFrom` instead
- --> $DIR/fallible_impl_from.rs:5:1
+ --> $DIR/fallible_impl_from.rs:6:1
|
LL | / impl From<String> for Foo {
LL | | fn from(s: String) -> Self {
@@ -8,20 +8,20 @@ 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:7:13
+ --> $DIR/fallible_impl_from.rs:8:13
|
LL | Foo(s.parse().unwrap())
| ^^^^^^^^^^^^^^^^^^
+note: the lint level is defined here
+ --> $DIR/fallible_impl_from.rs:1:9
+ |
+LL | #![deny(clippy::fallible_impl_from)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: consider implementing `TryFrom` instead
- --> $DIR/fallible_impl_from.rs:26:1
+ --> $DIR/fallible_impl_from.rs:27:1
|
LL | / impl From<usize> for Invalid {
LL | | fn from(i: usize) -> Invalid {
@@ -34,14 +34,14 @@ 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)
- --> $DIR/fallible_impl_from.rs:29:13
+ --> $DIR/fallible_impl_from.rs:30:13
|
LL | panic!();
| ^^^^^^^^
= note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
error: consider implementing `TryFrom` instead
- --> $DIR/fallible_impl_from.rs:35:1
+ --> $DIR/fallible_impl_from.rs:36:1
|
LL | / impl From<Option<String>> for Invalid {
LL | | fn from(s: Option<String>) -> Invalid {
@@ -54,7 +54,7 @@ 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)
- --> $DIR/fallible_impl_from.rs:37:17
+ --> $DIR/fallible_impl_from.rs:38:17
|
LL | let s = s.unwrap();
| ^^^^^^^^^^
@@ -68,7 +68,7 @@ LL | panic!("{:?}", s);
= note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
error: consider implementing `TryFrom` instead
- --> $DIR/fallible_impl_from.rs:53:1
+ --> $DIR/fallible_impl_from.rs:54: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 {
@@ -81,7 +81,7 @@ 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)
- --> $DIR/fallible_impl_from.rs:55:12
+ --> $DIR/fallible_impl_from.rs:56:12
|
LL | if s.parse::<u32>().ok().unwrap() != 42 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.stderr b/src/tools/clippy/tests/ui/field_reassign_with_default.stderr
index 3ce4b91a5..710bb66a4 100644
--- a/src/tools/clippy/tests/ui/field_reassign_with_default.stderr
+++ b/src/tools/clippy/tests/ui/field_reassign_with_default.stderr
@@ -4,12 +4,12 @@ error: field assignment outside of initializer for an instance created with Defa
LL | a.i = 42;
| ^^^^^^^^^
|
- = note: `-D clippy::field-reassign-with-default` implied by `-D warnings`
note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments
--> $DIR/field_reassign_with_default.rs:62:5
|
LL | let mut a: A = Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: `-D clippy::field-reassign-with-default` implied by `-D warnings`
error: field assignment outside of initializer for an instance created with Default::default()
--> $DIR/field_reassign_with_default.rs:103:5
diff --git a/src/tools/clippy/tests/ui/filetype_is_file.stderr b/src/tools/clippy/tests/ui/filetype_is_file.stderr
index cd1e3ac37..e51a90d6c 100644
--- a/src/tools/clippy/tests/ui/filetype_is_file.stderr
+++ b/src/tools/clippy/tests/ui/filetype_is_file.stderr
@@ -4,8 +4,8 @@ error: `FileType::is_file()` only covers regular files
LL | if fs::metadata("foo.txt")?.file_type().is_file() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::filetype-is-file` implied by `-D warnings`
= help: use `!FileType::is_dir()` instead
+ = note: `-D clippy::filetype-is-file` implied by `-D warnings`
error: `!FileType::is_file()` only denies regular files
--> $DIR/filetype_is_file.rs:13:8
diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed b/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed
index c3992d7e9..41828ddd7 100644
--- a/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed
+++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed
@@ -1,6 +1,8 @@
// run-rustfix
+#![feature(custom_inner_attributes)]
#![warn(clippy::all, clippy::pedantic)]
+#![allow(unused)]
fn main() {
let a = ["1", "lol", "3", "NaN", "5"];
@@ -8,3 +10,17 @@ fn main() {
let element: Option<i32> = a.iter().find_map(|s| s.parse().ok());
assert_eq!(element, Some(1));
}
+
+fn msrv_1_29() {
+ #![clippy::msrv = "1.29"]
+
+ let a = ["1", "lol", "3", "NaN", "5"];
+ let _: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
+}
+
+fn msrv_1_30() {
+ #![clippy::msrv = "1.30"]
+
+ let a = ["1", "lol", "3", "NaN", "5"];
+ let _: Option<i32> = a.iter().find_map(|s| s.parse().ok());
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.rs b/src/tools/clippy/tests/ui/filter_map_next_fixable.rs
index 447219a96..be492a81b 100644
--- a/src/tools/clippy/tests/ui/filter_map_next_fixable.rs
+++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.rs
@@ -1,6 +1,8 @@
// run-rustfix
+#![feature(custom_inner_attributes)]
#![warn(clippy::all, clippy::pedantic)]
+#![allow(unused)]
fn main() {
let a = ["1", "lol", "3", "NaN", "5"];
@@ -8,3 +10,17 @@ fn main() {
let element: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
assert_eq!(element, Some(1));
}
+
+fn msrv_1_29() {
+ #![clippy::msrv = "1.29"]
+
+ let a = ["1", "lol", "3", "NaN", "5"];
+ let _: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
+}
+
+fn msrv_1_30() {
+ #![clippy::msrv = "1.30"]
+
+ let a = ["1", "lol", "3", "NaN", "5"];
+ let _: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr b/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
index 3bb062ffd..e789efeab 100644
--- a/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
+++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
@@ -1,10 +1,16 @@
error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead
- --> $DIR/filter_map_next_fixable.rs:8:32
+ --> $DIR/filter_map_next_fixable.rs:10:32
|
LL | let element: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `a.iter().find_map(|s| s.parse().ok())`
|
= note: `-D clippy::filter-map-next` implied by `-D warnings`
-error: aborting due to previous error
+error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead
+ --> $DIR/filter_map_next_fixable.rs:25:26
+ |
+LL | let _: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `a.iter().find_map(|s| s.parse().ok())`
+
+error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/float_cmp.stderr b/src/tools/clippy/tests/ui/float_cmp.stderr
index 9cc1f1b75..e3e9f3949 100644
--- a/src/tools/clippy/tests/ui/float_cmp.stderr
+++ b/src/tools/clippy/tests/ui/float_cmp.stderr
@@ -4,8 +4,8 @@ error: strict comparison of `f32` or `f64`
LL | ONE as f64 != 2.0;
| ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin`
|
- = note: `-D clippy::float-cmp` implied by `-D warnings`
= note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
+ = note: `-D clippy::float-cmp` implied by `-D warnings`
error: strict comparison of `f32` or `f64`
--> $DIR/float_cmp.rs:62:5
diff --git a/src/tools/clippy/tests/ui/float_cmp_const.stderr b/src/tools/clippy/tests/ui/float_cmp_const.stderr
index d8182cf85..65c45648a 100644
--- a/src/tools/clippy/tests/ui/float_cmp_const.stderr
+++ b/src/tools/clippy/tests/ui/float_cmp_const.stderr
@@ -4,8 +4,8 @@ error: strict comparison of `f32` or `f64` constant
LL | 1f32 == ONE;
| ^^^^^^^^^^^ help: consider comparing them within some margin of error: `(1f32 - ONE).abs() < error_margin`
|
- = note: `-D clippy::float-cmp-const` implied by `-D warnings`
= note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
+ = note: `-D clippy::float-cmp-const` implied by `-D warnings`
error: strict comparison of `f32` or `f64` constant
--> $DIR/float_cmp_const.rs:17:5
diff --git a/src/tools/clippy/tests/ui/floating_point_exp.fixed b/src/tools/clippy/tests/ui/floating_point_exp.fixed
index ae7805fdf..b9e3d89c2 100644
--- a/src/tools/clippy/tests/ui/floating_point_exp.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_exp.fixed
@@ -1,10 +1,12 @@
// run-rustfix
#![warn(clippy::imprecise_flops)]
+#![allow(clippy::unnecessary_cast)]
fn main() {
let x = 2f32;
let _ = x.exp_m1();
let _ = x.exp_m1() + 2.0;
+ let _ = (x as f32).exp_m1() + 2.0;
// Cases where the lint shouldn't be applied
let _ = x.exp() - 2.0;
let _ = x.exp() - 1.0 * 2.0;
diff --git a/src/tools/clippy/tests/ui/floating_point_exp.rs b/src/tools/clippy/tests/ui/floating_point_exp.rs
index 27e0b9bcb..ef008dd9b 100644
--- a/src/tools/clippy/tests/ui/floating_point_exp.rs
+++ b/src/tools/clippy/tests/ui/floating_point_exp.rs
@@ -1,10 +1,12 @@
// run-rustfix
#![warn(clippy::imprecise_flops)]
+#![allow(clippy::unnecessary_cast)]
fn main() {
let x = 2f32;
let _ = x.exp() - 1.0;
let _ = x.exp() - 1.0 + 2.0;
+ let _ = (x as f32).exp() - 1.0 + 2.0;
// Cases where the lint shouldn't be applied
let _ = x.exp() - 2.0;
let _ = x.exp() - 1.0 * 2.0;
diff --git a/src/tools/clippy/tests/ui/floating_point_exp.stderr b/src/tools/clippy/tests/ui/floating_point_exp.stderr
index 5cd999ad4..b92fae56e 100644
--- a/src/tools/clippy/tests/ui/floating_point_exp.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_exp.stderr
@@ -1,5 +1,5 @@
error: (e.pow(x) - 1) can be computed more accurately
- --> $DIR/floating_point_exp.rs:6:13
+ --> $DIR/floating_point_exp.rs:7:13
|
LL | let _ = x.exp() - 1.0;
| ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
@@ -7,22 +7,28 @@ LL | let _ = x.exp() - 1.0;
= note: `-D clippy::imprecise-flops` implied by `-D warnings`
error: (e.pow(x) - 1) can be computed more accurately
- --> $DIR/floating_point_exp.rs:7:13
+ --> $DIR/floating_point_exp.rs:8:13
|
LL | let _ = x.exp() - 1.0 + 2.0;
| ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
error: (e.pow(x) - 1) can be computed more accurately
- --> $DIR/floating_point_exp.rs:13:13
+ --> $DIR/floating_point_exp.rs:9:13
+ |
+LL | let _ = (x as f32).exp() - 1.0 + 2.0;
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).exp_m1()`
+
+error: (e.pow(x) - 1) can be computed more accurately
+ --> $DIR/floating_point_exp.rs:15:13
|
LL | let _ = x.exp() - 1.0;
| ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
error: (e.pow(x) - 1) can be computed more accurately
- --> $DIR/floating_point_exp.rs:14:13
+ --> $DIR/floating_point_exp.rs:16:13
|
LL | let _ = x.exp() - 1.0 + 2.0;
| ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/floating_point_log.fixed b/src/tools/clippy/tests/ui/floating_point_log.fixed
index 5b487bb8f..ee5406461 100644
--- a/src/tools/clippy/tests/ui/floating_point_log.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_log.fixed
@@ -1,5 +1,5 @@
// run-rustfix
-#![allow(dead_code, clippy::double_parens)]
+#![allow(dead_code, clippy::double_parens, clippy::unnecessary_cast)]
#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]
const TWO: f32 = 2.0;
@@ -12,6 +12,7 @@ fn check_log_base() {
let _ = x.ln();
let _ = x.log2();
let _ = x.ln();
+ let _ = (x as f32).log2();
let x = 1f64;
let _ = x.log2();
diff --git a/src/tools/clippy/tests/ui/floating_point_log.rs b/src/tools/clippy/tests/ui/floating_point_log.rs
index 01181484e..0590670a5 100644
--- a/src/tools/clippy/tests/ui/floating_point_log.rs
+++ b/src/tools/clippy/tests/ui/floating_point_log.rs
@@ -1,5 +1,5 @@
// run-rustfix
-#![allow(dead_code, clippy::double_parens)]
+#![allow(dead_code, clippy::double_parens, clippy::unnecessary_cast)]
#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]
const TWO: f32 = 2.0;
@@ -12,6 +12,7 @@ fn check_log_base() {
let _ = x.log(std::f32::consts::E);
let _ = x.log(TWO);
let _ = x.log(E);
+ let _ = (x as f32).log(2f32);
let x = 1f64;
let _ = x.log(2f64);
diff --git a/src/tools/clippy/tests/ui/floating_point_log.stderr b/src/tools/clippy/tests/ui/floating_point_log.stderr
index 96e5a1544..89800a13a 100644
--- a/src/tools/clippy/tests/ui/floating_point_log.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_log.stderr
@@ -31,25 +31,31 @@ LL | let _ = x.log(E);
| ^^^^^^^^ help: consider using: `x.ln()`
error: logarithm for bases 2, 10 and e can be computed more accurately
- --> $DIR/floating_point_log.rs:17:13
+ --> $DIR/floating_point_log.rs:15:13
+ |
+LL | let _ = (x as f32).log(2f32);
+ | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).log2()`
+
+error: logarithm for bases 2, 10 and e can be computed more accurately
+ --> $DIR/floating_point_log.rs:18:13
|
LL | let _ = x.log(2f64);
| ^^^^^^^^^^^ help: consider using: `x.log2()`
error: logarithm for bases 2, 10 and e can be computed more accurately
- --> $DIR/floating_point_log.rs:18:13
+ --> $DIR/floating_point_log.rs:19:13
|
LL | let _ = x.log(10f64);
| ^^^^^^^^^^^^ help: consider using: `x.log10()`
error: logarithm for bases 2, 10 and e can be computed more accurately
- --> $DIR/floating_point_log.rs:19:13
+ --> $DIR/floating_point_log.rs:20:13
|
LL | let _ = x.log(std::f64::consts::E);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:24:13
+ --> $DIR/floating_point_log.rs:25:13
|
LL | let _ = (1f32 + 2.).ln();
| ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()`
@@ -57,118 +63,118 @@ LL | let _ = (1f32 + 2.).ln();
= note: `-D clippy::imprecise-flops` implied by `-D warnings`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:25:13
+ --> $DIR/floating_point_log.rs:26:13
|
LL | let _ = (1f32 + 2.0).ln();
| ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:26:13
+ --> $DIR/floating_point_log.rs:27:13
|
LL | let _ = (1.0 + x).ln();
| ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:27:13
+ --> $DIR/floating_point_log.rs:28:13
|
LL | let _ = (1.0 + x / 2.0).ln();
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:28:13
+ --> $DIR/floating_point_log.rs:29:13
|
LL | let _ = (1.0 + x.powi(3)).ln();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:29:13
+ --> $DIR/floating_point_log.rs:30:13
|
LL | let _ = (1.0 + x.powi(3) / 2.0).ln();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(3) / 2.0).ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:30:13
+ --> $DIR/floating_point_log.rs:31:13
|
LL | let _ = (1.0 + (std::f32::consts::E - 1.0)).ln();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(std::f32::consts::E - 1.0).ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:31:13
+ --> $DIR/floating_point_log.rs:32:13
|
LL | let _ = (x + 1.0).ln();
| ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:32:13
+ --> $DIR/floating_point_log.rs:33:13
|
LL | let _ = (x.powi(3) + 1.0).ln();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:33:13
+ --> $DIR/floating_point_log.rs:34:13
|
LL | let _ = (x + 2.0 + 1.0).ln();
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:34:13
+ --> $DIR/floating_point_log.rs:35:13
|
LL | let _ = (x / 2.0 + 1.0).ln();
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:42:13
+ --> $DIR/floating_point_log.rs:43:13
|
LL | let _ = (1f64 + 2.).ln();
| ^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:43:13
+ --> $DIR/floating_point_log.rs:44:13
|
LL | let _ = (1f64 + 2.0).ln();
| ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:44:13
+ --> $DIR/floating_point_log.rs:45:13
|
LL | let _ = (1.0 + x).ln();
| ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:45:13
+ --> $DIR/floating_point_log.rs:46:13
|
LL | let _ = (1.0 + x / 2.0).ln();
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:46:13
+ --> $DIR/floating_point_log.rs:47:13
|
LL | let _ = (1.0 + x.powi(3)).ln();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:47:13
+ --> $DIR/floating_point_log.rs:48:13
|
LL | let _ = (x + 1.0).ln();
| ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:48:13
+ --> $DIR/floating_point_log.rs:49:13
|
LL | let _ = (x.powi(3) + 1.0).ln();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:49:13
+ --> $DIR/floating_point_log.rs:50:13
|
LL | let _ = (x + 2.0 + 1.0).ln();
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()`
error: ln(1 + x) can be computed more accurately
- --> $DIR/floating_point_log.rs:50:13
+ --> $DIR/floating_point_log.rs:51:13
|
LL | let _ = (x / 2.0 + 1.0).ln();
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
-error: aborting due to 28 previous errors
+error: aborting due to 29 previous errors
diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.fixed b/src/tools/clippy/tests/ui/floating_point_logbase.fixed
index 13962a272..7347bf72c 100644
--- a/src/tools/clippy/tests/ui/floating_point_logbase.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_logbase.fixed
@@ -1,10 +1,12 @@
// run-rustfix
#![warn(clippy::suboptimal_flops)]
+#![allow(clippy::unnecessary_cast)]
fn main() {
let x = 3f32;
let y = 5f32;
let _ = x.log(y);
+ let _ = (x as f32).log(y);
let _ = x.log(y);
let _ = x.log(y);
let _ = x.log(y);
diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.rs b/src/tools/clippy/tests/ui/floating_point_logbase.rs
index 26bc20d53..ba5b8d406 100644
--- a/src/tools/clippy/tests/ui/floating_point_logbase.rs
+++ b/src/tools/clippy/tests/ui/floating_point_logbase.rs
@@ -1,10 +1,12 @@
// run-rustfix
#![warn(clippy::suboptimal_flops)]
+#![allow(clippy::unnecessary_cast)]
fn main() {
let x = 3f32;
let y = 5f32;
let _ = x.ln() / y.ln();
+ let _ = (x as f32).ln() / y.ln();
let _ = x.log2() / y.log2();
let _ = x.log10() / y.log10();
let _ = x.log(5f32) / y.log(5f32);
diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.stderr b/src/tools/clippy/tests/ui/floating_point_logbase.stderr
index 78354c2f6..9d736b5e1 100644
--- a/src/tools/clippy/tests/ui/floating_point_logbase.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_logbase.stderr
@@ -1,5 +1,5 @@
error: log base can be expressed more clearly
- --> $DIR/floating_point_logbase.rs:7:13
+ --> $DIR/floating_point_logbase.rs:8:13
|
LL | let _ = x.ln() / y.ln();
| ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
@@ -7,22 +7,28 @@ LL | let _ = x.ln() / y.ln();
= note: `-D clippy::suboptimal-flops` implied by `-D warnings`
error: log base can be expressed more clearly
- --> $DIR/floating_point_logbase.rs:8:13
+ --> $DIR/floating_point_logbase.rs:9:13
+ |
+LL | let _ = (x as f32).ln() / y.ln();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).log(y)`
+
+error: log base can be expressed more clearly
+ --> $DIR/floating_point_logbase.rs:10:13
|
LL | let _ = x.log2() / y.log2();
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
error: log base can be expressed more clearly
- --> $DIR/floating_point_logbase.rs:9:13
+ --> $DIR/floating_point_logbase.rs:11:13
|
LL | let _ = x.log10() / y.log10();
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
error: log base can be expressed more clearly
- --> $DIR/floating_point_logbase.rs:10:13
+ --> $DIR/floating_point_logbase.rs:12:13
|
LL | let _ = x.log(5f32) / y.log(5f32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed
index 169ec02f8..d3e536ba3 100644
--- a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed
@@ -19,7 +19,9 @@ fn main() {
let d: f64 = 0.0001;
let _ = a.mul_add(b, c);
+ let _ = a.mul_add(b, -c);
let _ = a.mul_add(b, c);
+ let _ = a.mul_add(-b, c);
let _ = 2.0f64.mul_add(4.0, a);
let _ = 2.0f64.mul_add(4., a);
diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.rs b/src/tools/clippy/tests/ui/floating_point_mul_add.rs
index 5338d4fc2..5d4a9e35c 100644
--- a/src/tools/clippy/tests/ui/floating_point_mul_add.rs
+++ b/src/tools/clippy/tests/ui/floating_point_mul_add.rs
@@ -19,7 +19,9 @@ fn main() {
let d: f64 = 0.0001;
let _ = a * b + c;
+ let _ = a * b - c;
let _ = c + a * b;
+ let _ = c - a * b;
let _ = a + 2.0 * 4.0;
let _ = a + 2. * 4.;
diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr
index e637bbf90..a79ae94e8 100644
--- a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr
@@ -9,56 +9,68 @@ LL | let _ = a * b + c;
error: multiply and add expressions can be calculated more efficiently and accurately
--> $DIR/floating_point_mul_add.rs:22:13
|
+LL | let _ = a * b - c;
+ | ^^^^^^^^^ help: consider using: `a.mul_add(b, -c)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+ --> $DIR/floating_point_mul_add.rs:23:13
+ |
LL | let _ = c + a * b;
| ^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:23:13
+ --> $DIR/floating_point_mul_add.rs:24:13
+ |
+LL | let _ = c - a * b;
+ | ^^^^^^^^^ help: consider using: `a.mul_add(-b, c)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+ --> $DIR/floating_point_mul_add.rs:25:13
|
LL | let _ = a + 2.0 * 4.0;
| ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, a)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:24:13
+ --> $DIR/floating_point_mul_add.rs:26:13
|
LL | let _ = a + 2. * 4.;
| ^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4., a)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:26:13
+ --> $DIR/floating_point_mul_add.rs:28:13
|
LL | let _ = (a * b) + c;
| ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:27:13
+ --> $DIR/floating_point_mul_add.rs:29:13
|
LL | let _ = c + (a * b);
| ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:28:13
+ --> $DIR/floating_point_mul_add.rs:30:13
|
LL | let _ = a * b * c + d;
| ^^^^^^^^^^^^^ help: consider using: `(a * b).mul_add(c, d)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:30:13
+ --> $DIR/floating_point_mul_add.rs:32:13
|
LL | let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:31:13
+ --> $DIR/floating_point_mul_add.rs:33:13
|
LL | let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_mul_add.rs:33:13
+ --> $DIR/floating_point_mul_add.rs:35:13
|
LL | let _ = (a * a + b).sqrt();
| ^^^^^^^^^^^ help: consider using: `a.mul_add(a, b)`
-error: aborting due to 10 previous errors
+error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/floating_point_powf.fixed b/src/tools/clippy/tests/ui/floating_point_powf.fixed
index b0641a100..f7f93de29 100644
--- a/src/tools/clippy/tests/ui/floating_point_powf.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_powf.fixed
@@ -1,5 +1,6 @@
// run-rustfix
#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]
+#![allow(clippy::unnecessary_cast)]
fn main() {
let x = 3f32;
@@ -11,10 +12,18 @@ fn main() {
let _ = (-3.1f32).exp();
let _ = x.sqrt();
let _ = x.cbrt();
+ let _ = (x as f32).cbrt();
let _ = x.powi(3);
let _ = x.powi(-2);
let _ = x.powi(16_777_215);
let _ = x.powi(-16_777_215);
+ let _ = (x as f32).powi(-16_777_215);
+ let _ = (x as f32).powi(3);
+ let _ = (1.5_f32 + 1.0).cbrt();
+ let _ = 1.5_f64.cbrt();
+ let _ = 1.5_f64.sqrt();
+ let _ = 1.5_f64.powi(3);
+
// Cases where the lint shouldn't be applied
let _ = x.powf(2.1);
let _ = x.powf(-2.1);
diff --git a/src/tools/clippy/tests/ui/floating_point_powf.rs b/src/tools/clippy/tests/ui/floating_point_powf.rs
index a0a2c9739..499fc0e15 100644
--- a/src/tools/clippy/tests/ui/floating_point_powf.rs
+++ b/src/tools/clippy/tests/ui/floating_point_powf.rs
@@ -1,5 +1,6 @@
// run-rustfix
#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]
+#![allow(clippy::unnecessary_cast)]
fn main() {
let x = 3f32;
@@ -11,10 +12,18 @@ fn main() {
let _ = std::f32::consts::E.powf(-3.1);
let _ = x.powf(1.0 / 2.0);
let _ = x.powf(1.0 / 3.0);
+ let _ = (x as f32).powf(1.0 / 3.0);
let _ = x.powf(3.0);
let _ = x.powf(-2.0);
let _ = x.powf(16_777_215.0);
let _ = x.powf(-16_777_215.0);
+ let _ = (x as f32).powf(-16_777_215.0);
+ let _ = (x as f32).powf(3.0);
+ let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0);
+ let _ = 1.5_f64.powf(1.0 / 3.0);
+ let _ = 1.5_f64.powf(1.0 / 2.0);
+ let _ = 1.5_f64.powf(3.0);
+
// Cases where the lint shouldn't be applied
let _ = x.powf(2.1);
let _ = x.powf(-2.1);
diff --git a/src/tools/clippy/tests/ui/floating_point_powf.stderr b/src/tools/clippy/tests/ui/floating_point_powf.stderr
index 2422eb911..7c9d50db2 100644
--- a/src/tools/clippy/tests/ui/floating_point_powf.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_powf.stderr
@@ -1,5 +1,5 @@
error: exponent for bases 2 and e can be computed more accurately
- --> $DIR/floating_point_powf.rs:6:13
+ --> $DIR/floating_point_powf.rs:7:13
|
LL | let _ = 2f32.powf(x);
| ^^^^^^^^^^^^ help: consider using: `x.exp2()`
@@ -7,144 +7,186 @@ LL | let _ = 2f32.powf(x);
= note: `-D clippy::suboptimal-flops` implied by `-D warnings`
error: exponent for bases 2 and e can be computed more accurately
- --> $DIR/floating_point_powf.rs:7:13
+ --> $DIR/floating_point_powf.rs:8:13
|
LL | let _ = 2f32.powf(3.1);
| ^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp2()`
error: exponent for bases 2 and e can be computed more accurately
- --> $DIR/floating_point_powf.rs:8:13
+ --> $DIR/floating_point_powf.rs:9:13
|
LL | let _ = 2f32.powf(-3.1);
| ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp2()`
error: exponent for bases 2 and e can be computed more accurately
- --> $DIR/floating_point_powf.rs:9:13
+ --> $DIR/floating_point_powf.rs:10:13
|
LL | let _ = std::f32::consts::E.powf(x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()`
error: exponent for bases 2 and e can be computed more accurately
- --> $DIR/floating_point_powf.rs:10:13
+ --> $DIR/floating_point_powf.rs:11:13
|
LL | let _ = std::f32::consts::E.powf(3.1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp()`
error: exponent for bases 2 and e can be computed more accurately
- --> $DIR/floating_point_powf.rs:11:13
+ --> $DIR/floating_point_powf.rs:12:13
|
LL | let _ = std::f32::consts::E.powf(-3.1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp()`
error: square-root of a number can be computed more efficiently and accurately
- --> $DIR/floating_point_powf.rs:12:13
+ --> $DIR/floating_point_powf.rs:13:13
|
LL | let _ = x.powf(1.0 / 2.0);
| ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()`
error: cube-root of a number can be computed more accurately
- --> $DIR/floating_point_powf.rs:13:13
+ --> $DIR/floating_point_powf.rs:14:13
|
LL | let _ = x.powf(1.0 / 3.0);
| ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
|
= note: `-D clippy::imprecise-flops` implied by `-D warnings`
+error: cube-root of a number can be computed more accurately
+ --> $DIR/floating_point_powf.rs:15:13
+ |
+LL | let _ = (x as f32).powf(1.0 / 3.0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).cbrt()`
+
error: exponentiation with integer powers can be computed more efficiently
- --> $DIR/floating_point_powf.rs:14:13
+ --> $DIR/floating_point_powf.rs:16:13
|
LL | let _ = x.powf(3.0);
| ^^^^^^^^^^^ help: consider using: `x.powi(3)`
error: exponentiation with integer powers can be computed more efficiently
- --> $DIR/floating_point_powf.rs:15:13
+ --> $DIR/floating_point_powf.rs:17:13
|
LL | let _ = x.powf(-2.0);
| ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
error: exponentiation with integer powers can be computed more efficiently
- --> $DIR/floating_point_powf.rs:16:13
+ --> $DIR/floating_point_powf.rs:18:13
|
LL | let _ = x.powf(16_777_215.0);
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(16_777_215)`
error: exponentiation with integer powers can be computed more efficiently
- --> $DIR/floating_point_powf.rs:17:13
+ --> $DIR/floating_point_powf.rs:19:13
|
LL | let _ = x.powf(-16_777_215.0);
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-16_777_215)`
-error: exponent for bases 2 and e can be computed more accurately
+error: exponentiation with integer powers can be computed more efficiently
+ --> $DIR/floating_point_powf.rs:20:13
+ |
+LL | let _ = (x as f32).powf(-16_777_215.0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(-16_777_215)`
+
+error: exponentiation with integer powers can be computed more efficiently
+ --> $DIR/floating_point_powf.rs:21:13
+ |
+LL | let _ = (x as f32).powf(3.0);
+ | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(3)`
+
+error: cube-root of a number can be computed more accurately
+ --> $DIR/floating_point_powf.rs:22:13
+ |
+LL | let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(1.5_f32 + 1.0).cbrt()`
+
+error: cube-root of a number can be computed more accurately
+ --> $DIR/floating_point_powf.rs:23:13
+ |
+LL | let _ = 1.5_f64.powf(1.0 / 3.0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.cbrt()`
+
+error: square-root of a number can be computed more efficiently and accurately
+ --> $DIR/floating_point_powf.rs:24:13
+ |
+LL | let _ = 1.5_f64.powf(1.0 / 2.0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.sqrt()`
+
+error: exponentiation with integer powers can be computed more efficiently
--> $DIR/floating_point_powf.rs:25:13
|
+LL | let _ = 1.5_f64.powf(3.0);
+ | ^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.powi(3)`
+
+error: exponent for bases 2 and e can be computed more accurately
+ --> $DIR/floating_point_powf.rs:34:13
+ |
LL | let _ = 2f64.powf(x);
| ^^^^^^^^^^^^ help: consider using: `x.exp2()`
error: exponent for bases 2 and e can be computed more accurately
- --> $DIR/floating_point_powf.rs:26:13
+ --> $DIR/floating_point_powf.rs:35:13
|
LL | let _ = 2f64.powf(3.1);
| ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()`
error: exponent for bases 2 and e can be computed more accurately
- --> $DIR/floating_point_powf.rs:27:13
+ --> $DIR/floating_point_powf.rs:36:13
|
LL | let _ = 2f64.powf(-3.1);
| ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()`
error: exponent for bases 2 and e can be computed more accurately
- --> $DIR/floating_point_powf.rs:28:13
+ --> $DIR/floating_point_powf.rs:37:13
|
LL | let _ = std::f64::consts::E.powf(x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()`
error: exponent for bases 2 and e can be computed more accurately
- --> $DIR/floating_point_powf.rs:29:13
+ --> $DIR/floating_point_powf.rs:38:13
|
LL | let _ = std::f64::consts::E.powf(3.1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()`
error: exponent for bases 2 and e can be computed more accurately
- --> $DIR/floating_point_powf.rs:30:13
+ --> $DIR/floating_point_powf.rs:39:13
|
LL | let _ = std::f64::consts::E.powf(-3.1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()`
error: square-root of a number can be computed more efficiently and accurately
- --> $DIR/floating_point_powf.rs:31:13
+ --> $DIR/floating_point_powf.rs:40:13
|
LL | let _ = x.powf(1.0 / 2.0);
| ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()`
error: cube-root of a number can be computed more accurately
- --> $DIR/floating_point_powf.rs:32:13
+ --> $DIR/floating_point_powf.rs:41:13
|
LL | let _ = x.powf(1.0 / 3.0);
| ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
error: exponentiation with integer powers can be computed more efficiently
- --> $DIR/floating_point_powf.rs:33:13
+ --> $DIR/floating_point_powf.rs:42:13
|
LL | let _ = x.powf(3.0);
| ^^^^^^^^^^^ help: consider using: `x.powi(3)`
error: exponentiation with integer powers can be computed more efficiently
- --> $DIR/floating_point_powf.rs:34:13
+ --> $DIR/floating_point_powf.rs:43:13
|
LL | let _ = x.powf(-2.0);
| ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
error: exponentiation with integer powers can be computed more efficiently
- --> $DIR/floating_point_powf.rs:35:13
+ --> $DIR/floating_point_powf.rs:44:13
|
LL | let _ = x.powf(-2_147_483_648.0);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)`
error: exponentiation with integer powers can be computed more efficiently
- --> $DIR/floating_point_powf.rs:36:13
+ --> $DIR/floating_point_powf.rs:45:13
|
LL | let _ = x.powf(2_147_483_647.0);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)`
-error: aborting due to 24 previous errors
+error: aborting due to 31 previous errors
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.fixed b/src/tools/clippy/tests/ui/floating_point_powi.fixed
index 85f7c531e..884d05fed 100644
--- a/src/tools/clippy/tests/ui/floating_point_powi.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_powi.fixed
@@ -1,5 +1,6 @@
// run-rustfix
#![warn(clippy::suboptimal_flops)]
+#![allow(clippy::unnecessary_cast)]
fn main() {
let one = 1;
@@ -7,7 +8,10 @@ fn main() {
let y = 4f32;
let _ = x.mul_add(x, y);
+ let _ = x.mul_add(x, -y);
let _ = y.mul_add(y, x);
+ let _ = y.mul_add(-y, x);
+ let _ = (y as f32).mul_add(y as f32, x);
let _ = x.mul_add(x, y).sqrt();
let _ = y.mul_add(y, x).sqrt();
// Cases where the lint shouldn't be applied
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.rs b/src/tools/clippy/tests/ui/floating_point_powi.rs
index ece61d1be..e6a1c8953 100644
--- a/src/tools/clippy/tests/ui/floating_point_powi.rs
+++ b/src/tools/clippy/tests/ui/floating_point_powi.rs
@@ -1,5 +1,6 @@
// run-rustfix
#![warn(clippy::suboptimal_flops)]
+#![allow(clippy::unnecessary_cast)]
fn main() {
let one = 1;
@@ -7,7 +8,10 @@ fn main() {
let y = 4f32;
let _ = x.powi(2) + y;
+ let _ = x.powi(2) - y;
let _ = x + y.powi(2);
+ let _ = x - y.powi(2);
+ let _ = x + (y as f32).powi(2);
let _ = (x.powi(2) + y).sqrt();
let _ = (x + y.powi(2)).sqrt();
// Cases where the lint shouldn't be applied
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.stderr b/src/tools/clippy/tests/ui/floating_point_powi.stderr
index 37d840988..5df0de1fe 100644
--- a/src/tools/clippy/tests/ui/floating_point_powi.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_powi.stderr
@@ -1,5 +1,5 @@
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_powi.rs:9:13
+ --> $DIR/floating_point_powi.rs:10:13
|
LL | let _ = x.powi(2) + y;
| ^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)`
@@ -7,22 +7,40 @@ LL | let _ = x.powi(2) + y;
= note: `-D clippy::suboptimal-flops` implied by `-D warnings`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_powi.rs:10:13
+ --> $DIR/floating_point_powi.rs:11:13
+ |
+LL | let _ = x.powi(2) - y;
+ | ^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, -y)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+ --> $DIR/floating_point_powi.rs:12:13
|
LL | let _ = x + y.powi(2);
| ^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_powi.rs:11:13
+ --> $DIR/floating_point_powi.rs:13:13
+ |
+LL | let _ = x - y.powi(2);
+ | ^^^^^^^^^^^^^ help: consider using: `y.mul_add(-y, x)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+ --> $DIR/floating_point_powi.rs:14:13
+ |
+LL | let _ = x + (y as f32).powi(2);
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y as f32).mul_add(y as f32, x)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+ --> $DIR/floating_point_powi.rs:15:13
|
LL | let _ = (x.powi(2) + y).sqrt();
| ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)`
error: multiply and add expressions can be calculated more efficiently and accurately
- --> $DIR/floating_point_powi.rs:12:13
+ --> $DIR/floating_point_powi.rs:16:13
|
LL | let _ = (x + y.powi(2)).sqrt();
| ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
-error: aborting due to 4 previous errors
+error: aborting due to 7 previous errors
diff --git a/src/tools/clippy/tests/ui/floating_point_rad.fixed b/src/tools/clippy/tests/ui/floating_point_rad.fixed
index ce91fe176..27674b8a4 100644
--- a/src/tools/clippy/tests/ui/floating_point_rad.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_rad.fixed
@@ -8,6 +8,11 @@ pub const fn const_context() {
let _ = x * 180f32 / std::f32::consts::PI;
}
+pub fn issue9391(degrees: i64) {
+ let _ = (degrees as f64).to_radians();
+ let _ = (degrees as f64).to_degrees();
+}
+
fn main() {
let x = 3f32;
let _ = x.to_degrees();
diff --git a/src/tools/clippy/tests/ui/floating_point_rad.rs b/src/tools/clippy/tests/ui/floating_point_rad.rs
index 8f3234986..f1ea73df3 100644
--- a/src/tools/clippy/tests/ui/floating_point_rad.rs
+++ b/src/tools/clippy/tests/ui/floating_point_rad.rs
@@ -8,6 +8,11 @@ pub const fn const_context() {
let _ = x * 180f32 / std::f32::consts::PI;
}
+pub fn issue9391(degrees: i64) {
+ let _ = degrees as f64 * std::f64::consts::PI / 180.0;
+ let _ = degrees as f64 * 180.0 / std::f64::consts::PI;
+}
+
fn main() {
let x = 3f32;
let _ = x * 180f32 / std::f32::consts::PI;
diff --git a/src/tools/clippy/tests/ui/floating_point_rad.stderr b/src/tools/clippy/tests/ui/floating_point_rad.stderr
index f12d3d23f..979442f2c 100644
--- a/src/tools/clippy/tests/ui/floating_point_rad.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_rad.stderr
@@ -1,40 +1,52 @@
+error: conversion to radians can be done more accurately
+ --> $DIR/floating_point_rad.rs:12:13
+ |
+LL | let _ = degrees as f64 * std::f64::consts::PI / 180.0;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(degrees as f64).to_radians()`
+ |
+ = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
+
error: conversion to degrees can be done more accurately
--> $DIR/floating_point_rad.rs:13:13
|
+LL | let _ = degrees as f64 * 180.0 / std::f64::consts::PI;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(degrees as f64).to_degrees()`
+
+error: conversion to degrees can be done more accurately
+ --> $DIR/floating_point_rad.rs:18:13
+ |
LL | let _ = x * 180f32 / std::f32::consts::PI;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_degrees()`
- |
- = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
error: conversion to degrees can be done more accurately
- --> $DIR/floating_point_rad.rs:14:13
+ --> $DIR/floating_point_rad.rs:19:13
|
LL | let _ = 90. * 180f64 / std::f64::consts::PI;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_degrees()`
error: conversion to degrees can be done more accurately
- --> $DIR/floating_point_rad.rs:15:13
+ --> $DIR/floating_point_rad.rs:20:13
|
LL | let _ = 90.5 * 180f64 / std::f64::consts::PI;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_degrees()`
error: conversion to radians can be done more accurately
- --> $DIR/floating_point_rad.rs:16:13
+ --> $DIR/floating_point_rad.rs:21:13
|
LL | let _ = x * std::f32::consts::PI / 180f32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_radians()`
error: conversion to radians can be done more accurately
- --> $DIR/floating_point_rad.rs:17:13
+ --> $DIR/floating_point_rad.rs:22:13
|
LL | let _ = 90. * std::f32::consts::PI / 180f32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_radians()`
error: conversion to radians can be done more accurately
- --> $DIR/floating_point_rad.rs:18:13
+ --> $DIR/floating_point_rad.rs:23:13
|
LL | let _ = 90.5 * std::f32::consts::PI / 180f32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_radians()`
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/fn_params_excessive_bools.stderr b/src/tools/clippy/tests/ui/fn_params_excessive_bools.stderr
index cd9d07fa1..116271056 100644
--- a/src/tools/clippy/tests/ui/fn_params_excessive_bools.stderr
+++ b/src/tools/clippy/tests/ui/fn_params_excessive_bools.stderr
@@ -4,8 +4,8 @@ error: more than 3 bools in function parameters
LL | fn g(_: bool, _: bool, _: bool, _: bool) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings`
= help: consider refactoring bools into two-variant enums
+ = note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings`
error: more than 3 bools in function parameters
--> $DIR/fn_params_excessive_bools.rs:21:1
diff --git a/src/tools/clippy/tests/ui/for_loop_fixable.fixed b/src/tools/clippy/tests/ui/for_loop_fixable.fixed
index aa69781d1..e9dd38fe4 100644
--- a/src/tools/clippy/tests/ui/for_loop_fixable.fixed
+++ b/src/tools/clippy/tests/ui/for_loop_fixable.fixed
@@ -1,6 +1,6 @@
// run-rustfix
-
#![allow(dead_code, unused)]
+#![allow(clippy::uninlined_format_args)]
use std::collections::*;
diff --git a/src/tools/clippy/tests/ui/for_loop_fixable.rs b/src/tools/clippy/tests/ui/for_loop_fixable.rs
index 7c063d995..534fb4dd4 100644
--- a/src/tools/clippy/tests/ui/for_loop_fixable.rs
+++ b/src/tools/clippy/tests/ui/for_loop_fixable.rs
@@ -1,6 +1,6 @@
// run-rustfix
-
#![allow(dead_code, unused)]
+#![allow(clippy::uninlined_format_args)]
use std::collections::*;
diff --git a/src/tools/clippy/tests/ui/for_loop_unfixable.rs b/src/tools/clippy/tests/ui/for_loop_unfixable.rs
index efcaffce2..55fb3788a 100644
--- a/src/tools/clippy/tests/ui/for_loop_unfixable.rs
+++ b/src/tools/clippy/tests/ui/for_loop_unfixable.rs
@@ -8,6 +8,7 @@
clippy::for_kv_map
)]
#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)]
+#[allow(for_loops_over_fallibles)]
fn main() {
let vec = vec![1, 2, 3, 4];
diff --git a/src/tools/clippy/tests/ui/for_loop_unfixable.stderr b/src/tools/clippy/tests/ui/for_loop_unfixable.stderr
index f769b4bdc..50a86eaa6 100644
--- a/src/tools/clippy/tests/ui/for_loop_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/for_loop_unfixable.stderr
@@ -1,5 +1,5 @@
error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
- --> $DIR/for_loop_unfixable.rs:14:15
+ --> $DIR/for_loop_unfixable.rs:15:15
|
LL | for _v in vec.iter().next() {}
| ^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/for_loops_over_fallibles.rs b/src/tools/clippy/tests/ui/for_loops_over_fallibles.rs
deleted file mode 100644
index 3390111d0..000000000
--- a/src/tools/clippy/tests/ui/for_loops_over_fallibles.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-#![warn(clippy::for_loops_over_fallibles)]
-
-fn for_loops_over_fallibles() {
- let option = Some(1);
- let mut result = option.ok_or("x not found");
- let v = vec![0, 1, 2];
-
- // check over an `Option`
- for x in option {
- println!("{}", x);
- }
-
- // check over an `Option`
- for x in option.iter() {
- println!("{}", x);
- }
-
- // check over a `Result`
- for x in result {
- println!("{}", x);
- }
-
- // check over a `Result`
- for x in result.iter_mut() {
- println!("{}", x);
- }
-
- // check over a `Result`
- for x in result.into_iter() {
- println!("{}", x);
- }
-
- for x in option.ok_or("x not found") {
- println!("{}", x);
- }
-
- // make sure LOOP_OVER_NEXT lint takes clippy::precedence when next() is the last call
- // in the chain
- for x in v.iter().next() {
- println!("{}", x);
- }
-
- // make sure we lint when next() is not the last call in the chain
- for x in v.iter().next().and(Some(0)) {
- println!("{}", x);
- }
-
- for x in v.iter().next().ok_or("x not found") {
- println!("{}", x);
- }
-
- // check for false positives
-
- // for loop false positive
- for x in v {
- println!("{}", x);
- }
-
- // while let false positive for Option
- while let Some(x) = option {
- println!("{}", x);
- break;
- }
-
- // while let false positive for Result
- while let Ok(x) = result {
- println!("{}", x);
- break;
- }
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/for_loops_over_fallibles.stderr b/src/tools/clippy/tests/ui/for_loops_over_fallibles.stderr
deleted file mode 100644
index 8c8c02224..000000000
--- a/src/tools/clippy/tests/ui/for_loops_over_fallibles.stderr
+++ /dev/null
@@ -1,95 +0,0 @@
-error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement
- --> $DIR/for_loops_over_fallibles.rs:9:14
- |
-LL | for x in option {
- | ^^^^^^
- |
- = note: `-D clippy::for-loops-over-fallibles` implied by `-D warnings`
- = help: consider replacing `for x in option` with `if let Some(x) = option`
-
-error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement
- --> $DIR/for_loops_over_fallibles.rs:14:14
- |
-LL | for x in option.iter() {
- | ^^^^^^
- |
- = help: consider replacing `for x in option.iter()` with `if let Some(x) = option`
-
-error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement
- --> $DIR/for_loops_over_fallibles.rs:19:14
- |
-LL | for x in result {
- | ^^^^^^
- |
- = help: consider replacing `for x in result` with `if let Ok(x) = result`
-
-error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement
- --> $DIR/for_loops_over_fallibles.rs:24:14
- |
-LL | for x in result.iter_mut() {
- | ^^^^^^
- |
- = help: consider replacing `for x in result.iter_mut()` with `if let Ok(x) = result`
-
-error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement
- --> $DIR/for_loops_over_fallibles.rs:29:14
- |
-LL | for x in result.into_iter() {
- | ^^^^^^
- |
- = help: consider replacing `for x in result.into_iter()` with `if let Ok(x) = result`
-
-error: for loop over `option.ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement
- --> $DIR/for_loops_over_fallibles.rs:33:14
- |
-LL | for x in option.ok_or("x not found") {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider replacing `for x in option.ok_or("x not found")` with `if let Ok(x) = option.ok_or("x not found")`
-
-error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
- --> $DIR/for_loops_over_fallibles.rs:39:14
- |
-LL | for x in v.iter().next() {
- | ^^^^^^^^^^^^^^^
- |
- = note: `#[deny(clippy::iter_next_loop)]` on by default
-
-error: for loop over `v.iter().next().and(Some(0))`, which is an `Option`. This is more readably written as an `if let` statement
- --> $DIR/for_loops_over_fallibles.rs:44:14
- |
-LL | for x in v.iter().next().and(Some(0)) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider replacing `for x in v.iter().next().and(Some(0))` with `if let Some(x) = v.iter().next().and(Some(0))`
-
-error: for loop over `v.iter().next().ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement
- --> $DIR/for_loops_over_fallibles.rs:48:14
- |
-LL | for x in v.iter().next().ok_or("x not found") {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider replacing `for x in v.iter().next().ok_or("x not found")` with `if let Ok(x) = v.iter().next().ok_or("x not found")`
-
-error: this loop never actually loops
- --> $DIR/for_loops_over_fallibles.rs:60:5
- |
-LL | / while let Some(x) = option {
-LL | | println!("{}", x);
-LL | | break;
-LL | | }
- | |_____^
- |
- = note: `#[deny(clippy::never_loop)]` on by default
-
-error: this loop never actually loops
- --> $DIR/for_loops_over_fallibles.rs:66:5
- |
-LL | / while let Ok(x) = result {
-LL | | println!("{}", x);
-LL | | break;
-LL | | }
- | |_____^
-
-error: aborting due to 11 previous errors
-
diff --git a/src/tools/clippy/tests/ui/forget_non_drop.stderr b/src/tools/clippy/tests/ui/forget_non_drop.stderr
index 03fb00960..194e37c8b 100644
--- a/src/tools/clippy/tests/ui/forget_non_drop.stderr
+++ b/src/tools/clippy/tests/ui/forget_non_drop.stderr
@@ -4,12 +4,12 @@ error: call to `std::mem::forget` with a value that does not implement `Drop`. F
LL | forget(Foo);
| ^^^^^^^^^^^
|
- = note: `-D clippy::forget-non-drop` implied by `-D warnings`
note: argument has type `main::Foo`
--> $DIR/forget_non_drop.rs:13:12
|
LL | forget(Foo);
| ^^^
+ = note: `-D clippy::forget-non-drop` implied by `-D warnings`
error: call to `std::mem::forget` with a value that does not implement `Drop`. Forgetting such a type is the same as dropping it
--> $DIR/forget_non_drop.rs:24:5
diff --git a/src/tools/clippy/tests/ui/forget_ref.stderr b/src/tools/clippy/tests/ui/forget_ref.stderr
index df5cd8cac..011cdefc6 100644
--- a/src/tools/clippy/tests/ui/forget_ref.stderr
+++ b/src/tools/clippy/tests/ui/forget_ref.stderr
@@ -4,12 +4,12 @@ error: calls to `std::mem::forget` with a reference instead of an owned value. F
LL | forget(&SomeStruct);
| ^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::forget-ref` implied by `-D warnings`
note: argument has type `&SomeStruct`
--> $DIR/forget_ref.rs:11:12
|
LL | forget(&SomeStruct);
| ^^^^^^^^^^^
+ = note: `-D clippy::forget-ref` implied by `-D warnings`
error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
--> $DIR/forget_ref.rs:14:5
diff --git a/src/tools/clippy/tests/ui/format.fixed b/src/tools/clippy/tests/ui/format.fixed
index 6b754f3bd..beedf2c1d 100644
--- a/src/tools/clippy/tests/ui/format.fixed
+++ b/src/tools/clippy/tests/ui/format.fixed
@@ -1,13 +1,13 @@
// run-rustfix
-
+#![warn(clippy::useless_format)]
#![allow(
unused_tuple_struct_fields,
clippy::print_literal,
clippy::redundant_clone,
clippy::to_string_in_format_args,
- clippy::needless_borrow
+ clippy::needless_borrow,
+ clippy::uninlined_format_args
)]
-#![warn(clippy::useless_format)]
struct Foo(pub String);
@@ -28,18 +28,14 @@ fn main() {
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();
+ let arg = String::new();
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);
diff --git a/src/tools/clippy/tests/ui/format.rs b/src/tools/clippy/tests/ui/format.rs
index ca9826b35..e805f1818 100644
--- a/src/tools/clippy/tests/ui/format.rs
+++ b/src/tools/clippy/tests/ui/format.rs
@@ -1,13 +1,13 @@
// run-rustfix
-
+#![warn(clippy::useless_format)]
#![allow(
unused_tuple_struct_fields,
clippy::print_literal,
clippy::redundant_clone,
clippy::to_string_in_format_args,
- clippy::needless_borrow
+ clippy::needless_borrow,
+ clippy::uninlined_format_args
)]
-#![warn(clippy::useless_format)]
struct Foo(pub String);
@@ -30,18 +30,14 @@ fn main() {
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();
+ let arg = String::new();
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);
diff --git a/src/tools/clippy/tests/ui/format.stderr b/src/tools/clippy/tests/ui/format.stderr
index 6c35caeb0..0ef0ac655 100644
--- a/src/tools/clippy/tests/ui/format.stderr
+++ b/src/tools/clippy/tests/ui/format.stderr
@@ -46,82 +46,58 @@ LL | format!("{}", "foo");
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:33: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:34: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:39:5
+ --> $DIR/format.rs:37:5
|
LL | format!("{}", arg);
| ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:43: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:44: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:71:5
+ --> $DIR/format.rs:67:5
|
LL | format!("{}", 42.to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:73:5
+ --> $DIR/format.rs:69:5
|
LL | format!("{}", x.display().to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:77:18
+ --> $DIR/format.rs:73:18
|
LL | let _ = Some(format!("{}", a + "bar"));
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
error: useless use of `format!`
- --> $DIR/format.rs:81:22
+ --> $DIR/format.rs:77:22
|
LL | let _s: String = format!("{}", &*v.join("/n"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:87:13
+ --> $DIR/format.rs:83:13
|
LL | let _ = format!("{x}");
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:89:13
+ --> $DIR/format.rs:85:13
|
LL | let _ = format!("{y}", y = x);
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:93:13
+ --> $DIR/format.rs:89:13
|
LL | let _ = format!("{abc}");
| ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:95:13
+ --> $DIR/format.rs:91:13
|
LL | let _ = format!("{xx}");
| ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()`
-error: aborting due to 19 previous errors
+error: aborting due to 15 previous errors
diff --git a/src/tools/clippy/tests/ui/format_args.fixed b/src/tools/clippy/tests/ui/format_args.fixed
index 69b5e1c72..825e122be 100644
--- a/src/tools/clippy/tests/ui/format_args.fixed
+++ b/src/tools/clippy/tests/ui/format_args.fixed
@@ -1,12 +1,13 @@
// 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)]
+#![allow(unused)]
+#![allow(
+ clippy::assertions_on_constants,
+ clippy::double_parens,
+ clippy::eq_op,
+ clippy::print_literal,
+ clippy::uninlined_format_args
+)]
use std::io::{stdout, Write};
use std::ops::Deref;
@@ -114,4 +115,53 @@ fn main() {
println!("error: something failed at {}", my_other_macro!());
// https://github.com/rust-lang/rust-clippy/issues/7903
println!("{foo}{foo:?}", foo = "foo".to_string());
+ print!("{}", (Location::caller()));
+ print!("{}", ((Location::caller())));
+}
+
+fn issue8643(vendor_id: usize, product_id: usize, name: &str) {
+ println!(
+ "{:<9} {:<10} {}",
+ format!("0x{:x}", vendor_id),
+ format!("0x{:x}", product_id),
+ name
+ );
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/8855
+mod issue_8855 {
+ #![allow(dead_code)]
+
+ struct A {}
+
+ impl std::fmt::Display for A {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "test")
+ }
+ }
+
+ fn main() {
+ let a = A {};
+ let b = A {};
+
+ let x = format!("{} {}", a, b);
+ dbg!(x);
+
+ let x = format!("{:>6} {:>6}", a, b.to_string());
+ dbg!(x);
+ }
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/9256
+mod issue_9256 {
+ #![allow(dead_code)]
+
+ fn print_substring(original: &str) {
+ assert!(original.len() > 10);
+ println!("{}", &original[..10]);
+ }
+
+ fn main() {
+ print_substring("Hello, world!");
+ }
}
diff --git a/src/tools/clippy/tests/ui/format_args.rs b/src/tools/clippy/tests/ui/format_args.rs
index 3a434c5bf..a41e53389 100644
--- a/src/tools/clippy/tests/ui/format_args.rs
+++ b/src/tools/clippy/tests/ui/format_args.rs
@@ -1,12 +1,13 @@
// 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)]
+#![allow(unused)]
+#![allow(
+ clippy::assertions_on_constants,
+ clippy::double_parens,
+ clippy::eq_op,
+ clippy::print_literal,
+ clippy::uninlined_format_args
+)]
use std::io::{stdout, Write};
use std::ops::Deref;
@@ -114,4 +115,53 @@ fn main() {
println!("error: something failed at {}", my_other_macro!());
// https://github.com/rust-lang/rust-clippy/issues/7903
println!("{foo}{foo:?}", foo = "foo".to_string());
+ print!("{}", (Location::caller().to_string()));
+ print!("{}", ((Location::caller()).to_string()));
+}
+
+fn issue8643(vendor_id: usize, product_id: usize, name: &str) {
+ println!(
+ "{:<9} {:<10} {}",
+ format!("0x{:x}", vendor_id),
+ format!("0x{:x}", product_id),
+ name
+ );
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/8855
+mod issue_8855 {
+ #![allow(dead_code)]
+
+ struct A {}
+
+ impl std::fmt::Display for A {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "test")
+ }
+ }
+
+ fn main() {
+ let a = A {};
+ let b = A {};
+
+ let x = format!("{} {}", a, b.to_string());
+ dbg!(x);
+
+ let x = format!("{:>6} {:>6}", a, b.to_string());
+ dbg!(x);
+ }
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/9256
+mod issue_9256 {
+ #![allow(dead_code)]
+
+ fn print_substring(original: &str) {
+ assert!(original.len() > 10);
+ println!("{}", original[..10].to_string());
+ }
+
+ fn main() {
+ print_substring("Hello, world!");
+ }
}
diff --git a/src/tools/clippy/tests/ui/format_args.stderr b/src/tools/clippy/tests/ui/format_args.stderr
index c0cbca507..f1832b970 100644
--- a/src/tools/clippy/tests/ui/format_args.stderr
+++ b/src/tools/clippy/tests/ui/format_args.stderr
@@ -1,5 +1,5 @@
error: `to_string` applied to a type that implements `Display` in `format!` args
- --> $DIR/format_args.rs:76:72
+ --> $DIR/format_args.rs:77:72
|
LL | let _ = format!("error: something failed at {}", Location::caller().to_string());
| ^^^^^^^^^^^^ help: remove this
@@ -7,124 +7,148 @@ LL | let _ = format!("error: something failed at {}", Location::caller().to_
= 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:80:27
+ --> $DIR/format_args.rs:81: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:85:27
+ --> $DIR/format_args.rs:86: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:63
+ --> $DIR/format_args.rs:88: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:65
+ --> $DIR/format_args.rs:89: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:64
+ --> $DIR/format_args.rs:90: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:66
+ --> $DIR/format_args.rs:91: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:77
+ --> $DIR/format_args.rs:92: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:70
+ --> $DIR/format_args.rs:93: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:94: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:73
+ --> $DIR/format_args.rs:95: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:63
+ --> $DIR/format_args.rs:96: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:97: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:20
+ --> $DIR/format_args.rs:98: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:24
+ --> $DIR/format_args.rs:99: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:100:20
|
LL | println!("{}", x.to_string());
| ^^^^^^^^^^^^^ help: use this: `**x`
error: `to_string` applied to a type that implements `Display` in `println!` args
- --> $DIR/format_args.rs:100:20
+ --> $DIR/format_args.rs:101: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
+ --> $DIR/format_args.rs:103: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
+ --> $DIR/format_args.rs:104: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
+ --> $DIR/format_args.rs:105: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
+ --> $DIR/format_args.rs:106:52
|
LL | println!("{foo}{bar}", bar = "bar", foo = "foo".to_string());
| ^^^^^^^^^^^^ help: remove this
-error: aborting due to 21 previous errors
+error: `to_string` applied to a type that implements `Display` in `print!` args
+ --> $DIR/format_args.rs:118:37
+ |
+LL | print!("{}", (Location::caller().to_string()));
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `print!` args
+ --> $DIR/format_args.rs:119:39
+ |
+LL | print!("{}", ((Location::caller()).to_string()));
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `format!` args
+ --> $DIR/format_args.rs:147:38
+ |
+LL | let x = format!("{} {}", a, b.to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:161:24
+ |
+LL | println!("{}", original[..10].to_string());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use this: `&original[..10]`
+
+error: aborting due to 25 previous errors
diff --git a/src/tools/clippy/tests/ui/format_args_unfixable.rs b/src/tools/clippy/tests/ui/format_args_unfixable.rs
index b24ddf732..eb0ac15bf 100644
--- a/src/tools/clippy/tests/ui/format_args_unfixable.rs
+++ b/src/tools/clippy/tests/ui/format_args_unfixable.rs
@@ -1,7 +1,5 @@
-#![allow(clippy::assertions_on_constants)]
-#![allow(clippy::eq_op)]
-#![warn(clippy::format_in_format_args)]
-#![warn(clippy::to_string_in_format_args)]
+#![warn(clippy::format_in_format_args, clippy::to_string_in_format_args)]
+#![allow(clippy::assertions_on_constants, clippy::eq_op, clippy::uninlined_format_args)]
use std::io::{stdout, Error, ErrorKind, Write};
use std::ops::Deref;
diff --git a/src/tools/clippy/tests/ui/format_args_unfixable.stderr b/src/tools/clippy/tests/ui/format_args_unfixable.stderr
index 4476218ad..b291d475a 100644
--- a/src/tools/clippy/tests/ui/format_args_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/format_args_unfixable.stderr
@@ -1,15 +1,15 @@
error: `format!` in `println!` args
- --> $DIR/format_args_unfixable.rs:27:5
+ --> $DIR/format_args_unfixable.rs:25:5
|
LL | println!("error: {}", format!("something failed at {}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::format-in-format-args` implied by `-D warnings`
= help: combine the `format!(..)` arguments with the outer `println!(..)` call
= help: or consider changing `format!` to `format_args!`
+ = note: `-D clippy::format-in-format-args` implied by `-D warnings`
error: `format!` in `println!` args
- --> $DIR/format_args_unfixable.rs:28:5
+ --> $DIR/format_args_unfixable.rs:26:5
|
LL | println!("{}: {}", error, format!("something failed at {}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -18,7 +18,7 @@ LL | println!("{}: {}", error, format!("something failed at {}", Location::c
= help: or consider changing `format!` to `format_args!`
error: `format!` in `println!` args
- --> $DIR/format_args_unfixable.rs:29:5
+ --> $DIR/format_args_unfixable.rs:27:5
|
LL | println!("{:?}: {}", error, format!("something failed at {}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -27,7 +27,7 @@ LL | println!("{:?}: {}", error, format!("something failed at {}", Location:
= help: or consider changing `format!` to `format_args!`
error: `format!` in `println!` args
- --> $DIR/format_args_unfixable.rs:30:5
+ --> $DIR/format_args_unfixable.rs:28:5
|
LL | println!("{{}}: {}", format!("something failed at {}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL | println!("{{}}: {}", format!("something failed at {}", Location::caller
= help: or consider changing `format!` to `format_args!`
error: `format!` in `println!` args
- --> $DIR/format_args_unfixable.rs:31:5
+ --> $DIR/format_args_unfixable.rs:29:5
|
LL | println!(r#"error: "{}""#, format!("something failed at {}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL | println!(r#"error: "{}""#, format!("something failed at {}", Location::
= help: or consider changing `format!` to `format_args!`
error: `format!` in `println!` args
- --> $DIR/format_args_unfixable.rs:32:5
+ --> $DIR/format_args_unfixable.rs:30:5
|
LL | println!("error: {}", format!(r#"something failed at "{}""#, Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -54,7 +54,7 @@ LL | println!("error: {}", format!(r#"something failed at "{}""#, Location::
= help: or consider changing `format!` to `format_args!`
error: `format!` in `println!` args
- --> $DIR/format_args_unfixable.rs:33:5
+ --> $DIR/format_args_unfixable.rs:31:5
|
LL | println!("error: {}", format!("something failed at {} {0}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ LL | println!("error: {}", format!("something failed at {} {0}", Location::c
= help: or consider changing `format!` to `format_args!`
error: `format!` in `format!` args
- --> $DIR/format_args_unfixable.rs:34:13
+ --> $DIR/format_args_unfixable.rs:32:13
|
LL | let _ = format!("error: {}", format!("something failed at {}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL | let _ = format!("error: {}", format!("something failed at {}", Location
= help: or consider changing `format!` to `format_args!`
error: `format!` in `write!` args
- --> $DIR/format_args_unfixable.rs:35:13
+ --> $DIR/format_args_unfixable.rs:33:13
|
LL | let _ = write!(
| _____________^
@@ -86,7 +86,7 @@ LL | | );
= help: or consider changing `format!` to `format_args!`
error: `format!` in `writeln!` args
- --> $DIR/format_args_unfixable.rs:40:13
+ --> $DIR/format_args_unfixable.rs:38:13
|
LL | let _ = writeln!(
| _____________^
@@ -100,7 +100,7 @@ LL | | );
= help: or consider changing `format!` to `format_args!`
error: `format!` in `print!` args
- --> $DIR/format_args_unfixable.rs:45:5
+ --> $DIR/format_args_unfixable.rs:43:5
|
LL | print!("error: {}", format!("something failed at {}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -109,7 +109,7 @@ LL | print!("error: {}", format!("something failed at {}", Location::caller(
= help: or consider changing `format!` to `format_args!`
error: `format!` in `eprint!` args
- --> $DIR/format_args_unfixable.rs:46:5
+ --> $DIR/format_args_unfixable.rs:44:5
|
LL | eprint!("error: {}", format!("something failed at {}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -118,7 +118,7 @@ LL | eprint!("error: {}", format!("something failed at {}", Location::caller
= help: or consider changing `format!` to `format_args!`
error: `format!` in `eprintln!` args
- --> $DIR/format_args_unfixable.rs:47:5
+ --> $DIR/format_args_unfixable.rs:45:5
|
LL | eprintln!("error: {}", format!("something failed at {}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -127,7 +127,7 @@ LL | eprintln!("error: {}", format!("something failed at {}", Location::call
= help: or consider changing `format!` to `format_args!`
error: `format!` in `format_args!` args
- --> $DIR/format_args_unfixable.rs:48:13
+ --> $DIR/format_args_unfixable.rs:46:13
|
LL | let _ = format_args!("error: {}", format!("something failed at {}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -136,7 +136,7 @@ LL | let _ = format_args!("error: {}", format!("something failed at {}", Loc
= help: or consider changing `format!` to `format_args!`
error: `format!` in `assert!` args
- --> $DIR/format_args_unfixable.rs:49:5
+ --> $DIR/format_args_unfixable.rs:47:5
|
LL | assert!(true, "error: {}", format!("something failed at {}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -145,7 +145,7 @@ LL | assert!(true, "error: {}", format!("something failed at {}", Location::
= help: or consider changing `format!` to `format_args!`
error: `format!` in `assert_eq!` args
- --> $DIR/format_args_unfixable.rs:50:5
+ --> $DIR/format_args_unfixable.rs:48:5
|
LL | assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -154,7 +154,7 @@ LL | assert_eq!(0, 0, "error: {}", format!("something failed at {}", Locatio
= help: or consider changing `format!` to `format_args!`
error: `format!` in `assert_ne!` args
- --> $DIR/format_args_unfixable.rs:51:5
+ --> $DIR/format_args_unfixable.rs:49:5
|
LL | assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -163,7 +163,7 @@ LL | assert_ne!(0, 0, "error: {}", format!("something failed at {}", Locatio
= help: or consider changing `format!` to `format_args!`
error: `format!` in `panic!` args
- --> $DIR/format_args_unfixable.rs:52:5
+ --> $DIR/format_args_unfixable.rs:50:5
|
LL | panic!("error: {}", format!("something failed at {}", Location::caller()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/format_push_string.stderr b/src/tools/clippy/tests/ui/format_push_string.stderr
index 953784bcc..d7be9a5f2 100644
--- a/src/tools/clippy/tests/ui/format_push_string.stderr
+++ b/src/tools/clippy/tests/ui/format_push_string.stderr
@@ -4,8 +4,8 @@ error: `format!(..)` appended to existing `String`
LL | string += &format!("{:?}", 1234);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::format-push-string` implied by `-D warnings`
= help: consider using `write!` to avoid the extra allocation
+ = note: `-D clippy::format-push-string` implied by `-D warnings`
error: `format!(..)` appended to existing `String`
--> $DIR/format_push_string.rs:6:5
diff --git a/src/tools/clippy/tests/ui/formatting.stderr b/src/tools/clippy/tests/ui/formatting.stderr
index 9272cd604..caccd5cba 100644
--- a/src/tools/clippy/tests/ui/formatting.stderr
+++ b/src/tools/clippy/tests/ui/formatting.stderr
@@ -4,8 +4,8 @@ error: this looks like you are trying to use `.. -= ..`, but you really are doin
LL | a =- 35;
| ^^^^
|
- = note: `-D clippy::suspicious-assignment-formatting` implied by `-D warnings`
= note: to remove this lint, use either `-=` or `= -`
+ = note: `-D clippy::suspicious-assignment-formatting` implied by `-D warnings`
error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)`
--> $DIR/formatting.rs:17:6
@@ -29,8 +29,8 @@ error: possibly missing a comma here
LL | -1, -2, -3 // <= no comma here
| ^
|
- = note: `-D clippy::possible-missing-comma` implied by `-D warnings`
= note: to remove this lint, add a comma or write the expr in a single line
+ = note: `-D clippy::possible-missing-comma` implied by `-D warnings`
error: possibly missing a comma here
--> $DIR/formatting.rs:33:19
diff --git a/src/tools/clippy/tests/ui/from_over_into.fixed b/src/tools/clippy/tests/ui/from_over_into.fixed
new file mode 100644
index 000000000..1cf49ca45
--- /dev/null
+++ b/src/tools/clippy/tests/ui/from_over_into.fixed
@@ -0,0 +1,87 @@
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::from_over_into)]
+#![allow(unused)]
+
+// this should throw an error
+struct StringWrapper(String);
+
+impl From<String> for StringWrapper {
+ fn from(val: String) -> Self {
+ StringWrapper(val)
+ }
+}
+
+struct SelfType(String);
+
+impl From<String> for SelfType {
+ fn from(val: String) -> Self {
+ SelfType(String::new())
+ }
+}
+
+#[derive(Default)]
+struct X;
+
+impl X {
+ const FOO: &'static str = "a";
+}
+
+struct SelfKeywords;
+
+impl From<X> for SelfKeywords {
+ fn from(val: X) -> Self {
+ let _ = X::default();
+ let _ = X::FOO;
+ let _: X = val;
+
+ SelfKeywords
+ }
+}
+
+struct ExplicitPaths(bool);
+
+impl core::convert::From<crate::ExplicitPaths> for bool {
+ fn from(mut val: crate::ExplicitPaths) -> Self {
+ let in_closure = || val.0;
+
+ val.0 = false;
+ val.0
+ }
+}
+
+// this is fine
+struct A(String);
+
+impl From<String> for A {
+ fn from(s: String) -> A {
+ A(s)
+ }
+}
+
+fn msrv_1_40() {
+ #![clippy::msrv = "1.40"]
+
+ struct FromOverInto<T>(Vec<T>);
+
+ impl<T> Into<FromOverInto<T>> for Vec<T> {
+ fn into(self) -> FromOverInto<T> {
+ FromOverInto(self)
+ }
+ }
+}
+
+fn msrv_1_41() {
+ #![clippy::msrv = "1.41"]
+
+ struct FromOverInto<T>(Vec<T>);
+
+ impl<T> From<Vec<T>> for FromOverInto<T> {
+ fn from(val: Vec<T>) -> Self {
+ FromOverInto(val)
+ }
+ }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/from_over_into.rs b/src/tools/clippy/tests/ui/from_over_into.rs
index 292d0924f..d30f3c3fc 100644
--- a/src/tools/clippy/tests/ui/from_over_into.rs
+++ b/src/tools/clippy/tests/ui/from_over_into.rs
@@ -1,4 +1,8 @@
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
#![warn(clippy::from_over_into)]
+#![allow(unused)]
// this should throw an error
struct StringWrapper(String);
@@ -9,6 +13,44 @@ impl Into<StringWrapper> for String {
}
}
+struct SelfType(String);
+
+impl Into<SelfType> for String {
+ fn into(self) -> SelfType {
+ SelfType(Self::new())
+ }
+}
+
+#[derive(Default)]
+struct X;
+
+impl X {
+ const FOO: &'static str = "a";
+}
+
+struct SelfKeywords;
+
+impl Into<SelfKeywords> for X {
+ fn into(self) -> SelfKeywords {
+ let _ = Self::default();
+ let _ = Self::FOO;
+ let _: Self = self;
+
+ SelfKeywords
+ }
+}
+
+struct ExplicitPaths(bool);
+
+impl core::convert::Into<bool> for crate::ExplicitPaths {
+ fn into(mut self) -> bool {
+ let in_closure = || self.0;
+
+ self.0 = false;
+ self.0
+ }
+}
+
// this is fine
struct A(String);
@@ -18,4 +60,28 @@ impl From<String> for A {
}
}
+fn msrv_1_40() {
+ #![clippy::msrv = "1.40"]
+
+ struct FromOverInto<T>(Vec<T>);
+
+ impl<T> Into<FromOverInto<T>> for Vec<T> {
+ fn into(self) -> FromOverInto<T> {
+ FromOverInto(self)
+ }
+ }
+}
+
+fn msrv_1_41() {
+ #![clippy::msrv = "1.41"]
+
+ struct FromOverInto<T>(Vec<T>);
+
+ impl<T> Into<FromOverInto<T>> for Vec<T> {
+ fn into(self) -> FromOverInto<T> {
+ FromOverInto(self)
+ }
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/from_over_into.stderr b/src/tools/clippy/tests/ui/from_over_into.stderr
index 2951e6bda..9c2a7c04c 100644
--- a/src/tools/clippy/tests/ui/from_over_into.stderr
+++ b/src/tools/clippy/tests/ui/from_over_into.stderr
@@ -1,11 +1,75 @@
error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
- --> $DIR/from_over_into.rs:6:1
+ --> $DIR/from_over_into.rs:10:1
|
LL | impl Into<StringWrapper> for String {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::from-over-into` implied by `-D warnings`
- = help: consider to implement `From<std::string::String>` instead
+help: replace the `Into` implentation with `From<std::string::String>`
+ |
+LL ~ impl From<String> for StringWrapper {
+LL ~ fn from(val: String) -> Self {
+LL ~ StringWrapper(val)
+ |
+
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+ --> $DIR/from_over_into.rs:18:1
+ |
+LL | impl Into<SelfType> for String {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace the `Into` implentation with `From<std::string::String>`
+ |
+LL ~ impl From<String> for SelfType {
+LL ~ fn from(val: String) -> Self {
+LL ~ SelfType(String::new())
+ |
+
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+ --> $DIR/from_over_into.rs:33:1
+ |
+LL | impl Into<SelfKeywords> for X {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace the `Into` implentation with `From<X>`
+ |
+LL ~ impl From<X> for SelfKeywords {
+LL ~ fn from(val: X) -> Self {
+LL ~ let _ = X::default();
+LL ~ let _ = X::FOO;
+LL ~ let _: X = val;
+ |
+
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+ --> $DIR/from_over_into.rs:45:1
+ |
+LL | impl core::convert::Into<bool> for crate::ExplicitPaths {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see
+ https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence
+help: replace the `Into` implentation with `From<ExplicitPaths>`
+ |
+LL ~ impl core::convert::From<crate::ExplicitPaths> for bool {
+LL ~ fn from(mut val: crate::ExplicitPaths) -> Self {
+LL ~ let in_closure = || val.0;
+LL |
+LL ~ val.0 = false;
+LL ~ val.0
+ |
+
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+ --> $DIR/from_over_into.rs:80:5
+ |
+LL | impl<T> Into<FromOverInto<T>> for Vec<T> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace the `Into` implentation with `From<std::vec::Vec<T>>`
+ |
+LL ~ impl<T> From<Vec<T>> for FromOverInto<T> {
+LL ~ fn from(val: Vec<T>) -> Self {
+LL ~ FromOverInto(val)
+ |
-error: aborting due to previous error
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.rs b/src/tools/clippy/tests/ui/from_over_into_unfixable.rs
new file mode 100644
index 000000000..3b280b748
--- /dev/null
+++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.rs
@@ -0,0 +1,35 @@
+#![warn(clippy::from_over_into)]
+
+struct InMacro(String);
+
+macro_rules! in_macro {
+ ($e:ident) => {
+ $e
+ };
+}
+
+impl Into<InMacro> for String {
+ fn into(self) -> InMacro {
+ InMacro(in_macro!(self))
+ }
+}
+
+struct WeirdUpperSelf;
+
+impl Into<WeirdUpperSelf> for &'static [u8] {
+ fn into(self) -> WeirdUpperSelf {
+ let _ = Self::default();
+ WeirdUpperSelf
+ }
+}
+
+struct ContainsVal;
+
+impl Into<u8> for ContainsVal {
+ fn into(self) -> u8 {
+ let val = 1;
+ val + 1
+ }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr
new file mode 100644
index 000000000..6f6ce3519
--- /dev/null
+++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr
@@ -0,0 +1,29 @@
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+ --> $DIR/from_over_into_unfixable.rs:11:1
+ |
+LL | impl Into<InMacro> for String {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: replace the `Into` implentation with `From<std::string::String>`
+ = note: `-D clippy::from-over-into` implied by `-D warnings`
+
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+ --> $DIR/from_over_into_unfixable.rs:19:1
+ |
+LL | impl Into<WeirdUpperSelf> for &'static [u8] {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: replace the `Into` implentation with `From<&'static [u8]>`
+
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+ --> $DIR/from_over_into_unfixable.rs:28:1
+ |
+LL | impl Into<u8> for ContainsVal {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see
+ https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence
+ = help: replace the `Into` implentation with `From<ContainsVal>`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/functions.rs b/src/tools/clippy/tests/ui/functions.rs
index 5521870ea..18149bfbc 100644
--- a/src/tools/clippy/tests/ui/functions.rs
+++ b/src/tools/clippy/tests/ui/functions.rs
@@ -1,6 +1,6 @@
#![warn(clippy::all)]
-#![allow(dead_code)]
-#![allow(unused_unsafe, clippy::missing_safety_doc)]
+#![allow(dead_code, unused_unsafe)]
+#![allow(clippy::missing_safety_doc, clippy::uninlined_format_args)]
// TOO_MANY_ARGUMENTS
fn good(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool) {}
diff --git a/src/tools/clippy/tests/ui/future_not_send.stderr b/src/tools/clippy/tests/ui/future_not_send.stderr
index a9f2ad36d..5b6858e45 100644
--- a/src/tools/clippy/tests/ui/future_not_send.stderr
+++ b/src/tools/clippy/tests/ui/future_not_send.stderr
@@ -4,7 +4,6 @@ error: future cannot be sent between threads safely
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:8:19
|
@@ -25,6 +24,7 @@ LL | async { true }.await
LL | }
| - `cell` is later dropped here
= note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
+ = note: `-D clippy::future-not-send` implied by `-D warnings`
error: future cannot be sent between threads safely
--> $DIR/future_not_send.rs:11:42
diff --git a/src/tools/clippy/tests/ui/get_unwrap.stderr b/src/tools/clippy/tests/ui/get_unwrap.stderr
index ea8fec527..937f85904 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/get_unwrap.stderr
@@ -16,8 +16,8 @@ error: used `unwrap()` on `an Option` value
LL | let _ = boxed_slice.get(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::unwrap-used` implied by `-D warnings`
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: `-D clippy::unwrap-used` implied by `-D warnings`
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
--> $DIR/get_unwrap.rs:36:17
diff --git a/src/tools/clippy/tests/ui/identity_op.fixed b/src/tools/clippy/tests/ui/identity_op.fixed
index 5f9cebe21..e7b9a78c5 100644
--- a/src/tools/clippy/tests/ui/identity_op.fixed
+++ b/src/tools/clippy/tests/ui/identity_op.fixed
@@ -1,13 +1,13 @@
// run-rustfix
-
#![warn(clippy::identity_op)]
+#![allow(unused)]
#![allow(
clippy::eq_op,
clippy::no_effect,
clippy::unnecessary_operation,
clippy::op_ref,
clippy::double_parens,
- unused
+ clippy::uninlined_format_args
)]
use std::fmt::Write as _;
@@ -68,7 +68,7 @@ fn main() {
&x;
x;
- let mut a = A("".into());
+ let mut a = A(String::new());
let b = a << 0; // no error: non-integer
1 * Meter; // no error: non-integer
diff --git a/src/tools/clippy/tests/ui/identity_op.rs b/src/tools/clippy/tests/ui/identity_op.rs
index ca799c9cf..9a435cdbb 100644
--- a/src/tools/clippy/tests/ui/identity_op.rs
+++ b/src/tools/clippy/tests/ui/identity_op.rs
@@ -1,13 +1,13 @@
// run-rustfix
-
#![warn(clippy::identity_op)]
+#![allow(unused)]
#![allow(
clippy::eq_op,
clippy::no_effect,
clippy::unnecessary_operation,
clippy::op_ref,
clippy::double_parens,
- unused
+ clippy::uninlined_format_args
)]
use std::fmt::Write as _;
@@ -68,7 +68,7 @@ fn main() {
&x >> 0;
x >> &0;
- let mut a = A("".into());
+ let mut a = A(String::new());
let b = a << 0; // no error: non-integer
1 * Meter; // no error: non-integer
diff --git a/src/tools/clippy/tests/ui/if_let_mutex.rs b/src/tools/clippy/tests/ui/if_let_mutex.rs
index 6cbfafbb3..321feb022 100644
--- a/src/tools/clippy/tests/ui/if_let_mutex.rs
+++ b/src/tools/clippy/tests/ui/if_let_mutex.rs
@@ -39,4 +39,12 @@ fn if_let_different_mutex() {
};
}
+fn mutex_ref(mutex: &Mutex<i32>) {
+ if let Ok(i) = mutex.lock() {
+ do_stuff(i);
+ } else {
+ let _x = mutex.lock();
+ };
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/if_let_mutex.stderr b/src/tools/clippy/tests/ui/if_let_mutex.stderr
index e9c4d9163..da0cc25f0 100644
--- a/src/tools/clippy/tests/ui/if_let_mutex.stderr
+++ b/src/tools/clippy/tests/ui/if_let_mutex.stderr
@@ -1,29 +1,53 @@
error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
--> $DIR/if_let_mutex.rs:10:5
|
-LL | / if let Err(locked) = m.lock() {
+LL | if let Err(locked) = m.lock() {
+ | ^ - this Mutex will remain locked for the entire `if let`-block...
+ | _____|
+ | |
LL | | do_stuff(locked);
LL | | } else {
LL | | let lock = m.lock().unwrap();
+ | | - ... and is tried to lock again here, which will always deadlock.
LL | | do_stuff(lock);
LL | | };
| |_____^
|
- = note: `-D clippy::if-let-mutex` implied by `-D warnings`
= help: move the lock call outside of the `if let ...` expression
+ = note: `-D clippy::if-let-mutex` implied by `-D warnings`
error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
--> $DIR/if_let_mutex.rs:22:5
|
-LL | / if let Some(locked) = m.lock().unwrap().deref() {
+LL | if let Some(locked) = m.lock().unwrap().deref() {
+ | ^ - this Mutex will remain locked for the entire `if let`-block...
+ | _____|
+ | |
LL | | do_stuff(locked);
LL | | } else {
LL | | let lock = m.lock().unwrap();
+ | | - ... and is tried to lock again here, which will always deadlock.
LL | | do_stuff(lock);
LL | | };
| |_____^
|
= help: move the lock call outside of the `if let ...` expression
-error: aborting due to 2 previous errors
+error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
+ --> $DIR/if_let_mutex.rs:43:5
+ |
+LL | if let Ok(i) = mutex.lock() {
+ | ^ ----- this Mutex will remain locked for the entire `if let`-block...
+ | _____|
+ | |
+LL | | do_stuff(i);
+LL | | } else {
+LL | | let _x = mutex.lock();
+ | | ----- ... and is tried to lock again here, which will always deadlock.
+LL | | };
+ | |_____^
+ |
+ = help: move the lock call outside of the `if let ...` expression
+
+error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/if_not_else.stderr b/src/tools/clippy/tests/ui/if_not_else.stderr
index 8c8cc44bb..46671c152 100644
--- a/src/tools/clippy/tests/ui/if_not_else.stderr
+++ b/src/tools/clippy/tests/ui/if_not_else.stderr
@@ -8,8 +8,8 @@ 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`
+ = note: `-D clippy::if-not-else` implied by `-D warnings`
error: unnecessary `!=` operation
--> $DIR/if_not_else.rs:17:5
diff --git a/src/tools/clippy/tests/ui/if_same_then_else.rs b/src/tools/clippy/tests/ui/if_same_then_else.rs
index 2598c2ab4..07d2002eb 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else.rs
+++ b/src/tools/clippy/tests/ui/if_same_then_else.rs
@@ -1,6 +1,6 @@
#![warn(clippy::if_same_then_else)]
#![allow(
- clippy::blacklisted_name,
+ clippy::disallowed_names,
clippy::eq_op,
clippy::never_loop,
clippy::no_effect,
diff --git a/src/tools/clippy/tests/ui/if_same_then_else.stderr b/src/tools/clippy/tests/ui/if_same_then_else.stderr
index 2cdf44248..fb23b81d3 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else.stderr
+++ b/src/tools/clippy/tests/ui/if_same_then_else.stderr
@@ -11,7 +11,6 @@ LL | | foo();
LL | | } else {
| |_____^
|
- = note: `-D clippy::if-same-then-else` implied by `-D warnings`
note: same as this
--> $DIR/if_same_then_else.rs:31:12
|
@@ -24,6 +23,7 @@ LL | | 0..10;
LL | | foo();
LL | | }
| |_____^
+ = note: `-D clippy::if-same-then-else` implied by `-D warnings`
error: this `if` has identical blocks
--> $DIR/if_same_then_else.rs:67:21
diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.rs b/src/tools/clippy/tests/ui/if_same_then_else2.rs
index 0016009a0..58167f444 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else2.rs
+++ b/src/tools/clippy/tests/ui/if_same_then_else2.rs
@@ -1,6 +1,6 @@
#![warn(clippy::if_same_then_else)]
#![allow(
- clippy::blacklisted_name,
+ clippy::disallowed_names,
clippy::collapsible_else_if,
clippy::equatable_if_let,
clippy::collapsible_if,
diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.stderr b/src/tools/clippy/tests/ui/if_same_then_else2.stderr
index cac788f85..704cfd966 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else2.stderr
+++ b/src/tools/clippy/tests/ui/if_same_then_else2.stderr
@@ -11,7 +11,6 @@ LL | | }
LL | | } else {
| |_____^
|
- = note: `-D clippy::if-same-then-else` implied by `-D warnings`
note: same as this
--> $DIR/if_same_then_else2.rs:23:12
|
@@ -24,6 +23,7 @@ LL | | let bar: &Option<_> = &Some::<u8>(42);
LL | | }
LL | | }
| |_____^
+ = note: `-D clippy::if-same-then-else` implied by `-D warnings`
error: this `if` has identical blocks
--> $DIR/if_same_then_else2.rs:35:13
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
index 8cb22d569..24e0b5947 100644
--- a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
@@ -10,8 +10,8 @@ LL | | None
LL | | };
| |_____^
|
- = note: `-D clippy::if-then-some-else-none` implied by `-D warnings`
= help: consider using `bool::then` like: `foo().then(|| { /* snippet */ "foo" })`
+ = note: `-D clippy::if-then-some-else-none` implied by `-D warnings`
error: this could be simplified with `bool::then`
--> $DIR/if_then_some_else_none.rs:14:13
@@ -27,21 +27,21 @@ LL | | };
|
= help: consider using `bool::then` like: `matches!(true, true).then(|| { /* snippet */ matches!(true, false) })`
-error: this could be simplified with `bool::then`
+error: this could be simplified with `bool::then_some`
--> $DIR/if_then_some_else_none.rs:23:28
|
LL | let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: consider using `bool::then` like: `(o < 32).then(|| o)`
+ = help: consider using `bool::then_some` like: `(o < 32).then_some(o)`
-error: this could be simplified with `bool::then`
+error: this could be simplified with `bool::then_some`
--> $DIR/if_then_some_else_none.rs:27:13
|
LL | let _ = if !x { Some(0) } else { None };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: consider using `bool::then` like: `(!x).then(|| 0)`
+ = help: consider using `bool::then_some` like: `(!x).then_some(0)`
error: this could be simplified with `bool::then`
--> $DIR/if_then_some_else_none.rs:82:13
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.rs b/src/tools/clippy/tests/ui/ifs_same_cond.rs
index 80e9839ff..9850fc091 100644
--- a/src/tools/clippy/tests/ui/ifs_same_cond.rs
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.rs
@@ -32,9 +32,9 @@ fn ifs_same_cond() {
};
let mut v = vec![1];
- if v.pop() == None {
+ if v.pop().is_none() {
// ok, functions
- } else if v.pop() == None {
+ } else if v.pop().is_none() {
}
if v.len() == 42 {
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.stderr b/src/tools/clippy/tests/ui/ifs_same_cond.stderr
index 0c8f49b86..411308732 100644
--- a/src/tools/clippy/tests/ui/ifs_same_cond.stderr
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.stderr
@@ -4,12 +4,12 @@ error: this `if` has the same condition as a previous `if`
LL | } else if b {
| ^
|
- = note: `-D clippy::ifs-same-cond` implied by `-D warnings`
note: same as this
--> $DIR/ifs_same_cond.rs:8:8
|
LL | if b {
| ^
+ = note: `-D clippy::ifs-same-cond` implied by `-D warnings`
error: this `if` has the same condition as a previous `if`
--> $DIR/ifs_same_cond.rs:14:15
diff --git a/src/tools/clippy/tests/ui/impl.stderr b/src/tools/clippy/tests/ui/impl.stderr
index 8703ecac9..e28b1bf0c 100644
--- a/src/tools/clippy/tests/ui/impl.stderr
+++ b/src/tools/clippy/tests/ui/impl.stderr
@@ -6,7 +6,6 @@ LL | | fn second() {}
LL | | }
| |_^
|
- = note: `-D clippy::multiple-inherent-impl` implied by `-D warnings`
note: first implementation here
--> $DIR/impl.rs:6:1
|
@@ -14,6 +13,7 @@ LL | / impl MyStruct {
LL | | fn first() {}
LL | | }
| |_^
+ = note: `-D clippy::multiple-inherent-impl` implied by `-D warnings`
error: multiple implementations of this structure
--> $DIR/impl.rs:24:5
diff --git a/src/tools/clippy/tests/ui/implicit_saturating_add.fixed b/src/tools/clippy/tests/ui/implicit_saturating_add.fixed
new file mode 100644
index 000000000..7d363d59a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/implicit_saturating_add.fixed
@@ -0,0 +1,106 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::implicit_saturating_add)]
+
+fn main() {
+ let mut u_8: u8 = 255;
+ let mut u_16: u16 = 500;
+ let mut u_32: u32 = 7000;
+ let mut u_64: u64 = 7000;
+ let mut i_8: i8 = 30;
+ let mut i_16: i16 = 500;
+ let mut i_32: i32 = 7000;
+ let mut i_64: i64 = 7000;
+
+ if i_8 < 42 {
+ i_8 += 1;
+ }
+ if i_8 != 42 {
+ i_8 += 1;
+ }
+
+ u_8 = u_8.saturating_add(1);
+
+ u_8 = u_8.saturating_add(1);
+
+ if u_8 < 15 {
+ u_8 += 1;
+ }
+
+ u_16 = u_16.saturating_add(1);
+
+ u_16 = u_16.saturating_add(1);
+
+ u_16 = u_16.saturating_add(1);
+
+ u_32 = u_32.saturating_add(1);
+
+ u_32 = u_32.saturating_add(1);
+
+ u_32 = u_32.saturating_add(1);
+
+ u_64 = u_64.saturating_add(1);
+
+ u_64 = u_64.saturating_add(1);
+
+ u_64 = u_64.saturating_add(1);
+
+ i_8 = i_8.saturating_add(1);
+
+ i_8 = i_8.saturating_add(1);
+
+ i_8 = i_8.saturating_add(1);
+
+ i_16 = i_16.saturating_add(1);
+
+ i_16 = i_16.saturating_add(1);
+
+ i_16 = i_16.saturating_add(1);
+
+ i_32 = i_32.saturating_add(1);
+
+ i_32 = i_32.saturating_add(1);
+
+ i_32 = i_32.saturating_add(1);
+
+ i_64 = i_64.saturating_add(1);
+
+ i_64 = i_64.saturating_add(1);
+
+ i_64 = i_64.saturating_add(1);
+
+ if i_64 < 42 {
+ i_64 += 1;
+ }
+
+ if 42 > i_64 {
+ i_64 += 1;
+ }
+
+ let a = 12;
+ let mut b = 8;
+
+ if a < u8::MAX {
+ b += 1;
+ }
+
+ if u8::MAX > a {
+ b += 1;
+ }
+
+ if u_32 < u32::MAX {
+ u_32 += 1;
+ } else {
+ println!("don't lint this");
+ }
+
+ if u_32 < u32::MAX {
+ println!("don't lint this");
+ u_32 += 1;
+ }
+
+ if u_32 < 42 {
+ println!("brace yourself!");
+ } else {u_32 = u_32.saturating_add(1); }
+}
diff --git a/src/tools/clippy/tests/ui/implicit_saturating_add.rs b/src/tools/clippy/tests/ui/implicit_saturating_add.rs
new file mode 100644
index 000000000..31a591627
--- /dev/null
+++ b/src/tools/clippy/tests/ui/implicit_saturating_add.rs
@@ -0,0 +1,154 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::implicit_saturating_add)]
+
+fn main() {
+ let mut u_8: u8 = 255;
+ let mut u_16: u16 = 500;
+ let mut u_32: u32 = 7000;
+ let mut u_64: u64 = 7000;
+ let mut i_8: i8 = 30;
+ let mut i_16: i16 = 500;
+ let mut i_32: i32 = 7000;
+ let mut i_64: i64 = 7000;
+
+ if i_8 < 42 {
+ i_8 += 1;
+ }
+ if i_8 != 42 {
+ i_8 += 1;
+ }
+
+ if u_8 != u8::MAX {
+ u_8 += 1;
+ }
+
+ if u_8 < u8::MAX {
+ u_8 += 1;
+ }
+
+ if u_8 < 15 {
+ u_8 += 1;
+ }
+
+ if u_16 != u16::MAX {
+ u_16 += 1;
+ }
+
+ if u_16 < u16::MAX {
+ u_16 += 1;
+ }
+
+ if u16::MAX > u_16 {
+ u_16 += 1;
+ }
+
+ if u_32 != u32::MAX {
+ u_32 += 1;
+ }
+
+ if u_32 < u32::MAX {
+ u_32 += 1;
+ }
+
+ if u32::MAX > u_32 {
+ u_32 += 1;
+ }
+
+ if u_64 != u64::MAX {
+ u_64 += 1;
+ }
+
+ if u_64 < u64::MAX {
+ u_64 += 1;
+ }
+
+ if u64::MAX > u_64 {
+ u_64 += 1;
+ }
+
+ if i_8 != i8::MAX {
+ i_8 += 1;
+ }
+
+ if i_8 < i8::MAX {
+ i_8 += 1;
+ }
+
+ if i8::MAX > i_8 {
+ i_8 += 1;
+ }
+
+ if i_16 != i16::MAX {
+ i_16 += 1;
+ }
+
+ if i_16 < i16::MAX {
+ i_16 += 1;
+ }
+
+ if i16::MAX > i_16 {
+ i_16 += 1;
+ }
+
+ if i_32 != i32::MAX {
+ i_32 += 1;
+ }
+
+ if i_32 < i32::MAX {
+ i_32 += 1;
+ }
+
+ if i32::MAX > i_32 {
+ i_32 += 1;
+ }
+
+ if i_64 != i64::MAX {
+ i_64 += 1;
+ }
+
+ if i_64 < i64::MAX {
+ i_64 += 1;
+ }
+
+ if i64::MAX > i_64 {
+ i_64 += 1;
+ }
+
+ if i_64 < 42 {
+ i_64 += 1;
+ }
+
+ if 42 > i_64 {
+ i_64 += 1;
+ }
+
+ let a = 12;
+ let mut b = 8;
+
+ if a < u8::MAX {
+ b += 1;
+ }
+
+ if u8::MAX > a {
+ b += 1;
+ }
+
+ if u_32 < u32::MAX {
+ u_32 += 1;
+ } else {
+ println!("don't lint this");
+ }
+
+ if u_32 < u32::MAX {
+ println!("don't lint this");
+ u_32 += 1;
+ }
+
+ if u_32 < 42 {
+ println!("brace yourself!");
+ } else if u_32 < u32::MAX {
+ u_32 += 1;
+ }
+}
diff --git a/src/tools/clippy/tests/ui/implicit_saturating_add.stderr b/src/tools/clippy/tests/ui/implicit_saturating_add.stderr
new file mode 100644
index 000000000..42ae1b488
--- /dev/null
+++ b/src/tools/clippy/tests/ui/implicit_saturating_add.stderr
@@ -0,0 +1,197 @@
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:23:5
+ |
+LL | / if u_8 != u8::MAX {
+LL | | u_8 += 1;
+LL | | }
+ | |_____^ help: use instead: `u_8 = u_8.saturating_add(1);`
+ |
+ = note: `-D clippy::implicit-saturating-add` implied by `-D warnings`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:27:5
+ |
+LL | / if u_8 < u8::MAX {
+LL | | u_8 += 1;
+LL | | }
+ | |_____^ help: use instead: `u_8 = u_8.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:35:5
+ |
+LL | / if u_16 != u16::MAX {
+LL | | u_16 += 1;
+LL | | }
+ | |_____^ help: use instead: `u_16 = u_16.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:39:5
+ |
+LL | / if u_16 < u16::MAX {
+LL | | u_16 += 1;
+LL | | }
+ | |_____^ help: use instead: `u_16 = u_16.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:43:5
+ |
+LL | / if u16::MAX > u_16 {
+LL | | u_16 += 1;
+LL | | }
+ | |_____^ help: use instead: `u_16 = u_16.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:47:5
+ |
+LL | / if u_32 != u32::MAX {
+LL | | u_32 += 1;
+LL | | }
+ | |_____^ help: use instead: `u_32 = u_32.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:51:5
+ |
+LL | / if u_32 < u32::MAX {
+LL | | u_32 += 1;
+LL | | }
+ | |_____^ help: use instead: `u_32 = u_32.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:55:5
+ |
+LL | / if u32::MAX > u_32 {
+LL | | u_32 += 1;
+LL | | }
+ | |_____^ help: use instead: `u_32 = u_32.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:59:5
+ |
+LL | / if u_64 != u64::MAX {
+LL | | u_64 += 1;
+LL | | }
+ | |_____^ help: use instead: `u_64 = u_64.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:63:5
+ |
+LL | / if u_64 < u64::MAX {
+LL | | u_64 += 1;
+LL | | }
+ | |_____^ help: use instead: `u_64 = u_64.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:67:5
+ |
+LL | / if u64::MAX > u_64 {
+LL | | u_64 += 1;
+LL | | }
+ | |_____^ help: use instead: `u_64 = u_64.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:71:5
+ |
+LL | / if i_8 != i8::MAX {
+LL | | i_8 += 1;
+LL | | }
+ | |_____^ help: use instead: `i_8 = i_8.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:75:5
+ |
+LL | / if i_8 < i8::MAX {
+LL | | i_8 += 1;
+LL | | }
+ | |_____^ help: use instead: `i_8 = i_8.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:79:5
+ |
+LL | / if i8::MAX > i_8 {
+LL | | i_8 += 1;
+LL | | }
+ | |_____^ help: use instead: `i_8 = i_8.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:83:5
+ |
+LL | / if i_16 != i16::MAX {
+LL | | i_16 += 1;
+LL | | }
+ | |_____^ help: use instead: `i_16 = i_16.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:87:5
+ |
+LL | / if i_16 < i16::MAX {
+LL | | i_16 += 1;
+LL | | }
+ | |_____^ help: use instead: `i_16 = i_16.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:91:5
+ |
+LL | / if i16::MAX > i_16 {
+LL | | i_16 += 1;
+LL | | }
+ | |_____^ help: use instead: `i_16 = i_16.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:95:5
+ |
+LL | / if i_32 != i32::MAX {
+LL | | i_32 += 1;
+LL | | }
+ | |_____^ help: use instead: `i_32 = i_32.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:99:5
+ |
+LL | / if i_32 < i32::MAX {
+LL | | i_32 += 1;
+LL | | }
+ | |_____^ help: use instead: `i_32 = i_32.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:103:5
+ |
+LL | / if i32::MAX > i_32 {
+LL | | i_32 += 1;
+LL | | }
+ | |_____^ help: use instead: `i_32 = i_32.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:107:5
+ |
+LL | / if i_64 != i64::MAX {
+LL | | i_64 += 1;
+LL | | }
+ | |_____^ help: use instead: `i_64 = i_64.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:111:5
+ |
+LL | / if i_64 < i64::MAX {
+LL | | i_64 += 1;
+LL | | }
+ | |_____^ help: use instead: `i_64 = i_64.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:115:5
+ |
+LL | / if i64::MAX > i_64 {
+LL | | i_64 += 1;
+LL | | }
+ | |_____^ help: use instead: `i_64 = i_64.saturating_add(1);`
+
+error: manual saturating add detected
+ --> $DIR/implicit_saturating_add.rs:151:12
+ |
+LL | } else if u_32 < u32::MAX {
+ | ____________^
+LL | | u_32 += 1;
+LL | | }
+ | |_____^ help: use instead: `{u_32 = u_32.saturating_add(1); }`
+
+error: aborting due to 24 previous errors
+
diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed b/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed
index e6f57e926..93df81b1a 100644
--- a/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed
+++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed
@@ -2,6 +2,21 @@
#![allow(unused_assignments, unused_mut, clippy::assign_op_pattern)]
#![warn(clippy::implicit_saturating_sub)]
+use std::cmp::PartialEq;
+use std::ops::SubAssign;
+// Mock type
+struct Mock;
+
+impl PartialEq<u32> for Mock {
+ fn eq(&self, _: &u32) -> bool {
+ true
+ }
+}
+
+impl SubAssign<u32> for Mock {
+ fn sub_assign(&mut self, _: u32) {}
+}
+
fn main() {
// Tests for unsigned integers
@@ -165,4 +180,39 @@ fn main() {
} else {
println!("side effect");
}
+
+ // Extended tests
+ let mut m = Mock;
+ let mut u_32 = 3000;
+ let a = 200;
+ let mut _b = 8;
+
+ if m != 0 {
+ m -= 1;
+ }
+
+ if a > 0 {
+ _b -= 1;
+ }
+
+ if 0 > a {
+ _b -= 1;
+ }
+
+ if u_32 > 0 {
+ u_32 -= 1;
+ } else {
+ println!("don't lint this");
+ }
+
+ if u_32 > 0 {
+ println!("don't lint this");
+ u_32 -= 1;
+ }
+
+ if u_32 > 42 {
+ println!("brace yourself!");
+ } else if u_32 > 0 {
+ u_32 -= 1;
+ }
}
diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.rs b/src/tools/clippy/tests/ui/implicit_saturating_sub.rs
index 8bb28d149..8340bc826 100644
--- a/src/tools/clippy/tests/ui/implicit_saturating_sub.rs
+++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.rs
@@ -2,6 +2,21 @@
#![allow(unused_assignments, unused_mut, clippy::assign_op_pattern)]
#![warn(clippy::implicit_saturating_sub)]
+use std::cmp::PartialEq;
+use std::ops::SubAssign;
+// Mock type
+struct Mock;
+
+impl PartialEq<u32> for Mock {
+ fn eq(&self, _: &u32) -> bool {
+ true
+ }
+}
+
+impl SubAssign<u32> for Mock {
+ fn sub_assign(&mut self, _: u32) {}
+}
+
fn main() {
// Tests for unsigned integers
@@ -211,4 +226,39 @@ fn main() {
} else {
println!("side effect");
}
+
+ // Extended tests
+ let mut m = Mock;
+ let mut u_32 = 3000;
+ let a = 200;
+ let mut _b = 8;
+
+ if m != 0 {
+ m -= 1;
+ }
+
+ if a > 0 {
+ _b -= 1;
+ }
+
+ if 0 > a {
+ _b -= 1;
+ }
+
+ if u_32 > 0 {
+ u_32 -= 1;
+ } else {
+ println!("don't lint this");
+ }
+
+ if u_32 > 0 {
+ println!("don't lint this");
+ u_32 -= 1;
+ }
+
+ if u_32 > 42 {
+ println!("brace yourself!");
+ } else if u_32 > 0 {
+ u_32 -= 1;
+ }
}
diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr b/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr
index 5bb9a6064..5e589d931 100644
--- a/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr
+++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr
@@ -1,5 +1,5 @@
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:13:5
+ --> $DIR/implicit_saturating_sub.rs:28:5
|
LL | / if u_8 > 0 {
LL | | u_8 = u_8 - 1;
@@ -9,7 +9,7 @@ LL | | }
= note: `-D clippy::implicit-saturating-sub` implied by `-D warnings`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:20:13
+ --> $DIR/implicit_saturating_sub.rs:35:13
|
LL | / if u_8 > 0 {
LL | | u_8 -= 1;
@@ -17,7 +17,7 @@ LL | | }
| |_____________^ help: try: `u_8 = u_8.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:34:5
+ --> $DIR/implicit_saturating_sub.rs:49:5
|
LL | / if u_16 > 0 {
LL | | u_16 -= 1;
@@ -25,7 +25,7 @@ LL | | }
| |_____^ help: try: `u_16 = u_16.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:44:5
+ --> $DIR/implicit_saturating_sub.rs:59:5
|
LL | / if u_32 != 0 {
LL | | u_32 -= 1;
@@ -33,7 +33,7 @@ LL | | }
| |_____^ help: try: `u_32 = u_32.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:65:5
+ --> $DIR/implicit_saturating_sub.rs:80:5
|
LL | / if u_64 > 0 {
LL | | u_64 -= 1;
@@ -41,7 +41,7 @@ LL | | }
| |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:70:5
+ --> $DIR/implicit_saturating_sub.rs:85:5
|
LL | / if 0 < u_64 {
LL | | u_64 -= 1;
@@ -49,7 +49,7 @@ LL | | }
| |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:75:5
+ --> $DIR/implicit_saturating_sub.rs:90:5
|
LL | / if 0 != u_64 {
LL | | u_64 -= 1;
@@ -57,7 +57,7 @@ LL | | }
| |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:96:5
+ --> $DIR/implicit_saturating_sub.rs:111:5
|
LL | / if u_usize > 0 {
LL | | u_usize -= 1;
@@ -65,7 +65,7 @@ LL | | }
| |_____^ help: try: `u_usize = u_usize.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:108:5
+ --> $DIR/implicit_saturating_sub.rs:123:5
|
LL | / if i_8 > i8::MIN {
LL | | i_8 -= 1;
@@ -73,7 +73,7 @@ LL | | }
| |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:113:5
+ --> $DIR/implicit_saturating_sub.rs:128:5
|
LL | / if i_8 > i8::MIN {
LL | | i_8 -= 1;
@@ -81,7 +81,7 @@ LL | | }
| |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:118:5
+ --> $DIR/implicit_saturating_sub.rs:133:5
|
LL | / if i_8 != i8::MIN {
LL | | i_8 -= 1;
@@ -89,7 +89,7 @@ LL | | }
| |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:123:5
+ --> $DIR/implicit_saturating_sub.rs:138:5
|
LL | / if i_8 != i8::MIN {
LL | | i_8 -= 1;
@@ -97,7 +97,7 @@ LL | | }
| |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:133:5
+ --> $DIR/implicit_saturating_sub.rs:148:5
|
LL | / if i_16 > i16::MIN {
LL | | i_16 -= 1;
@@ -105,7 +105,7 @@ LL | | }
| |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:138:5
+ --> $DIR/implicit_saturating_sub.rs:153:5
|
LL | / if i_16 > i16::MIN {
LL | | i_16 -= 1;
@@ -113,7 +113,7 @@ LL | | }
| |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:143:5
+ --> $DIR/implicit_saturating_sub.rs:158:5
|
LL | / if i_16 != i16::MIN {
LL | | i_16 -= 1;
@@ -121,7 +121,7 @@ LL | | }
| |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:148:5
+ --> $DIR/implicit_saturating_sub.rs:163:5
|
LL | / if i_16 != i16::MIN {
LL | | i_16 -= 1;
@@ -129,7 +129,7 @@ LL | | }
| |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:158:5
+ --> $DIR/implicit_saturating_sub.rs:173:5
|
LL | / if i_32 > i32::MIN {
LL | | i_32 -= 1;
@@ -137,7 +137,7 @@ LL | | }
| |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:163:5
+ --> $DIR/implicit_saturating_sub.rs:178:5
|
LL | / if i_32 > i32::MIN {
LL | | i_32 -= 1;
@@ -145,7 +145,7 @@ LL | | }
| |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:168:5
+ --> $DIR/implicit_saturating_sub.rs:183:5
|
LL | / if i_32 != i32::MIN {
LL | | i_32 -= 1;
@@ -153,7 +153,7 @@ LL | | }
| |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:173:5
+ --> $DIR/implicit_saturating_sub.rs:188:5
|
LL | / if i_32 != i32::MIN {
LL | | i_32 -= 1;
@@ -161,7 +161,7 @@ LL | | }
| |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:183:5
+ --> $DIR/implicit_saturating_sub.rs:198:5
|
LL | / if i64::MIN < i_64 {
LL | | i_64 -= 1;
@@ -169,7 +169,7 @@ LL | | }
| |_____^ help: try: `i_64 = i_64.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:188:5
+ --> $DIR/implicit_saturating_sub.rs:203:5
|
LL | / if i64::MIN != i_64 {
LL | | i_64 -= 1;
@@ -177,7 +177,7 @@ LL | | }
| |_____^ help: try: `i_64 = i_64.saturating_sub(1);`
error: implicitly performing saturating subtraction
- --> $DIR/implicit_saturating_sub.rs:193:5
+ --> $DIR/implicit_saturating_sub.rs:208:5
|
LL | / if i64::MIN < i_64 {
LL | | i_64 -= 1;
diff --git a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs
index c2c0c520d..0a3374d11 100644
--- a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs
+++ b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs
@@ -1,4 +1,5 @@
#![deny(clippy::index_refutable_slice)]
+#![allow(clippy::uninlined_format_args)]
enum SomeEnum<T> {
One(T),
diff --git a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.stderr b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.stderr
index a607df9b8..0a13ac135 100644
--- a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.stderr
+++ b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.stderr
@@ -1,5 +1,5 @@
error: this binding can be a slice pattern to avoid indexing
- --> $DIR/if_let_slice_binding.rs:13:17
+ --> $DIR/if_let_slice_binding.rs:14:17
|
LL | if let Some(slice) = slice {
| ^^^^^
@@ -19,7 +19,7 @@ LL | println!("{}", slice_0);
| ~~~~~~~
error: this binding can be a slice pattern to avoid indexing
- --> $DIR/if_let_slice_binding.rs:19:17
+ --> $DIR/if_let_slice_binding.rs:20:17
|
LL | if let Some(slice) = slice {
| ^^^^^
@@ -34,7 +34,7 @@ LL | println!("{}", slice_0);
| ~~~~~~~
error: this binding can be a slice pattern to avoid indexing
- --> $DIR/if_let_slice_binding.rs:25:17
+ --> $DIR/if_let_slice_binding.rs:26:17
|
LL | if let Some(slice) = slice {
| ^^^^^
@@ -50,7 +50,7 @@ LL ~ println!("{}", slice_0);
|
error: this binding can be a slice pattern to avoid indexing
- --> $DIR/if_let_slice_binding.rs:32:26
+ --> $DIR/if_let_slice_binding.rs:33:26
|
LL | if let SomeEnum::One(slice) | SomeEnum::Three(slice) = slice_wrapped {
| ^^^^^
@@ -65,7 +65,7 @@ LL | println!("{}", slice_0);
| ~~~~~~~
error: this binding can be a slice pattern to avoid indexing
- --> $DIR/if_let_slice_binding.rs:39:29
+ --> $DIR/if_let_slice_binding.rs:40:29
|
LL | if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) {
| ^
@@ -80,7 +80,7 @@ LL | println!("{} -> {}", a_2, b[1]);
| ~~~
error: this binding can be a slice pattern to avoid indexing
- --> $DIR/if_let_slice_binding.rs:39:38
+ --> $DIR/if_let_slice_binding.rs:40:38
|
LL | if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) {
| ^
@@ -95,7 +95,7 @@ LL | println!("{} -> {}", a[2], b_1);
| ~~~
error: this binding can be a slice pattern to avoid indexing
- --> $DIR/if_let_slice_binding.rs:46:21
+ --> $DIR/if_let_slice_binding.rs:47:21
|
LL | if let Some(ref slice) = slice {
| ^^^^^
@@ -110,7 +110,7 @@ LL | println!("{:?}", slice_1);
| ~~~~~~~
error: this binding can be a slice pattern to avoid indexing
- --> $DIR/if_let_slice_binding.rs:54:17
+ --> $DIR/if_let_slice_binding.rs:55:17
|
LL | if let Some(slice) = &slice {
| ^^^^^
@@ -125,7 +125,7 @@ LL | println!("{:?}", slice_0);
| ~~~~~~~
error: this binding can be a slice pattern to avoid indexing
- --> $DIR/if_let_slice_binding.rs:123:17
+ --> $DIR/if_let_slice_binding.rs:124:17
|
LL | if let Some(slice) = wrap.inner {
| ^^^^^
@@ -140,7 +140,7 @@ LL | println!("This is awesome! {}", slice_0);
| ~~~~~~~
error: this binding can be a slice pattern to avoid indexing
- --> $DIR/if_let_slice_binding.rs:130:17
+ --> $DIR/if_let_slice_binding.rs:131:17
|
LL | if let Some(slice) = wrap.inner {
| ^^^^^
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.rs b/src/tools/clippy/tests/ui/indexing_slicing_index.rs
index 45a430edc..4476e0eb9 100644
--- a/src/tools/clippy/tests/ui/indexing_slicing_index.rs
+++ b/src/tools/clippy/tests/ui/indexing_slicing_index.rs
@@ -3,7 +3,7 @@
// We also check the out_of_bounds_indexing lint here, because it lints similar things and
// we want to avoid false positives.
#![warn(clippy::out_of_bounds_indexing)]
-#![allow(const_err, clippy::no_effect, clippy::unnecessary_operation)]
+#![allow(unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)]
const ARR: [i32; 2] = [1, 2];
const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr.
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
index 6ae700753..da5bc38b3 100644
--- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
+++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
@@ -16,8 +16,8 @@ error: indexing may panic
LL | x[index];
| ^^^^^^^^
|
- = note: `-D clippy::indexing-slicing` implied by `-D warnings`
= help: consider using `.get(n)` or `.get_mut(n)` instead
+ = note: `-D clippy::indexing-slicing` implied by `-D warnings`
error: indexing may panic
--> $DIR/indexing_slicing_index.rs:38:5
@@ -59,6 +59,12 @@ LL | v[M];
|
= help: consider using `.get(n)` or `.get_mut(n)` instead
-error: aborting due to 8 previous errors
+error[E0080]: evaluation of constant value failed
+ --> $DIR/indexing_slicing_index.rs:10:24
+ |
+LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
+ | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
+
+error: aborting due to 9 previous errors
For more information about this error, try `rustc --explain E0080`.
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr b/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr
index f70722b92..dc54bd413 100644
--- a/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr
+++ b/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr
@@ -4,8 +4,8 @@ error: slicing may panic
LL | &x[index..];
| ^^^^^^^^^^
|
- = note: `-D clippy::indexing-slicing` implied by `-D warnings`
= help: consider using `.get(n..)` or .get_mut(n..)` instead
+ = note: `-D clippy::indexing-slicing` implied by `-D warnings`
error: slicing may panic
--> $DIR/indexing_slicing_slice.rs:13:6
diff --git a/src/tools/clippy/tests/ui/inefficient_to_string.stderr b/src/tools/clippy/tests/ui/inefficient_to_string.stderr
index 4be46161e..914dc92bf 100644
--- a/src/tools/clippy/tests/ui/inefficient_to_string.stderr
+++ b/src/tools/clippy/tests/ui/inefficient_to_string.stderr
@@ -4,12 +4,12 @@ error: calling `to_string` on `&&str`
LL | let _: String = rrstr.to_string();
| ^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrstr).to_string()`
|
+ = help: `&str` implements `ToString` through a slower blanket impl, but `str` has a fast specialization of `ToString`
note: the lint level is defined here
--> $DIR/inefficient_to_string.rs:2:9
|
LL | #![deny(clippy::inefficient_to_string)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: `&str` implements `ToString` through a slower blanket impl, but `str` has a fast specialization of `ToString`
error: calling `to_string` on `&&&str`
--> $DIR/inefficient_to_string.rs:12:21
@@ -35,21 +35,21 @@ LL | let _: String = rrrstring.to_string();
|
= help: `&&std::string::String` implements `ToString` through a slower blanket impl, but `std::string::String` has a fast specialization of `ToString`
-error: calling `to_string` on `&&std::borrow::Cow<str>`
+error: calling `to_string` on `&&std::borrow::Cow<'_, str>`
--> $DIR/inefficient_to_string.rs:29:21
|
LL | let _: String = rrcow.to_string();
| ^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrcow).to_string()`
|
- = help: `&std::borrow::Cow<str>` implements `ToString` through a slower blanket impl, but `std::borrow::Cow<str>` has a fast specialization of `ToString`
+ = help: `&std::borrow::Cow<'_, str>` implements `ToString` through a slower blanket impl, but `std::borrow::Cow<'_, str>` has a fast specialization of `ToString`
-error: calling `to_string` on `&&&std::borrow::Cow<str>`
+error: calling `to_string` on `&&&std::borrow::Cow<'_, str>`
--> $DIR/inefficient_to_string.rs:30:21
|
LL | let _: String = rrrcow.to_string();
| ^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrcow).to_string()`
|
- = help: `&&std::borrow::Cow<str>` implements `ToString` through a slower blanket impl, but `std::borrow::Cow<str>` has a fast specialization of `ToString`
+ = help: `&&std::borrow::Cow<'_, str>` implements `ToString` through a slower blanket impl, but `std::borrow::Cow<'_, str>` has a fast specialization of `ToString`
error: aborting due to 6 previous errors
diff --git a/src/tools/clippy/tests/ui/infinite_iter.rs b/src/tools/clippy/tests/ui/infinite_iter.rs
index a1e5fad0c..622644f67 100644
--- a/src/tools/clippy/tests/ui/infinite_iter.rs
+++ b/src/tools/clippy/tests/ui/infinite_iter.rs
@@ -1,3 +1,5 @@
+#![allow(clippy::uninlined_format_args)]
+
use std::iter::repeat;
fn square_is_lower_64(x: &u32) -> bool {
x * x < 64
diff --git a/src/tools/clippy/tests/ui/infinite_iter.stderr b/src/tools/clippy/tests/ui/infinite_iter.stderr
index ba277e363..b911163f7 100644
--- a/src/tools/clippy/tests/ui/infinite_iter.stderr
+++ b/src/tools/clippy/tests/ui/infinite_iter.stderr
@@ -1,29 +1,29 @@
error: infinite iteration detected
- --> $DIR/infinite_iter.rs:9:5
+ --> $DIR/infinite_iter.rs:11:5
|
LL | repeat(0_u8).collect::<Vec<_>>(); // infinite iter
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/infinite_iter.rs:7:8
+ --> $DIR/infinite_iter.rs:9:8
|
LL | #[deny(clippy::infinite_iter)]
| ^^^^^^^^^^^^^^^^^^^^^
error: infinite iteration detected
- --> $DIR/infinite_iter.rs:10:5
+ --> $DIR/infinite_iter.rs:12:5
|
LL | (0..8_u32).take_while(square_is_lower_64).cycle().count(); // infinite iter
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: infinite iteration detected
- --> $DIR/infinite_iter.rs:11:5
+ --> $DIR/infinite_iter.rs:13:5
|
LL | (0..8_u64).chain(0..).max(); // infinite iter
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: infinite iteration detected
- --> $DIR/infinite_iter.rs:16:5
+ --> $DIR/infinite_iter.rs:18:5
|
LL | / (0..8_u32)
LL | | .rev()
@@ -33,37 +33,37 @@ LL | | .for_each(|x| println!("{}", x)); // infinite iter
| |________________________________________^
error: infinite iteration detected
- --> $DIR/infinite_iter.rs:22:5
+ --> $DIR/infinite_iter.rs:24:5
|
LL | (0_usize..).flat_map(|x| 0..x).product::<usize>(); // infinite iter
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: infinite iteration detected
- --> $DIR/infinite_iter.rs:23:5
+ --> $DIR/infinite_iter.rs:25:5
|
LL | (0_u64..).filter(|x| x % 2 == 0).last(); // infinite iter
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: possible infinite iteration detected
- --> $DIR/infinite_iter.rs:30:5
+ --> $DIR/infinite_iter.rs:32:5
|
LL | (0..).zip((0..).take_while(square_is_lower_64)).count(); // maybe infinite iter
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/infinite_iter.rs:28:8
+ --> $DIR/infinite_iter.rs:30:8
|
LL | #[deny(clippy::maybe_infinite_iter)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: possible infinite iteration detected
- --> $DIR/infinite_iter.rs:31:5
+ --> $DIR/infinite_iter.rs:33:5
|
LL | repeat(42).take_while(|x| *x == 42).chain(0..42).max(); // maybe infinite iter
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: possible infinite iteration detected
- --> $DIR/infinite_iter.rs:32:5
+ --> $DIR/infinite_iter.rs:34:5
|
LL | / (1..)
LL | | .scan(0, |state, x| {
@@ -74,31 +74,31 @@ LL | | .min(); // maybe infinite iter
| |______________^
error: possible infinite iteration detected
- --> $DIR/infinite_iter.rs:38:5
+ --> $DIR/infinite_iter.rs:40:5
|
LL | (0..).find(|x| *x == 24); // maybe infinite iter
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: possible infinite iteration detected
- --> $DIR/infinite_iter.rs:39:5
+ --> $DIR/infinite_iter.rs:41:5
|
LL | (0..).position(|x| x == 24); // maybe infinite iter
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: possible infinite iteration detected
- --> $DIR/infinite_iter.rs:40:5
+ --> $DIR/infinite_iter.rs:42:5
|
LL | (0..).any(|x| x == 24); // maybe infinite iter
| ^^^^^^^^^^^^^^^^^^^^^^
error: possible infinite iteration detected
- --> $DIR/infinite_iter.rs:41:5
+ --> $DIR/infinite_iter.rs:43:5
|
LL | (0..).all(|x| x == 24); // maybe infinite iter
| ^^^^^^^^^^^^^^^^^^^^^^
error: infinite iteration detected
- --> $DIR/infinite_iter.rs:63:31
+ --> $DIR/infinite_iter.rs:65:31
|
LL | let _: HashSet<i32> = (0..).collect(); // Infinite iter
| ^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/infinite_loop.stderr b/src/tools/clippy/tests/ui/infinite_loop.stderr
index 4ec7d900a..85258b9d6 100644
--- a/src/tools/clippy/tests/ui/infinite_loop.stderr
+++ b/src/tools/clippy/tests/ui/infinite_loop.stderr
@@ -4,8 +4,8 @@ error: variables in the condition are not mutated in the loop body
LL | while y < 10 {
| ^^^^^^
|
- = note: `#[deny(clippy::while_immutable_condition)]` on by default
= note: this may lead to an infinite or to a never running loop
+ = note: `#[deny(clippy::while_immutable_condition)]` on by default
error: variables in the condition are not mutated in the loop body
--> $DIR/infinite_loop.rs:25:11
diff --git a/src/tools/clippy/tests/ui/inherent_to_string.stderr b/src/tools/clippy/tests/ui/inherent_to_string.stderr
index 4f331f5be..443fecae1 100644
--- a/src/tools/clippy/tests/ui/inherent_to_string.stderr
+++ b/src/tools/clippy/tests/ui/inherent_to_string.stderr
@@ -6,8 +6,8 @@ LL | | "A.to_string()".to_string()
LL | | }
| |_____^
|
- = note: `-D clippy::inherent-to-string` implied by `-D warnings`
= help: implement trait `Display` for type `A` instead
+ = note: `-D clippy::inherent-to-string` implied by `-D warnings`
error: type `C` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`
--> $DIR/inherent_to_string.rs:44:5
@@ -17,12 +17,12 @@ LL | | "C.to_string()".to_string()
LL | | }
| |_____^
|
+ = help: remove the inherent method from type `C`
note: the lint level is defined here
--> $DIR/inherent_to_string.rs:2:9
|
LL | #![deny(clippy::inherent_to_string_shadow_display)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove the inherent method from type `C`
error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/inspect_for_each.stderr b/src/tools/clippy/tests/ui/inspect_for_each.stderr
index 9f976bb74..67c2d5e53 100644
--- a/src/tools/clippy/tests/ui/inspect_for_each.stderr
+++ b/src/tools/clippy/tests/ui/inspect_for_each.stderr
@@ -9,8 +9,8 @@ LL | | b.push(z);
LL | | });
| |______^
|
- = note: `-D clippy::inspect-for-each` implied by `-D warnings`
= help: move the code from `inspect(..)` to `for_each(..)` and remove the `inspect(..)`
+ = note: `-D clippy::inspect-for-each` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/integer_division.stderr b/src/tools/clippy/tests/ui/integer_division.stderr
index cbb7f8814..ca8001279 100644
--- a/src/tools/clippy/tests/ui/integer_division.stderr
+++ b/src/tools/clippy/tests/ui/integer_division.stderr
@@ -4,8 +4,8 @@ error: integer division
LL | let n = 1 / 2;
| ^^^^^
|
- = note: `-D clippy::integer-division` implied by `-D warnings`
= help: division of integers may cause loss of precision. consider using floats
+ = note: `-D clippy::integer-division` implied by `-D warnings`
error: integer division
--> $DIR/integer_division.rs:6:13
diff --git a/src/tools/clippy/tests/ui/issue_2356.fixed b/src/tools/clippy/tests/ui/issue_2356.fixed
index 942e99fa8..a73ee0fb2 100644
--- a/src/tools/clippy/tests/ui/issue_2356.fixed
+++ b/src/tools/clippy/tests/ui/issue_2356.fixed
@@ -1,6 +1,7 @@
// run-rustfix
#![deny(clippy::while_let_on_iterator)]
#![allow(unused_mut)]
+#![allow(clippy::uninlined_format_args)]
use std::iter::Iterator;
diff --git a/src/tools/clippy/tests/ui/issue_2356.rs b/src/tools/clippy/tests/ui/issue_2356.rs
index b000234ea..9dd906960 100644
--- a/src/tools/clippy/tests/ui/issue_2356.rs
+++ b/src/tools/clippy/tests/ui/issue_2356.rs
@@ -1,6 +1,7 @@
// run-rustfix
#![deny(clippy::while_let_on_iterator)]
#![allow(unused_mut)]
+#![allow(clippy::uninlined_format_args)]
use std::iter::Iterator;
diff --git a/src/tools/clippy/tests/ui/issue_2356.stderr b/src/tools/clippy/tests/ui/issue_2356.stderr
index 4e3ff7522..a24b0b32e 100644
--- a/src/tools/clippy/tests/ui/issue_2356.stderr
+++ b/src/tools/clippy/tests/ui/issue_2356.stderr
@@ -1,5 +1,5 @@
error: this loop could be written as a `for` loop
- --> $DIR/issue_2356.rs:17:9
+ --> $DIR/issue_2356.rs:18:9
|
LL | while let Some(e) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for e in it`
diff --git a/src/tools/clippy/tests/ui/issue_4266.rs b/src/tools/clippy/tests/ui/issue_4266.rs
index d9d48189b..8e0620e52 100644
--- a/src/tools/clippy/tests/ui/issue_4266.rs
+++ b/src/tools/clippy/tests/ui/issue_4266.rs
@@ -1,4 +1,5 @@
#![allow(dead_code)]
+#![allow(clippy::uninlined_format_args)]
async fn sink1<'a>(_: &'a str) {} // lint
async fn sink1_elided(_: &str) {} // ok
diff --git a/src/tools/clippy/tests/ui/issue_4266.stderr b/src/tools/clippy/tests/ui/issue_4266.stderr
index e5042aaa7..fb2a93c95 100644
--- a/src/tools/clippy/tests/ui/issue_4266.stderr
+++ b/src/tools/clippy/tests/ui/issue_4266.stderr
@@ -1,5 +1,5 @@
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/issue_4266.rs:3:1
+ --> $DIR/issue_4266.rs:4:1
|
LL | async fn sink1<'a>(_: &'a str) {} // lint
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,19 +7,19 @@ 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
+ --> $DIR/issue_4266.rs:8:1
|
LL | async fn one_to_one<'a>(s: &'a str) -> &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: methods called `new` usually take no `self`
- --> $DIR/issue_4266.rs:27:22
+ --> $DIR/issue_4266.rs:28:22
|
LL | pub async fn new(&mut self) -> Self {
| ^^^^^^^^^
|
- = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
= help: consider choosing a less ambiguous name
+ = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/item_after_statement.rs b/src/tools/clippy/tests/ui/item_after_statement.rs
index d439ca1e4..5e92dcab1 100644
--- a/src/tools/clippy/tests/ui/item_after_statement.rs
+++ b/src/tools/clippy/tests/ui/item_after_statement.rs
@@ -1,4 +1,5 @@
#![warn(clippy::items_after_statements)]
+#![allow(clippy::uninlined_format_args)]
fn ok() {
fn foo() {
diff --git a/src/tools/clippy/tests/ui/item_after_statement.stderr b/src/tools/clippy/tests/ui/item_after_statement.stderr
index ab4a6374c..2523c53ac 100644
--- a/src/tools/clippy/tests/ui/item_after_statement.stderr
+++ b/src/tools/clippy/tests/ui/item_after_statement.stderr
@@ -1,5 +1,5 @@
error: adding items after statements is confusing, since items exist from the start of the scope
- --> $DIR/item_after_statement.rs:12:5
+ --> $DIR/item_after_statement.rs:13:5
|
LL | / fn foo() {
LL | | println!("foo");
@@ -9,7 +9,7 @@ LL | | }
= note: `-D clippy::items-after-statements` implied by `-D warnings`
error: adding items after statements is confusing, since items exist from the start of the scope
- --> $DIR/item_after_statement.rs:19:5
+ --> $DIR/item_after_statement.rs:20:5
|
LL | / fn foo() {
LL | | println!("foo");
@@ -17,7 +17,7 @@ LL | | }
| |_____^
error: adding items after statements is confusing, since items exist from the start of the scope
- --> $DIR/item_after_statement.rs:32:13
+ --> $DIR/item_after_statement.rs:33:13
|
LL | / fn say_something() {
LL | | println!("something");
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.fixed b/src/tools/clippy/tests/ui/iter_kv_map.fixed
new file mode 100644
index 000000000..83fee0408
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_kv_map.fixed
@@ -0,0 +1,64 @@
+// run-rustfix
+
+#![warn(clippy::iter_kv_map)]
+#![allow(clippy::redundant_clone)]
+#![allow(clippy::suspicious_map)]
+#![allow(clippy::map_identity)]
+
+use std::collections::{BTreeMap, HashMap};
+
+fn main() {
+ let get_key = |(key, _val)| key;
+
+ let map: HashMap<u32, u32> = HashMap::new();
+
+ let _ = map.keys().collect::<Vec<_>>();
+ let _ = map.values().collect::<Vec<_>>();
+ let _ = map.values().map(|v| v + 2).collect::<Vec<_>>();
+
+ let _ = map.clone().into_keys().collect::<Vec<_>>();
+ let _ = map.clone().into_keys().map(|key| key + 2).collect::<Vec<_>>();
+
+ let _ = map.clone().into_values().collect::<Vec<_>>();
+ let _ = map.clone().into_values().map(|val| val + 2).collect::<Vec<_>>();
+
+ let _ = map.clone().values().collect::<Vec<_>>();
+ let _ = map.keys().filter(|x| *x % 2 == 0).count();
+
+ // Don't lint
+ let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
+ let _ = map.iter().map(get_key).collect::<Vec<_>>();
+
+ // Linting the following could be an improvement to the lint
+ // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
+
+ // Lint
+ let _ = map.keys().map(|key| key * 9).count();
+ let _ = map.values().map(|value| value * 17).count();
+
+ let map: BTreeMap<u32, u32> = BTreeMap::new();
+
+ let _ = map.keys().collect::<Vec<_>>();
+ let _ = map.values().collect::<Vec<_>>();
+ let _ = map.values().map(|v| v + 2).collect::<Vec<_>>();
+
+ let _ = map.clone().into_keys().collect::<Vec<_>>();
+ let _ = map.clone().into_keys().map(|key| key + 2).collect::<Vec<_>>();
+
+ let _ = map.clone().into_values().collect::<Vec<_>>();
+ let _ = map.clone().into_values().map(|val| val + 2).collect::<Vec<_>>();
+
+ let _ = map.clone().values().collect::<Vec<_>>();
+ let _ = map.keys().filter(|x| *x % 2 == 0).count();
+
+ // Don't lint
+ let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
+ let _ = map.iter().map(get_key).collect::<Vec<_>>();
+
+ // Linting the following could be an improvement to the lint
+ // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
+
+ // Lint
+ let _ = map.keys().map(|key| key * 9).count();
+ let _ = map.values().map(|value| value * 17).count();
+}
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.rs b/src/tools/clippy/tests/ui/iter_kv_map.rs
new file mode 100644
index 000000000..7a1f1fb01
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_kv_map.rs
@@ -0,0 +1,64 @@
+// run-rustfix
+
+#![warn(clippy::iter_kv_map)]
+#![allow(clippy::redundant_clone)]
+#![allow(clippy::suspicious_map)]
+#![allow(clippy::map_identity)]
+
+use std::collections::{BTreeMap, HashMap};
+
+fn main() {
+ let get_key = |(key, _val)| key;
+
+ let map: HashMap<u32, u32> = HashMap::new();
+
+ let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
+ let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
+ let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
+
+ let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
+ let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
+
+ let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
+ let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
+
+ let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
+ let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
+
+ // Don't lint
+ let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
+ let _ = map.iter().map(get_key).collect::<Vec<_>>();
+
+ // Linting the following could be an improvement to the lint
+ // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
+
+ // Lint
+ let _ = map.iter().map(|(key, _value)| key * 9).count();
+ let _ = map.iter().map(|(_key, value)| value * 17).count();
+
+ let map: BTreeMap<u32, u32> = BTreeMap::new();
+
+ let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
+ let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
+ let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
+
+ let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
+ let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
+
+ let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
+ let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
+
+ let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
+ let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
+
+ // Don't lint
+ let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
+ let _ = map.iter().map(get_key).collect::<Vec<_>>();
+
+ // Linting the following could be an improvement to the lint
+ // map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
+
+ // Lint
+ let _ = map.iter().map(|(key, _value)| key * 9).count();
+ let _ = map.iter().map(|(_key, value)| value * 17).count();
+}
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.stderr b/src/tools/clippy/tests/ui/iter_kv_map.stderr
new file mode 100644
index 000000000..9b9b04c97
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_kv_map.stderr
@@ -0,0 +1,136 @@
+error: iterating on a map's keys
+ --> $DIR/iter_kv_map.rs:15:13
+ |
+LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
+ |
+ = note: `-D clippy::iter-kv-map` implied by `-D warnings`
+
+error: iterating on a map's values
+ --> $DIR/iter_kv_map.rs:16:13
+ |
+LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
+
+error: iterating on a map's values
+ --> $DIR/iter_kv_map.rs:17:13
+ |
+LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
+
+error: iterating on a map's keys
+ --> $DIR/iter_kv_map.rs:19:13
+ |
+LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
+
+error: iterating on a map's keys
+ --> $DIR/iter_kv_map.rs:20:13
+ |
+LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
+
+error: iterating on a map's values
+ --> $DIR/iter_kv_map.rs:22:13
+ |
+LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
+
+error: iterating on a map's values
+ --> $DIR/iter_kv_map.rs:23:13
+ |
+LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
+
+error: iterating on a map's values
+ --> $DIR/iter_kv_map.rs:25:13
+ |
+LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
+
+error: iterating on a map's keys
+ --> $DIR/iter_kv_map.rs:26:13
+ |
+LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
+
+error: iterating on a map's keys
+ --> $DIR/iter_kv_map.rs:36:13
+ |
+LL | let _ = map.iter().map(|(key, _value)| key * 9).count();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
+
+error: iterating on a map's values
+ --> $DIR/iter_kv_map.rs:37:13
+ |
+LL | let _ = map.iter().map(|(_key, value)| value * 17).count();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
+
+error: iterating on a map's keys
+ --> $DIR/iter_kv_map.rs:41:13
+ |
+LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
+
+error: iterating on a map's values
+ --> $DIR/iter_kv_map.rs:42:13
+ |
+LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
+
+error: iterating on a map's values
+ --> $DIR/iter_kv_map.rs:43:13
+ |
+LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
+
+error: iterating on a map's keys
+ --> $DIR/iter_kv_map.rs:45:13
+ |
+LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
+
+error: iterating on a map's keys
+ --> $DIR/iter_kv_map.rs:46:13
+ |
+LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
+
+error: iterating on a map's values
+ --> $DIR/iter_kv_map.rs:48:13
+ |
+LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
+
+error: iterating on a map's values
+ --> $DIR/iter_kv_map.rs:49:13
+ |
+LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
+
+error: iterating on a map's values
+ --> $DIR/iter_kv_map.rs:51:13
+ |
+LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
+
+error: iterating on a map's keys
+ --> $DIR/iter_kv_map.rs:52:13
+ |
+LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
+
+error: iterating on a map's keys
+ --> $DIR/iter_kv_map.rs:62:13
+ |
+LL | let _ = map.iter().map(|(key, _value)| key * 9).count();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
+
+error: iterating on a map's values
+ --> $DIR/iter_kv_map.rs:63:13
+ |
+LL | let _ = map.iter().map(|(_key, value)| value * 17).count();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
+
+error: aborting due to 22 previous errors
+
diff --git a/src/tools/clippy/tests/ui/iter_nth.stderr b/src/tools/clippy/tests/ui/iter_nth.stderr
index d00b2fb67..a0fe353bc 100644
--- a/src/tools/clippy/tests/ui/iter_nth.stderr
+++ b/src/tools/clippy/tests/ui/iter_nth.stderr
@@ -4,8 +4,8 @@ error: called `.iter().nth()` on a Vec
LL | let bad_vec = some_vec.iter().nth(3);
| ^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::iter-nth` implied by `-D warnings`
= help: calling `.get()` is both faster and more readable
+ = note: `-D clippy::iter-nth` implied by `-D warnings`
error: called `.iter().nth()` on a slice
--> $DIR/iter_nth.rs:34:26
diff --git a/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed b/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed
new file mode 100644
index 000000000..bd9b07aef
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::iter_on_empty_collections)]
+#![allow(clippy::iter_next_slice, clippy::redundant_clone)]
+
+fn array() {
+ assert_eq!(std::iter::empty().next(), Option::<i32>::None);
+ assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None);
+ assert_eq!(std::iter::empty().next(), Option::<&i32>::None);
+ assert_eq!(std::iter::empty().next(), Option::<i32>::None);
+ assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None);
+ assert_eq!(std::iter::empty().next(), Option::<&i32>::None);
+
+ // Don't trigger on non-iter methods
+ let _: Option<String> = None.clone();
+ let _: [String; 0] = [].clone();
+
+ // Don't trigger on match or if branches
+ let _ = match 123 {
+ 123 => [].iter(),
+ _ => ["test"].iter(),
+ };
+
+ let _ = if false { ["test"].iter() } else { [].iter() };
+}
+
+macro_rules! in_macros {
+ () => {
+ assert_eq!([].into_iter().next(), Option::<i32>::None);
+ assert_eq!([].iter_mut().next(), Option::<&mut i32>::None);
+ assert_eq!([].iter().next(), Option::<&i32>::None);
+ assert_eq!(None.into_iter().next(), Option::<i32>::None);
+ assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None);
+ assert_eq!(None.iter().next(), Option::<&i32>::None);
+ };
+}
+
+// Don't trigger on a `None` that isn't std's option
+mod custom_option {
+ #[allow(unused)]
+ enum CustomOption {
+ Some(i32),
+ None,
+ }
+
+ impl CustomOption {
+ fn iter(&self) {}
+ fn iter_mut(&mut self) {}
+ fn into_iter(self) {}
+ }
+ use CustomOption::*;
+
+ pub fn custom_option() {
+ None.iter();
+ None.iter_mut();
+ None.into_iter();
+ }
+}
+
+fn main() {
+ array();
+ custom_option::custom_option();
+ in_macros!();
+}
diff --git a/src/tools/clippy/tests/ui/iter_on_empty_collections.rs b/src/tools/clippy/tests/ui/iter_on_empty_collections.rs
new file mode 100644
index 000000000..e15ba94bd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_on_empty_collections.rs
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::iter_on_empty_collections)]
+#![allow(clippy::iter_next_slice, clippy::redundant_clone)]
+
+fn array() {
+ assert_eq!([].into_iter().next(), Option::<i32>::None);
+ assert_eq!([].iter_mut().next(), Option::<&mut i32>::None);
+ assert_eq!([].iter().next(), Option::<&i32>::None);
+ assert_eq!(None.into_iter().next(), Option::<i32>::None);
+ assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None);
+ assert_eq!(None.iter().next(), Option::<&i32>::None);
+
+ // Don't trigger on non-iter methods
+ let _: Option<String> = None.clone();
+ let _: [String; 0] = [].clone();
+
+ // Don't trigger on match or if branches
+ let _ = match 123 {
+ 123 => [].iter(),
+ _ => ["test"].iter(),
+ };
+
+ let _ = if false { ["test"].iter() } else { [].iter() };
+}
+
+macro_rules! in_macros {
+ () => {
+ assert_eq!([].into_iter().next(), Option::<i32>::None);
+ assert_eq!([].iter_mut().next(), Option::<&mut i32>::None);
+ assert_eq!([].iter().next(), Option::<&i32>::None);
+ assert_eq!(None.into_iter().next(), Option::<i32>::None);
+ assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None);
+ assert_eq!(None.iter().next(), Option::<&i32>::None);
+ };
+}
+
+// Don't trigger on a `None` that isn't std's option
+mod custom_option {
+ #[allow(unused)]
+ enum CustomOption {
+ Some(i32),
+ None,
+ }
+
+ impl CustomOption {
+ fn iter(&self) {}
+ fn iter_mut(&mut self) {}
+ fn into_iter(self) {}
+ }
+ use CustomOption::*;
+
+ pub fn custom_option() {
+ None.iter();
+ None.iter_mut();
+ None.into_iter();
+ }
+}
+
+fn main() {
+ array();
+ custom_option::custom_option();
+ in_macros!();
+}
diff --git a/src/tools/clippy/tests/ui/iter_on_empty_collections.stderr b/src/tools/clippy/tests/ui/iter_on_empty_collections.stderr
new file mode 100644
index 000000000..cbd611769
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_on_empty_collections.stderr
@@ -0,0 +1,40 @@
+error: `into_iter` call on an empty collection
+ --> $DIR/iter_on_empty_collections.rs:6:16
+ |
+LL | assert_eq!([].into_iter().next(), Option::<i32>::None);
+ | ^^^^^^^^^^^^^^ help: try: `std::iter::empty()`
+ |
+ = note: `-D clippy::iter-on-empty-collections` implied by `-D warnings`
+
+error: `iter_mut` call on an empty collection
+ --> $DIR/iter_on_empty_collections.rs:7:16
+ |
+LL | assert_eq!([].iter_mut().next(), Option::<&mut i32>::None);
+ | ^^^^^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: `iter` call on an empty collection
+ --> $DIR/iter_on_empty_collections.rs:8:16
+ |
+LL | assert_eq!([].iter().next(), Option::<&i32>::None);
+ | ^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: `into_iter` call on an empty collection
+ --> $DIR/iter_on_empty_collections.rs:9:16
+ |
+LL | assert_eq!(None.into_iter().next(), Option::<i32>::None);
+ | ^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: `iter_mut` call on an empty collection
+ --> $DIR/iter_on_empty_collections.rs:10:16
+ |
+LL | assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None);
+ | ^^^^^^^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: `iter` call on an empty collection
+ --> $DIR/iter_on_empty_collections.rs:11:16
+ |
+LL | assert_eq!(None.iter().next(), Option::<&i32>::None);
+ | ^^^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/iter_on_single_items.fixed b/src/tools/clippy/tests/ui/iter_on_single_items.fixed
new file mode 100644
index 000000000..1fa4b0364
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_on_single_items.fixed
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::iter_on_single_items)]
+#![allow(clippy::iter_next_slice, clippy::redundant_clone)]
+
+fn array() {
+ assert_eq!(std::iter::once(123).next(), Some(123));
+ assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123));
+ assert_eq!(std::iter::once(&123).next(), Some(&123));
+ assert_eq!(std::iter::once(123).next(), Some(123));
+ assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123));
+ assert_eq!(std::iter::once(&123).next(), Some(&123));
+
+ // Don't trigger on non-iter methods
+ let _: Option<String> = Some("test".to_string()).clone();
+ let _: [String; 1] = ["test".to_string()].clone();
+
+ // Don't trigger on match or if branches
+ let _ = match 123 {
+ 123 => [].iter(),
+ _ => ["test"].iter(),
+ };
+
+ let _ = if false { ["test"].iter() } else { [].iter() };
+}
+
+macro_rules! in_macros {
+ () => {
+ assert_eq!([123].into_iter().next(), Some(123));
+ assert_eq!([123].iter_mut().next(), Some(&mut 123));
+ assert_eq!([123].iter().next(), Some(&123));
+ assert_eq!(Some(123).into_iter().next(), Some(123));
+ assert_eq!(Some(123).iter_mut().next(), Some(&mut 123));
+ assert_eq!(Some(123).iter().next(), Some(&123));
+ };
+}
+
+// Don't trigger on a `Some` that isn't std's option
+mod custom_option {
+ #[allow(unused)]
+ enum CustomOption {
+ Some(i32),
+ None,
+ }
+
+ impl CustomOption {
+ fn iter(&self) {}
+ fn iter_mut(&mut self) {}
+ fn into_iter(self) {}
+ }
+ use CustomOption::*;
+
+ pub fn custom_option() {
+ Some(3).iter();
+ Some(3).iter_mut();
+ Some(3).into_iter();
+ }
+}
+
+fn main() {
+ array();
+ custom_option::custom_option();
+ in_macros!();
+}
diff --git a/src/tools/clippy/tests/ui/iter_on_single_items.rs b/src/tools/clippy/tests/ui/iter_on_single_items.rs
new file mode 100644
index 000000000..ea96d8066
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_on_single_items.rs
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::iter_on_single_items)]
+#![allow(clippy::iter_next_slice, clippy::redundant_clone)]
+
+fn array() {
+ assert_eq!([123].into_iter().next(), Some(123));
+ assert_eq!([123].iter_mut().next(), Some(&mut 123));
+ assert_eq!([123].iter().next(), Some(&123));
+ assert_eq!(Some(123).into_iter().next(), Some(123));
+ assert_eq!(Some(123).iter_mut().next(), Some(&mut 123));
+ assert_eq!(Some(123).iter().next(), Some(&123));
+
+ // Don't trigger on non-iter methods
+ let _: Option<String> = Some("test".to_string()).clone();
+ let _: [String; 1] = ["test".to_string()].clone();
+
+ // Don't trigger on match or if branches
+ let _ = match 123 {
+ 123 => [].iter(),
+ _ => ["test"].iter(),
+ };
+
+ let _ = if false { ["test"].iter() } else { [].iter() };
+}
+
+macro_rules! in_macros {
+ () => {
+ assert_eq!([123].into_iter().next(), Some(123));
+ assert_eq!([123].iter_mut().next(), Some(&mut 123));
+ assert_eq!([123].iter().next(), Some(&123));
+ assert_eq!(Some(123).into_iter().next(), Some(123));
+ assert_eq!(Some(123).iter_mut().next(), Some(&mut 123));
+ assert_eq!(Some(123).iter().next(), Some(&123));
+ };
+}
+
+// Don't trigger on a `Some` that isn't std's option
+mod custom_option {
+ #[allow(unused)]
+ enum CustomOption {
+ Some(i32),
+ None,
+ }
+
+ impl CustomOption {
+ fn iter(&self) {}
+ fn iter_mut(&mut self) {}
+ fn into_iter(self) {}
+ }
+ use CustomOption::*;
+
+ pub fn custom_option() {
+ Some(3).iter();
+ Some(3).iter_mut();
+ Some(3).into_iter();
+ }
+}
+
+fn main() {
+ array();
+ custom_option::custom_option();
+ in_macros!();
+}
diff --git a/src/tools/clippy/tests/ui/iter_on_single_items.stderr b/src/tools/clippy/tests/ui/iter_on_single_items.stderr
new file mode 100644
index 000000000..d6c547116
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_on_single_items.stderr
@@ -0,0 +1,40 @@
+error: `into_iter` call on a collection with only one item
+ --> $DIR/iter_on_single_items.rs:6:16
+ |
+LL | assert_eq!([123].into_iter().next(), Some(123));
+ | ^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)`
+ |
+ = note: `-D clippy::iter-on-single-items` implied by `-D warnings`
+
+error: `iter_mut` call on a collection with only one item
+ --> $DIR/iter_on_single_items.rs:7:16
+ |
+LL | assert_eq!([123].iter_mut().next(), Some(&mut 123));
+ | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)`
+
+error: `iter` call on a collection with only one item
+ --> $DIR/iter_on_single_items.rs:8:16
+ |
+LL | assert_eq!([123].iter().next(), Some(&123));
+ | ^^^^^^^^^^^^ help: try: `std::iter::once(&123)`
+
+error: `into_iter` call on a collection with only one item
+ --> $DIR/iter_on_single_items.rs:9:16
+ |
+LL | assert_eq!(Some(123).into_iter().next(), Some(123));
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)`
+
+error: `iter_mut` call on a collection with only one item
+ --> $DIR/iter_on_single_items.rs:10:16
+ |
+LL | assert_eq!(Some(123).iter_mut().next(), Some(&mut 123));
+ | ^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)`
+
+error: `iter` call on a collection with only one item
+ --> $DIR/iter_on_single_items.rs:11:16
+ |
+LL | assert_eq!(Some(123).iter().next(), Some(&123));
+ | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&123)`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/iter_skip_next.fixed b/src/tools/clippy/tests/ui/iter_skip_next.fixed
index 2db4c2bee..d56d623b5 100644
--- a/src/tools/clippy/tests/ui/iter_skip_next.fixed
+++ b/src/tools/clippy/tests/ui/iter_skip_next.fixed
@@ -2,7 +2,7 @@
// aux-build:option_helpers.rs
#![warn(clippy::iter_skip_next)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
#![allow(clippy::iter_nth)]
#![allow(unused_mut, dead_code)]
diff --git a/src/tools/clippy/tests/ui/iter_skip_next.rs b/src/tools/clippy/tests/ui/iter_skip_next.rs
index 692edb9ae..3ec5d1b82 100644
--- a/src/tools/clippy/tests/ui/iter_skip_next.rs
+++ b/src/tools/clippy/tests/ui/iter_skip_next.rs
@@ -2,7 +2,7 @@
// aux-build:option_helpers.rs
#![warn(clippy::iter_skip_next)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
#![allow(clippy::iter_nth)]
#![allow(unused_mut, dead_code)]
diff --git a/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr b/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr
index 74c327c74..4062706f9 100644
--- a/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr
@@ -4,12 +4,12 @@ error: called `skip(..).next()` on an iterator
LL | let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect();
| ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)`
|
- = note: `-D clippy::iter-skip-next` implied by `-D warnings`
help: for this change `sp` has to be mutable
--> $DIR/iter_skip_next_unfixable.rs:8:9
|
LL | let sp = test_string.split('|').map(|s| s.trim());
| ^^
+ = note: `-D clippy::iter-skip-next` implied by `-D warnings`
error: called `skip(..).next()` on an iterator
--> $DIR/iter_skip_next_unfixable.rs:11:29
diff --git a/src/tools/clippy/tests/ui/large_enum_variant.rs b/src/tools/clippy/tests/ui/large_enum_variant.rs
index 23152a133..3b96f09d7 100644
--- a/src/tools/clippy/tests/ui/large_enum_variant.rs
+++ b/src/tools/clippy/tests/ui/large_enum_variant.rs
@@ -101,12 +101,12 @@ struct Struct2 {
#[derive(Copy, Clone)]
enum CopyableLargeEnum {
A(bool),
- B([u128; 4000]),
+ B([u64; 8000]),
}
enum ManuallyCopyLargeEnum {
A(bool),
- B([u128; 4000]),
+ B([u64; 8000]),
}
impl Clone for ManuallyCopyLargeEnum {
@@ -130,6 +130,30 @@ impl<T: Copy> Clone for SomeGenericPossiblyCopyEnum<T> {
impl<T: Copy> Copy for SomeGenericPossiblyCopyEnum<T> {}
+enum LargeEnumWithGenerics<T> {
+ Small,
+ Large((T, [u8; 512])),
+}
+
+struct Foo<T> {
+ foo: T,
+}
+
+enum WithGenerics {
+ Large([Foo<u64>; 64]),
+ Small(u8),
+}
+
+enum PossiblyLargeEnumWithConst<const U: usize> {
+ SmallBuffer([u8; 4]),
+ MightyBuffer([u16; U]),
+}
+
+enum LargeEnumOfConst {
+ Ok,
+ Error(PossiblyLargeEnumWithConst<256>),
+}
+
fn main() {
large_enum_variant!();
}
diff --git a/src/tools/clippy/tests/ui/large_enum_variant.stderr b/src/tools/clippy/tests/ui/large_enum_variant.stderr
index 024832726..709972b4a 100644
--- a/src/tools/clippy/tests/ui/large_enum_variant.stderr
+++ b/src/tools/clippy/tests/ui/large_enum_variant.stderr
@@ -1,143 +1,177 @@
error: large size difference between variants
- --> $DIR/large_enum_variant.rs:12:5
+ --> $DIR/large_enum_variant.rs:10:1
|
-LL | B([i32; 8000]),
- | ^^^^^^^^^^^^^^ this variant is 32000 bytes
+LL | / enum LargeEnum {
+LL | | A(i32),
+ | | ------ the second-largest variant contains at least 4 bytes
+LL | | B([i32; 8000]),
+ | | -------------- the largest variant contains at least 32000 bytes
+LL | | }
+ | |_^ the entire enum is at least 32004 bytes
|
= note: `-D clippy::large-enum-variant` implied by `-D warnings`
-note: and the second-largest variant is 4 bytes:
- --> $DIR/large_enum_variant.rs:11:5
- |
-LL | A(i32),
- | ^^^^^^
help: consider boxing the large fields to reduce the total size of the enum
|
LL | B(Box<[i32; 8000]>),
| ~~~~~~~~~~~~~~~~
error: large size difference between variants
- --> $DIR/large_enum_variant.rs:36:5
- |
-LL | ContainingLargeEnum(LargeEnum),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
+ --> $DIR/large_enum_variant.rs:34:1
|
-note: and the second-largest variant is 8 bytes:
- --> $DIR/large_enum_variant.rs:35:5
+LL | / enum LargeEnum2 {
+LL | | VariantOk(i32, u32),
+ | | ------------------- the second-largest variant contains at least 8 bytes
+LL | | ContainingLargeEnum(LargeEnum),
+ | | ------------------------------ the largest variant contains at least 32004 bytes
+LL | | }
+ | |_^ the entire enum is at least 32004 bytes
|
-LL | VariantOk(i32, u32),
- | ^^^^^^^^^^^^^^^^^^^
help: consider boxing the large fields to reduce the total size of the enum
|
LL | ContainingLargeEnum(Box<LargeEnum>),
| ~~~~~~~~~~~~~~
error: large size difference between variants
- --> $DIR/large_enum_variant.rs:40:5
- |
-LL | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70004 bytes
+ --> $DIR/large_enum_variant.rs:39:1
|
-note: and the second-largest variant is 8 bytes:
- --> $DIR/large_enum_variant.rs:42:5
+LL | / enum LargeEnum3 {
+LL | | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
+ | | --------------------------------------------------------- the largest variant contains at least 70004 bytes
+LL | | VoidVariant,
+LL | | StructLikeLittle { x: i32, y: i32 },
+ | | ----------------------------------- the second-largest variant contains at least 8 bytes
+LL | | }
+ | |_^ the entire enum is at least 70008 bytes
|
-LL | StructLikeLittle { x: i32, y: i32 },
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider boxing the large fields to reduce the total size of the enum
|
LL | ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>),
| ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
error: large size difference between variants
- --> $DIR/large_enum_variant.rs:47:5
+ --> $DIR/large_enum_variant.rs:45:1
|
-LL | StructLikeLarge { x: [i32; 8000], y: i32 },
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
+LL | / enum LargeEnum4 {
+LL | | VariantOk(i32, u32),
+ | | ------------------- the second-largest variant contains at least 8 bytes
+LL | | StructLikeLarge { x: [i32; 8000], y: i32 },
+ | | ------------------------------------------ the largest variant contains at least 32004 bytes
+LL | | }
+ | |_^ the entire enum is at least 32008 bytes
|
-note: and the second-largest variant is 8 bytes:
- --> $DIR/large_enum_variant.rs:46:5
- |
-LL | VariantOk(i32, u32),
- | ^^^^^^^^^^^^^^^^^^^
help: consider boxing the large fields to reduce the total size of the enum
|
LL | StructLikeLarge { x: Box<[i32; 8000]>, y: i32 },
| ~~~~~~~~~~~~~~~~
error: large size difference between variants
- --> $DIR/large_enum_variant.rs:52:5
- |
-LL | StructLikeLarge2 { x: [i32; 8000] },
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32000 bytes
+ --> $DIR/large_enum_variant.rs:50:1
|
-note: and the second-largest variant is 8 bytes:
- --> $DIR/large_enum_variant.rs:51:5
+LL | / enum LargeEnum5 {
+LL | | VariantOk(i32, u32),
+ | | ------------------- the second-largest variant contains at least 8 bytes
+LL | | StructLikeLarge2 { x: [i32; 8000] },
+ | | ----------------------------------- the largest variant contains at least 32000 bytes
+LL | | }
+ | |_^ the entire enum is at least 32004 bytes
|
-LL | VariantOk(i32, u32),
- | ^^^^^^^^^^^^^^^^^^^
help: consider boxing the large fields to reduce the total size of the enum
|
LL | StructLikeLarge2 { x: Box<[i32; 8000]> },
| ~~~~~~~~~~~~~~~~
error: large size difference between variants
- --> $DIR/large_enum_variant.rs:68:5
- |
-LL | B([u8; 1255]),
- | ^^^^^^^^^^^^^ this variant is 1255 bytes
+ --> $DIR/large_enum_variant.rs:66:1
|
-note: and the second-largest variant is 200 bytes:
- --> $DIR/large_enum_variant.rs:69:5
+LL | / enum LargeEnum7 {
+LL | | A,
+LL | | B([u8; 1255]),
+ | | ------------- the largest variant contains at least 1255 bytes
+LL | | C([u8; 200]),
+ | | ------------ the second-largest variant contains at least 200 bytes
+LL | | }
+ | |_^ the entire enum is at least 1256 bytes
|
-LL | C([u8; 200]),
- | ^^^^^^^^^^^^
help: consider boxing the large fields to reduce the total size of the enum
|
LL | B(Box<[u8; 1255]>),
| ~~~~~~~~~~~~~~~
error: large size difference between variants
- --> $DIR/large_enum_variant.rs:74:5
+ --> $DIR/large_enum_variant.rs:72:1
|
-LL | ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70128 bytes
+LL | / enum LargeEnum8 {
+LL | | VariantOk(i32, u32),
+ | | ------------------- the second-largest variant contains at least 8 bytes
+LL | | ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]),
+ | | ------------------------------------------------------------------------- the largest variant contains at least 70128 bytes
+LL | | }
+ | |_^ the entire enum is at least 70132 bytes
|
-note: and the second-largest variant is 8 bytes:
- --> $DIR/large_enum_variant.rs:73:5
- |
-LL | VariantOk(i32, u32),
- | ^^^^^^^^^^^^^^^^^^^
help: consider boxing the large fields to reduce the total size of the enum
|
LL | ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]),
| ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
error: large size difference between variants
- --> $DIR/large_enum_variant.rs:79:5
+ --> $DIR/large_enum_variant.rs:77:1
+ |
+LL | / enum LargeEnum9 {
+LL | | A(Struct<()>),
+ | | ------------- the second-largest variant contains at least 4 bytes
+LL | | B(Struct2),
+ | | ---------- the largest variant contains at least 32000 bytes
+LL | | }
+ | |_^ the entire enum is at least 32004 bytes
+ |
+help: consider boxing the large fields to reduce the total size of the enum
|
-LL | B(Struct2),
- | ^^^^^^^^^^ this variant is 32000 bytes
+LL | B(Box<Struct2>),
+ | ~~~~~~~~~~~~
+
+error: large size difference between variants
+ --> $DIR/large_enum_variant.rs:82:1
|
-note: and the second-largest variant is 4 bytes:
- --> $DIR/large_enum_variant.rs:78:5
+LL | / enum LargeEnumOk2<T> {
+LL | | A(T),
+ | | ---- the second-largest variant contains at least 0 bytes
+LL | | B(Struct2),
+ | | ---------- the largest variant contains at least 32000 bytes
+LL | | }
+ | |_^ the entire enum is at least 32000 bytes
|
-LL | A(Struct<()>),
- | ^^^^^^^^^^^^^
help: consider boxing the large fields to reduce the total size of the enum
|
LL | B(Box<Struct2>),
| ~~~~~~~~~~~~
error: large size difference between variants
- --> $DIR/large_enum_variant.rs:104:5
+ --> $DIR/large_enum_variant.rs:87:1
+ |
+LL | / enum LargeEnumOk3<T> {
+LL | | A(Struct<T>),
+ | | ------------ the second-largest variant contains at least 4 bytes
+LL | | B(Struct2),
+ | | ---------- the largest variant contains at least 32000 bytes
+LL | | }
+ | |_^ the entire enum is at least 32000 bytes
+ |
+help: consider boxing the large fields to reduce the total size of the enum
|
-LL | B([u128; 4000]),
- | ^^^^^^^^^^^^^^^ this variant is 64000 bytes
+LL | B(Box<Struct2>),
+ | ~~~~~~~~~~~~
+
+error: large size difference between variants
+ --> $DIR/large_enum_variant.rs:102:1
|
-note: and the second-largest variant is 1 bytes:
- --> $DIR/large_enum_variant.rs:103:5
+LL | / enum CopyableLargeEnum {
+LL | | A(bool),
+ | | ------- the second-largest variant contains at least 1 bytes
+LL | | B([u64; 8000]),
+ | | -------------- the largest variant contains at least 64000 bytes
+LL | | }
+ | |_^ the entire enum is at least 64008 bytes
|
-LL | A(bool),
- | ^^^^^^^
note: boxing a variant would require the type no longer be `Copy`
--> $DIR/large_enum_variant.rs:102:6
|
@@ -146,20 +180,20 @@ LL | enum CopyableLargeEnum {
help: consider boxing the large fields to reduce the total size of the enum
--> $DIR/large_enum_variant.rs:104:5
|
-LL | B([u128; 4000]),
- | ^^^^^^^^^^^^^^^
+LL | B([u64; 8000]),
+ | ^^^^^^^^^^^^^^
error: large size difference between variants
- --> $DIR/large_enum_variant.rs:109:5
+ --> $DIR/large_enum_variant.rs:107:1
|
-LL | B([u128; 4000]),
- | ^^^^^^^^^^^^^^^ this variant is 64000 bytes
+LL | / enum ManuallyCopyLargeEnum {
+LL | | A(bool),
+ | | ------- the second-largest variant contains at least 1 bytes
+LL | | B([u64; 8000]),
+ | | -------------- the largest variant contains at least 64000 bytes
+LL | | }
+ | |_^ the entire enum is at least 64008 bytes
|
-note: and the second-largest variant is 1 bytes:
- --> $DIR/large_enum_variant.rs:108:5
- |
-LL | A(bool),
- | ^^^^^^^
note: boxing a variant would require the type no longer be `Copy`
--> $DIR/large_enum_variant.rs:107:6
|
@@ -168,20 +202,20 @@ LL | enum ManuallyCopyLargeEnum {
help: consider boxing the large fields to reduce the total size of the enum
--> $DIR/large_enum_variant.rs:109:5
|
-LL | B([u128; 4000]),
- | ^^^^^^^^^^^^^^^
+LL | B([u64; 8000]),
+ | ^^^^^^^^^^^^^^
error: large size difference between variants
- --> $DIR/large_enum_variant.rs:122:5
+ --> $DIR/large_enum_variant.rs:120:1
|
-LL | B([u64; 4000]),
- | ^^^^^^^^^^^^^^ this variant is 32000 bytes
- |
-note: and the second-largest variant is 1 bytes:
- --> $DIR/large_enum_variant.rs:121:5
+LL | / enum SomeGenericPossiblyCopyEnum<T> {
+LL | | A(bool, std::marker::PhantomData<T>),
+ | | ------------------------------------ the second-largest variant contains at least 1 bytes
+LL | | B([u64; 4000]),
+ | | -------------- the largest variant contains at least 32000 bytes
+LL | | }
+ | |_^ the entire enum is at least 32008 bytes
|
-LL | A(bool, std::marker::PhantomData<T>),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: boxing a variant would require the type no longer be `Copy`
--> $DIR/large_enum_variant.rs:120:6
|
@@ -193,5 +227,53 @@ help: consider boxing the large fields to reduce the total size of the enum
LL | B([u64; 4000]),
| ^^^^^^^^^^^^^^
-error: aborting due to 11 previous errors
+error: large size difference between variants
+ --> $DIR/large_enum_variant.rs:133:1
+ |
+LL | / enum LargeEnumWithGenerics<T> {
+LL | | Small,
+ | | ----- the second-largest variant carries no data at all
+LL | | Large((T, [u8; 512])),
+ | | --------------------- the largest variant contains at least 512 bytes
+LL | | }
+ | |_^ the entire enum is at least 512 bytes
+ |
+help: consider boxing the large fields to reduce the total size of the enum
+ |
+LL | Large(Box<(T, [u8; 512])>),
+ | ~~~~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+ --> $DIR/large_enum_variant.rs:142:1
+ |
+LL | / enum WithGenerics {
+LL | | Large([Foo<u64>; 64]),
+ | | --------------------- the largest variant contains at least 512 bytes
+LL | | Small(u8),
+ | | --------- the second-largest variant contains at least 1 bytes
+LL | | }
+ | |_^ the entire enum is at least 520 bytes
+ |
+help: consider boxing the large fields to reduce the total size of the enum
+ |
+LL | Large(Box<[Foo<u64>; 64]>),
+ | ~~~~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+ --> $DIR/large_enum_variant.rs:152:1
+ |
+LL | / enum LargeEnumOfConst {
+LL | | Ok,
+ | | -- the second-largest variant carries no data at all
+LL | | Error(PossiblyLargeEnumWithConst<256>),
+ | | -------------------------------------- the largest variant contains at least 514 bytes
+LL | | }
+ | |_^ the entire enum is at least 514 bytes
+ |
+help: consider boxing the large fields to reduce the total size of the enum
+ |
+LL | Error(Box<PossiblyLargeEnumWithConst<256>>),
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 16 previous errors
diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.rs b/src/tools/clippy/tests/ui/large_stack_arrays.rs
index d9161bfcf..6790765f8 100644
--- a/src/tools/clippy/tests/ui/large_stack_arrays.rs
+++ b/src/tools/clippy/tests/ui/large_stack_arrays.rs
@@ -12,6 +12,12 @@ enum E {
T(u32),
}
+pub static DOESNOTLINT: [u8; 512_001] = [0; 512_001];
+pub static DOESNOTLINT2: [u8; 512_001] = {
+ let x = 0;
+ [x; 512_001]
+};
+
fn main() {
let bad = (
[0u32; 20_000_000],
diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.stderr b/src/tools/clippy/tests/ui/large_stack_arrays.stderr
index 58c0a77c1..c7bf941ad 100644
--- a/src/tools/clippy/tests/ui/large_stack_arrays.stderr
+++ b/src/tools/clippy/tests/ui/large_stack_arrays.stderr
@@ -1,14 +1,14 @@
error: allocating a local array larger than 512000 bytes
- --> $DIR/large_stack_arrays.rs:17:9
+ --> $DIR/large_stack_arrays.rs:23:9
|
LL | [0u32; 20_000_000],
| ^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::large-stack-arrays` implied by `-D warnings`
= help: consider allocating on the heap with `vec![0u32; 20_000_000].into_boxed_slice()`
+ = note: `-D clippy::large-stack-arrays` implied by `-D warnings`
error: allocating a local array larger than 512000 bytes
- --> $DIR/large_stack_arrays.rs:18:9
+ --> $DIR/large_stack_arrays.rs:24:9
|
LL | [S { data: [0; 32] }; 5000],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL | [S { data: [0; 32] }; 5000],
= help: consider allocating on the heap with `vec![S { data: [0; 32] }; 5000].into_boxed_slice()`
error: allocating a local array larger than 512000 bytes
- --> $DIR/large_stack_arrays.rs:19:9
+ --> $DIR/large_stack_arrays.rs:25:9
|
LL | [Some(""); 20_000_000],
| ^^^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL | [Some(""); 20_000_000],
= help: consider allocating on the heap with `vec![Some(""); 20_000_000].into_boxed_slice()`
error: allocating a local array larger than 512000 bytes
- --> $DIR/large_stack_arrays.rs:20:9
+ --> $DIR/large_stack_arrays.rs:26:9
|
LL | [E::T(0); 5000],
| ^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/len_without_is_empty.rs b/src/tools/clippy/tests/ui/len_without_is_empty.rs
index 1e938e72b..78397c2af 100644
--- a/src/tools/clippy/tests/ui/len_without_is_empty.rs
+++ b/src/tools/clippy/tests/ui/len_without_is_empty.rs
@@ -274,7 +274,7 @@ impl AsyncLen {
}
pub async fn len(&self) -> usize {
- if self.async_task().await { 0 } else { 1 }
+ usize::from(!self.async_task().await)
}
pub async fn is_empty(&self) -> bool {
diff --git a/src/tools/clippy/tests/ui/len_without_is_empty.stderr b/src/tools/clippy/tests/ui/len_without_is_empty.stderr
index a1f48f761..8e890e2e2 100644
--- a/src/tools/clippy/tests/ui/len_without_is_empty.stderr
+++ b/src/tools/clippy/tests/ui/len_without_is_empty.stderr
@@ -92,8 +92,8 @@ error: this returns a `Result<_, ()>`
LL | pub fn len(&self) -> Result<usize, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::result-unit-err` implied by `-D warnings`
= help: use a custom `Error` type instead
+ = note: `-D clippy::result-unit-err` implied by `-D warnings`
error: this returns a `Result<_, ()>`
--> $DIR/len_without_is_empty.rs:240:5
diff --git a/src/tools/clippy/tests/ui/let_if_seq.rs b/src/tools/clippy/tests/ui/let_if_seq.rs
index c5cb2eb1f..959567f68 100644
--- a/src/tools/clippy/tests/ui/let_if_seq.rs
+++ b/src/tools/clippy/tests/ui/let_if_seq.rs
@@ -2,7 +2,7 @@
unused_variables,
unused_assignments,
clippy::similar_names,
- clippy::blacklisted_name,
+ clippy::disallowed_names,
clippy::branches_sharing_code,
clippy::needless_late_init
)]
diff --git a/src/tools/clippy/tests/ui/let_if_seq.stderr b/src/tools/clippy/tests/ui/let_if_seq.stderr
index 271ccce68..f2e0edb6f 100644
--- a/src/tools/clippy/tests/ui/let_if_seq.stderr
+++ b/src/tools/clippy/tests/ui/let_if_seq.stderr
@@ -7,8 +7,8 @@ LL | | foo = 42;
LL | | }
| |_____^ help: it is more idiomatic to write: `let <mut> foo = if f() { 42 } else { 0 };`
|
- = note: `-D clippy::useless-let-if-seq` implied by `-D warnings`
= note: you might not need `mut` at all
+ = note: `-D clippy::useless-let-if-seq` implied by `-D warnings`
error: `if _ { .. } else { .. }` is an expression
--> $DIR/let_if_seq.rs:71:5
diff --git a/src/tools/clippy/tests/ui/let_underscore_drop.stderr b/src/tools/clippy/tests/ui/let_underscore_drop.stderr
index ee7bbe995..324b7cd43 100644
--- a/src/tools/clippy/tests/ui/let_underscore_drop.stderr
+++ b/src/tools/clippy/tests/ui/let_underscore_drop.stderr
@@ -4,8 +4,8 @@ error: non-binding `let` on a type that implements `Drop`
LL | let _ = Box::new(());
| ^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::let-underscore-drop` implied by `-D warnings`
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+ = note: `-D clippy::let-underscore-drop` implied by `-D warnings`
error: non-binding `let` on a type that implements `Drop`
--> $DIR/let_underscore_drop.rs:18:5
diff --git a/src/tools/clippy/tests/ui/let_underscore_lock.stderr b/src/tools/clippy/tests/ui/let_underscore_lock.stderr
index 4365b48fa..d7779e7b6 100644
--- a/src/tools/clippy/tests/ui/let_underscore_lock.stderr
+++ b/src/tools/clippy/tests/ui/let_underscore_lock.stderr
@@ -4,8 +4,8 @@ error: non-binding let on a synchronization lock
LL | let _ = m.lock();
| ^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::let-underscore-lock` implied by `-D warnings`
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
+ = note: `-D clippy::let-underscore-lock` implied by `-D warnings`
error: non-binding let on a synchronization lock
--> $DIR/let_underscore_lock.rs:10:5
diff --git a/src/tools/clippy/tests/ui/let_underscore_must_use.stderr b/src/tools/clippy/tests/ui/let_underscore_must_use.stderr
index 5b751ea56..bae60f2ff 100644
--- a/src/tools/clippy/tests/ui/let_underscore_must_use.stderr
+++ b/src/tools/clippy/tests/ui/let_underscore_must_use.stderr
@@ -4,8 +4,8 @@ error: non-binding let on a result of a `#[must_use]` function
LL | let _ = f();
| ^^^^^^^^^^^^
|
- = note: `-D clippy::let-underscore-must-use` implied by `-D warnings`
= help: consider explicitly using function result
+ = note: `-D clippy::let-underscore-must-use` implied by `-D warnings`
error: non-binding let on an expression with `#[must_use]` type
--> $DIR/let_underscore_must_use.rs:68:5
diff --git a/src/tools/clippy/tests/ui/linkedlist.stderr b/src/tools/clippy/tests/ui/linkedlist.stderr
index 51327df13..c76c94961 100644
--- a/src/tools/clippy/tests/ui/linkedlist.stderr
+++ b/src/tools/clippy/tests/ui/linkedlist.stderr
@@ -4,8 +4,8 @@ error: you seem to be using a `LinkedList`! Perhaps you meant some other data st
LL | const C: LinkedList<i32> = LinkedList::new();
| ^^^^^^^^^^^^^^^
|
- = note: `-D clippy::linkedlist` implied by `-D warnings`
= help: a `VecDeque` might work
+ = note: `-D clippy::linkedlist` implied by `-D warnings`
error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure?
--> $DIR/linkedlist.rs:9:11
diff --git a/src/tools/clippy/tests/ui/literals.rs b/src/tools/clippy/tests/ui/literals.rs
index 0cadd5a3d..1a646e49c 100644
--- a/src/tools/clippy/tests/ui/literals.rs
+++ b/src/tools/clippy/tests/ui/literals.rs
@@ -40,3 +40,10 @@ fn main() {
let ok26 = 0x6_A0_BF;
let ok27 = 0b1_0010_0101;
}
+
+fn issue9651() {
+ // lint but octal form is not possible here
+ let _ = 08;
+ let _ = 09;
+ let _ = 089;
+}
diff --git a/src/tools/clippy/tests/ui/literals.stderr b/src/tools/clippy/tests/ui/literals.stderr
index 365b24074..603d47bac 100644
--- a/src/tools/clippy/tests/ui/literals.stderr
+++ b/src/tools/clippy/tests/ui/literals.stderr
@@ -135,5 +135,38 @@ error: digits of hex or binary literal not grouped by four
LL | let fail25 = 0b01_100_101;
| ^^^^^^^^^^^^ help: consider: `0b0110_0101`
-error: aborting due to 18 previous errors
+error: this is a decimal constant
+ --> $DIR/literals.rs:46:13
+ |
+LL | let _ = 08;
+ | ^^
+ |
+help: if you mean to use a decimal constant, remove the `0` to avoid confusion
+ |
+LL | let _ = 8;
+ | ~
+
+error: this is a decimal constant
+ --> $DIR/literals.rs:47:13
+ |
+LL | let _ = 09;
+ | ^^
+ |
+help: if you mean to use a decimal constant, remove the `0` to avoid confusion
+ |
+LL | let _ = 9;
+ | ~
+
+error: this is a decimal constant
+ --> $DIR/literals.rs:48:13
+ |
+LL | let _ = 089;
+ | ^^^
+ |
+help: if you mean to use a decimal constant, remove the `0` to avoid confusion
+ |
+LL | let _ = 89;
+ | ~~
+
+error: aborting due to 21 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
index d0bc640db..c9a819ba5 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
@@ -1,10 +1,11 @@
// revisions: edition2018 edition2021
-// [edition2018] edition:2018
-// [edition2021] edition:2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
// run-rustfix
#![warn(clippy::manual_assert)]
-#![allow(clippy::nonminimal_bool)]
+#![allow(dead_code, unused_doc_comments)]
+#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args)]
macro_rules! one {
() => {
@@ -17,7 +18,7 @@ fn main() {
let c = Some(2);
if !a.is_empty()
&& a.len() == 3
- && c != None
+ && c.is_some()
&& !a.is_empty()
&& a.len() == 3
&& !a.is_empty()
@@ -28,7 +29,9 @@ fn main() {
panic!("qaqaq{:?}", a);
}
assert!(a.is_empty(), "qaqaq{:?}", a);
- assert!(a.is_empty(), "qwqwq");
+ if !a.is_empty() {
+ panic!("qwqwq");
+ }
if a.len() == 3 {
println!("qwq");
println!("qwq");
@@ -43,10 +46,32 @@ fn main() {
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");
+ 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");
+ }
assert!(!a.is_empty(), "with expansion {}", one!());
}
+
+fn issue7730(a: u8) {
+ // Suggestion should preserve comment
+ if a > 2 {
+ // comment
+ /* this is a
+ multiline
+ comment */
+ /// Doc comment
+ panic!("panic with comment") // comment after `panic!`
+ }
+}
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
index a0f31afd6..1f2e1e308 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
@@ -1,68 +1,20 @@
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:30:5
+ --> $DIR/manual_assert.rs:31:5
|
LL | / if !a.is_empty() {
LL | | panic!("qaqaq{:?}", a);
LL | | }
- | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
+ | |_____^ help: try instead: `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:33: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:50: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:53: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:56: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:59: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:62:5
- |
-LL | / if a.is_empty() || !b.is_empty() {
-LL | | panic!("panic5");
-LL | | }
- | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
-
-error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:65:5
+ --> $DIR/manual_assert.rs:66:5
|
LL | / if a.is_empty() {
LL | | panic!("with expansion {}", one!())
LL | | }
- | |_____^ help: try: `assert!(!a.is_empty(), "with expansion {}", one!());`
+ | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());`
-error: aborting due to 8 previous errors
+error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
index d0bc640db..2f62de51c 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
@@ -1,10 +1,11 @@
// revisions: edition2018 edition2021
-// [edition2018] edition:2018
-// [edition2021] edition:2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
// run-rustfix
#![warn(clippy::manual_assert)]
-#![allow(clippy::nonminimal_bool)]
+#![allow(dead_code, unused_doc_comments)]
+#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args)]
macro_rules! one {
() => {
@@ -17,7 +18,7 @@ fn main() {
let c = Some(2);
if !a.is_empty()
&& a.len() == 3
- && c != None
+ && c.is_some()
&& !a.is_empty()
&& a.len() == 3
&& !a.is_empty()
@@ -50,3 +51,14 @@ fn main() {
assert!(!(a.is_empty() || !b.is_empty()), "panic5");
assert!(!a.is_empty(), "with expansion {}", one!());
}
+
+fn issue7730(a: u8) {
+ // Suggestion should preserve comment
+ // comment
+/* this is a
+ multiline
+ comment */
+/// Doc comment
+// comment after `panic!`
+assert!(!(a > 2), "panic with comment");
+}
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
index a0f31afd6..237638ee1 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
@@ -1,68 +1,85 @@
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:30:5
+ --> $DIR/manual_assert.rs:31:5
|
LL | / if !a.is_empty() {
LL | | panic!("qaqaq{:?}", a);
LL | | }
- | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
+ | |_____^ help: try instead: `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:33:5
+ --> $DIR/manual_assert.rs:34:5
|
LL | / if !a.is_empty() {
LL | | panic!("qwqwq");
LL | | }
- | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
+ | |_____^ help: try instead: `assert!(a.is_empty(), "qwqwq");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:50:5
+ --> $DIR/manual_assert.rs:51:5
|
LL | / if b.is_empty() {
LL | | panic!("panic1");
LL | | }
- | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
+ | |_____^ help: try instead: `assert!(!b.is_empty(), "panic1");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:53:5
+ --> $DIR/manual_assert.rs:54:5
|
LL | / if b.is_empty() && a.is_empty() {
LL | | panic!("panic2");
LL | | }
- | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
+ | |_____^ help: try instead: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:56:5
+ --> $DIR/manual_assert.rs:57:5
|
LL | / if a.is_empty() && !b.is_empty() {
LL | | panic!("panic3");
LL | | }
- | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
+ | |_____^ help: try instead: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:59:5
+ --> $DIR/manual_assert.rs:60:5
|
LL | / if b.is_empty() || a.is_empty() {
LL | | panic!("panic4");
LL | | }
- | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
+ | |_____^ help: try instead: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:62:5
+ --> $DIR/manual_assert.rs:63:5
|
LL | / if a.is_empty() || !b.is_empty() {
LL | | panic!("panic5");
LL | | }
- | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
+ | |_____^ help: try instead: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
error: only a `panic!` in `if`-then statement
- --> $DIR/manual_assert.rs:65:5
+ --> $DIR/manual_assert.rs:66:5
|
LL | / if a.is_empty() {
LL | | panic!("with expansion {}", one!())
LL | | }
- | |_____^ help: try: `assert!(!a.is_empty(), "with expansion {}", one!());`
+ | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());`
-error: aborting due to 8 previous errors
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:73:5
+ |
+LL | / if a > 2 {
+LL | | // comment
+LL | | /* this is a
+LL | | multiline
+... |
+LL | | panic!("panic with comment") // comment after `panic!`
+LL | | }
+ | |_____^
+ |
+help: try instead
+ |
+LL | assert!(!(a > 2), "panic with comment");
+ |
+
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_assert.fixed b/src/tools/clippy/tests/ui/manual_assert.fixed
deleted file mode 100644
index 6c2a25c37..000000000
--- a/src/tools/clippy/tests/ui/manual_assert.fixed
+++ /dev/null
@@ -1,45 +0,0 @@
-// revisions: edition2018 edition2021
-// [edition2018] edition:2018
-// [edition2021] edition:2021
-// run-rustfix
-
-#![warn(clippy::manual_assert)]
-#![allow(clippy::nonminimal_bool)]
-
-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");
-}
diff --git a/src/tools/clippy/tests/ui/manual_assert.rs b/src/tools/clippy/tests/ui/manual_assert.rs
index 027747d83..6a4cc2468 100644
--- a/src/tools/clippy/tests/ui/manual_assert.rs
+++ b/src/tools/clippy/tests/ui/manual_assert.rs
@@ -1,10 +1,11 @@
// revisions: edition2018 edition2021
-// [edition2018] edition:2018
-// [edition2021] edition:2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
// run-rustfix
#![warn(clippy::manual_assert)]
-#![allow(clippy::nonminimal_bool)]
+#![allow(dead_code, unused_doc_comments)]
+#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args)]
macro_rules! one {
() => {
@@ -17,7 +18,7 @@ fn main() {
let c = Some(2);
if !a.is_empty()
&& a.len() == 3
- && c != None
+ && c.is_some()
&& !a.is_empty()
&& a.len() == 3
&& !a.is_empty()
@@ -66,3 +67,15 @@ fn main() {
panic!("with expansion {}", one!())
}
}
+
+fn issue7730(a: u8) {
+ // Suggestion should preserve comment
+ if a > 2 {
+ // comment
+ /* this is a
+ multiline
+ comment */
+ /// Doc comment
+ panic!("panic with comment") // comment after `panic!`
+ }
+}
diff --git a/src/tools/clippy/tests/ui/manual_bits.fixed b/src/tools/clippy/tests/ui/manual_bits.fixed
index 386360dbd..e7f8cd878 100644
--- a/src/tools/clippy/tests/ui/manual_bits.fixed
+++ b/src/tools/clippy/tests/ui/manual_bits.fixed
@@ -6,7 +6,8 @@
clippy::useless_conversion,
path_statements,
unused_must_use,
- clippy::unnecessary_operation
+ clippy::unnecessary_operation,
+ clippy::unnecessary_cast
)]
use std::mem::{size_of, size_of_val};
diff --git a/src/tools/clippy/tests/ui/manual_bits.rs b/src/tools/clippy/tests/ui/manual_bits.rs
index 62638f047..7b1d15495 100644
--- a/src/tools/clippy/tests/ui/manual_bits.rs
+++ b/src/tools/clippy/tests/ui/manual_bits.rs
@@ -6,7 +6,8 @@
clippy::useless_conversion,
path_statements,
unused_must_use,
- clippy::unnecessary_operation
+ clippy::unnecessary_operation,
+ clippy::unnecessary_cast
)]
use std::mem::{size_of, size_of_val};
diff --git a/src/tools/clippy/tests/ui/manual_bits.stderr b/src/tools/clippy/tests/ui/manual_bits.stderr
index 69c591a20..652fafbc4 100644
--- a/src/tools/clippy/tests/ui/manual_bits.stderr
+++ b/src/tools/clippy/tests/ui/manual_bits.stderr
@@ -1,5 +1,5 @@
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:15:5
+ --> $DIR/manual_bits.rs:16:5
|
LL | size_of::<i8>() * 8;
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `i8::BITS as usize`
@@ -7,169 +7,169 @@ LL | size_of::<i8>() * 8;
= note: `-D clippy::manual-bits` implied by `-D warnings`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:16:5
+ --> $DIR/manual_bits.rs:17:5
|
LL | size_of::<i16>() * 8;
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i16::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:17:5
+ --> $DIR/manual_bits.rs:18:5
|
LL | size_of::<i32>() * 8;
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i32::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:18:5
+ --> $DIR/manual_bits.rs:19:5
|
LL | size_of::<i64>() * 8;
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i64::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:19:5
+ --> $DIR/manual_bits.rs:20:5
|
LL | size_of::<i128>() * 8;
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `i128::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:20:5
+ --> $DIR/manual_bits.rs:21:5
|
LL | size_of::<isize>() * 8;
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `isize::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:22:5
+ --> $DIR/manual_bits.rs:23:5
|
LL | size_of::<u8>() * 8;
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `u8::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:23:5
+ --> $DIR/manual_bits.rs:24:5
|
LL | size_of::<u16>() * 8;
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u16::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:24:5
+ --> $DIR/manual_bits.rs:25:5
|
LL | size_of::<u32>() * 8;
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u32::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:25:5
+ --> $DIR/manual_bits.rs:26:5
|
LL | size_of::<u64>() * 8;
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u64::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:26:5
+ --> $DIR/manual_bits.rs:27:5
|
LL | size_of::<u128>() * 8;
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:27:5
+ --> $DIR/manual_bits.rs:28:5
|
LL | size_of::<usize>() * 8;
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `usize::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:29:5
+ --> $DIR/manual_bits.rs:30:5
|
LL | 8 * size_of::<i8>();
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `i8::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:30:5
+ --> $DIR/manual_bits.rs:31:5
|
LL | 8 * size_of::<i16>();
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i16::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:31:5
+ --> $DIR/manual_bits.rs:32:5
|
LL | 8 * size_of::<i32>();
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i32::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:32:5
+ --> $DIR/manual_bits.rs:33:5
|
LL | 8 * size_of::<i64>();
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i64::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:33:5
+ --> $DIR/manual_bits.rs:34:5
|
LL | 8 * size_of::<i128>();
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `i128::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:34:5
+ --> $DIR/manual_bits.rs:35:5
|
LL | 8 * size_of::<isize>();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `isize::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:36:5
+ --> $DIR/manual_bits.rs:37:5
|
LL | 8 * size_of::<u8>();
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `u8::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:37:5
+ --> $DIR/manual_bits.rs:38:5
|
LL | 8 * size_of::<u16>();
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u16::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:38:5
+ --> $DIR/manual_bits.rs:39:5
|
LL | 8 * size_of::<u32>();
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u32::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:39:5
+ --> $DIR/manual_bits.rs:40:5
|
LL | 8 * size_of::<u64>();
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u64::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:40:5
+ --> $DIR/manual_bits.rs:41:5
|
LL | 8 * size_of::<u128>();
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:41:5
+ --> $DIR/manual_bits.rs:42:5
|
LL | 8 * size_of::<usize>();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `usize::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:51:5
+ --> $DIR/manual_bits.rs:52:5
|
LL | size_of::<Word>() * 8;
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `Word::BITS as usize`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:55:18
+ --> $DIR/manual_bits.rs:56:18
|
LL | let _: u32 = (size_of::<u128>() * 8) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:56:18
+ --> $DIR/manual_bits.rs:57:18
|
LL | let _: u32 = (size_of::<u128>() * 8).try_into().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:57:13
+ --> $DIR/manual_bits.rs:58:13
|
LL | let _ = (size_of::<u128>() * 8).pow(5);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(u128::BITS as usize)`
error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
- --> $DIR/manual_bits.rs:58:14
+ --> $DIR/manual_bits.rs:59:14
|
LL | let _ = &(size_of::<u128>() * 8);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(u128::BITS as usize)`
diff --git a/src/tools/clippy/tests/ui/manual_clamp.rs b/src/tools/clippy/tests/ui/manual_clamp.rs
new file mode 100644
index 000000000..331fd29b7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_clamp.rs
@@ -0,0 +1,331 @@
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_clamp)]
+#![allow(
+ unused,
+ dead_code,
+ clippy::unnecessary_operation,
+ clippy::no_effect,
+ clippy::if_same_then_else
+)]
+
+use std::cmp::{max as cmp_max, min as cmp_min};
+
+const CONST_MAX: i32 = 10;
+const CONST_MIN: i32 = 4;
+
+const CONST_F64_MAX: f64 = 10.0;
+const CONST_F64_MIN: f64 = 4.0;
+
+fn main() {
+ let (input, min, max) = (0, -2, 3);
+ // Lint
+ let x0 = if max < input {
+ max
+ } else if min > input {
+ min
+ } else {
+ input
+ };
+
+ let x1 = if input > max {
+ max
+ } else if input < min {
+ min
+ } else {
+ input
+ };
+
+ let x2 = if input < min {
+ min
+ } else if input > max {
+ max
+ } else {
+ input
+ };
+
+ let x3 = if min > input {
+ min
+ } else if max < input {
+ max
+ } else {
+ input
+ };
+
+ let x4 = input.max(min).min(max);
+
+ let x5 = input.min(max).max(min);
+
+ let x6 = match input {
+ x if x > max => max,
+ x if x < min => min,
+ x => x,
+ };
+
+ let x7 = match input {
+ x if x < min => min,
+ x if x > max => max,
+ x => x,
+ };
+
+ let x8 = match input {
+ x if max < x => max,
+ x if min > x => min,
+ x => x,
+ };
+
+ let mut x9 = input;
+ if x9 < min {
+ x9 = min;
+ }
+ if x9 > max {
+ x9 = max;
+ }
+
+ let x10 = match input {
+ x if min > x => min,
+ x if max < x => max,
+ x => x,
+ };
+
+ let mut x11 = input;
+ let _ = 1;
+ if x11 > max {
+ x11 = max;
+ }
+ if x11 < min {
+ x11 = min;
+ }
+
+ let mut x12 = input;
+ if min > x12 {
+ x12 = min;
+ }
+ if max < x12 {
+ x12 = max;
+ }
+
+ let mut x13 = input;
+ if max < x13 {
+ x13 = max;
+ }
+ if min > x13 {
+ x13 = min;
+ }
+
+ let x14 = if input > CONST_MAX {
+ CONST_MAX
+ } else if input < CONST_MIN {
+ CONST_MIN
+ } else {
+ input
+ };
+ {
+ let (input, min, max) = (0.0f64, -2.0, 3.0);
+ let x15 = if input > max {
+ max
+ } else if input < min {
+ min
+ } else {
+ input
+ };
+ }
+ {
+ let input: i32 = cmp_min_max(1);
+ // These can only be detected if exactly one of the arguments to the inner function is const.
+ let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN);
+ let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX);
+ let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX));
+ let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN));
+ let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN);
+ let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX);
+ let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input));
+ let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input));
+ let input: f64 = cmp_min_max(1) as f64;
+ let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN);
+ let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX);
+ let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX));
+ let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN));
+ let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN);
+ let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX);
+ let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input));
+ let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input));
+ }
+ let mut x32 = input;
+ if x32 < min {
+ x32 = min;
+ } else if x32 > max {
+ x32 = max;
+ }
+
+ // It's important this be the last set of statements
+ let mut x33 = input;
+ if max < x33 {
+ x33 = max;
+ }
+ if min > x33 {
+ x33 = min;
+ }
+}
+
+// This code intentionally nonsense.
+fn no_lint() {
+ let (input, min, max) = (0, -2, 3);
+ let x0 = if max < input {
+ max
+ } else if min > input {
+ max
+ } else {
+ min
+ };
+
+ let x1 = if input > max {
+ max
+ } else if input > min {
+ min
+ } else {
+ max
+ };
+
+ let x2 = if max < min {
+ min
+ } else if input > max {
+ input
+ } else {
+ input
+ };
+
+ let x3 = if min > input {
+ input
+ } else if max < input {
+ max
+ } else {
+ max
+ };
+
+ let x6 = match input {
+ x if x < max => x,
+ x if x < min => x,
+ x => x,
+ };
+
+ let x7 = match input {
+ x if x < min => max,
+ x if x > max => min,
+ x => x,
+ };
+
+ let x8 = match input {
+ x if max > x => max,
+ x if min > x => min,
+ x => x,
+ };
+
+ let mut x9 = input;
+ if x9 > min {
+ x9 = min;
+ }
+ if x9 > max {
+ x9 = max;
+ }
+
+ let x10 = match input {
+ x if min > x => min,
+ x if max < x => max,
+ x => min,
+ };
+
+ let mut x11 = input;
+ if x11 > max {
+ x11 = min;
+ }
+ if x11 < min {
+ x11 = max;
+ }
+
+ let mut x12 = input;
+ if min > x12 {
+ x12 = max * 3;
+ }
+ if max < x12 {
+ x12 = min;
+ }
+
+ let mut x13 = input;
+ if max < x13 {
+ let x13 = max;
+ }
+ if min > x13 {
+ x13 = min;
+ }
+ let mut x14 = input;
+ if x14 < min {
+ x14 = 3;
+ } else if x14 > max {
+ x14 = max;
+ }
+ {
+ let input: i32 = cmp_min_max(1);
+ // These can only be detected if exactly one of the arguments to the inner function is const.
+ let x16 = cmp_max(cmp_max(input, CONST_MAX), CONST_MIN);
+ let x17 = cmp_min(cmp_min(input, CONST_MIN), CONST_MAX);
+ let x18 = cmp_max(CONST_MIN, cmp_max(input, CONST_MAX));
+ let x19 = cmp_min(CONST_MAX, cmp_min(input, CONST_MIN));
+ let x20 = cmp_max(cmp_max(CONST_MAX, input), CONST_MIN);
+ let x21 = cmp_min(cmp_min(CONST_MIN, input), CONST_MAX);
+ let x22 = cmp_max(CONST_MIN, cmp_max(CONST_MAX, input));
+ let x23 = cmp_min(CONST_MAX, cmp_min(CONST_MIN, input));
+ let input: f64 = cmp_min_max(1) as f64;
+ let x24 = f64::max(f64::max(input, CONST_F64_MAX), CONST_F64_MIN);
+ let x25 = f64::min(f64::min(input, CONST_F64_MIN), CONST_F64_MAX);
+ let x26 = f64::max(CONST_F64_MIN, f64::max(input, CONST_F64_MAX));
+ let x27 = f64::min(CONST_F64_MAX, f64::min(input, CONST_F64_MIN));
+ let x28 = f64::max(f64::max(CONST_F64_MAX, input), CONST_F64_MIN);
+ let x29 = f64::min(f64::min(CONST_F64_MIN, input), CONST_F64_MAX);
+ let x30 = f64::max(CONST_F64_MIN, f64::max(CONST_F64_MAX, input));
+ let x31 = f64::min(CONST_F64_MAX, f64::min(CONST_F64_MIN, input));
+ let x32 = f64::min(CONST_F64_MAX, f64::min(CONST_F64_MIN, CONST_F64_MAX));
+ }
+}
+
+fn dont_tell_me_what_to_do() {
+ let (input, min, max) = (0, -2, 3);
+ let mut x_never = input;
+ #[allow(clippy::manual_clamp)]
+ if x_never < min {
+ x_never = min;
+ }
+ if x_never > max {
+ x_never = max;
+ }
+}
+
+/// Just to ensure this isn't const evaled
+fn cmp_min_max(input: i32) -> i32 {
+ input * 3
+}
+
+fn msrv_1_49() {
+ #![clippy::msrv = "1.49"]
+
+ let (input, min, max) = (0, -1, 2);
+ let _ = if input < min {
+ min
+ } else if input > max {
+ max
+ } else {
+ input
+ };
+}
+
+fn msrv_1_50() {
+ #![clippy::msrv = "1.50"]
+
+ let (input, min, max) = (0, -1, 2);
+ let _ = if input < min {
+ min
+ } else if input > max {
+ max
+ } else {
+ input
+ };
+}
diff --git a/src/tools/clippy/tests/ui/manual_clamp.stderr b/src/tools/clippy/tests/ui/manual_clamp.stderr
new file mode 100644
index 000000000..70abe2809
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_clamp.stderr
@@ -0,0 +1,390 @@
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:77:5
+ |
+LL | / if x9 < min {
+LL | | x9 = min;
+LL | | }
+LL | | if x9 > max {
+LL | | x9 = max;
+LL | | }
+ | |_____^ help: replace with clamp: `x9 = x9.clamp(min, max);`
+ |
+ = note: clamp will panic if max < min
+ = note: `-D clippy::manual-clamp` implied by `-D warnings`
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:92:5
+ |
+LL | / if x11 > max {
+LL | | x11 = max;
+LL | | }
+LL | | if x11 < min {
+LL | | x11 = min;
+LL | | }
+ | |_____^ help: replace with clamp: `x11 = x11.clamp(min, max);`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:100:5
+ |
+LL | / if min > x12 {
+LL | | x12 = min;
+LL | | }
+LL | | if max < x12 {
+LL | | x12 = max;
+LL | | }
+ | |_____^ help: replace with clamp: `x12 = x12.clamp(min, max);`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:108:5
+ |
+LL | / if max < x13 {
+LL | | x13 = max;
+LL | | }
+LL | | if min > x13 {
+LL | | x13 = min;
+LL | | }
+ | |_____^ help: replace with clamp: `x13 = x13.clamp(min, max);`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:162:5
+ |
+LL | / if max < x33 {
+LL | | x33 = max;
+LL | | }
+LL | | if min > x33 {
+LL | | x33 = min;
+LL | | }
+ | |_____^ help: replace with clamp: `x33 = x33.clamp(min, max);`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:22:14
+ |
+LL | let x0 = if max < input {
+ | ______________^
+LL | | max
+LL | | } else if min > input {
+LL | | min
+LL | | } else {
+LL | | input
+LL | | };
+ | |_____^ help: replace with clamp: `input.clamp(min, max)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:30:14
+ |
+LL | let x1 = if input > max {
+ | ______________^
+LL | | max
+LL | | } else if input < min {
+LL | | min
+LL | | } else {
+LL | | input
+LL | | };
+ | |_____^ help: replace with clamp: `input.clamp(min, max)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:38:14
+ |
+LL | let x2 = if input < min {
+ | ______________^
+LL | | min
+LL | | } else if input > max {
+LL | | max
+LL | | } else {
+LL | | input
+LL | | };
+ | |_____^ help: replace with clamp: `input.clamp(min, max)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:46:14
+ |
+LL | let x3 = if min > input {
+ | ______________^
+LL | | min
+LL | | } else if max < input {
+LL | | max
+LL | | } else {
+LL | | input
+LL | | };
+ | |_____^ help: replace with clamp: `input.clamp(min, max)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:54:14
+ |
+LL | let x4 = input.max(min).min(max);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(min, max)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:56:14
+ |
+LL | let x5 = input.min(max).max(min);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(min, max)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:58:14
+ |
+LL | let x6 = match input {
+ | ______________^
+LL | | x if x > max => max,
+LL | | x if x < min => min,
+LL | | x => x,
+LL | | };
+ | |_____^ help: replace with clamp: `input.clamp(min, max)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:64:14
+ |
+LL | let x7 = match input {
+ | ______________^
+LL | | x if x < min => min,
+LL | | x if x > max => max,
+LL | | x => x,
+LL | | };
+ | |_____^ help: replace with clamp: `input.clamp(min, max)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:70:14
+ |
+LL | let x8 = match input {
+ | ______________^
+LL | | x if max < x => max,
+LL | | x if min > x => min,
+LL | | x => x,
+LL | | };
+ | |_____^ help: replace with clamp: `input.clamp(min, max)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:84:15
+ |
+LL | let x10 = match input {
+ | _______________^
+LL | | x if min > x => min,
+LL | | x if max < x => max,
+LL | | x => x,
+LL | | };
+ | |_____^ help: replace with clamp: `input.clamp(min, max)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:115:15
+ |
+LL | let x14 = if input > CONST_MAX {
+ | _______________^
+LL | | CONST_MAX
+LL | | } else if input < CONST_MIN {
+LL | | CONST_MIN
+LL | | } else {
+LL | | input
+LL | | };
+ | |_____^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:124:19
+ |
+LL | let x15 = if input > max {
+ | ___________________^
+LL | | max
+LL | | } else if input < min {
+LL | | min
+LL | | } else {
+LL | | input
+LL | | };
+ | |_________^ help: replace with clamp: `input.clamp(min, max)`
+ |
+ = note: clamp will panic if max < min, min.is_nan(), or max.is_nan()
+ = note: clamp returns NaN if the input is NaN
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:135:19
+ |
+LL | let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:136:19
+ |
+LL | let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:137:19
+ |
+LL | let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:138:19
+ |
+LL | let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:139:19
+ |
+LL | let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:140:19
+ |
+LL | let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:141:19
+ |
+LL | let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:142:19
+ |
+LL | let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:144:19
+ |
+LL | let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
+ |
+ = note: clamp will panic if max < min, min.is_nan(), or max.is_nan()
+ = note: clamp returns NaN if the input is NaN
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:145:19
+ |
+LL | let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
+ |
+ = note: clamp will panic if max < min, min.is_nan(), or max.is_nan()
+ = note: clamp returns NaN if the input is NaN
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:146:19
+ |
+LL | let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
+ |
+ = note: clamp will panic if max < min, min.is_nan(), or max.is_nan()
+ = note: clamp returns NaN if the input is NaN
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:147:19
+ |
+LL | let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
+ |
+ = note: clamp will panic if max < min, min.is_nan(), or max.is_nan()
+ = note: clamp returns NaN if the input is NaN
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:148:19
+ |
+LL | let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
+ |
+ = note: clamp will panic if max < min, min.is_nan(), or max.is_nan()
+ = note: clamp returns NaN if the input is NaN
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:149:19
+ |
+LL | let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
+ |
+ = note: clamp will panic if max < min, min.is_nan(), or max.is_nan()
+ = note: clamp returns NaN if the input is NaN
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:150:19
+ |
+LL | let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
+ |
+ = note: clamp will panic if max < min, min.is_nan(), or max.is_nan()
+ = note: clamp returns NaN if the input is NaN
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:151:19
+ |
+LL | let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
+ |
+ = note: clamp will panic if max < min, min.is_nan(), or max.is_nan()
+ = note: clamp returns NaN if the input is NaN
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:154:5
+ |
+LL | / if x32 < min {
+LL | | x32 = min;
+LL | | } else if x32 > max {
+LL | | x32 = max;
+LL | | }
+ | |_____^ help: replace with clamp: `x32 = x32.clamp(min, max);`
+ |
+ = note: clamp will panic if max < min
+
+error: clamp-like pattern without using clamp function
+ --> $DIR/manual_clamp.rs:324:13
+ |
+LL | let _ = if input < min {
+ | _____________^
+LL | | min
+LL | | } else if input > max {
+LL | | max
+LL | | } else {
+LL | | input
+LL | | };
+ | |_____^ help: replace with clamp: `input.clamp(min, max)`
+ |
+ = note: clamp will panic if max < min
+
+error: aborting due to 35 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_filter.fixed b/src/tools/clippy/tests/ui/manual_filter.fixed
new file mode 100644
index 000000000..3553291b8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_filter.fixed
@@ -0,0 +1,119 @@
+// run-rustfix
+
+#![warn(clippy::manual_filter)]
+#![allow(unused_variables, dead_code)]
+
+fn main() {
+ Some(0).filter(|&x| x <= 0);
+
+ Some(1).filter(|&x| x <= 0);
+
+ Some(2).filter(|&x| x <= 0);
+
+ Some(3).filter(|&x| x > 0);
+
+ let y = Some(4);
+ y.filter(|&x| x <= 0);
+
+ Some(5).filter(|&x| x > 0);
+
+ Some(6).as_ref().filter(|&x| x > &0);
+
+ let external_cond = true;
+ Some(String::new()).filter(|x| external_cond);
+
+ Some(7).filter(|&x| external_cond);
+
+ Some(8).filter(|&x| x != 0);
+
+ Some(9).filter(|&x| x > 10 && x < 100);
+
+ const fn f1() {
+ // Don't lint, `.filter` is not const
+ match Some(10) {
+ Some(x) => {
+ if x > 10 && x < 100 {
+ Some(x)
+ } else {
+ None
+ }
+ },
+ None => None,
+ };
+ }
+
+ #[allow(clippy::blocks_in_if_conditions)]
+ Some(11).filter(|&x| {
+ println!("foo");
+ x > 10 && x < 100
+ });
+
+ match Some(12) {
+ // Don't Lint, statement is lost by `.filter`
+ Some(x) => {
+ if x > 10 && x < 100 {
+ println!("foo");
+ Some(x)
+ } else {
+ None
+ }
+ },
+ None => None,
+ };
+
+ match Some(13) {
+ // Don't Lint, because of `None => Some(1)`
+ Some(x) => {
+ if x > 10 && x < 100 {
+ println!("foo");
+ Some(x)
+ } else {
+ None
+ }
+ },
+ None => Some(1),
+ };
+
+ unsafe fn f(x: u32) -> bool {
+ true
+ }
+ let _ = Some(14).filter(|&x| unsafe { f(x) });
+ let _ = Some(15).filter(|&x| unsafe { f(x) });
+
+ #[allow(clippy::redundant_pattern_matching)]
+ if let Some(_) = Some(16) {
+ Some(16)
+ } else { Some(16).filter(|&x| x % 2 == 0) };
+
+ match Some((17, 17)) {
+ // Not linted for now could be
+ Some((x, y)) => {
+ if y != x {
+ Some((x, y))
+ } else {
+ None
+ }
+ },
+ None => None,
+ };
+
+ struct NamedTuple {
+ pub x: u8,
+ pub y: (i32, u32),
+ }
+
+ match Some(NamedTuple {
+ // Not linted for now could be
+ x: 17,
+ y: (18, 19),
+ }) {
+ Some(NamedTuple { x, y }) => {
+ if y.1 != x as u32 {
+ Some(NamedTuple { x, y })
+ } else {
+ None
+ }
+ },
+ None => None,
+ };
+}
diff --git a/src/tools/clippy/tests/ui/manual_filter.rs b/src/tools/clippy/tests/ui/manual_filter.rs
new file mode 100644
index 000000000..aa9f90f75
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_filter.rs
@@ -0,0 +1,243 @@
+// run-rustfix
+
+#![warn(clippy::manual_filter)]
+#![allow(unused_variables, dead_code)]
+
+fn main() {
+ match Some(0) {
+ None => None,
+ Some(x) => {
+ if x > 0 {
+ None
+ } else {
+ Some(x)
+ }
+ },
+ };
+
+ match Some(1) {
+ Some(x) => {
+ if x > 0 {
+ None
+ } else {
+ Some(x)
+ }
+ },
+ None => None,
+ };
+
+ match Some(2) {
+ Some(x) => {
+ if x > 0 {
+ None
+ } else {
+ Some(x)
+ }
+ },
+ _ => None,
+ };
+
+ match Some(3) {
+ Some(x) => {
+ if x > 0 {
+ Some(x)
+ } else {
+ None
+ }
+ },
+ None => None,
+ };
+
+ let y = Some(4);
+ match y {
+ // Some(4)
+ None => None,
+ Some(x) => {
+ if x > 0 {
+ None
+ } else {
+ Some(x)
+ }
+ },
+ };
+
+ match Some(5) {
+ Some(x) => {
+ if x > 0 {
+ Some(x)
+ } else {
+ None
+ }
+ },
+ _ => None,
+ };
+
+ match Some(6) {
+ Some(ref x) => {
+ if x > &0 {
+ Some(x)
+ } else {
+ None
+ }
+ },
+ _ => None,
+ };
+
+ let external_cond = true;
+ match Some(String::new()) {
+ Some(x) => {
+ if external_cond {
+ Some(x)
+ } else {
+ None
+ }
+ },
+ _ => None,
+ };
+
+ if let Some(x) = Some(7) {
+ if external_cond { Some(x) } else { None }
+ } else {
+ None
+ };
+
+ match &Some(8) {
+ &Some(x) => {
+ if x != 0 {
+ Some(x)
+ } else {
+ None
+ }
+ },
+ _ => None,
+ };
+
+ match Some(9) {
+ Some(x) => {
+ if x > 10 && x < 100 {
+ Some(x)
+ } else {
+ None
+ }
+ },
+ None => None,
+ };
+
+ const fn f1() {
+ // Don't lint, `.filter` is not const
+ match Some(10) {
+ Some(x) => {
+ if x > 10 && x < 100 {
+ Some(x)
+ } else {
+ None
+ }
+ },
+ None => None,
+ };
+ }
+
+ #[allow(clippy::blocks_in_if_conditions)]
+ match Some(11) {
+ // Lint, statement is preserved by `.filter`
+ Some(x) => {
+ if {
+ println!("foo");
+ x > 10 && x < 100
+ } {
+ Some(x)
+ } else {
+ None
+ }
+ },
+ None => None,
+ };
+
+ match Some(12) {
+ // Don't Lint, statement is lost by `.filter`
+ Some(x) => {
+ if x > 10 && x < 100 {
+ println!("foo");
+ Some(x)
+ } else {
+ None
+ }
+ },
+ None => None,
+ };
+
+ match Some(13) {
+ // Don't Lint, because of `None => Some(1)`
+ Some(x) => {
+ if x > 10 && x < 100 {
+ println!("foo");
+ Some(x)
+ } else {
+ None
+ }
+ },
+ None => Some(1),
+ };
+
+ unsafe fn f(x: u32) -> bool {
+ true
+ }
+ let _ = match Some(14) {
+ Some(x) => {
+ if unsafe { f(x) } {
+ Some(x)
+ } else {
+ None
+ }
+ },
+ None => None,
+ };
+ let _ = match Some(15) {
+ Some(x) => unsafe {
+ if f(x) { Some(x) } else { None }
+ },
+ None => None,
+ };
+
+ #[allow(clippy::redundant_pattern_matching)]
+ if let Some(_) = Some(16) {
+ Some(16)
+ } else if let Some(x) = Some(16) {
+ // Lint starting from here
+ if x % 2 == 0 { Some(x) } else { None }
+ } else {
+ None
+ };
+
+ match Some((17, 17)) {
+ // Not linted for now could be
+ Some((x, y)) => {
+ if y != x {
+ Some((x, y))
+ } else {
+ None
+ }
+ },
+ None => None,
+ };
+
+ struct NamedTuple {
+ pub x: u8,
+ pub y: (i32, u32),
+ }
+
+ match Some(NamedTuple {
+ // Not linted for now could be
+ x: 17,
+ y: (18, 19),
+ }) {
+ Some(NamedTuple { x, y }) => {
+ if y.1 != x as u32 {
+ Some(NamedTuple { x, y })
+ } else {
+ None
+ }
+ },
+ None => None,
+ };
+}
diff --git a/src/tools/clippy/tests/ui/manual_filter.stderr b/src/tools/clippy/tests/ui/manual_filter.stderr
new file mode 100644
index 000000000..53dea9229
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_filter.stderr
@@ -0,0 +1,191 @@
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:7:5
+ |
+LL | / match Some(0) {
+LL | | None => None,
+LL | | Some(x) => {
+LL | | if x > 0 {
+... |
+LL | | },
+LL | | };
+ | |_____^ help: try this: `Some(0).filter(|&x| x <= 0)`
+ |
+ = note: `-D clippy::manual-filter` implied by `-D warnings`
+
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:18:5
+ |
+LL | / match Some(1) {
+LL | | Some(x) => {
+LL | | if x > 0 {
+LL | | None
+... |
+LL | | None => None,
+LL | | };
+ | |_____^ help: try this: `Some(1).filter(|&x| x <= 0)`
+
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:29:5
+ |
+LL | / match Some(2) {
+LL | | Some(x) => {
+LL | | if x > 0 {
+LL | | None
+... |
+LL | | _ => None,
+LL | | };
+ | |_____^ help: try this: `Some(2).filter(|&x| x <= 0)`
+
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:40:5
+ |
+LL | / match Some(3) {
+LL | | Some(x) => {
+LL | | if x > 0 {
+LL | | Some(x)
+... |
+LL | | None => None,
+LL | | };
+ | |_____^ help: try this: `Some(3).filter(|&x| x > 0)`
+
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:52:5
+ |
+LL | / match y {
+LL | | // Some(4)
+LL | | None => None,
+LL | | Some(x) => {
+... |
+LL | | },
+LL | | };
+ | |_____^ help: try this: `y.filter(|&x| x <= 0)`
+
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:64:5
+ |
+LL | / match Some(5) {
+LL | | Some(x) => {
+LL | | if x > 0 {
+LL | | Some(x)
+... |
+LL | | _ => None,
+LL | | };
+ | |_____^ help: try this: `Some(5).filter(|&x| x > 0)`
+
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:75:5
+ |
+LL | / match Some(6) {
+LL | | Some(ref x) => {
+LL | | if x > &0 {
+LL | | Some(x)
+... |
+LL | | _ => None,
+LL | | };
+ | |_____^ help: try this: `Some(6).as_ref().filter(|&x| x > &0)`
+
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:87:5
+ |
+LL | / match Some(String::new()) {
+LL | | Some(x) => {
+LL | | if external_cond {
+LL | | Some(x)
+... |
+LL | | _ => None,
+LL | | };
+ | |_____^ help: try this: `Some(String::new()).filter(|x| external_cond)`
+
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:98:5
+ |
+LL | / if let Some(x) = Some(7) {
+LL | | if external_cond { Some(x) } else { None }
+LL | | } else {
+LL | | None
+LL | | };
+ | |_____^ help: try this: `Some(7).filter(|&x| external_cond)`
+
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:104:5
+ |
+LL | / match &Some(8) {
+LL | | &Some(x) => {
+LL | | if x != 0 {
+LL | | Some(x)
+... |
+LL | | _ => None,
+LL | | };
+ | |_____^ help: try this: `Some(8).filter(|&x| x != 0)`
+
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:115:5
+ |
+LL | / match Some(9) {
+LL | | Some(x) => {
+LL | | if x > 10 && x < 100 {
+LL | | Some(x)
+... |
+LL | | None => None,
+LL | | };
+ | |_____^ help: try this: `Some(9).filter(|&x| x > 10 && x < 100)`
+
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:141:5
+ |
+LL | / match Some(11) {
+LL | | // Lint, statement is preserved by `.filter`
+LL | | Some(x) => {
+LL | | if {
+... |
+LL | | None => None,
+LL | | };
+ | |_____^
+ |
+help: try this
+ |
+LL ~ Some(11).filter(|&x| {
+LL + println!("foo");
+LL + x > 10 && x < 100
+LL ~ });
+ |
+
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:185:13
+ |
+LL | let _ = match Some(14) {
+ | _____________^
+LL | | Some(x) => {
+LL | | if unsafe { f(x) } {
+LL | | Some(x)
+... |
+LL | | None => None,
+LL | | };
+ | |_____^ help: try this: `Some(14).filter(|&x| unsafe { f(x) })`
+
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:195:13
+ |
+LL | let _ = match Some(15) {
+ | _____________^
+LL | | Some(x) => unsafe {
+LL | | if f(x) { Some(x) } else { None }
+LL | | },
+LL | | None => None,
+LL | | };
+ | |_____^ help: try this: `Some(15).filter(|&x| unsafe { f(x) })`
+
+error: manual implementation of `Option::filter`
+ --> $DIR/manual_filter.rs:205:12
+ |
+LL | } else if let Some(x) = Some(16) {
+ | ____________^
+LL | | // Lint starting from here
+LL | | if x % 2 == 0 { Some(x) } else { None }
+LL | | } else {
+LL | | None
+LL | | };
+ | |_____^ help: try this: `{ Some(16).filter(|&x| x % 2 == 0) }`
+
+error: aborting due to 15 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_find.stderr b/src/tools/clippy/tests/ui/manual_find.stderr
index da0fd4aae..ea04bb066 100644
--- a/src/tools/clippy/tests/ui/manual_find.stderr
+++ b/src/tools/clippy/tests/ui/manual_find.stderr
@@ -9,8 +9,8 @@ LL | | }
LL | | None
| |________^ help: replace with an iterator: `strings.into_iter().find(|s| s == String::new())`
|
- = note: `-D clippy::manual-find` implied by `-D warnings`
= note: you may need to dereference some variables
+ = note: `-D clippy::manual-find` implied by `-D warnings`
error: manual implementation of `Iterator::find`
--> $DIR/manual_find.rs:14:5
diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.fixed b/src/tools/clippy/tests/ui/manual_find_fixable.fixed
index 36d1644c2..2bce6e624 100644
--- a/src/tools/clippy/tests/ui/manual_find_fixable.fixed
+++ b/src/tools/clippy/tests/ui/manual_find_fixable.fixed
@@ -1,7 +1,7 @@
// run-rustfix
-
-#![allow(unused, clippy::needless_return)]
#![warn(clippy::manual_find)]
+#![allow(unused)]
+#![allow(clippy::needless_return, clippy::uninlined_format_args)]
use std::collections::HashMap;
diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.rs b/src/tools/clippy/tests/ui/manual_find_fixable.rs
index ed277ddaa..f5c6de37a 100644
--- a/src/tools/clippy/tests/ui/manual_find_fixable.rs
+++ b/src/tools/clippy/tests/ui/manual_find_fixable.rs
@@ -1,7 +1,7 @@
// run-rustfix
-
-#![allow(unused, clippy::needless_return)]
#![warn(clippy::manual_find)]
+#![allow(unused)]
+#![allow(clippy::needless_return, clippy::uninlined_format_args)]
use std::collections::HashMap;
diff --git a/src/tools/clippy/tests/ui/manual_flatten.rs b/src/tools/clippy/tests/ui/manual_flatten.rs
index d922593bc..96cd87c0e 100644
--- a/src/tools/clippy/tests/ui/manual_flatten.rs
+++ b/src/tools/clippy/tests/ui/manual_flatten.rs
@@ -1,5 +1,5 @@
#![warn(clippy::manual_flatten)]
-#![allow(clippy::useless_vec)]
+#![allow(clippy::useless_vec, clippy::uninlined_format_args)]
fn main() {
// Test for loop over implicitly adjusted `Iterator` with `if let` expression
diff --git a/src/tools/clippy/tests/ui/manual_flatten.stderr b/src/tools/clippy/tests/ui/manual_flatten.stderr
index da053c056..180a6ff4e 100644
--- a/src/tools/clippy/tests/ui/manual_flatten.stderr
+++ b/src/tools/clippy/tests/ui/manual_flatten.stderr
@@ -11,7 +11,6 @@ LL | | }
LL | | }
| |_____^
|
- = note: `-D clippy::manual-flatten` implied by `-D warnings`
help: ...and remove the `if let` statement in the for loop
--> $DIR/manual_flatten.rs:8:9
|
@@ -19,6 +18,7 @@ LL | / if let Some(y) = n {
LL | | println!("{}", y);
LL | | }
| |_________^
+ = note: `-D clippy::manual-flatten` implied by `-D warnings`
error: unnecessary `if let` since only the `Ok` variant of the iterator element is used
--> $DIR/manual_flatten.rs:15:5
diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed b/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed
new file mode 100644
index 000000000..0fa776b7b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed
@@ -0,0 +1,27 @@
+// run-rustfix
+#![warn(clippy::manual_instant_elapsed)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(unused_variables)]
+#![allow(unused_must_use)]
+
+use std::time::Instant;
+
+fn main() {
+ let prev_instant = Instant::now();
+
+ {
+ // don't influence
+ let another_instant = Instant::now();
+ }
+
+ let duration = prev_instant.elapsed();
+
+ // don't catch
+ let duration = prev_instant.elapsed();
+
+ Instant::now() - duration;
+
+ let ref_to_instant = &Instant::now();
+
+ (*ref_to_instant).elapsed(); // to ensure parens are added correctly
+}
diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.rs b/src/tools/clippy/tests/ui/manual_instant_elapsed.rs
new file mode 100644
index 000000000..5b11b8453
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.rs
@@ -0,0 +1,27 @@
+// run-rustfix
+#![warn(clippy::manual_instant_elapsed)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(unused_variables)]
+#![allow(unused_must_use)]
+
+use std::time::Instant;
+
+fn main() {
+ let prev_instant = Instant::now();
+
+ {
+ // don't influence
+ let another_instant = Instant::now();
+ }
+
+ let duration = Instant::now() - prev_instant;
+
+ // don't catch
+ let duration = prev_instant.elapsed();
+
+ Instant::now() - duration;
+
+ let ref_to_instant = &Instant::now();
+
+ Instant::now() - *ref_to_instant; // to ensure parens are added correctly
+}
diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr b/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr
new file mode 100644
index 000000000..5537f5642
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr
@@ -0,0 +1,16 @@
+error: manual implementation of `Instant::elapsed`
+ --> $DIR/manual_instant_elapsed.rs:17:20
+ |
+LL | let duration = Instant::now() - prev_instant;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `prev_instant.elapsed()`
+ |
+ = note: `-D clippy::manual-instant-elapsed` implied by `-D warnings`
+
+error: manual implementation of `Instant::elapsed`
+ --> $DIR/manual_instant_elapsed.rs:26:5
+ |
+LL | Instant::now() - *ref_to_instant; // to ensure parens are added correctly
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*ref_to_instant).elapsed()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_map_option.fixed b/src/tools/clippy/tests/ui/manual_map_option.fixed
index a59da4ae1..e12ea7ec1 100644
--- a/src/tools/clippy/tests/ui/manual_map_option.fixed
+++ b/src/tools/clippy/tests/ui/manual_map_option.fixed
@@ -7,7 +7,7 @@
clippy::unit_arg,
clippy::match_ref_pats,
clippy::redundant_pattern_matching,
- clippy::for_loops_over_fallibles,
+ for_loops_over_fallibles,
dead_code
)]
diff --git a/src/tools/clippy/tests/ui/manual_map_option.rs b/src/tools/clippy/tests/ui/manual_map_option.rs
index 0bdbefa51..325a6db06 100644
--- a/src/tools/clippy/tests/ui/manual_map_option.rs
+++ b/src/tools/clippy/tests/ui/manual_map_option.rs
@@ -7,7 +7,7 @@
clippy::unit_arg,
clippy::match_ref_pats,
clippy::redundant_pattern_matching,
- clippy::for_loops_over_fallibles,
+ for_loops_over_fallibles,
dead_code
)]
diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr
index 144fe86df..087f766be 100644
--- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr
+++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr
@@ -13,12 +13,12 @@ LL | | _C,
LL | | }
| |_^
|
- = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings`
help: remove this variant
--> $DIR/manual_non_exhaustive_enum.rs:9:5
|
LL | _C,
| ^^
+ = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings`
error: this seems like a manual implementation of the non-exhaustive pattern
--> $DIR/manual_non_exhaustive_enum.rs:14:1
diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr b/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr
index e0766c17b..d0bed8e11 100644
--- a/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr
+++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_struct.stderr
@@ -12,12 +12,12 @@ LL | | _c: (),
LL | | }
| |_____^
|
- = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings`
help: remove this field
--> $DIR/manual_non_exhaustive_struct.rs:8:9
|
LL | _c: (),
| ^^^^^^
+ = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings`
error: this seems like a manual implementation of the non-exhaustive pattern
--> $DIR/manual_non_exhaustive_struct.rs:13:5
diff --git a/src/tools/clippy/tests/ui/manual_ok_or.fixed b/src/tools/clippy/tests/ui/manual_ok_or.fixed
index 887a97d7a..d864f8554 100644
--- a/src/tools/clippy/tests/ui/manual_ok_or.fixed
+++ b/src/tools/clippy/tests/ui/manual_ok_or.fixed
@@ -1,6 +1,6 @@
// run-rustfix
#![warn(clippy::manual_ok_or)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
#![allow(clippy::redundant_closure)]
#![allow(dead_code)]
#![allow(unused_must_use)]
diff --git a/src/tools/clippy/tests/ui/manual_ok_or.rs b/src/tools/clippy/tests/ui/manual_ok_or.rs
index 3c99872f5..626476846 100644
--- a/src/tools/clippy/tests/ui/manual_ok_or.rs
+++ b/src/tools/clippy/tests/ui/manual_ok_or.rs
@@ -1,6 +1,6 @@
// run-rustfix
#![warn(clippy::manual_ok_or)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
#![allow(clippy::redundant_closure)]
#![allow(dead_code)]
#![allow(unused_must_use)]
diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.fixed b/src/tools/clippy/tests/ui/manual_rem_euclid.fixed
index 5601c96c1..b942fbfe9 100644
--- a/src/tools/clippy/tests/ui/manual_rem_euclid.fixed
+++ b/src/tools/clippy/tests/ui/manual_rem_euclid.fixed
@@ -1,6 +1,7 @@
// run-rustfix
// aux-build:macro_rules.rs
+#![feature(custom_inner_attributes)]
#![warn(clippy::manual_rem_euclid)]
#[macro_use]
@@ -53,3 +54,32 @@ pub fn rem_euclid_4(num: i32) -> i32 {
pub const fn const_rem_euclid_4(num: i32) -> i32 {
num.rem_euclid(4)
}
+
+pub fn msrv_1_37() {
+ #![clippy::msrv = "1.37"]
+
+ let x: i32 = 10;
+ let _: i32 = ((x % 4) + 4) % 4;
+}
+
+pub fn msrv_1_38() {
+ #![clippy::msrv = "1.38"]
+
+ let x: i32 = 10;
+ let _: i32 = x.rem_euclid(4);
+}
+
+// For const fns:
+pub const fn msrv_1_51() {
+ #![clippy::msrv = "1.51"]
+
+ let x: i32 = 10;
+ let _: i32 = ((x % 4) + 4) % 4;
+}
+
+pub const fn msrv_1_52() {
+ #![clippy::msrv = "1.52"]
+
+ let x: i32 = 10;
+ let _: i32 = x.rem_euclid(4);
+}
diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.rs b/src/tools/clippy/tests/ui/manual_rem_euclid.rs
index 52135be26..7462d5321 100644
--- a/src/tools/clippy/tests/ui/manual_rem_euclid.rs
+++ b/src/tools/clippy/tests/ui/manual_rem_euclid.rs
@@ -1,6 +1,7 @@
// run-rustfix
// aux-build:macro_rules.rs
+#![feature(custom_inner_attributes)]
#![warn(clippy::manual_rem_euclid)]
#[macro_use]
@@ -53,3 +54,32 @@ pub fn rem_euclid_4(num: i32) -> i32 {
pub const fn const_rem_euclid_4(num: i32) -> i32 {
((num % 4) + 4) % 4
}
+
+pub fn msrv_1_37() {
+ #![clippy::msrv = "1.37"]
+
+ let x: i32 = 10;
+ let _: i32 = ((x % 4) + 4) % 4;
+}
+
+pub fn msrv_1_38() {
+ #![clippy::msrv = "1.38"]
+
+ let x: i32 = 10;
+ let _: i32 = ((x % 4) + 4) % 4;
+}
+
+// For const fns:
+pub const fn msrv_1_51() {
+ #![clippy::msrv = "1.51"]
+
+ let x: i32 = 10;
+ let _: i32 = ((x % 4) + 4) % 4;
+}
+
+pub const fn msrv_1_52() {
+ #![clippy::msrv = "1.52"]
+
+ let x: i32 = 10;
+ let _: i32 = ((x % 4) + 4) % 4;
+}
diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.stderr b/src/tools/clippy/tests/ui/manual_rem_euclid.stderr
index a237fd021..d51bac03b 100644
--- a/src/tools/clippy/tests/ui/manual_rem_euclid.stderr
+++ b/src/tools/clippy/tests/ui/manual_rem_euclid.stderr
@@ -1,5 +1,5 @@
error: manual `rem_euclid` implementation
- --> $DIR/manual_rem_euclid.rs:19:18
+ --> $DIR/manual_rem_euclid.rs:20:18
|
LL | let _: i32 = ((value % 4) + 4) % 4;
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
@@ -7,31 +7,31 @@ LL | let _: i32 = ((value % 4) + 4) % 4;
= note: `-D clippy::manual-rem-euclid` implied by `-D warnings`
error: manual `rem_euclid` implementation
- --> $DIR/manual_rem_euclid.rs:20:18
+ --> $DIR/manual_rem_euclid.rs:21:18
|
LL | let _: i32 = (4 + (value % 4)) % 4;
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
error: manual `rem_euclid` implementation
- --> $DIR/manual_rem_euclid.rs:21:18
+ --> $DIR/manual_rem_euclid.rs:22:18
|
LL | let _: i32 = (value % 4 + 4) % 4;
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
error: manual `rem_euclid` implementation
- --> $DIR/manual_rem_euclid.rs:22:18
+ --> $DIR/manual_rem_euclid.rs:23:18
|
LL | let _: i32 = (4 + value % 4) % 4;
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
error: manual `rem_euclid` implementation
- --> $DIR/manual_rem_euclid.rs:23:22
+ --> $DIR/manual_rem_euclid.rs:24:22
|
LL | let _: i32 = 1 + (4 + value % 4) % 4;
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
error: manual `rem_euclid` implementation
- --> $DIR/manual_rem_euclid.rs:12:22
+ --> $DIR/manual_rem_euclid.rs:13:22
|
LL | let _: i32 = ((value % 4) + 4) % 4;
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
@@ -42,16 +42,28 @@ LL | internal_rem_euclid!();
= note: this error originates in the macro `internal_rem_euclid` (in Nightly builds, run with -Z macro-backtrace for more info)
error: manual `rem_euclid` implementation
- --> $DIR/manual_rem_euclid.rs:49:5
+ --> $DIR/manual_rem_euclid.rs:50:5
|
LL | ((num % 4) + 4) % 4
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `num.rem_euclid(4)`
error: manual `rem_euclid` implementation
- --> $DIR/manual_rem_euclid.rs:54:5
+ --> $DIR/manual_rem_euclid.rs:55:5
|
LL | ((num % 4) + 4) % 4
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `num.rem_euclid(4)`
-error: aborting due to 8 previous errors
+error: manual `rem_euclid` implementation
+ --> $DIR/manual_rem_euclid.rs:69:18
+ |
+LL | let _: i32 = ((x % 4) + 4) % 4;
+ | ^^^^^^^^^^^^^^^^^ help: consider using: `x.rem_euclid(4)`
+
+error: manual `rem_euclid` implementation
+ --> $DIR/manual_rem_euclid.rs:84:18
+ |
+LL | let _: i32 = ((x % 4) + 4) % 4;
+ | ^^^^^^^^^^^^^^^^^ help: consider using: `x.rem_euclid(4)`
+
+error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_string_new.fixed b/src/tools/clippy/tests/ui/manual_string_new.fixed
new file mode 100644
index 000000000..a376411bf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_string_new.fixed
@@ -0,0 +1,63 @@
+// run-rustfix
+
+#![warn(clippy::manual_string_new)]
+
+macro_rules! create_strings_from_macro {
+ // When inside a macro, nothing should warn to prevent false positives.
+ ($some_str:expr) => {
+ let _: String = $some_str.into();
+ let _ = $some_str.to_string();
+ };
+}
+
+fn main() {
+ // Method calls
+ let _ = String::new();
+ let _ = "no warning".to_string();
+
+ let _ = String::new();
+ let _ = "no warning".to_owned();
+
+ let _: String = String::new();
+ let _: String = "no warning".into();
+
+ let _: SomeOtherStruct = "no warning".into();
+ let _: SomeOtherStruct = "".into(); // No warning too. We are not converting into String.
+
+ // Calls
+ let _ = String::new();
+ let _ = String::new();
+ let _ = String::from("no warning");
+ let _ = SomeOtherStruct::from("no warning");
+ let _ = SomeOtherStruct::from(""); // Again: no warning.
+
+ let _ = String::new();
+ let _ = String::try_from("no warning").unwrap();
+ let _ = String::try_from("no warning").expect("this should not warn");
+ let _ = SomeOtherStruct::try_from("no warning").unwrap();
+ let _ = SomeOtherStruct::try_from("").unwrap(); // Again: no warning.
+
+ let _: String = String::new();
+ let _: String = From::from("no warning");
+ let _: SomeOtherStruct = From::from("no warning");
+ let _: SomeOtherStruct = From::from(""); // Again: no warning.
+
+ let _: String = String::new();
+ let _: String = TryFrom::try_from("no warning").unwrap();
+ let _: String = TryFrom::try_from("no warning").expect("this should not warn");
+ let _: String = String::new();
+ let _: SomeOtherStruct = TryFrom::try_from("no_warning").unwrap();
+ let _: SomeOtherStruct = TryFrom::try_from("").unwrap(); // Again: no warning.
+
+ // Macros (never warn)
+ create_strings_from_macro!("");
+ create_strings_from_macro!("Hey");
+}
+
+struct SomeOtherStruct {}
+
+impl From<&str> for SomeOtherStruct {
+ fn from(_value: &str) -> Self {
+ Self {}
+ }
+}
diff --git a/src/tools/clippy/tests/ui/manual_string_new.rs b/src/tools/clippy/tests/ui/manual_string_new.rs
new file mode 100644
index 000000000..6bfc52fb1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_string_new.rs
@@ -0,0 +1,63 @@
+// run-rustfix
+
+#![warn(clippy::manual_string_new)]
+
+macro_rules! create_strings_from_macro {
+ // When inside a macro, nothing should warn to prevent false positives.
+ ($some_str:expr) => {
+ let _: String = $some_str.into();
+ let _ = $some_str.to_string();
+ };
+}
+
+fn main() {
+ // Method calls
+ let _ = "".to_string();
+ let _ = "no warning".to_string();
+
+ let _ = "".to_owned();
+ let _ = "no warning".to_owned();
+
+ let _: String = "".into();
+ let _: String = "no warning".into();
+
+ let _: SomeOtherStruct = "no warning".into();
+ let _: SomeOtherStruct = "".into(); // No warning too. We are not converting into String.
+
+ // Calls
+ let _ = String::from("");
+ let _ = <String>::from("");
+ let _ = String::from("no warning");
+ let _ = SomeOtherStruct::from("no warning");
+ let _ = SomeOtherStruct::from(""); // Again: no warning.
+
+ let _ = String::try_from("").unwrap();
+ let _ = String::try_from("no warning").unwrap();
+ let _ = String::try_from("no warning").expect("this should not warn");
+ let _ = SomeOtherStruct::try_from("no warning").unwrap();
+ let _ = SomeOtherStruct::try_from("").unwrap(); // Again: no warning.
+
+ let _: String = From::from("");
+ let _: String = From::from("no warning");
+ let _: SomeOtherStruct = From::from("no warning");
+ let _: SomeOtherStruct = From::from(""); // Again: no warning.
+
+ let _: String = TryFrom::try_from("").unwrap();
+ let _: String = TryFrom::try_from("no warning").unwrap();
+ let _: String = TryFrom::try_from("no warning").expect("this should not warn");
+ let _: String = TryFrom::try_from("").expect("this should warn");
+ let _: SomeOtherStruct = TryFrom::try_from("no_warning").unwrap();
+ let _: SomeOtherStruct = TryFrom::try_from("").unwrap(); // Again: no warning.
+
+ // Macros (never warn)
+ create_strings_from_macro!("");
+ create_strings_from_macro!("Hey");
+}
+
+struct SomeOtherStruct {}
+
+impl From<&str> for SomeOtherStruct {
+ fn from(_value: &str) -> Self {
+ Self {}
+ }
+}
diff --git a/src/tools/clippy/tests/ui/manual_string_new.stderr b/src/tools/clippy/tests/ui/manual_string_new.stderr
new file mode 100644
index 000000000..e5ecfc619
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_string_new.stderr
@@ -0,0 +1,58 @@
+error: empty String is being created manually
+ --> $DIR/manual_string_new.rs:15:13
+ |
+LL | let _ = "".to_string();
+ | ^^^^^^^^^^^^^^ help: consider using: `String::new()`
+ |
+ = note: `-D clippy::manual-string-new` implied by `-D warnings`
+
+error: empty String is being created manually
+ --> $DIR/manual_string_new.rs:18:13
+ |
+LL | let _ = "".to_owned();
+ | ^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+ --> $DIR/manual_string_new.rs:21:21
+ |
+LL | let _: String = "".into();
+ | ^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+ --> $DIR/manual_string_new.rs:28:13
+ |
+LL | let _ = String::from("");
+ | ^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+ --> $DIR/manual_string_new.rs:29:13
+ |
+LL | let _ = <String>::from("");
+ | ^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+ --> $DIR/manual_string_new.rs:34:13
+ |
+LL | let _ = String::try_from("").unwrap();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+ --> $DIR/manual_string_new.rs:40:21
+ |
+LL | let _: String = From::from("");
+ | ^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+ --> $DIR/manual_string_new.rs:45:21
+ |
+LL | let _: String = TryFrom::try_from("").unwrap();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+ --> $DIR/manual_string_new.rs:48:21
+ |
+LL | let _: String = TryFrom::try_from("").expect("this should warn");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_strip.rs b/src/tools/clippy/tests/ui/manual_strip.rs
index cbb84eb5c..85009d785 100644
--- a/src/tools/clippy/tests/ui/manual_strip.rs
+++ b/src/tools/clippy/tests/ui/manual_strip.rs
@@ -1,3 +1,4 @@
+#![feature(custom_inner_attributes)]
#![warn(clippy::manual_strip)]
fn main() {
@@ -64,3 +65,21 @@ fn main() {
s4[2..].to_string();
}
}
+
+fn msrv_1_44() {
+ #![clippy::msrv = "1.44"]
+
+ let s = "abc";
+ if s.starts_with('a') {
+ s[1..].to_string();
+ }
+}
+
+fn msrv_1_45() {
+ #![clippy::msrv = "1.45"]
+
+ let s = "abc";
+ if s.starts_with('a') {
+ s[1..].to_string();
+ }
+}
diff --git a/src/tools/clippy/tests/ui/manual_strip.stderr b/src/tools/clippy/tests/ui/manual_strip.stderr
index 896edf2ae..ad2a362f3 100644
--- a/src/tools/clippy/tests/ui/manual_strip.stderr
+++ b/src/tools/clippy/tests/ui/manual_strip.stderr
@@ -1,15 +1,15 @@
error: stripping a prefix manually
- --> $DIR/manual_strip.rs:7:24
+ --> $DIR/manual_strip.rs:8:24
|
LL | str::to_string(&s["ab".len()..]);
| ^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::manual-strip` implied by `-D warnings`
note: the prefix was tested here
- --> $DIR/manual_strip.rs:6:5
+ --> $DIR/manual_strip.rs:7:5
|
LL | if s.starts_with("ab") {
| ^^^^^^^^^^^^^^^^^^^^^^^
+ = note: `-D clippy::manual-strip` implied by `-D warnings`
help: try using the `strip_prefix` method
|
LL ~ if let Some(<stripped>) = s.strip_prefix("ab") {
@@ -21,13 +21,13 @@ LL ~ <stripped>.to_string();
|
error: stripping a suffix manually
- --> $DIR/manual_strip.rs:15:24
+ --> $DIR/manual_strip.rs:16:24
|
LL | str::to_string(&s[..s.len() - "bc".len()]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the suffix was tested here
- --> $DIR/manual_strip.rs:14:5
+ --> $DIR/manual_strip.rs:15:5
|
LL | if s.ends_with("bc") {
| ^^^^^^^^^^^^^^^^^^^^^
@@ -42,13 +42,13 @@ LL ~ <stripped>.to_string();
|
error: stripping a prefix manually
- --> $DIR/manual_strip.rs:24:24
+ --> $DIR/manual_strip.rs:25:24
|
LL | str::to_string(&s[1..]);
| ^^^^^^^
|
note: the prefix was tested here
- --> $DIR/manual_strip.rs:23:5
+ --> $DIR/manual_strip.rs:24:5
|
LL | if s.starts_with('a') {
| ^^^^^^^^^^^^^^^^^^^^^^
@@ -60,13 +60,13 @@ LL ~ <stripped>.to_string();
|
error: stripping a prefix manually
- --> $DIR/manual_strip.rs:31:24
+ --> $DIR/manual_strip.rs:32:24
|
LL | str::to_string(&s[prefix.len()..]);
| ^^^^^^^^^^^^^^^^^^
|
note: the prefix was tested here
- --> $DIR/manual_strip.rs:30:5
+ --> $DIR/manual_strip.rs:31:5
|
LL | if s.starts_with(prefix) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,13 +77,13 @@ LL ~ str::to_string(<stripped>);
|
error: stripping a prefix manually
- --> $DIR/manual_strip.rs:37:24
+ --> $DIR/manual_strip.rs:38:24
|
LL | str::to_string(&s[PREFIX.len()..]);
| ^^^^^^^^^^^^^^^^^^
|
note: the prefix was tested here
- --> $DIR/manual_strip.rs:36:5
+ --> $DIR/manual_strip.rs:37:5
|
LL | if s.starts_with(PREFIX) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -95,13 +95,13 @@ LL ~ str::to_string(<stripped>);
|
error: stripping a prefix manually
- --> $DIR/manual_strip.rs:44:24
+ --> $DIR/manual_strip.rs:45:24
|
LL | str::to_string(&TARGET[prefix.len()..]);
| ^^^^^^^^^^^^^^^^^^^^^^^
|
note: the prefix was tested here
- --> $DIR/manual_strip.rs:43:5
+ --> $DIR/manual_strip.rs:44:5
|
LL | if TARGET.starts_with(prefix) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,13 +112,13 @@ LL ~ str::to_string(<stripped>);
|
error: stripping a prefix manually
- --> $DIR/manual_strip.rs:50:9
+ --> $DIR/manual_strip.rs:51:9
|
LL | s1[2..].to_uppercase();
| ^^^^^^^
|
note: the prefix was tested here
- --> $DIR/manual_strip.rs:49:5
+ --> $DIR/manual_strip.rs:50:5
|
LL | if s1.starts_with("ab") {
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -128,5 +128,22 @@ LL ~ if let Some(<stripped>) = s1.strip_prefix("ab") {
LL ~ <stripped>.to_uppercase();
|
-error: aborting due to 7 previous errors
+error: stripping a prefix manually
+ --> $DIR/manual_strip.rs:83:9
+ |
+LL | s[1..].to_string();
+ | ^^^^^^
+ |
+note: the prefix was tested here
+ --> $DIR/manual_strip.rs:82:5
+ |
+LL | if s.starts_with('a') {
+ | ^^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_prefix` method
+ |
+LL ~ if let Some(<stripped>) = s.strip_prefix('a') {
+LL ~ <stripped>.to_string();
+ |
+
+error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/map_err.stderr b/src/tools/clippy/tests/ui/map_err.stderr
index c03584052..d44403a84 100644
--- a/src/tools/clippy/tests/ui/map_err.stderr
+++ b/src/tools/clippy/tests/ui/map_err.stderr
@@ -4,8 +4,8 @@ error: `map_err(|_|...` wildcard pattern discards the original error
LL | println!("{:?}", x.map_err(|_| Errors::Ignored));
| ^^^
|
- = note: `-D clippy::map-err-ignore` implied by `-D warnings`
= help: consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)
+ = note: `-D clippy::map-err-ignore` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.rs b/src/tools/clippy/tests/ui/map_unwrap_or.rs
index 87e16f5d0..396b22a9a 100644
--- a/src/tools/clippy/tests/ui/map_unwrap_or.rs
+++ b/src/tools/clippy/tests/ui/map_unwrap_or.rs
@@ -1,6 +1,8 @@
// aux-build:option_helpers.rs
+#![feature(custom_inner_attributes)]
#![warn(clippy::map_unwrap_or)]
+#![allow(clippy::uninlined_format_args, clippy::unnecessary_lazy_evaluations)]
#[macro_use]
extern crate option_helpers;
@@ -79,3 +81,19 @@ fn main() {
option_methods();
result_methods();
}
+
+fn msrv_1_40() {
+ #![clippy::msrv = "1.40"]
+
+ let res: Result<i32, ()> = Ok(1);
+
+ let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0);
+}
+
+fn msrv_1_41() {
+ #![clippy::msrv = "1.41"]
+
+ let res: Result<i32, ()> = Ok(1);
+
+ let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0);
+}
diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.stderr b/src/tools/clippy/tests/ui/map_unwrap_or.stderr
index abc9c1ece..d17d24a40 100644
--- a/src/tools/clippy/tests/ui/map_unwrap_or.stderr
+++ b/src/tools/clippy/tests/ui/map_unwrap_or.stderr
@@ -1,5 +1,5 @@
error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead
- --> $DIR/map_unwrap_or.rs:16:13
+ --> $DIR/map_unwrap_or.rs:18:13
|
LL | let _ = opt.map(|x| x + 1)
| _____________^
@@ -15,7 +15,7 @@ LL + let _ = opt.map_or(0, |x| x + 1);
|
error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead
- --> $DIR/map_unwrap_or.rs:20:13
+ --> $DIR/map_unwrap_or.rs:22:13
|
LL | let _ = opt.map(|x| {
| _____________^
@@ -33,7 +33,7 @@ LL ~ );
|
error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead
- --> $DIR/map_unwrap_or.rs:24:13
+ --> $DIR/map_unwrap_or.rs:26:13
|
LL | let _ = opt.map(|x| x + 1)
| _____________^
@@ -50,7 +50,7 @@ LL ~ }, |x| x + 1);
|
error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead
- --> $DIR/map_unwrap_or.rs:29:13
+ --> $DIR/map_unwrap_or.rs:31:13
|
LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -62,7 +62,7 @@ LL + let _ = opt.and_then(|x| Some(x + 1));
|
error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead
- --> $DIR/map_unwrap_or.rs:31:13
+ --> $DIR/map_unwrap_or.rs:33:13
|
LL | let _ = opt.map(|x| {
| _____________^
@@ -80,7 +80,7 @@ LL ~ );
|
error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead
- --> $DIR/map_unwrap_or.rs:35:13
+ --> $DIR/map_unwrap_or.rs:37:13
|
LL | let _ = opt
| _____________^
@@ -95,7 +95,7 @@ LL + .and_then(|x| Some(x + 1));
|
error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead
- --> $DIR/map_unwrap_or.rs:46:13
+ --> $DIR/map_unwrap_or.rs:48:13
|
LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -107,7 +107,7 @@ LL + let _ = Some("prefix").map_or(id, |p| format!("{}.", p));
|
error: called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead
- --> $DIR/map_unwrap_or.rs:50:13
+ --> $DIR/map_unwrap_or.rs:52:13
|
LL | let _ = opt.map(|x| {
| _____________^
@@ -117,7 +117,7 @@ LL | | ).unwrap_or_else(|| 0);
| |__________________________^
error: called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead
- --> $DIR/map_unwrap_or.rs:54:13
+ --> $DIR/map_unwrap_or.rs:56:13
|
LL | let _ = opt.map(|x| x + 1)
| _____________^
@@ -127,7 +127,7 @@ LL | | );
| |_________^
error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling `.map_or_else(<g>, <f>)` instead
- --> $DIR/map_unwrap_or.rs:66:13
+ --> $DIR/map_unwrap_or.rs:68:13
|
LL | let _ = res.map(|x| {
| _____________^
@@ -137,7 +137,7 @@ LL | | ).unwrap_or_else(|_e| 0);
| |____________________________^
error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling `.map_or_else(<g>, <f>)` instead
- --> $DIR/map_unwrap_or.rs:70:13
+ --> $DIR/map_unwrap_or.rs:72:13
|
LL | let _ = res.map(|x| x + 1)
| _____________^
@@ -146,5 +146,11 @@ LL | | 0
LL | | });
| |__________^
-error: aborting due to 11 previous errors
+error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling `.map_or_else(<g>, <f>)` instead
+ --> $DIR/map_unwrap_or.rs:98:13
+ |
+LL | let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `res.map_or_else(|_e| 0, |x| x + 1)`
+
+error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
index 1ccbfda64..249800769 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
@@ -1,5 +1,6 @@
// run-rustfix
+#![feature(custom_inner_attributes)]
#![warn(clippy::match_like_matches_macro)]
#![allow(unreachable_patterns, dead_code, clippy::equatable_if_let)]
@@ -167,4 +168,44 @@ fn main() {
_ => false,
};
}
+
+ let x = ' ';
+ // ignore if match block contains comment
+ let _line_comments = match x {
+ // numbers are bad!
+ '1' | '2' | '3' => true,
+ // spaces are very important to be true.
+ ' ' => true,
+ // as are dots
+ '.' => true,
+ _ => false,
+ };
+
+ let _block_comments = match x {
+ /* numbers are bad!
+ */
+ '1' | '2' | '3' => true,
+ /* spaces are very important to be true.
+ */
+ ' ' => true,
+ /* as are dots
+ */
+ '.' => true,
+ _ => false,
+ };
+}
+
+fn msrv_1_41() {
+ #![clippy::msrv = "1.41"]
+
+ let _y = match Some(5) {
+ Some(0) => true,
+ _ => false,
+ };
+}
+
+fn msrv_1_42() {
+ #![clippy::msrv = "1.42"]
+
+ let _y = matches!(Some(5), Some(0));
}
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
index a49991f59..b4e48499b 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
@@ -1,5 +1,6 @@
// run-rustfix
+#![feature(custom_inner_attributes)]
#![warn(clippy::match_like_matches_macro)]
#![allow(unreachable_patterns, dead_code, clippy::equatable_if_let)]
@@ -208,4 +209,47 @@ fn main() {
_ => false,
};
}
+
+ let x = ' ';
+ // ignore if match block contains comment
+ let _line_comments = match x {
+ // numbers are bad!
+ '1' | '2' | '3' => true,
+ // spaces are very important to be true.
+ ' ' => true,
+ // as are dots
+ '.' => true,
+ _ => false,
+ };
+
+ let _block_comments = match x {
+ /* numbers are bad!
+ */
+ '1' | '2' | '3' => true,
+ /* spaces are very important to be true.
+ */
+ ' ' => true,
+ /* as are dots
+ */
+ '.' => true,
+ _ => false,
+ };
+}
+
+fn msrv_1_41() {
+ #![clippy::msrv = "1.41"]
+
+ let _y = match Some(5) {
+ Some(0) => true,
+ _ => false,
+ };
+}
+
+fn msrv_1_42() {
+ #![clippy::msrv = "1.42"]
+
+ let _y = match Some(5) {
+ Some(0) => true,
+ _ => false,
+ };
}
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
index e94555e27..f1d1c23ae 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
@@ -1,5 +1,5 @@
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:10:14
+ --> $DIR/match_expr_like_matches_macro.rs:11:14
|
LL | let _y = match x {
| ______________^
@@ -11,7 +11,7 @@ LL | | };
= note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:16:14
+ --> $DIR/match_expr_like_matches_macro.rs:17:14
|
LL | let _w = match x {
| ______________^
@@ -21,7 +21,7 @@ LL | | };
| |_____^ help: try this: `matches!(x, Some(_))`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/match_expr_like_matches_macro.rs:22:14
+ --> $DIR/match_expr_like_matches_macro.rs:23:14
|
LL | let _z = match x {
| ______________^
@@ -33,7 +33,7 @@ LL | | };
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:28:15
+ --> $DIR/match_expr_like_matches_macro.rs:29:15
|
LL | let _zz = match x {
| _______________^
@@ -43,13 +43,13 @@ LL | | };
| |_____^ help: try this: `!matches!(x, Some(r) if r == 0)`
error: if let .. else expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:34:16
+ --> $DIR/match_expr_like_matches_macro.rs:35:16
|
LL | let _zzz = if let Some(5) = x { true } else { false };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `matches!(x, Some(5))`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:58:20
+ --> $DIR/match_expr_like_matches_macro.rs:59:20
|
LL | let _ans = match x {
| ____________________^
@@ -60,7 +60,7 @@ LL | | };
| |_________^ help: try this: `matches!(x, E::A(_) | E::B(_))`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:68:20
+ --> $DIR/match_expr_like_matches_macro.rs:69:20
|
LL | let _ans = match x {
| ____________________^
@@ -73,7 +73,7 @@ LL | | };
| |_________^ help: try this: `matches!(x, E::A(_) | E::B(_))`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:78:20
+ --> $DIR/match_expr_like_matches_macro.rs:79:20
|
LL | let _ans = match x {
| ____________________^
@@ -84,7 +84,7 @@ LL | | };
| |_________^ help: try this: `!matches!(x, E::B(_) | E::C)`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:138:18
+ --> $DIR/match_expr_like_matches_macro.rs:139:18
|
LL | let _z = match &z {
| __________________^
@@ -94,7 +94,7 @@ LL | | };
| |_________^ help: try this: `matches!(z, Some(3))`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:147:18
+ --> $DIR/match_expr_like_matches_macro.rs:148:18
|
LL | let _z = match &z {
| __________________^
@@ -104,7 +104,7 @@ LL | | };
| |_________^ help: try this: `matches!(&z, Some(3))`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:164:21
+ --> $DIR/match_expr_like_matches_macro.rs:165:21
|
LL | let _ = match &z {
| _____________________^
@@ -114,7 +114,7 @@ LL | | };
| |_____________^ help: try this: `matches!(&z, AnEnum::X)`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:178:20
+ --> $DIR/match_expr_like_matches_macro.rs:179:20
|
LL | let _res = match &val {
| ____________________^
@@ -124,7 +124,7 @@ LL | | };
| |_________^ help: try this: `matches!(&val, &Some(ref _a))`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:190:20
+ --> $DIR/match_expr_like_matches_macro.rs:191:20
|
LL | let _res = match &val {
| ____________________^
@@ -133,5 +133,15 @@ LL | | _ => false,
LL | | };
| |_________^ help: try this: `matches!(&val, &Some(ref _a))`
-error: aborting due to 13 previous errors
+error: match expression looks like `matches!` macro
+ --> $DIR/match_expr_like_matches_macro.rs:251:14
+ |
+LL | let _y = match Some(5) {
+ | ______________^
+LL | | Some(0) => true,
+LL | | _ => false,
+LL | | };
+ | |_____^ help: try this: `matches!(Some(5), Some(0))`
+
+error: aborting due to 14 previous errors
diff --git a/src/tools/clippy/tests/ui/match_overlapping_arm.rs b/src/tools/clippy/tests/ui/match_overlapping_arm.rs
index 2f85e6357..b4097fa96 100644
--- a/src/tools/clippy/tests/ui/match_overlapping_arm.rs
+++ b/src/tools/clippy/tests/ui/match_overlapping_arm.rs
@@ -1,5 +1,4 @@
#![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)]
diff --git a/src/tools/clippy/tests/ui/match_overlapping_arm.stderr b/src/tools/clippy/tests/ui/match_overlapping_arm.stderr
index b81bb1ecf..b98d4799e 100644
--- a/src/tools/clippy/tests/ui/match_overlapping_arm.stderr
+++ b/src/tools/clippy/tests/ui/match_overlapping_arm.stderr
@@ -1,96 +1,96 @@
error: some ranges overlap
- --> $DIR/match_overlapping_arm.rs:13:9
+ --> $DIR/match_overlapping_arm.rs:12:9
|
LL | 0..=10 => println!("0..=10"),
| ^^^^^^
|
- = note: `-D clippy::match-overlapping-arm` implied by `-D warnings`
note: overlaps with this
- --> $DIR/match_overlapping_arm.rs:14:9
+ --> $DIR/match_overlapping_arm.rs:13:9
|
LL | 0..=11 => println!("0..=11"),
| ^^^^^^
+ = note: `-D clippy::match-overlapping-arm` implied by `-D warnings`
error: some ranges overlap
- --> $DIR/match_overlapping_arm.rs:19:9
+ --> $DIR/match_overlapping_arm.rs:18:9
|
LL | 0..=5 => println!("0..=5"),
| ^^^^^
|
note: overlaps with this
- --> $DIR/match_overlapping_arm.rs:21:9
+ --> $DIR/match_overlapping_arm.rs:20:9
|
LL | FOO..=11 => println!("FOO..=11"),
| ^^^^^^^^
error: some ranges overlap
- --> $DIR/match_overlapping_arm.rs:56:9
+ --> $DIR/match_overlapping_arm.rs:55:9
|
LL | 0..11 => println!("0..11"),
| ^^^^^
|
note: overlaps with this
- --> $DIR/match_overlapping_arm.rs:57:9
+ --> $DIR/match_overlapping_arm.rs:56:9
|
LL | 0..=11 => println!("0..=11"),
| ^^^^^^
error: some ranges overlap
- --> $DIR/match_overlapping_arm.rs:81:9
+ --> $DIR/match_overlapping_arm.rs:80:9
|
LL | 0..=10 => println!("0..=10"),
| ^^^^^^
|
note: overlaps with this
- --> $DIR/match_overlapping_arm.rs:80:9
+ --> $DIR/match_overlapping_arm.rs:79:9
|
LL | 5..14 => println!("5..14"),
| ^^^^^
error: some ranges overlap
- --> $DIR/match_overlapping_arm.rs:86:9
+ --> $DIR/match_overlapping_arm.rs:85:9
|
LL | 0..7 => println!("0..7"),
| ^^^^
|
note: overlaps with this
- --> $DIR/match_overlapping_arm.rs:87:9
+ --> $DIR/match_overlapping_arm.rs:86:9
|
LL | 0..=10 => println!("0..=10"),
| ^^^^^^
error: some ranges overlap
- --> $DIR/match_overlapping_arm.rs:98:9
+ --> $DIR/match_overlapping_arm.rs:97:9
|
LL | ..=23 => println!("..=23"),
| ^^^^^
|
note: overlaps with this
- --> $DIR/match_overlapping_arm.rs:99:9
+ --> $DIR/match_overlapping_arm.rs:98:9
|
LL | ..26 => println!("..26"),
| ^^^^
error: some ranges overlap
- --> $DIR/match_overlapping_arm.rs:107:9
+ --> $DIR/match_overlapping_arm.rs:106:9
|
LL | 21..=30 => (),
| ^^^^^^^
|
note: overlaps with this
- --> $DIR/match_overlapping_arm.rs:108:9
+ --> $DIR/match_overlapping_arm.rs:107:9
|
LL | 21..=40 => (),
| ^^^^^^^
error: some ranges overlap
- --> $DIR/match_overlapping_arm.rs:121:9
+ --> $DIR/match_overlapping_arm.rs:120:9
|
LL | 0..=0x0000_0000_0000_00ff => (),
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: overlaps with this
- --> $DIR/match_overlapping_arm.rs:122:9
+ --> $DIR/match_overlapping_arm.rs:121:9
|
LL | 0..=0x0000_0000_0000_ffff => (),
| ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/match_ref_pats.fixed b/src/tools/clippy/tests/ui/match_ref_pats.fixed
index 1b6c2d924..cf37fc6dc 100644
--- a/src/tools/clippy/tests/ui/match_ref_pats.fixed
+++ b/src/tools/clippy/tests/ui/match_ref_pats.fixed
@@ -1,6 +1,7 @@
// run-rustfix
#![warn(clippy::match_ref_pats)]
-#![allow(dead_code, unused_variables, clippy::equatable_if_let, clippy::enum_variant_names)]
+#![allow(dead_code, unused_variables)]
+#![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)]
fn ref_pats() {
{
diff --git a/src/tools/clippy/tests/ui/match_ref_pats.rs b/src/tools/clippy/tests/ui/match_ref_pats.rs
index 68dfac4e2..3220b97d1 100644
--- a/src/tools/clippy/tests/ui/match_ref_pats.rs
+++ b/src/tools/clippy/tests/ui/match_ref_pats.rs
@@ -1,6 +1,7 @@
// run-rustfix
#![warn(clippy::match_ref_pats)]
-#![allow(dead_code, unused_variables, clippy::equatable_if_let, clippy::enum_variant_names)]
+#![allow(dead_code, unused_variables)]
+#![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)]
fn ref_pats() {
{
diff --git a/src/tools/clippy/tests/ui/match_ref_pats.stderr b/src/tools/clippy/tests/ui/match_ref_pats.stderr
index 353f7399d..7d9646c84 100644
--- a/src/tools/clippy/tests/ui/match_ref_pats.stderr
+++ b/src/tools/clippy/tests/ui/match_ref_pats.stderr
@@ -1,5 +1,5 @@
error: you don't need to add `&` to all patterns
- --> $DIR/match_ref_pats.rs:8:9
+ --> $DIR/match_ref_pats.rs:9:9
|
LL | / match v {
LL | | &Some(v) => println!("{:?}", v),
@@ -16,7 +16,7 @@ LL ~ None => println!("none"),
|
error: you don't need to add `&` to both the expression and the patterns
- --> $DIR/match_ref_pats.rs:25:5
+ --> $DIR/match_ref_pats.rs:26:5
|
LL | / match &w {
LL | | &Some(v) => println!("{:?}", v),
@@ -32,7 +32,7 @@ LL ~ None => println!("none"),
|
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/match_ref_pats.rs:37:12
+ --> $DIR/match_ref_pats.rs:38:12
|
LL | if let &None = a {
| -------^^^^^---- help: try this: `if a.is_none()`
@@ -40,13 +40,13 @@ LL | if let &None = a {
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/match_ref_pats.rs:42:12
+ --> $DIR/match_ref_pats.rs:43:12
|
LL | if let &None = &b {
| -------^^^^^----- help: try this: `if b.is_none()`
error: you don't need to add `&` to all patterns
- --> $DIR/match_ref_pats.rs:102:9
+ --> $DIR/match_ref_pats.rs:103:9
|
LL | / match foobar_variant!(0) {
LL | | &FooBar::Foo => println!("Foo"),
diff --git a/src/tools/clippy/tests/ui/match_result_ok.fixed b/src/tools/clippy/tests/ui/match_result_ok.fixed
index d4760a975..8b91b9854 100644
--- a/src/tools/clippy/tests/ui/match_result_ok.fixed
+++ b/src/tools/clippy/tests/ui/match_result_ok.fixed
@@ -1,8 +1,7 @@
// run-rustfix
-
#![warn(clippy::match_result_ok)]
-#![allow(clippy::boxed_local)]
#![allow(dead_code)]
+#![allow(clippy::boxed_local, clippy::uninlined_format_args)]
// Checking `if` cases
diff --git a/src/tools/clippy/tests/ui/match_result_ok.rs b/src/tools/clippy/tests/ui/match_result_ok.rs
index 0b818723d..bc2c4b50e 100644
--- a/src/tools/clippy/tests/ui/match_result_ok.rs
+++ b/src/tools/clippy/tests/ui/match_result_ok.rs
@@ -1,8 +1,7 @@
// run-rustfix
-
#![warn(clippy::match_result_ok)]
-#![allow(clippy::boxed_local)]
#![allow(dead_code)]
+#![allow(clippy::boxed_local, clippy::uninlined_format_args)]
// Checking `if` cases
diff --git a/src/tools/clippy/tests/ui/match_result_ok.stderr b/src/tools/clippy/tests/ui/match_result_ok.stderr
index cc3bc8c76..98a95705c 100644
--- a/src/tools/clippy/tests/ui/match_result_ok.stderr
+++ b/src/tools/clippy/tests/ui/match_result_ok.stderr
@@ -1,5 +1,5 @@
error: matching on `Some` with `ok()` is redundant
- --> $DIR/match_result_ok.rs:10:5
+ --> $DIR/match_result_ok.rs:9:5
|
LL | if let Some(y) = x.parse().ok() { y } else { 0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -11,7 +11,7 @@ LL | if let Ok(y) = x.parse() { y } else { 0 }
| ~~~~~~~~~~~~~~~~~~~~~~~~
error: matching on `Some` with `ok()` is redundant
- --> $DIR/match_result_ok.rs:20:9
+ --> $DIR/match_result_ok.rs:19:9
|
LL | if let Some(y) = x . parse() . ok () {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -22,7 +22,7 @@ LL | if let Ok(y) = x . parse() {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: matching on `Some` with `ok()` is redundant
- --> $DIR/match_result_ok.rs:46:5
+ --> $DIR/match_result_ok.rs:45:5
|
LL | while let Some(a) = wat.next().ok() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/match_same_arms.stderr b/src/tools/clippy/tests/ui/match_same_arms.stderr
index b6d04263b..db85b5964 100644
--- a/src/tools/clippy/tests/ui/match_same_arms.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms.stderr
@@ -4,13 +4,13 @@ error: this match arm has an identical body to the `_` wildcard arm
LL | Abc::A => 0,
| ^^^^^^^^^^^ help: try removing the arm
|
- = note: `-D clippy::match-same-arms` implied by `-D warnings`
= help: or try changing either arm body
note: `_` wildcard arm here
--> $DIR/match_same_arms.rs:13:9
|
LL | _ => 0, //~ ERROR match arms have same body
| ^^^^^^
+ = note: `-D clippy::match-same-arms` implied by `-D warnings`
error: this match arm has an identical body to another arm
--> $DIR/match_same_arms.rs:17:9
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs
index 7aba5b447..82b2c433d 100644
--- a/src/tools/clippy/tests/ui/match_same_arms2.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms2.rs
@@ -1,5 +1,9 @@
#![warn(clippy::match_same_arms)]
-#![allow(clippy::blacklisted_name, clippy::diverging_sub_expression)]
+#![allow(
+ clippy::disallowed_names,
+ clippy::diverging_sub_expression,
+ clippy::uninlined_format_args
+)]
fn bar<T>(_: T) {}
fn foo() -> bool {
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr
index 14a672ba2..06cd43000 100644
--- a/src/tools/clippy/tests/ui/match_same_arms2.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr
@@ -1,5 +1,5 @@
error: this match arm has an identical body to the `_` wildcard arm
- --> $DIR/match_same_arms2.rs:11:9
+ --> $DIR/match_same_arms2.rs:15:9
|
LL | / 42 => {
LL | | foo();
@@ -10,10 +10,9 @@ LL | | a
LL | | },
| |_________^ help: try removing the arm
|
- = note: `-D clippy::match-same-arms` implied by `-D warnings`
= help: or try changing either arm body
note: `_` wildcard arm here
- --> $DIR/match_same_arms2.rs:20:9
+ --> $DIR/match_same_arms2.rs:24:9
|
LL | / _ => {
LL | | //~ ERROR match arms have same body
@@ -23,9 +22,10 @@ LL | | let mut a = 42 + [23].len() as i32;
LL | | a
LL | | },
| |_________^
+ = note: `-D clippy::match-same-arms` implied by `-D warnings`
error: this match arm has an identical body to another arm
- --> $DIR/match_same_arms2.rs:34:9
+ --> $DIR/match_same_arms2.rs:38:9
|
LL | 51 => foo(), //~ ERROR match arms have same body
| --^^^^^^^^^
@@ -34,13 +34,13 @@ LL | 51 => foo(), //~ ERROR match arms have same body
|
= help: or try changing either arm body
note: other arm here
- --> $DIR/match_same_arms2.rs:33:9
+ --> $DIR/match_same_arms2.rs:37:9
|
LL | 42 => foo(),
| ^^^^^^^^^^^
error: this match arm has an identical body to another arm
- --> $DIR/match_same_arms2.rs:40:9
+ --> $DIR/match_same_arms2.rs:44:9
|
LL | None => 24, //~ ERROR match arms have same body
| ----^^^^^^
@@ -49,13 +49,13 @@ LL | None => 24, //~ ERROR match arms have same body
|
= help: or try changing either arm body
note: other arm here
- --> $DIR/match_same_arms2.rs:39:9
+ --> $DIR/match_same_arms2.rs:43:9
|
LL | Some(_) => 24,
| ^^^^^^^^^^^^^
error: this match arm has an identical body to another arm
- --> $DIR/match_same_arms2.rs:62:9
+ --> $DIR/match_same_arms2.rs:66:9
|
LL | (None, Some(a)) => bar(a), //~ ERROR match arms have same body
| ---------------^^^^^^^^^^
@@ -64,13 +64,13 @@ LL | (None, Some(a)) => bar(a), //~ ERROR match arms have same body
|
= help: or try changing either arm body
note: other arm here
- --> $DIR/match_same_arms2.rs:61:9
+ --> $DIR/match_same_arms2.rs:65:9
|
LL | (Some(a), None) => bar(a),
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: this match arm has an identical body to another arm
- --> $DIR/match_same_arms2.rs:67:9
+ --> $DIR/match_same_arms2.rs:71:9
|
LL | (Some(a), ..) => bar(a),
| -------------^^^^^^^^^^
@@ -79,13 +79,13 @@ LL | (Some(a), ..) => bar(a),
|
= help: or try changing either arm body
note: other arm here
- --> $DIR/match_same_arms2.rs:68:9
+ --> $DIR/match_same_arms2.rs:72:9
|
LL | (.., Some(a)) => bar(a), //~ ERROR match arms have same body
| ^^^^^^^^^^^^^^^^^^^^^^^
error: this match arm has an identical body to another arm
- --> $DIR/match_same_arms2.rs:101:9
+ --> $DIR/match_same_arms2.rs:105:9
|
LL | (Ok(x), Some(_)) => println!("ok {}", x),
| ----------------^^^^^^^^^^^^^^^^^^^^^^^^
@@ -94,13 +94,13 @@ LL | (Ok(x), Some(_)) => println!("ok {}", x),
|
= help: or try changing either arm body
note: other arm here
- --> $DIR/match_same_arms2.rs:102:9
+ --> $DIR/match_same_arms2.rs:106:9
|
LL | (Ok(_), Some(x)) => println!("ok {}", x),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this match arm has an identical body to another arm
- --> $DIR/match_same_arms2.rs:117:9
+ --> $DIR/match_same_arms2.rs:121:9
|
LL | Ok(_) => println!("ok"),
| -----^^^^^^^^^^^^^^^^^^
@@ -109,13 +109,13 @@ LL | Ok(_) => println!("ok"),
|
= help: or try changing either arm body
note: other arm here
- --> $DIR/match_same_arms2.rs:116:9
+ --> $DIR/match_same_arms2.rs:120:9
|
LL | Ok(3) => println!("ok"),
| ^^^^^^^^^^^^^^^^^^^^^^^
error: this match arm has an identical body to another arm
- --> $DIR/match_same_arms2.rs:144:9
+ --> $DIR/match_same_arms2.rs:148:9
|
LL | 1 => {
| ^ help: try merging the arm patterns: `1 | 0`
@@ -127,7 +127,7 @@ LL | | },
|
= help: or try changing either arm body
note: other arm here
- --> $DIR/match_same_arms2.rs:141:9
+ --> $DIR/match_same_arms2.rs:145:9
|
LL | / 0 => {
LL | | empty!(0);
@@ -135,7 +135,7 @@ LL | | },
| |_________^
error: match expression looks like `matches!` macro
- --> $DIR/match_same_arms2.rs:162:16
+ --> $DIR/match_same_arms2.rs:166:16
|
LL | let _ans = match x {
| ________________^
@@ -148,7 +148,7 @@ LL | | };
= note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
error: this match arm has an identical body to another arm
- --> $DIR/match_same_arms2.rs:194:9
+ --> $DIR/match_same_arms2.rs:198:9
|
LL | Foo::X(0) => 1,
| ---------^^^^^
@@ -157,13 +157,13 @@ LL | Foo::X(0) => 1,
|
= help: or try changing either arm body
note: other arm here
- --> $DIR/match_same_arms2.rs:196:9
+ --> $DIR/match_same_arms2.rs:200:9
|
LL | Foo::Z(_) => 1,
| ^^^^^^^^^^^^^^
error: this match arm has an identical body to another arm
- --> $DIR/match_same_arms2.rs:204:9
+ --> $DIR/match_same_arms2.rs:208:9
|
LL | Foo::Z(_) => 1,
| ---------^^^^^
@@ -172,13 +172,13 @@ LL | Foo::Z(_) => 1,
|
= help: or try changing either arm body
note: other arm here
- --> $DIR/match_same_arms2.rs:202:9
+ --> $DIR/match_same_arms2.rs:206:9
|
LL | Foo::X(0) => 1,
| ^^^^^^^^^^^^^^
error: this match arm has an identical body to another arm
- --> $DIR/match_same_arms2.rs:227:9
+ --> $DIR/match_same_arms2.rs:231:9
|
LL | Some(Bar { y: 0, x: 5, .. }) => 1,
| ----------------------------^^^^^
@@ -187,7 +187,7 @@ LL | Some(Bar { y: 0, x: 5, .. }) => 1,
|
= help: or try changing either arm body
note: other arm here
- --> $DIR/match_same_arms2.rs:224:9
+ --> $DIR/match_same_arms2.rs:228:9
|
LL | Some(Bar { x: 0, y: 5, .. }) => 1,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed
index de46e6cff..a6e315e47 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.fixed
+++ b/src/tools/clippy/tests/ui/match_single_binding.fixed
@@ -1,7 +1,7 @@
// run-rustfix
-
#![warn(clippy::match_single_binding)]
-#![allow(unused_variables, clippy::toplevel_ref_arg)]
+#![allow(unused_variables)]
+#![allow(clippy::toplevel_ref_arg, clippy::uninlined_format_args)]
struct Point {
x: i32,
@@ -124,3 +124,12 @@ fn issue_8723() {
let _ = val;
}
+
+#[allow(dead_code)]
+fn issue_9575() {
+ fn side_effects() {}
+ let _ = || {
+ side_effects();
+ println!("Needs curlies");
+ };
+}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs
index eea64fcb2..cecbd703e 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.rs
+++ b/src/tools/clippy/tests/ui/match_single_binding.rs
@@ -1,7 +1,7 @@
// run-rustfix
-
#![warn(clippy::match_single_binding)]
-#![allow(unused_variables, clippy::toplevel_ref_arg)]
+#![allow(unused_variables)]
+#![allow(clippy::toplevel_ref_arg, clippy::uninlined_format_args)]
struct Point {
x: i32,
@@ -140,3 +140,11 @@ fn issue_8723() {
let _ = val;
}
+
+#[allow(dead_code)]
+fn issue_9575() {
+ fn side_effects() {}
+ let _ = || match side_effects() {
+ _ => println!("Needs curlies"),
+ };
+}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr
index 5d4e7314b..2b9ec7ee7 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.stderr
+++ b/src/tools/clippy/tests/ui/match_single_binding.stderr
@@ -196,5 +196,22 @@ LL + suf
LL ~ };
|
-error: aborting due to 13 previous errors
+error: this match could be replaced by its scrutinee and body
+ --> $DIR/match_single_binding.rs:147:16
+ |
+LL | let _ = || match side_effects() {
+ | ________________^
+LL | | _ => println!("Needs curlies"),
+LL | | };
+ | |_____^
+ |
+help: consider using the scrutinee and body instead
+ |
+LL ~ let _ = || {
+LL + side_effects();
+LL + println!("Needs curlies");
+LL ~ };
+ |
+
+error: aborting due to 14 previous errors
diff --git a/src/tools/clippy/tests/ui/match_single_binding2.fixed b/src/tools/clippy/tests/ui/match_single_binding2.fixed
index a91fcc212..6a7db67e3 100644
--- a/src/tools/clippy/tests/ui/match_single_binding2.fixed
+++ b/src/tools/clippy/tests/ui/match_single_binding2.fixed
@@ -1,7 +1,7 @@
// run-rustfix
-
#![warn(clippy::match_single_binding)]
#![allow(unused_variables)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
// Lint (additional curly braces needed, see #6572)
diff --git a/src/tools/clippy/tests/ui/match_single_binding2.rs b/src/tools/clippy/tests/ui/match_single_binding2.rs
index 476386eba..5a4bb8441 100644
--- a/src/tools/clippy/tests/ui/match_single_binding2.rs
+++ b/src/tools/clippy/tests/ui/match_single_binding2.rs
@@ -1,7 +1,7 @@
// run-rustfix
-
#![warn(clippy::match_single_binding)]
#![allow(unused_variables)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
// Lint (additional curly braces needed, see #6572)
diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.edition2018.stderr b/src/tools/clippy/tests/ui/match_wild_err_arm.edition2018.stderr
deleted file mode 100644
index 2a4012039..000000000
--- a/src/tools/clippy/tests/ui/match_wild_err_arm.edition2018.stderr
+++ /dev/null
@@ -1,35 +0,0 @@
-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
-
diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.rs b/src/tools/clippy/tests/ui/match_wild_err_arm.rs
index 0a86144b9..823be65ef 100644
--- a/src/tools/clippy/tests/ui/match_wild_err_arm.rs
+++ b/src/tools/clippy/tests/ui/match_wild_err_arm.rs
@@ -1,6 +1,3 @@
-// revisions: edition2018 edition2021
-// [edition2018] edition:2018
-// [edition2021] edition:2021
#![feature(exclusive_range_pattern)]
#![allow(clippy::match_same_arms)]
#![warn(clippy::match_wild_err_arm)]
diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr b/src/tools/clippy/tests/ui/match_wild_err_arm.stderr
index 2a4012039..b016d6826 100644
--- a/src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/match_wild_err_arm.stderr
@@ -1,35 +1,35 @@
error: `Err(_)` matches all errors
- --> $DIR/match_wild_err_arm.rs:14:9
+ --> $DIR/match_wild_err_arm.rs:11:9
|
LL | Err(_) => panic!("err"),
| ^^^^^^
|
+ = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
= 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
+ --> $DIR/match_wild_err_arm.rs:17:9
|
LL | Err(_) => panic!(),
| ^^^^^^
|
- = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+ = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
error: `Err(_)` matches all errors
- --> $DIR/match_wild_err_arm.rs:26:9
+ --> $DIR/match_wild_err_arm.rs:23:9
|
LL | Err(_) => {
| ^^^^^^
|
- = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+ = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
error: `Err(_e)` matches all errors
- --> $DIR/match_wild_err_arm.rs:34:9
+ --> $DIR/match_wild_err_arm.rs:31: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
+ = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/mem_replace.fixed b/src/tools/clippy/tests/ui/mem_replace.fixed
index b609ba659..ae237395b 100644
--- a/src/tools/clippy/tests/ui/mem_replace.fixed
+++ b/src/tools/clippy/tests/ui/mem_replace.fixed
@@ -1,5 +1,7 @@
// run-rustfix
-#![allow(unused_imports)]
+
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
#![warn(
clippy::all,
clippy::style,
@@ -77,3 +79,17 @@ fn main() {
replace_with_default();
dont_lint_primitive();
}
+
+fn msrv_1_39() {
+ #![clippy::msrv = "1.39"]
+
+ let mut s = String::from("foo");
+ let _ = std::mem::replace(&mut s, String::default());
+}
+
+fn msrv_1_40() {
+ #![clippy::msrv = "1.40"]
+
+ let mut s = String::from("foo");
+ let _ = std::mem::take(&mut s);
+}
diff --git a/src/tools/clippy/tests/ui/mem_replace.rs b/src/tools/clippy/tests/ui/mem_replace.rs
index 93f6dcdec..3202e99e0 100644
--- a/src/tools/clippy/tests/ui/mem_replace.rs
+++ b/src/tools/clippy/tests/ui/mem_replace.rs
@@ -1,5 +1,7 @@
// run-rustfix
-#![allow(unused_imports)]
+
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
#![warn(
clippy::all,
clippy::style,
@@ -77,3 +79,17 @@ fn main() {
replace_with_default();
dont_lint_primitive();
}
+
+fn msrv_1_39() {
+ #![clippy::msrv = "1.39"]
+
+ let mut s = String::from("foo");
+ let _ = std::mem::replace(&mut s, String::default());
+}
+
+fn msrv_1_40() {
+ #![clippy::msrv = "1.40"]
+
+ let mut s = String::from("foo");
+ let _ = std::mem::replace(&mut s, String::default());
+}
diff --git a/src/tools/clippy/tests/ui/mem_replace.stderr b/src/tools/clippy/tests/ui/mem_replace.stderr
index 90dc6c95f..dd8a50dab 100644
--- a/src/tools/clippy/tests/ui/mem_replace.stderr
+++ b/src/tools/clippy/tests/ui/mem_replace.stderr
@@ -1,5 +1,5 @@
error: replacing an `Option` with `None`
- --> $DIR/mem_replace.rs:15:13
+ --> $DIR/mem_replace.rs:17:13
|
LL | let _ = mem::replace(&mut an_option, None);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
@@ -7,13 +7,13 @@ LL | let _ = mem::replace(&mut an_option, None);
= note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings`
error: replacing an `Option` with `None`
- --> $DIR/mem_replace.rs:17:13
+ --> $DIR/mem_replace.rs:19:13
|
LL | let _ = mem::replace(an_option, None);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:22:13
+ --> $DIR/mem_replace.rs:24:13
|
LL | let _ = std::mem::replace(&mut s, String::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)`
@@ -21,100 +21,106 @@ LL | let _ = std::mem::replace(&mut s, String::default());
= note: `-D clippy::mem-replace-with-default` implied by `-D warnings`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:25:13
+ --> $DIR/mem_replace.rs:27:13
|
LL | let _ = std::mem::replace(s, String::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:26:13
+ --> $DIR/mem_replace.rs:28:13
|
LL | let _ = std::mem::replace(s, Default::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:29:13
+ --> $DIR/mem_replace.rs:31:13
|
LL | let _ = std::mem::replace(&mut v, Vec::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:30:13
+ --> $DIR/mem_replace.rs:32:13
|
LL | let _ = std::mem::replace(&mut v, Default::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:31:13
+ --> $DIR/mem_replace.rs:33:13
|
LL | let _ = std::mem::replace(&mut v, Vec::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:32:13
+ --> $DIR/mem_replace.rs:34:13
|
LL | let _ = std::mem::replace(&mut v, vec![]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:35:13
+ --> $DIR/mem_replace.rs:37:13
|
LL | let _ = std::mem::replace(&mut hash_map, HashMap::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_map)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:38:13
+ --> $DIR/mem_replace.rs:40:13
|
LL | let _ = std::mem::replace(&mut btree_map, BTreeMap::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_map)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:41:13
+ --> $DIR/mem_replace.rs:43:13
|
LL | let _ = std::mem::replace(&mut vd, VecDeque::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut vd)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:44:13
+ --> $DIR/mem_replace.rs:46:13
|
LL | let _ = std::mem::replace(&mut hash_set, HashSet::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_set)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:47:13
+ --> $DIR/mem_replace.rs:49:13
|
LL | let _ = std::mem::replace(&mut btree_set, BTreeSet::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_set)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:50:13
+ --> $DIR/mem_replace.rs:52:13
|
LL | let _ = std::mem::replace(&mut list, LinkedList::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut list)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:53:13
+ --> $DIR/mem_replace.rs:55:13
|
LL | let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut binary_heap)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:56:13
+ --> $DIR/mem_replace.rs:58:13
|
LL | let _ = std::mem::replace(&mut tuple, (vec![], BinaryHeap::new()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut tuple)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:59:13
+ --> $DIR/mem_replace.rs:61:13
|
LL | let _ = std::mem::replace(&mut refstr, "");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut refstr)`
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
- --> $DIR/mem_replace.rs:62:13
+ --> $DIR/mem_replace.rs:64:13
|
LL | let _ = std::mem::replace(&mut slice, &[]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut slice)`
-error: aborting due to 19 previous errors
+error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
+ --> $DIR/mem_replace.rs:94:13
+ |
+LL | let _ = std::mem::replace(&mut s, String::default());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)`
+
+error: aborting due to 20 previous errors
diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs
index 1970c2eae..6f22366ea 100644
--- a/src/tools/clippy/tests/ui/methods.rs
+++ b/src/tools/clippy/tests/ui/methods.rs
@@ -2,7 +2,7 @@
#![warn(clippy::all, clippy::pedantic)]
#![allow(
- clippy::blacklisted_name,
+ clippy::disallowed_names,
clippy::default_trait_access,
clippy::missing_docs_in_private_items,
clippy::missing_safety_doc,
diff --git a/src/tools/clippy/tests/ui/min_max.rs b/src/tools/clippy/tests/ui/min_max.rs
index b2bc97f47..24e52afd6 100644
--- a/src/tools/clippy/tests/ui/min_max.rs
+++ b/src/tools/clippy/tests/ui/min_max.rs
@@ -1,4 +1,5 @@
#![warn(clippy::all)]
+#![allow(clippy::manual_clamp)]
use std::cmp::max as my_max;
use std::cmp::min as my_min;
diff --git a/src/tools/clippy/tests/ui/min_max.stderr b/src/tools/clippy/tests/ui/min_max.stderr
index c70b77eab..069d90686 100644
--- a/src/tools/clippy/tests/ui/min_max.stderr
+++ b/src/tools/clippy/tests/ui/min_max.stderr
@@ -1,5 +1,5 @@
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:23:5
+ --> $DIR/min_max.rs:24:5
|
LL | min(1, max(3, x));
| ^^^^^^^^^^^^^^^^^
@@ -7,73 +7,73 @@ LL | min(1, max(3, x));
= note: `-D clippy::min-max` implied by `-D warnings`
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:24:5
+ --> $DIR/min_max.rs:25:5
|
LL | min(max(3, x), 1);
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:25:5
+ --> $DIR/min_max.rs:26:5
|
LL | max(min(x, 1), 3);
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:26:5
+ --> $DIR/min_max.rs:27:5
|
LL | max(3, min(x, 1));
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:28:5
+ --> $DIR/min_max.rs:29:5
|
LL | my_max(3, my_min(x, 1));
| ^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:38:5
+ --> $DIR/min_max.rs:39:5
|
LL | min("Apple", max("Zoo", s));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:39:5
+ --> $DIR/min_max.rs:40:5
|
LL | max(min(s, "Apple"), "Zoo");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:44:5
+ --> $DIR/min_max.rs:45:5
|
LL | x.min(1).max(3);
| ^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:45:5
+ --> $DIR/min_max.rs:46:5
|
LL | x.max(3).min(1);
| ^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:46:5
+ --> $DIR/min_max.rs:47:5
|
LL | f.max(3f32).min(1f32);
| ^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:52:5
+ --> $DIR/min_max.rs:53:5
|
LL | max(x.min(1), 3);
| ^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:55:5
+ --> $DIR/min_max.rs:56:5
|
LL | s.max("Zoo").min("Apple");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:56:5
+ --> $DIR/min_max.rs:57:5
|
LL | s.min("Apple").max("Zoo");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/min_rust_version_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_attr.rs
index 44e407bd1..cd148063b 100644
--- a/src/tools/clippy/tests/ui/min_rust_version_attr.rs
+++ b/src/tools/clippy/tests/ui/min_rust_version_attr.rs
@@ -1,228 +1,29 @@
#![allow(clippy::redundant_clone)]
#![feature(custom_inner_attributes)]
-#![clippy::msrv = "1.0.0"]
-use std::ops::{Deref, RangeFrom};
+fn main() {}
-fn approx_const() {
+fn just_under_msrv() {
+ #![clippy::msrv = "1.42.0"]
let log2_10 = 3.321928094887362;
- let log10_2 = 0.301029995663981;
}
-fn cloned_instead_of_copied() {
- let _ = [1].iter().cloned();
-}
-
-fn option_as_ref_deref() {
- let mut opt = Some(String::from("123"));
-
- let _ = opt.as_ref().map(String::as_str);
- let _ = opt.as_ref().map(|x| x.as_str());
- let _ = opt.as_mut().map(String::as_mut_str);
- let _ = opt.as_mut().map(|x| x.as_mut_str());
-}
-
-fn match_like_matches() {
- let _y = match Some(5) {
- Some(0) => true,
- _ => false,
- };
-}
-
-fn match_same_arms() {
- match (1, 2, 3) {
- (1, .., 3) => 42,
- (.., 3) => 42, //~ ERROR match arms have same body
- _ => 0,
- };
-}
-
-fn match_same_arms2() {
- let _ = match Some(42) {
- Some(_) => 24,
- None => 24, //~ ERROR match arms have same body
- };
-}
-
-pub fn manual_strip_msrv() {
- let s = "hello, world!";
- if s.starts_with("hello, ") {
- assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
- }
-}
-
-pub fn redundant_fieldnames() {
- let start = 0;
- let _ = RangeFrom { start: start };
-}
-
-pub fn redundant_static_lifetime() {
- const VAR_ONE: &'static str = "Test constant #1";
-}
-
-pub fn checked_conversion() {
- let value: i64 = 42;
- let _ = value <= (u32::max_value() as i64) && value >= 0;
- let _ = value <= (u32::MAX as i64) && value >= 0;
-}
-
-pub struct FromOverInto(String);
-
-impl Into<FromOverInto> for String {
- fn into(self) -> FromOverInto {
- FromOverInto(self)
- }
-}
-
-pub fn filter_map_next() {
- let a = ["1", "lol", "3", "NaN", "5"];
-
- #[rustfmt::skip]
- let _: Option<u32> = vec![1, 2, 3, 4, 5, 6]
- .into_iter()
- .filter_map(|x| {
- if x == 2 {
- Some(x * 2)
- } else {
- None
- }
- })
- .next();
-}
-
-#[allow(clippy::no_effect)]
-#[allow(clippy::short_circuit_statement)]
-#[allow(clippy::unnecessary_operation)]
-pub fn manual_range_contains() {
- let x = 5;
- x >= 8 && x < 12;
-}
-
-pub fn use_self() {
- struct Foo;
-
- impl Foo {
- fn new() -> Foo {
- Foo {}
- }
- fn test() -> Foo {
- Foo::new()
- }
- }
-}
-
-fn replace_with_default() {
- let mut s = String::from("foo");
- let _ = std::mem::replace(&mut s, String::default());
-}
-
-fn map_unwrap_or() {
- let opt = Some(1);
-
- // Check for `option.map(_).unwrap_or(_)` use.
- // Single line case.
- let _ = opt
- .map(|x| x + 1)
- // Should lint even though this call is on a separate line.
- .unwrap_or(0);
-}
-
-// Could be const
-fn missing_const_for_fn() -> i32 {
- 1
-}
-
-fn unnest_or_patterns() {
- struct TS(u8, u8);
- if let TS(0, x) | TS(1, x) = TS(0, 0) {}
-}
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-fn deprecated_cfg_attr() {}
-
-#[warn(clippy::cast_lossless)]
-fn int_from_bool() -> u8 {
- true as u8
-}
-
-fn err_expect() {
- let x: Result<u32, &str> = Ok(10);
- x.err().expect("Testing expect_err");
-}
-
-fn cast_abs_to_unsigned() {
- let x: i32 = 10;
- assert_eq!(10u32, x.abs() as u32);
-}
-
-fn manual_rem_euclid() {
- let x: i32 = 10;
- let _: i32 = ((x % 4) + 4) % 4;
-}
-
-fn main() {
- filter_map_next();
- checked_conversion();
- redundant_fieldnames();
- redundant_static_lifetime();
- option_as_ref_deref();
- match_like_matches();
- match_same_arms();
- match_same_arms2();
- manual_strip_msrv();
- manual_range_contains();
- use_self();
- replace_with_default();
- map_unwrap_or();
- missing_const_for_fn();
- unnest_or_patterns();
- int_from_bool();
- err_expect();
- cast_abs_to_unsigned();
- manual_rem_euclid();
+fn meets_msrv() {
+ #![clippy::msrv = "1.43.0"]
+ let log2_10 = 3.321928094887362;
}
-mod just_under_msrv {
- #![feature(custom_inner_attributes)]
+fn just_above_msrv() {
#![clippy::msrv = "1.44.0"]
-
- fn main() {
- let s = "hello, world!";
- if s.starts_with("hello, ") {
- assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
- }
- }
-}
-
-mod meets_msrv {
- #![feature(custom_inner_attributes)]
- #![clippy::msrv = "1.45.0"]
-
- fn main() {
- let s = "hello, world!";
- if s.starts_with("hello, ") {
- assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
- }
- }
+ let log2_10 = 3.321928094887362;
}
-mod just_above_msrv {
- #![feature(custom_inner_attributes)]
- #![clippy::msrv = "1.46.0"]
-
- fn main() {
- let s = "hello, world!";
- if s.starts_with("hello, ") {
- assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
- }
- }
+fn no_patch_under() {
+ #![clippy::msrv = "1.42"]
+ let log2_10 = 3.321928094887362;
}
-mod const_rem_euclid {
- #![feature(custom_inner_attributes)]
- #![clippy::msrv = "1.50.0"]
-
- pub const fn const_rem_euclid_4(num: i32) -> i32 {
- ((num % 4) + 4) % 4
- }
+fn no_patch_meets() {
+ #![clippy::msrv = "1.43"]
+ let log2_10 = 3.321928094887362;
}
diff --git a/src/tools/clippy/tests/ui/min_rust_version_attr.stderr b/src/tools/clippy/tests/ui/min_rust_version_attr.stderr
index b1c23b539..68aa58748 100644
--- a/src/tools/clippy/tests/ui/min_rust_version_attr.stderr
+++ b/src/tools/clippy/tests/ui/min_rust_version_attr.stderr
@@ -1,37 +1,27 @@
-error: stripping a prefix manually
- --> $DIR/min_rust_version_attr.rs:204:24
+error: approximate value of `f{32, 64}::consts::LOG2_10` found
+ --> $DIR/min_rust_version_attr.rs:13:19
|
-LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = note: `-D clippy::manual-strip` implied by `-D warnings`
-note: the prefix was tested here
- --> $DIR/min_rust_version_attr.rs:203:9
- |
-LL | if s.starts_with("hello, ") {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: try using the `strip_prefix` method
- |
-LL ~ if let Some(<stripped>) = s.strip_prefix("hello, ") {
-LL ~ assert_eq!(<stripped>.to_uppercase(), "WORLD!");
+LL | let log2_10 = 3.321928094887362;
+ | ^^^^^^^^^^^^^^^^^
|
+ = help: consider using the constant directly
+ = note: `#[deny(clippy::approx_constant)]` on by default
-error: stripping a prefix manually
- --> $DIR/min_rust_version_attr.rs:216:24
+error: approximate value of `f{32, 64}::consts::LOG2_10` found
+ --> $DIR/min_rust_version_attr.rs:18:19
|
-LL | assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
- | ^^^^^^^^^^^^^^^^^^^^
+LL | let log2_10 = 3.321928094887362;
+ | ^^^^^^^^^^^^^^^^^
|
-note: the prefix was tested here
- --> $DIR/min_rust_version_attr.rs:215:9
- |
-LL | if s.starts_with("hello, ") {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: try using the `strip_prefix` method
+ = help: consider using the constant directly
+
+error: approximate value of `f{32, 64}::consts::LOG2_10` found
+ --> $DIR/min_rust_version_attr.rs:28:19
|
-LL ~ if let Some(<stripped>) = s.strip_prefix("hello, ") {
-LL ~ assert_eq!(<stripped>.to_uppercase(), "WORLD!");
+LL | let log2_10 = 3.321928094887362;
+ | ^^^^^^^^^^^^^^^^^
|
+ = help: consider using the constant directly
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs
index f20841891..02892f329 100644
--- a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs
+++ b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs
@@ -2,3 +2,17 @@
#![clippy::msrv = "invalid.version"]
fn main() {}
+
+#[clippy::msrv = "invalid.version"]
+fn outer_attr() {}
+
+mod multiple {
+ #![clippy::msrv = "1.40"]
+ #![clippy::msrv = "=1.35.0"]
+ #![clippy::msrv = "1.10.1"]
+
+ mod foo {
+ #![clippy::msrv = "1"]
+ #![clippy::msrv = "1.0.0"]
+ }
+}
diff --git a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr
index 6ff88ca56..93370a0fa 100644
--- a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr
+++ b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr
@@ -4,5 +4,47 @@ error: `invalid.version` is not a valid Rust version
LL | #![clippy::msrv = "invalid.version"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error: `msrv` cannot be an outer attribute
+ --> $DIR/min_rust_version_invalid_attr.rs:6:1
+ |
+LL | #[clippy::msrv = "invalid.version"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `msrv` is defined multiple times
+ --> $DIR/min_rust_version_invalid_attr.rs:11:5
+ |
+LL | #![clippy::msrv = "=1.35.0"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: first definition found here
+ --> $DIR/min_rust_version_invalid_attr.rs:10:5
+ |
+LL | #![clippy::msrv = "1.40"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `msrv` is defined multiple times
+ --> $DIR/min_rust_version_invalid_attr.rs:12:5
+ |
+LL | #![clippy::msrv = "1.10.1"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: first definition found here
+ --> $DIR/min_rust_version_invalid_attr.rs:10:5
+ |
+LL | #![clippy::msrv = "1.40"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `msrv` is defined multiple times
+ --> $DIR/min_rust_version_invalid_attr.rs:16:9
+ |
+LL | #![clippy::msrv = "1.0.0"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: first definition found here
+ --> $DIR/min_rust_version_invalid_attr.rs:15:9
+ |
+LL | #![clippy::msrv = "1"]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.rs
deleted file mode 100644
index e882d5ccf..000000000
--- a/src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(custom_inner_attributes)]
-#![clippy::msrv = "1.40"]
-#![clippy::msrv = "=1.35.0"]
-#![clippy::msrv = "1.10.1"]
-
-mod foo {
- #![clippy::msrv = "1"]
- #![clippy::msrv = "1.0.0"]
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.stderr b/src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.stderr
deleted file mode 100644
index e3ff6605c..000000000
--- a/src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.stderr
+++ /dev/null
@@ -1,38 +0,0 @@
-error: `msrv` is defined multiple times
- --> $DIR/min_rust_version_multiple_inner_attr.rs:3:1
- |
-LL | #![clippy::msrv = "=1.35.0"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: first definition found here
- --> $DIR/min_rust_version_multiple_inner_attr.rs:2:1
- |
-LL | #![clippy::msrv = "1.40"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `msrv` is defined multiple times
- --> $DIR/min_rust_version_multiple_inner_attr.rs:4:1
- |
-LL | #![clippy::msrv = "1.10.1"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: first definition found here
- --> $DIR/min_rust_version_multiple_inner_attr.rs:2:1
- |
-LL | #![clippy::msrv = "1.40"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `msrv` is defined multiple times
- --> $DIR/min_rust_version_multiple_inner_attr.rs:8:5
- |
-LL | #![clippy::msrv = "1.0.0"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: first definition found here
- --> $DIR/min_rust_version_multiple_inner_attr.rs:7:5
- |
-LL | #![clippy::msrv = "1"]
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
diff --git a/src/tools/clippy/tests/ui/min_rust_version_no_patch.rs b/src/tools/clippy/tests/ui/min_rust_version_no_patch.rs
deleted file mode 100644
index 98fffe1e3..000000000
--- a/src/tools/clippy/tests/ui/min_rust_version_no_patch.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-#![allow(clippy::redundant_clone)]
-#![feature(custom_inner_attributes)]
-#![clippy::msrv = "1.0"]
-
-fn manual_strip_msrv() {
- let s = "hello, world!";
- if s.starts_with("hello, ") {
- assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
- }
-}
-
-fn main() {
- manual_strip_msrv()
-}
diff --git a/src/tools/clippy/tests/ui/min_rust_version_outer_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_outer_attr.rs
deleted file mode 100644
index 551948bd7..000000000
--- a/src/tools/clippy/tests/ui/min_rust_version_outer_attr.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#![feature(custom_inner_attributes)]
-
-#[clippy::msrv = "invalid.version"]
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/min_rust_version_outer_attr.stderr b/src/tools/clippy/tests/ui/min_rust_version_outer_attr.stderr
deleted file mode 100644
index 579ee7a87..000000000
--- a/src/tools/clippy/tests/ui/min_rust_version_outer_attr.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `msrv` cannot be an outer attribute
- --> $DIR/min_rust_version_outer_attr.rs:3:1
- |
-LL | #[clippy::msrv = "invalid.version"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr b/src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr
index 3534b5328..9822c77c9 100644
--- a/src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr
+++ b/src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr
@@ -6,8 +6,8 @@ LL | #[cfg(linux)]
| |
| help: try: `target_os = "linux"`
|
- = note: `-D clippy::mismatched-target-os` implied by `-D warnings`
= help: did you mean `unix`?
+ = note: `-D clippy::mismatched-target-os` implied by `-D warnings`
error: operating system used in target family position
--> $DIR/mismatched_target_os_unix.rs:9:1
diff --git a/src/tools/clippy/tests/ui/mismatching_type_param_order.rs b/src/tools/clippy/tests/ui/mismatching_type_param_order.rs
index 8c0da84d8..40c1fcae1 100644
--- a/src/tools/clippy/tests/ui/mismatching_type_param_order.rs
+++ b/src/tools/clippy/tests/ui/mismatching_type_param_order.rs
@@ -1,5 +1,5 @@
#![warn(clippy::mismatching_type_param_order)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
fn main() {
struct Foo<A, B> {
diff --git a/src/tools/clippy/tests/ui/mismatching_type_param_order.stderr b/src/tools/clippy/tests/ui/mismatching_type_param_order.stderr
index cb720256c..204d49905 100644
--- a/src/tools/clippy/tests/ui/mismatching_type_param_order.stderr
+++ b/src/tools/clippy/tests/ui/mismatching_type_param_order.stderr
@@ -4,8 +4,8 @@ error: `Foo` has a similarly named generic type parameter `B` in its declaration
LL | impl<B, A> Foo<B, A> {}
| ^
|
- = note: `-D clippy::mismatching-type-param-order` implied by `-D warnings`
= help: try `A`, or a name that does not conflict with `Foo`'s generic params
+ = note: `-D clippy::mismatching-type-param-order` implied by `-D warnings`
error: `Foo` has a similarly named generic type parameter `A` in its declaration, but in a different order
--> $DIR/mismatching_type_param_order.rs:11:23
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
index aa60d0504..b950248ef 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
@@ -3,12 +3,16 @@
//! The .stderr output of this test should be empty. Otherwise it's a bug somewhere.
// aux-build:helper.rs
+// aux-build:../../auxiliary/proc_macro_with_span.rs
#![warn(clippy::missing_const_for_fn)]
#![feature(start)]
#![feature(custom_inner_attributes)]
extern crate helper;
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
struct Game;
@@ -119,3 +123,8 @@ mod const_fn_stabilized_after_msrv {
byte.is_ascii_digit();
}
}
+
+with_span! {
+ span
+ fn dont_check_in_proc_macro() {}
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index 88f6935d2..b85e88784 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -77,5 +77,17 @@ mod const_fn_stabilized_before_msrv {
}
}
+fn msrv_1_45() -> i32 {
+ #![clippy::msrv = "1.45"]
+
+ 45
+}
+
+fn msrv_1_46() -> i32 {
+ #![clippy::msrv = "1.46"]
+
+ 46
+}
+
// Should not be const
fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
index 3eb52b682..f8e221c82 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -81,5 +81,15 @@ LL | | byte.is_ascii_digit();
LL | | }
| |_____^
-error: aborting due to 10 previous errors
+error: this could be a `const fn`
+ --> $DIR/could_be_const.rs:86:1
+ |
+LL | / fn msrv_1_46() -> i32 {
+LL | | #![clippy::msrv = "1.46"]
+LL | |
+LL | | 46
+LL | | }
+ | |_^
+
+error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/missing-doc.rs b/src/tools/clippy/tests/ui/missing_doc.rs
index 6e2e710e2..590ad63c9 100644
--- a/src/tools/clippy/tests/ui/missing-doc.rs
+++ b/src/tools/clippy/tests/ui/missing_doc.rs
@@ -1,3 +1,6 @@
+// needs-asm-support
+// aux-build: proc_macro_with_span.rs
+
#![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.
@@ -5,6 +8,9 @@
//! Some garbage docs for the crate here
#![doc = "More garbage"]
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
use std::arch::global_asm;
type Typedef = String;
@@ -100,3 +106,11 @@ fn main() {}
// Ensure global asm doesn't require documentation.
global_asm! { "" }
+
+// Don't lint proc macro output with an unexpected span.
+with_span!(span pub struct FooPm { pub field: u32});
+with_span!(span pub struct FooPm2;);
+with_span!(span pub enum FooPm3 { A, B(u32), C { field: u32 }});
+with_span!(span pub fn foo_pm() {});
+with_span!(span pub static FOO_PM: u32 = 0;);
+with_span!(span pub const FOO2_PM: u32 = 0;);
diff --git a/src/tools/clippy/tests/ui/missing-doc.stderr b/src/tools/clippy/tests/ui/missing_doc.stderr
index a876dc078..d3bef28bf 100644
--- a/src/tools/clippy/tests/ui/missing-doc.stderr
+++ b/src/tools/clippy/tests/ui/missing_doc.stderr
@@ -1,5 +1,5 @@
error: missing documentation for a type alias
- --> $DIR/missing-doc.rs:10:1
+ --> $DIR/missing_doc.rs:16:1
|
LL | type Typedef = String;
| ^^^^^^^^^^^^^^^^^^^^^^
@@ -7,37 +7,37 @@ 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:11:1
+ --> $DIR/missing_doc.rs:17:1
|
LL | pub type PubTypedef = String;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a module
- --> $DIR/missing-doc.rs:13:1
+ --> $DIR/missing_doc.rs:19:1
|
LL | mod module_no_dox {}
| ^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a module
- --> $DIR/missing-doc.rs:14:1
+ --> $DIR/missing_doc.rs:20:1
|
LL | pub mod pub_module_no_dox {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:18:1
+ --> $DIR/missing_doc.rs:24:1
|
LL | pub fn foo2() {}
| ^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:19:1
+ --> $DIR/missing_doc.rs:25:1
|
LL | fn foo3() {}
| ^^^^^^^^^^^^
error: missing documentation for an enum
- --> $DIR/missing-doc.rs:33:1
+ --> $DIR/missing_doc.rs:39:1
|
LL | / enum Baz {
LL | | BazA { a: isize, b: isize },
@@ -46,31 +46,31 @@ LL | | }
| |_^
error: missing documentation for a variant
- --> $DIR/missing-doc.rs:34:5
+ --> $DIR/missing_doc.rs:40:5
|
LL | BazA { a: isize, b: isize },
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:34:12
+ --> $DIR/missing_doc.rs:40:12
|
LL | BazA { a: isize, b: isize },
| ^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:34:22
+ --> $DIR/missing_doc.rs:40:22
|
LL | BazA { a: isize, b: isize },
| ^^^^^^^^
error: missing documentation for a variant
- --> $DIR/missing-doc.rs:35:5
+ --> $DIR/missing_doc.rs:41:5
|
LL | BarB,
| ^^^^
error: missing documentation for an enum
- --> $DIR/missing-doc.rs:38:1
+ --> $DIR/missing_doc.rs:44:1
|
LL | / pub enum PubBaz {
LL | | PubBazA { a: isize },
@@ -78,43 +78,43 @@ LL | | }
| |_^
error: missing documentation for a variant
- --> $DIR/missing-doc.rs:39:5
+ --> $DIR/missing_doc.rs:45:5
|
LL | PubBazA { a: isize },
| ^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:39:15
+ --> $DIR/missing_doc.rs:45:15
|
LL | PubBazA { a: isize },
| ^^^^^^^^
error: missing documentation for a constant
- --> $DIR/missing-doc.rs:59:1
+ --> $DIR/missing_doc.rs:65:1
|
LL | const FOO: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^
error: missing documentation for a constant
- --> $DIR/missing-doc.rs:66:1
+ --> $DIR/missing_doc.rs:72:1
|
LL | pub const FOO4: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a static
- --> $DIR/missing-doc.rs:68:1
+ --> $DIR/missing_doc.rs:74:1
|
LL | static BAR: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a static
- --> $DIR/missing-doc.rs:75:1
+ --> $DIR/missing_doc.rs:81:1
|
LL | pub static BAR4: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a module
- --> $DIR/missing-doc.rs:77:1
+ --> $DIR/missing_doc.rs:83:1
|
LL | / mod internal_impl {
LL | | /// dox
@@ -126,31 +126,31 @@ LL | | }
| |_^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:80:5
+ --> $DIR/missing_doc.rs:86:5
|
LL | pub fn undocumented1() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:81:5
+ --> $DIR/missing_doc.rs:87:5
|
LL | pub fn undocumented2() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:82:5
+ --> $DIR/missing_doc.rs:88:5
|
LL | fn undocumented3() {}
| ^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:87:9
+ --> $DIR/missing_doc.rs:93:9
|
LL | pub fn also_undocumented1() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:88:9
+ --> $DIR/missing_doc.rs:94:9
|
LL | fn also_undocumented2() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/missing-doc-crate.rs b/src/tools/clippy/tests/ui/missing_doc_crate.rs
index e00c7fbfe..e00c7fbfe 100644
--- a/src/tools/clippy/tests/ui/missing-doc-crate.rs
+++ b/src/tools/clippy/tests/ui/missing_doc_crate.rs
diff --git a/src/tools/clippy/tests/ui/missing-doc-crate-missing.rs b/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs
index 51fd57df8..51fd57df8 100644
--- a/src/tools/clippy/tests/ui/missing-doc-crate-missing.rs
+++ b/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs
diff --git a/src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr b/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr
index d56c5cc4c..19516bf5f 100644
--- a/src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr
+++ b/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr
@@ -1,5 +1,5 @@
error: missing documentation for the crate
- --> $DIR/missing-doc-crate-missing.rs:1:1
+ --> $DIR/missing_doc_crate_missing.rs:1:1
|
LL | / #![warn(clippy::missing_docs_in_private_items)]
LL | |
diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.rs b/src/tools/clippy/tests/ui/missing_doc_impl.rs
index d5724bf66..0396d1193 100644
--- a/src/tools/clippy/tests/ui/missing-doc-impl.rs
+++ b/src/tools/clippy/tests/ui/missing_doc_impl.rs
@@ -1,3 +1,5 @@
+// aux-build: proc_macro_with_span.rs
+
#![warn(clippy::missing_docs_in_private_items)]
#![allow(dead_code)]
#![feature(associated_type_defaults)]
@@ -5,6 +7,9 @@
//! Some garbage docs for the crate here
#![doc = "More garbage"]
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
struct Foo {
a: isize,
b: isize,
@@ -90,3 +95,13 @@ impl F for Foo {
}
fn main() {}
+
+// don't lint proc macro output
+with_span!(span
+ pub struct FooPm;
+ impl FooPm {
+ pub fn foo() {}
+ pub const fn bar() {}
+ pub const X: u32 = 0;
+ }
+);
diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.stderr b/src/tools/clippy/tests/ui/missing_doc_impl.stderr
index bda63d66a..f22fa19db 100644
--- a/src/tools/clippy/tests/ui/missing-doc-impl.stderr
+++ b/src/tools/clippy/tests/ui/missing_doc_impl.stderr
@@ -1,5 +1,5 @@
error: missing documentation for a struct
- --> $DIR/missing-doc-impl.rs:8:1
+ --> $DIR/missing_doc_impl.rs:13:1
|
LL | / struct Foo {
LL | | a: isize,
@@ -10,19 +10,19 @@ LL | | }
= note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
error: missing documentation for a struct field
- --> $DIR/missing-doc-impl.rs:9:5
+ --> $DIR/missing_doc_impl.rs:14:5
|
LL | a: isize,
| ^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/missing-doc-impl.rs:10:5
+ --> $DIR/missing_doc_impl.rs:15:5
|
LL | b: isize,
| ^^^^^^^^
error: missing documentation for a struct
- --> $DIR/missing-doc-impl.rs:13:1
+ --> $DIR/missing_doc_impl.rs:18:1
|
LL | / pub struct PubFoo {
LL | | pub a: isize,
@@ -31,19 +31,19 @@ LL | | }
| |_^
error: missing documentation for a struct field
- --> $DIR/missing-doc-impl.rs:14:5
+ --> $DIR/missing_doc_impl.rs:19:5
|
LL | pub a: isize,
| ^^^^^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/missing-doc-impl.rs:15:5
+ --> $DIR/missing_doc_impl.rs:20:5
|
LL | b: isize,
| ^^^^^^^^
error: missing documentation for a trait
- --> $DIR/missing-doc-impl.rs:38:1
+ --> $DIR/missing_doc_impl.rs:43:1
|
LL | / pub trait C {
LL | | fn foo(&self);
@@ -52,31 +52,31 @@ LL | | }
| |_^
error: missing documentation for an associated function
- --> $DIR/missing-doc-impl.rs:39:5
+ --> $DIR/missing_doc_impl.rs:44:5
|
LL | fn foo(&self);
| ^^^^^^^^^^^^^^
error: missing documentation for an associated function
- --> $DIR/missing-doc-impl.rs:40:5
+ --> $DIR/missing_doc_impl.rs:45:5
|
LL | fn foo_with_impl(&self) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for an associated type
- --> $DIR/missing-doc-impl.rs:50:5
+ --> $DIR/missing_doc_impl.rs:55:5
|
LL | type AssociatedType;
| ^^^^^^^^^^^^^^^^^^^^
error: missing documentation for an associated type
- --> $DIR/missing-doc-impl.rs:51:5
+ --> $DIR/missing_doc_impl.rs:56:5
|
LL | type AssociatedTypeDef = Self;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for an associated function
- --> $DIR/missing-doc-impl.rs:62:5
+ --> $DIR/missing_doc_impl.rs:67:5
|
LL | / pub fn new() -> Self {
LL | | Foo { a: 0, b: 0 }
@@ -84,19 +84,19 @@ LL | | }
| |_____^
error: missing documentation for an associated function
- --> $DIR/missing-doc-impl.rs:65:5
+ --> $DIR/missing_doc_impl.rs:70:5
|
LL | fn bar() {}
| ^^^^^^^^^^^
error: missing documentation for an associated function
- --> $DIR/missing-doc-impl.rs:69:5
+ --> $DIR/missing_doc_impl.rs:74:5
|
LL | pub fn foo() {}
| ^^^^^^^^^^^^^^^
error: missing documentation for an associated function
- --> $DIR/missing-doc-impl.rs:73:5
+ --> $DIR/missing_doc_impl.rs:78:5
|
LL | / fn foo2() -> u32 {
LL | | 1
diff --git a/src/tools/clippy/tests/ui/missing_panics_doc.stderr b/src/tools/clippy/tests/ui/missing_panics_doc.stderr
index 91ebd6952..c9ded7f1a 100644
--- a/src/tools/clippy/tests/ui/missing_panics_doc.stderr
+++ b/src/tools/clippy/tests/ui/missing_panics_doc.stderr
@@ -7,12 +7,12 @@ 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:8:5
|
LL | result.unwrap()
| ^^^^^^^^^^^^^^^
+ = note: `-D clippy::missing-panics-doc` implied by `-D warnings`
error: docs for function which may panic missing `# Panics` section
--> $DIR/missing_panics_doc.rs:12:1
diff --git a/src/tools/clippy/tests/ui/missing_trait_methods.rs b/src/tools/clippy/tests/ui/missing_trait_methods.rs
new file mode 100644
index 000000000..8df885919
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_trait_methods.rs
@@ -0,0 +1,50 @@
+#![allow(unused, clippy::needless_lifetimes)]
+#![warn(clippy::missing_trait_methods)]
+
+trait A {
+ fn provided() {}
+}
+
+trait B {
+ fn required();
+
+ fn a(_: usize) -> usize {
+ 1
+ }
+
+ fn b<'a, T: AsRef<[u8]>>(a: &'a T) -> &'a [u8] {
+ a.as_ref()
+ }
+}
+
+struct Partial;
+
+impl A for Partial {}
+
+impl B for Partial {
+ fn required() {}
+
+ fn a(_: usize) -> usize {
+ 2
+ }
+}
+
+struct Complete;
+
+impl A for Complete {
+ fn provided() {}
+}
+
+impl B for Complete {
+ fn required() {}
+
+ fn a(_: usize) -> usize {
+ 2
+ }
+
+ fn b<T: AsRef<[u8]>>(a: &T) -> &[u8] {
+ a.as_ref()
+ }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_trait_methods.stderr b/src/tools/clippy/tests/ui/missing_trait_methods.stderr
new file mode 100644
index 000000000..0c5205e19
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_trait_methods.stderr
@@ -0,0 +1,27 @@
+error: missing trait method provided by default: `provided`
+ --> $DIR/missing_trait_methods.rs:22:1
+ |
+LL | impl A for Partial {}
+ | ^^^^^^^^^^^^^^^^^^
+ |
+help: implement the method
+ --> $DIR/missing_trait_methods.rs:5:5
+ |
+LL | fn provided() {}
+ | ^^^^^^^^^^^^^
+ = note: `-D clippy::missing-trait-methods` implied by `-D warnings`
+
+error: missing trait method provided by default: `b`
+ --> $DIR/missing_trait_methods.rs:24:1
+ |
+LL | impl B for Partial {
+ | ^^^^^^^^^^^^^^^^^^
+ |
+help: implement the method
+ --> $DIR/missing_trait_methods.rs:15:5
+ |
+LL | fn b<'a, T: AsRef<[u8]>>(a: &'a T) -> &'a [u8] {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
index a7b36d53c..becb9562a 100644
--- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
@@ -1,4 +1,5 @@
// run-rustfix
+// aux-build: proc_macro_with_span.rs
#![allow(
dead_code,
@@ -9,6 +10,9 @@
clippy::unusual_byte_groupings
)]
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
fn main() {
let fail14 = 2_i32;
let fail15 = 4_i64;
@@ -40,4 +44,6 @@ fn main() {
let ok38 = 124_64.0;
let _ = 1.123_45E1_f32;
+
+ let _ = with_span!(1 2_u32);
}
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
index c97b31965..ee841bcd7 100644
--- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
@@ -1,4 +1,5 @@
// run-rustfix
+// aux-build: proc_macro_with_span.rs
#![allow(
dead_code,
@@ -9,6 +10,9 @@
clippy::unusual_byte_groupings
)]
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
fn main() {
let fail14 = 2_32;
let fail15 = 4_64;
@@ -40,4 +44,6 @@ fn main() {
let ok38 = 124_64.0;
let _ = 1.12345E1_32;
+
+ let _ = with_span!(1 2_u32);
}
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr b/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
index fb761d9bd..ef8e6a33d 100644
--- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
@@ -1,5 +1,5 @@
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:13:18
+ --> $DIR/mistyped_literal_suffix.rs:17:18
|
LL | let fail14 = 2_32;
| ^^^^ help: did you mean to write: `2_i32`
@@ -7,91 +7,91 @@ LL | let fail14 = 2_32;
= note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:14:18
+ --> $DIR/mistyped_literal_suffix.rs:18:18
|
LL | let fail15 = 4_64;
| ^^^^ help: did you mean to write: `4_i64`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:15:18
+ --> $DIR/mistyped_literal_suffix.rs:19:18
|
LL | let fail16 = 7_8; //
| ^^^ help: did you mean to write: `7_i8`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:16:18
+ --> $DIR/mistyped_literal_suffix.rs:20:18
|
LL | let fail17 = 23_16; //
| ^^^^^ help: did you mean to write: `23_i16`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:19:18
+ --> $DIR/mistyped_literal_suffix.rs:23:18
|
LL | let fail20 = 2__8; //
| ^^^^ help: did you mean to write: `2_i8`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:20:18
+ --> $DIR/mistyped_literal_suffix.rs:24:18
|
LL | let fail21 = 4___16; //
| ^^^^^^ help: did you mean to write: `4_i16`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:23:18
+ --> $DIR/mistyped_literal_suffix.rs:27:18
|
LL | let fail25 = 1E2_32;
| ^^^^^^ help: did you mean to write: `1E2_f32`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:24:18
+ --> $DIR/mistyped_literal_suffix.rs:28:18
|
LL | let fail26 = 43E7_64;
| ^^^^^^^ help: did you mean to write: `43E7_f64`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:25:18
+ --> $DIR/mistyped_literal_suffix.rs:29:18
|
LL | let fail27 = 243E17_32;
| ^^^^^^^^^ help: did you mean to write: `243E17_f32`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:26:18
+ --> $DIR/mistyped_literal_suffix.rs:30:18
|
LL | let fail28 = 241251235E723_64;
| ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:30:18
+ --> $DIR/mistyped_literal_suffix.rs:34:18
|
LL | let fail30 = 127_8; // should be i8
| ^^^^^ help: did you mean to write: `127_i8`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:31:18
+ --> $DIR/mistyped_literal_suffix.rs:35:18
|
LL | let fail31 = 240_8; // should be u8
| ^^^^^ help: did you mean to write: `240_u8`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:33:18
+ --> $DIR/mistyped_literal_suffix.rs:37:18
|
LL | let fail33 = 0x1234_16;
| ^^^^^^^^^ help: did you mean to write: `0x1234_i16`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:34:18
+ --> $DIR/mistyped_literal_suffix.rs:38:18
|
LL | let fail34 = 0xABCD_16;
| ^^^^^^^^^ help: did you mean to write: `0xABCD_u16`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:36:18
+ --> $DIR/mistyped_literal_suffix.rs:40:18
|
LL | let fail36 = 0xFFFF_FFFF_FFFF_FFFF_64; // u64
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to write: `0xFFFF_FFFF_FFFF_FFFF_u64`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:42:13
+ --> $DIR/mistyped_literal_suffix.rs:46:13
|
LL | let _ = 1.12345E1_32;
| ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32`
diff --git a/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs
index 7640057ab..6efc7657e 100644
--- a/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs
@@ -4,7 +4,7 @@
unused_variables,
clippy::no_effect,
dead_code,
- clippy::blacklisted_name
+ clippy::disallowed_names
)]
fn main() {
let mut x = 0;
diff --git a/src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr
index 2e951cdbc..8cc68b0ac 100644
--- a/src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr
+++ b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr
@@ -4,12 +4,12 @@ error: unsequenced read of `x`
LL | } + x;
| ^
|
- = note: `-D clippy::mixed-read-write-in-expression` implied by `-D warnings`
note: whether read occurs before this write depends on evaluation order
--> $DIR/mixed_read_write_in_expression.rs:12:9
|
LL | x = 1;
| ^^^^^
+ = note: `-D clippy::mixed-read-write-in-expression` implied by `-D warnings`
error: unsequenced read of `x`
--> $DIR/mixed_read_write_in_expression.rs:17:5
diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr b/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr
index 97844aaaa..36106de31 100644
--- a/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr
+++ b/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr
@@ -4,8 +4,8 @@ error: you are using modulo operator on constants with different signs: `-1.600
LL | -1.6 % 2.1;
| ^^^^^^^^^^
|
- = note: `-D clippy::modulo-arithmetic` implied by `-D warnings`
= note: double check for expected result especially when interoperating with different languages
+ = note: `-D clippy::modulo-arithmetic` implied by `-D warnings`
error: you are using modulo operator on constants with different signs: `1.600 % -2.100`
--> $DIR/modulo_arithmetic_float.rs:7:5
diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr b/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr
index f71adf5b0..9ff676ff6 100644
--- a/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr
+++ b/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr
@@ -4,9 +4,9 @@ error: you are using modulo operator on types that might have different signs
LL | a % b;
| ^^^^^
|
- = note: `-D clippy::modulo-arithmetic` implied by `-D warnings`
= note: double check for expected result especially when interoperating with different languages
= note: or consider using `rem_euclid` or similar function
+ = note: `-D clippy::modulo-arithmetic` implied by `-D warnings`
error: you are using modulo operator on types that might have different signs
--> $DIR/modulo_arithmetic_integral.rs:9:5
diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr b/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr
index 11b5f7746..1453d44f4 100644
--- a/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr
+++ b/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr
@@ -4,9 +4,9 @@ error: you are using modulo operator on constants with different signs: `-1 % 2`
LL | -1 % 2;
| ^^^^^^
|
- = note: `-D clippy::modulo-arithmetic` implied by `-D warnings`
= note: double check for expected result especially when interoperating with different languages
= note: or consider using `rem_euclid` or similar function
+ = note: `-D clippy::modulo-arithmetic` implied by `-D warnings`
error: you are using modulo operator on constants with different signs: `1 % -2`
--> $DIR/modulo_arithmetic_integral_const.rs:12:5
diff --git a/src/tools/clippy/tests/ui/multi_assignments.rs b/src/tools/clippy/tests/ui/multi_assignments.rs
new file mode 100644
index 000000000..b186bf8bb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/multi_assignments.rs
@@ -0,0 +1,9 @@
+#![warn(clippy::multi_assignments)]
+fn main() {
+ let (mut a, mut b, mut c, mut d) = ((), (), (), ());
+ a = b = c;
+ a = b = c = d;
+ a = b = { c };
+ a = { b = c };
+ a = (b = c);
+}
diff --git a/src/tools/clippy/tests/ui/multi_assignments.stderr b/src/tools/clippy/tests/ui/multi_assignments.stderr
new file mode 100644
index 000000000..d6c42bb69
--- /dev/null
+++ b/src/tools/clippy/tests/ui/multi_assignments.stderr
@@ -0,0 +1,40 @@
+error: assignments don't nest intuitively
+ --> $DIR/multi_assignments.rs:4:5
+ |
+LL | a = b = c;
+ | ^^^^^^^^^
+ |
+ = note: `-D clippy::multi-assignments` implied by `-D warnings`
+
+error: assignments don't nest intuitively
+ --> $DIR/multi_assignments.rs:5:5
+ |
+LL | a = b = c = d;
+ | ^^^^^^^^^^^^^
+
+error: assignments don't nest intuitively
+ --> $DIR/multi_assignments.rs:5:9
+ |
+LL | a = b = c = d;
+ | ^^^^^^^^^
+
+error: assignments don't nest intuitively
+ --> $DIR/multi_assignments.rs:6:5
+ |
+LL | a = b = { c };
+ | ^^^^^^^^^^^^^
+
+error: assignments don't nest intuitively
+ --> $DIR/multi_assignments.rs:7:5
+ |
+LL | a = { b = c };
+ | ^^^^^^^^^^^^^
+
+error: assignments don't nest intuitively
+ --> $DIR/multi_assignments.rs:8:5
+ |
+LL | a = (b = c);
+ | ^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mut_from_ref.stderr b/src/tools/clippy/tests/ui/mut_from_ref.stderr
index b76d6a13f..c20ff54bf 100644
--- a/src/tools/clippy/tests/ui/mut_from_ref.stderr
+++ b/src/tools/clippy/tests/ui/mut_from_ref.stderr
@@ -4,12 +4,12 @@ error: mutable borrow from immutable input(s)
LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo {
| ^^^^^^^^
|
- = note: `-D clippy::mut-from-ref` implied by `-D warnings`
note: immutable borrow here
--> $DIR/mut_from_ref.rs:7:29
|
LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo {
| ^^^^^
+ = note: `-D clippy::mut-from-ref` implied by `-D warnings`
error: mutable borrow from immutable input(s)
--> $DIR/mut_from_ref.rs:13:25
diff --git a/src/tools/clippy/tests/ui/mut_mut.rs b/src/tools/clippy/tests/ui/mut_mut.rs
index be854d941..ac8fd9d8f 100644
--- a/src/tools/clippy/tests/ui/mut_mut.rs
+++ b/src/tools/clippy/tests/ui/mut_mut.rs
@@ -1,7 +1,7 @@
// aux-build:macro_rules.rs
-
-#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
#![warn(clippy::mut_mut)]
+#![allow(unused)]
+#![allow(clippy::no_effect, clippy::uninlined_format_args, clippy::unnecessary_operation)]
#[macro_use]
extern crate macro_rules;
diff --git a/src/tools/clippy/tests/ui/mut_mutex_lock.fixed b/src/tools/clippy/tests/ui/mut_mutex_lock.fixed
index 36bc52e33..ecad10a82 100644
--- a/src/tools/clippy/tests/ui/mut_mutex_lock.fixed
+++ b/src/tools/clippy/tests/ui/mut_mutex_lock.fixed
@@ -18,4 +18,11 @@ fn no_owned_mutex_lock() {
*value += 1;
}
+fn issue9415() {
+ let mut arc_mutex = Arc::new(Mutex::new(42_u8));
+ let arc_mutex: &mut Arc<Mutex<u8>> = &mut arc_mutex;
+ let mut guard = arc_mutex.lock().unwrap();
+ *guard += 1;
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/mut_mutex_lock.rs b/src/tools/clippy/tests/ui/mut_mutex_lock.rs
index ea60df5ae..f2b1d6fbf 100644
--- a/src/tools/clippy/tests/ui/mut_mutex_lock.rs
+++ b/src/tools/clippy/tests/ui/mut_mutex_lock.rs
@@ -18,4 +18,11 @@ fn no_owned_mutex_lock() {
*value += 1;
}
+fn issue9415() {
+ let mut arc_mutex = Arc::new(Mutex::new(42_u8));
+ let arc_mutex: &mut Arc<Mutex<u8>> = &mut arc_mutex;
+ let mut guard = arc_mutex.lock().unwrap();
+ *guard += 1;
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/mut_range_bound.stderr b/src/tools/clippy/tests/ui/mut_range_bound.stderr
index 4b5a3fc1e..e0c8dced3 100644
--- a/src/tools/clippy/tests/ui/mut_range_bound.stderr
+++ b/src/tools/clippy/tests/ui/mut_range_bound.stderr
@@ -4,8 +4,8 @@ error: attempt to mutate range bound within loop
LL | m = 5;
| ^
|
- = note: `-D clippy::mut-range-bound` implied by `-D warnings`
= note: the range of the loop is unchanged
+ = note: `-D clippy::mut-range-bound` implied by `-D warnings`
error: attempt to mutate range bound within loop
--> $DIR/mut_range_bound.rs:15:9
diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed
index bfd2725ec..340e89d2d 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrow.fixed
@@ -1,9 +1,13 @@
// run-rustfix
-
-#![feature(lint_reasons)]
+#![feature(custom_inner_attributes, lint_reasons)]
#[warn(clippy::all, clippy::needless_borrow)]
-#[allow(unused_variables, clippy::unnecessary_mut_passed)]
+#[allow(unused_variables)]
+#[allow(
+ clippy::uninlined_format_args,
+ clippy::unnecessary_mut_passed,
+ clippy::unnecessary_to_owned
+)]
fn main() {
let a = 5;
let ref_a = &a;
@@ -127,6 +131,21 @@ fn main() {
0
}
}
+
+ let _ = std::process::Command::new("ls").args(["-a", "-l"]).status().unwrap();
+ let _ = std::path::Path::new(".").join(".");
+ deref_target_is_x(X);
+ multiple_constraints([[""]]);
+ multiple_constraints_normalizes_to_same(X, X);
+ let _ = Some("").unwrap_or("");
+ let _ = std::fs::write("x", "".to_string());
+
+ only_sized(&""); // Don't lint. `Sized` is only bound
+ let _ = std::any::Any::type_id(&""); // Don't lint. `Any` is only bound
+ let _ = Box::new(&""); // Don't lint. Type parameter appears in return type
+ ref_as_ref_path(&""); // Don't lint. Argument type is not a type parameter
+ refs_only(&()); // Don't lint. `&T` implements trait, but `T` doesn't
+ multiple_constraints_normalizes_to_different(&[[""]], &[""]); // Don't lint. Projected type appears in arguments
}
#[allow(clippy::needless_borrowed_reference)]
@@ -183,3 +202,186 @@ mod issue9160 {
}
}
}
+
+#[derive(Clone, Copy)]
+struct X;
+
+impl std::ops::Deref for X {
+ type Target = X;
+ fn deref(&self) -> &Self::Target {
+ self
+ }
+}
+
+fn deref_target_is_x<T>(_: T)
+where
+ T: std::ops::Deref<Target = X>,
+{
+}
+
+fn multiple_constraints<T, U, V, X, Y>(_: T)
+where
+ T: IntoIterator<Item = U> + IntoIterator<Item = X>,
+ U: IntoIterator<Item = V>,
+ V: AsRef<str>,
+ X: IntoIterator<Item = Y>,
+ Y: AsRef<std::ffi::OsStr>,
+{
+}
+
+fn multiple_constraints_normalizes_to_same<T, U, V>(_: T, _: V)
+where
+ T: std::ops::Deref<Target = U>,
+ U: std::ops::Deref<Target = V>,
+{
+}
+
+fn only_sized<T>(_: T) {}
+
+fn ref_as_ref_path<T: 'static>(_: &'static T)
+where
+ &'static T: AsRef<std::path::Path>,
+{
+}
+
+trait RefsOnly {
+ type Referent;
+}
+
+impl<T> RefsOnly for &T {
+ type Referent = T;
+}
+
+fn refs_only<T, U>(_: T)
+where
+ T: RefsOnly<Referent = U>,
+{
+}
+
+fn multiple_constraints_normalizes_to_different<T, U, V>(_: T, _: U)
+where
+ T: IntoIterator<Item = U>,
+ U: IntoIterator<Item = V>,
+ V: AsRef<str>,
+{
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321
+#[allow(dead_code)]
+mod copyable_iterator {
+ #[derive(Clone, Copy)]
+ struct Iter;
+ impl Iterator for Iter {
+ type Item = ();
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+ }
+ fn takes_iter(_: impl Iterator) {}
+ fn dont_warn(mut x: Iter) {
+ takes_iter(&mut x);
+ }
+ #[allow(unused_mut)]
+ fn warn(mut x: &mut Iter) {
+ takes_iter(x)
+ }
+}
+
+mod under_msrv {
+ #![allow(dead_code)]
+ #![clippy::msrv = "1.52.0"]
+
+ fn foo() {
+ let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+ }
+}
+
+mod meets_msrv {
+ #![allow(dead_code)]
+ #![clippy::msrv = "1.53.0"]
+
+ fn foo() {
+ let _ = std::process::Command::new("ls").args(["-a", "-l"]).status().unwrap();
+ }
+}
+
+#[allow(unused)]
+fn issue9383() {
+ // Should not lint because unions need explicit deref when accessing field
+ use std::mem::ManuallyDrop;
+
+ union Coral {
+ crab: ManuallyDrop<Vec<i32>>,
+ }
+
+ union Ocean {
+ coral: ManuallyDrop<Coral>,
+ }
+
+ let mut ocean = Ocean {
+ coral: ManuallyDrop::new(Coral {
+ crab: ManuallyDrop::new(vec![1, 2, 3]),
+ }),
+ };
+
+ unsafe {
+ ManuallyDrop::drop(&mut (&mut ocean.coral).crab);
+
+ (*ocean.coral).crab = ManuallyDrop::new(vec![4, 5, 6]);
+ ManuallyDrop::drop(&mut (*ocean.coral).crab);
+
+ ManuallyDrop::drop(&mut ocean.coral);
+ }
+}
+
+#[allow(dead_code)]
+fn closure_test() {
+ let env = "env".to_owned();
+ let arg = "arg".to_owned();
+ let f = |arg| {
+ let loc = "loc".to_owned();
+ let _ = std::fs::write("x", &env); // Don't lint. In environment
+ let _ = std::fs::write("x", arg);
+ let _ = std::fs::write("x", loc);
+ };
+ let _ = std::fs::write("x", &env); // Don't lint. Borrowed by `f`
+ f(arg);
+}
+
+#[allow(dead_code)]
+mod significant_drop {
+ #[derive(Debug)]
+ struct X;
+
+ #[derive(Debug)]
+ struct Y;
+
+ impl Drop for Y {
+ fn drop(&mut self) {}
+ }
+
+ fn foo(x: X, y: Y) {
+ debug(x);
+ debug(&y); // Don't lint. Has significant drop
+ }
+
+ fn debug(_: impl std::fmt::Debug) {}
+}
+
+#[allow(dead_code)]
+mod used_exactly_once {
+ fn foo(x: String) {
+ use_x(x);
+ }
+ fn use_x(_: impl AsRef<str>) {}
+}
+
+#[allow(dead_code)]
+mod used_more_than_once {
+ fn foo(x: String) {
+ use_x(&x);
+ use_x_again(&x);
+ }
+ fn use_x(_: impl AsRef<str>) {}
+ fn use_x_again(_: impl AsRef<str>) {}
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs
index c457d8c54..c93711ac8 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.rs
+++ b/src/tools/clippy/tests/ui/needless_borrow.rs
@@ -1,9 +1,13 @@
// run-rustfix
-
-#![feature(lint_reasons)]
+#![feature(custom_inner_attributes, lint_reasons)]
#[warn(clippy::all, clippy::needless_borrow)]
-#[allow(unused_variables, clippy::unnecessary_mut_passed)]
+#[allow(unused_variables)]
+#[allow(
+ clippy::uninlined_format_args,
+ clippy::unnecessary_mut_passed,
+ clippy::unnecessary_to_owned
+)]
fn main() {
let a = 5;
let ref_a = &a;
@@ -127,6 +131,21 @@ fn main() {
0
}
}
+
+ let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+ let _ = std::path::Path::new(".").join(&&".");
+ deref_target_is_x(&X);
+ multiple_constraints(&[[""]]);
+ multiple_constraints_normalizes_to_same(&X, X);
+ let _ = Some("").unwrap_or(&"");
+ let _ = std::fs::write("x", &"".to_string());
+
+ only_sized(&""); // Don't lint. `Sized` is only bound
+ let _ = std::any::Any::type_id(&""); // Don't lint. `Any` is only bound
+ let _ = Box::new(&""); // Don't lint. Type parameter appears in return type
+ ref_as_ref_path(&""); // Don't lint. Argument type is not a type parameter
+ refs_only(&()); // Don't lint. `&T` implements trait, but `T` doesn't
+ multiple_constraints_normalizes_to_different(&[[""]], &[""]); // Don't lint. Projected type appears in arguments
}
#[allow(clippy::needless_borrowed_reference)]
@@ -183,3 +202,186 @@ mod issue9160 {
}
}
}
+
+#[derive(Clone, Copy)]
+struct X;
+
+impl std::ops::Deref for X {
+ type Target = X;
+ fn deref(&self) -> &Self::Target {
+ self
+ }
+}
+
+fn deref_target_is_x<T>(_: T)
+where
+ T: std::ops::Deref<Target = X>,
+{
+}
+
+fn multiple_constraints<T, U, V, X, Y>(_: T)
+where
+ T: IntoIterator<Item = U> + IntoIterator<Item = X>,
+ U: IntoIterator<Item = V>,
+ V: AsRef<str>,
+ X: IntoIterator<Item = Y>,
+ Y: AsRef<std::ffi::OsStr>,
+{
+}
+
+fn multiple_constraints_normalizes_to_same<T, U, V>(_: T, _: V)
+where
+ T: std::ops::Deref<Target = U>,
+ U: std::ops::Deref<Target = V>,
+{
+}
+
+fn only_sized<T>(_: T) {}
+
+fn ref_as_ref_path<T: 'static>(_: &'static T)
+where
+ &'static T: AsRef<std::path::Path>,
+{
+}
+
+trait RefsOnly {
+ type Referent;
+}
+
+impl<T> RefsOnly for &T {
+ type Referent = T;
+}
+
+fn refs_only<T, U>(_: T)
+where
+ T: RefsOnly<Referent = U>,
+{
+}
+
+fn multiple_constraints_normalizes_to_different<T, U, V>(_: T, _: U)
+where
+ T: IntoIterator<Item = U>,
+ U: IntoIterator<Item = V>,
+ V: AsRef<str>,
+{
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321
+#[allow(dead_code)]
+mod copyable_iterator {
+ #[derive(Clone, Copy)]
+ struct Iter;
+ impl Iterator for Iter {
+ type Item = ();
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+ }
+ fn takes_iter(_: impl Iterator) {}
+ fn dont_warn(mut x: Iter) {
+ takes_iter(&mut x);
+ }
+ #[allow(unused_mut)]
+ fn warn(mut x: &mut Iter) {
+ takes_iter(&mut x)
+ }
+}
+
+mod under_msrv {
+ #![allow(dead_code)]
+ #![clippy::msrv = "1.52.0"]
+
+ fn foo() {
+ let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+ }
+}
+
+mod meets_msrv {
+ #![allow(dead_code)]
+ #![clippy::msrv = "1.53.0"]
+
+ fn foo() {
+ let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+ }
+}
+
+#[allow(unused)]
+fn issue9383() {
+ // Should not lint because unions need explicit deref when accessing field
+ use std::mem::ManuallyDrop;
+
+ union Coral {
+ crab: ManuallyDrop<Vec<i32>>,
+ }
+
+ union Ocean {
+ coral: ManuallyDrop<Coral>,
+ }
+
+ let mut ocean = Ocean {
+ coral: ManuallyDrop::new(Coral {
+ crab: ManuallyDrop::new(vec![1, 2, 3]),
+ }),
+ };
+
+ unsafe {
+ ManuallyDrop::drop(&mut (&mut ocean.coral).crab);
+
+ (*ocean.coral).crab = ManuallyDrop::new(vec![4, 5, 6]);
+ ManuallyDrop::drop(&mut (*ocean.coral).crab);
+
+ ManuallyDrop::drop(&mut ocean.coral);
+ }
+}
+
+#[allow(dead_code)]
+fn closure_test() {
+ let env = "env".to_owned();
+ let arg = "arg".to_owned();
+ let f = |arg| {
+ let loc = "loc".to_owned();
+ let _ = std::fs::write("x", &env); // Don't lint. In environment
+ let _ = std::fs::write("x", &arg);
+ let _ = std::fs::write("x", &loc);
+ };
+ let _ = std::fs::write("x", &env); // Don't lint. Borrowed by `f`
+ f(arg);
+}
+
+#[allow(dead_code)]
+mod significant_drop {
+ #[derive(Debug)]
+ struct X;
+
+ #[derive(Debug)]
+ struct Y;
+
+ impl Drop for Y {
+ fn drop(&mut self) {}
+ }
+
+ fn foo(x: X, y: Y) {
+ debug(&x);
+ debug(&y); // Don't lint. Has significant drop
+ }
+
+ fn debug(_: impl std::fmt::Debug) {}
+}
+
+#[allow(dead_code)]
+mod used_exactly_once {
+ fn foo(x: String) {
+ use_x(&x);
+ }
+ fn use_x(_: impl AsRef<str>) {}
+}
+
+#[allow(dead_code)]
+mod used_more_than_once {
+ fn foo(x: String) {
+ use_x(&x);
+ use_x_again(&x);
+ }
+ fn use_x(_: impl AsRef<str>) {}
+ fn use_x_again(_: impl AsRef<str>) {}
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr
index 66588689d..8b593268b 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrow.stderr
@@ -1,5 +1,5 @@
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:11:15
+ --> $DIR/needless_borrow.rs:15:15
|
LL | let _ = x(&&a); // warn
| ^^^ help: change this to: `&a`
@@ -7,130 +7,208 @@ LL | let _ = x(&&a); // warn
= note: `-D clippy::needless-borrow` implied by `-D warnings`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:15:13
+ --> $DIR/needless_borrow.rs:19:13
|
LL | mut_ref(&mut &mut b); // warn
| ^^^^^^^^^^^ help: change this to: `&mut b`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:27:13
+ --> $DIR/needless_borrow.rs:31:13
|
LL | &&a
| ^^^ help: change this to: `&a`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:29:15
+ --> $DIR/needless_borrow.rs:33:15
|
LL | 46 => &&a,
| ^^^ help: change this to: `&a`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:35:27
+ --> $DIR/needless_borrow.rs:39:27
|
LL | break &ref_a;
| ^^^^^^ help: change this to: `ref_a`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:42:15
+ --> $DIR/needless_borrow.rs:46:15
|
LL | let _ = x(&&&a);
| ^^^^ help: change this to: `&a`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:43:15
+ --> $DIR/needless_borrow.rs:47:15
|
LL | let _ = x(&mut &&a);
| ^^^^^^^^ help: change this to: `&a`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:44:15
+ --> $DIR/needless_borrow.rs:48:15
|
LL | let _ = x(&&&mut b);
| ^^^^^^^^ help: change this to: `&mut b`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:45:15
+ --> $DIR/needless_borrow.rs:49:15
|
LL | let _ = x(&&ref_a);
| ^^^^^^^ help: change this to: `ref_a`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:48:11
+ --> $DIR/needless_borrow.rs:52:11
|
LL | x(&b);
| ^^ help: change this to: `b`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:55:13
+ --> $DIR/needless_borrow.rs:59:13
|
LL | mut_ref(&mut x);
| ^^^^^^ help: change this to: `x`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:56:13
+ --> $DIR/needless_borrow.rs:60:13
|
LL | mut_ref(&mut &mut x);
| ^^^^^^^^^^^ help: change this to: `x`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:57:23
+ --> $DIR/needless_borrow.rs:61:23
|
LL | let y: &mut i32 = &mut x;
| ^^^^^^ help: change this to: `x`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:58:23
+ --> $DIR/needless_borrow.rs:62:23
|
LL | let y: &mut i32 = &mut &mut x;
| ^^^^^^^^^^^ help: change this to: `x`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:67:14
+ --> $DIR/needless_borrow.rs:71:14
|
LL | 0 => &mut x,
| ^^^^^^ help: change this to: `x`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:73:14
+ --> $DIR/needless_borrow.rs:77:14
|
LL | 0 => &mut x,
| ^^^^^^ help: change this to: `x`
error: this expression borrows a value the compiler would automatically borrow
- --> $DIR/needless_borrow.rs:85:13
+ --> $DIR/needless_borrow.rs:89:13
|
LL | let _ = (&x).0;
| ^^^^ help: change this to: `x`
error: this expression borrows a value the compiler would automatically borrow
- --> $DIR/needless_borrow.rs:87:22
+ --> $DIR/needless_borrow.rs:91:22
|
LL | let _ = unsafe { (&*x).0 };
| ^^^^^ help: change this to: `(*x)`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:97:5
+ --> $DIR/needless_borrow.rs:101:5
|
LL | (&&()).foo();
| ^^^^^^ help: change this to: `(&())`
error: this expression creates a reference which is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:106:5
+ --> $DIR/needless_borrow.rs:110:5
|
LL | (&&5).foo();
| ^^^^^ help: change this to: `(&5)`
+error: the borrowed expression implements the required traits
+ --> $DIR/needless_borrow.rs:135:51
+ |
+LL | let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+ | ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]`
+
+error: the borrowed expression implements the required traits
+ --> $DIR/needless_borrow.rs:136:44
+ |
+LL | let _ = std::path::Path::new(".").join(&&".");
+ | ^^^^^ help: change this to: `"."`
+
+error: the borrowed expression implements the required traits
+ --> $DIR/needless_borrow.rs:137:23
+ |
+LL | deref_target_is_x(&X);
+ | ^^ help: change this to: `X`
+
+error: the borrowed expression implements the required traits
+ --> $DIR/needless_borrow.rs:138:26
+ |
+LL | multiple_constraints(&[[""]]);
+ | ^^^^^^^ help: change this to: `[[""]]`
+
+error: the borrowed expression implements the required traits
+ --> $DIR/needless_borrow.rs:139:45
+ |
+LL | multiple_constraints_normalizes_to_same(&X, X);
+ | ^^ help: change this to: `X`
+
+error: this expression creates a reference which is immediately dereferenced by the compiler
+ --> $DIR/needless_borrow.rs:140:32
+ |
+LL | let _ = Some("").unwrap_or(&"");
+ | ^^^ help: change this to: `""`
+
+error: the borrowed expression implements the required traits
+ --> $DIR/needless_borrow.rs:141:33
+ |
+LL | let _ = std::fs::write("x", &"".to_string());
+ | ^^^^^^^^^^^^^^^ help: change this to: `"".to_string()`
+
error: this expression borrows a value the compiler would automatically borrow
- --> $DIR/needless_borrow.rs:173:13
+ --> $DIR/needless_borrow.rs:192:13
|
LL | (&self.f)()
| ^^^^^^^^^ help: change this to: `(self.f)`
error: this expression borrows a value the compiler would automatically borrow
- --> $DIR/needless_borrow.rs:182:13
+ --> $DIR/needless_borrow.rs:201:13
|
LL | (&mut self.f)()
| ^^^^^^^^^^^^^ help: change this to: `(self.f)`
-error: aborting due to 22 previous errors
+error: the borrowed expression implements the required traits
+ --> $DIR/needless_borrow.rs:286:20
+ |
+LL | takes_iter(&mut x)
+ | ^^^^^^ help: change this to: `x`
+
+error: the borrowed expression implements the required traits
+ --> $DIR/needless_borrow.rs:304:55
+ |
+LL | let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+ | ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]`
+
+error: the borrowed expression implements the required traits
+ --> $DIR/needless_borrow.rs:344:37
+ |
+LL | let _ = std::fs::write("x", &arg);
+ | ^^^^ help: change this to: `arg`
+
+error: the borrowed expression implements the required traits
+ --> $DIR/needless_borrow.rs:345:37
+ |
+LL | let _ = std::fs::write("x", &loc);
+ | ^^^^ help: change this to: `loc`
+
+error: the borrowed expression implements the required traits
+ --> $DIR/needless_borrow.rs:364:15
+ |
+LL | debug(&x);
+ | ^^ help: change this to: `x`
+
+error: the borrowed expression implements the required traits
+ --> $DIR/needless_borrow.rs:374:15
+ |
+LL | use_x(&x);
+ | ^^ help: change this to: `x`
+
+error: aborting due to 35 previous errors
diff --git a/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed b/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed
index a0937a2c5..bcb4eb2dd 100644
--- a/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed
@@ -1,17 +1,38 @@
// run-rustfix
-#[warn(clippy::needless_borrowed_reference)]
-#[allow(unused_variables)]
-fn main() {
+#![warn(clippy::needless_borrowed_reference)]
+#![allow(unused, clippy::needless_borrow)]
+
+fn main() {}
+
+fn should_lint(array: [u8; 4], slice: &[u8], slice_of_refs: &[&u8], vec: Vec<u8>) {
let mut v = Vec::<String>::new();
let _ = v.iter_mut().filter(|a| a.is_empty());
- // ^ should be linted
let var = 3;
let thingy = Some(&var);
- if let Some(&ref v) = thingy {
- // ^ should be linted
- }
+ if let Some(v) = thingy {}
+
+ if let &[a, ref b] = slice_of_refs {}
+
+ let [a, ..] = &array;
+ let [a, b, ..] = &array;
+
+ if let [a, b] = slice {}
+ if let [a, b] = &vec[..] {}
+
+ if let [a, b, ..] = slice {}
+ if let [a, .., b] = slice {}
+ if let [.., a, b] = slice {}
+}
+
+fn should_not_lint(array: [u8; 4], slice: &[u8], slice_of_refs: &[&u8], vec: Vec<u8>) {
+ if let [ref a] = slice {}
+ if let &[ref a, b] = slice {}
+ if let &[ref a, .., b] = slice {}
+
+ // must not be removed as variables must be bound consistently across | patterns
+ if let (&[ref a], _) | ([], ref a) = (slice_of_refs, &1u8) {}
let mut var2 = 5;
let thingy2 = Some(&mut var2);
@@ -28,17 +49,15 @@ fn main() {
}
}
-#[allow(dead_code)]
enum Animal {
Cat(u64),
Dog(u64),
}
-#[allow(unused_variables)]
-#[allow(dead_code)]
fn foo(a: &Animal, b: &Animal) {
match (a, b) {
- (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
+ // lifetime mismatch error if there is no '&ref' before `feature(nll)` stabilization in 1.63
+ (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (),
// ^ and ^ should **not** be linted
(&Animal::Dog(ref a), &Animal::Dog(_)) => (), // ^ should **not** be linted
}
diff --git a/src/tools/clippy/tests/ui/needless_borrowed_ref.rs b/src/tools/clippy/tests/ui/needless_borrowed_ref.rs
index 500ac448f..f6de1a6d8 100644
--- a/src/tools/clippy/tests/ui/needless_borrowed_ref.rs
+++ b/src/tools/clippy/tests/ui/needless_borrowed_ref.rs
@@ -1,17 +1,38 @@
// run-rustfix
-#[warn(clippy::needless_borrowed_reference)]
-#[allow(unused_variables)]
-fn main() {
+#![warn(clippy::needless_borrowed_reference)]
+#![allow(unused, clippy::needless_borrow)]
+
+fn main() {}
+
+fn should_lint(array: [u8; 4], slice: &[u8], slice_of_refs: &[&u8], vec: Vec<u8>) {
let mut v = Vec::<String>::new();
let _ = v.iter_mut().filter(|&ref a| a.is_empty());
- // ^ should be linted
let var = 3;
let thingy = Some(&var);
- if let Some(&ref v) = thingy {
- // ^ should be linted
- }
+ if let Some(&ref v) = thingy {}
+
+ if let &[&ref a, ref b] = slice_of_refs {}
+
+ let &[ref a, ..] = &array;
+ let &[ref a, ref b, ..] = &array;
+
+ if let &[ref a, ref b] = slice {}
+ if let &[ref a, ref b] = &vec[..] {}
+
+ if let &[ref a, ref b, ..] = slice {}
+ if let &[ref a, .., ref b] = slice {}
+ if let &[.., ref a, ref b] = slice {}
+}
+
+fn should_not_lint(array: [u8; 4], slice: &[u8], slice_of_refs: &[&u8], vec: Vec<u8>) {
+ if let [ref a] = slice {}
+ if let &[ref a, b] = slice {}
+ if let &[ref a, .., b] = slice {}
+
+ // must not be removed as variables must be bound consistently across | patterns
+ if let (&[ref a], _) | ([], ref a) = (slice_of_refs, &1u8) {}
let mut var2 = 5;
let thingy2 = Some(&mut var2);
@@ -28,17 +49,15 @@ fn main() {
}
}
-#[allow(dead_code)]
enum Animal {
Cat(u64),
Dog(u64),
}
-#[allow(unused_variables)]
-#[allow(dead_code)]
fn foo(a: &Animal, b: &Animal) {
match (a, b) {
- (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
+ // lifetime mismatch error if there is no '&ref' before `feature(nll)` stabilization in 1.63
+ (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (),
// ^ and ^ should **not** be linted
(&Animal::Dog(ref a), &Animal::Dog(_)) => (), // ^ should **not** be linted
}
diff --git a/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr b/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr
index 0a5cfb3db..7453542e6 100644
--- a/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr
@@ -1,10 +1,123 @@
-error: this pattern takes a reference on something that is being de-referenced
- --> $DIR/needless_borrowed_ref.rs:7:34
+error: this pattern takes a reference on something that is being dereferenced
+ --> $DIR/needless_borrowed_ref.rs:10:34
|
LL | let _ = v.iter_mut().filter(|&ref a| a.is_empty());
- | ^^^^^^ help: try removing the `&ref` part and just keep: `a`
+ | ^^^^^^
|
= note: `-D clippy::needless-borrowed-reference` implied by `-D warnings`
+help: try removing the `&ref` part
+ |
+LL - let _ = v.iter_mut().filter(|&ref a| a.is_empty());
+LL + let _ = v.iter_mut().filter(|a| a.is_empty());
+ |
+
+error: this pattern takes a reference on something that is being dereferenced
+ --> $DIR/needless_borrowed_ref.rs:14:17
+ |
+LL | if let Some(&ref v) = thingy {}
+ | ^^^^^^
+ |
+help: try removing the `&ref` part
+ |
+LL - if let Some(&ref v) = thingy {}
+LL + if let Some(v) = thingy {}
+ |
+
+error: this pattern takes a reference on something that is being dereferenced
+ --> $DIR/needless_borrowed_ref.rs:16:14
+ |
+LL | if let &[&ref a, ref b] = slice_of_refs {}
+ | ^^^^^^
+ |
+help: try removing the `&ref` part
+ |
+LL - if let &[&ref a, ref b] = slice_of_refs {}
+LL + if let &[a, ref b] = slice_of_refs {}
+ |
+
+error: dereferencing a slice pattern where every element takes a reference
+ --> $DIR/needless_borrowed_ref.rs:18:9
+ |
+LL | let &[ref a, ..] = &array;
+ | ^^^^^^^^^^^^
+ |
+help: try removing the `&` and `ref` parts
+ |
+LL - let &[ref a, ..] = &array;
+LL + let [a, ..] = &array;
+ |
+
+error: dereferencing a slice pattern where every element takes a reference
+ --> $DIR/needless_borrowed_ref.rs:19:9
+ |
+LL | let &[ref a, ref b, ..] = &array;
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+help: try removing the `&` and `ref` parts
+ |
+LL - let &[ref a, ref b, ..] = &array;
+LL + let [a, b, ..] = &array;
+ |
+
+error: dereferencing a slice pattern where every element takes a reference
+ --> $DIR/needless_borrowed_ref.rs:21:12
+ |
+LL | if let &[ref a, ref b] = slice {}
+ | ^^^^^^^^^^^^^^^
+ |
+help: try removing the `&` and `ref` parts
+ |
+LL - if let &[ref a, ref b] = slice {}
+LL + if let [a, b] = slice {}
+ |
+
+error: dereferencing a slice pattern where every element takes a reference
+ --> $DIR/needless_borrowed_ref.rs:22:12
+ |
+LL | if let &[ref a, ref b] = &vec[..] {}
+ | ^^^^^^^^^^^^^^^
+ |
+help: try removing the `&` and `ref` parts
+ |
+LL - if let &[ref a, ref b] = &vec[..] {}
+LL + if let [a, b] = &vec[..] {}
+ |
+
+error: dereferencing a slice pattern where every element takes a reference
+ --> $DIR/needless_borrowed_ref.rs:24:12
+ |
+LL | if let &[ref a, ref b, ..] = slice {}
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+help: try removing the `&` and `ref` parts
+ |
+LL - if let &[ref a, ref b, ..] = slice {}
+LL + if let [a, b, ..] = slice {}
+ |
+
+error: dereferencing a slice pattern where every element takes a reference
+ --> $DIR/needless_borrowed_ref.rs:25:12
+ |
+LL | if let &[ref a, .., ref b] = slice {}
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+help: try removing the `&` and `ref` parts
+ |
+LL - if let &[ref a, .., ref b] = slice {}
+LL + if let [a, .., b] = slice {}
+ |
+
+error: dereferencing a slice pattern where every element takes a reference
+ --> $DIR/needless_borrowed_ref.rs:26:12
+ |
+LL | if let &[.., ref a, ref b] = slice {}
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+help: try removing the `&` and `ref` parts
+ |
+LL - if let &[.., ref a, ref b] = slice {}
+LL + if let [.., a, b] = slice {}
+ |
-error: aborting due to previous error
+error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.rs b/src/tools/clippy/tests/ui/needless_collect_indirect.rs
index 1f11d1f8d..6d213b46c 100644
--- a/src/tools/clippy/tests/ui/needless_collect_indirect.rs
+++ b/src/tools/clippy/tests/ui/needless_collect_indirect.rs
@@ -1,3 +1,5 @@
+#![allow(clippy::uninlined_format_args)]
+
use std::collections::{BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
fn main() {
@@ -112,3 +114,192 @@ fn allow_test() {
let v = [1].iter().collect::<Vec<_>>();
v.into_iter().collect::<HashSet<_>>();
}
+
+mod issue_8553 {
+ fn test_for() {
+ let vec = vec![1, 2];
+ let w: Vec<usize> = vec.iter().map(|i| i * i).collect();
+
+ for i in 0..2 {
+ // Do not lint, because this method call is in the loop
+ w.contains(&i);
+ }
+
+ for i in 0..2 {
+ let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+ let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+ // Do lint
+ y.contains(&i);
+ for j in 0..2 {
+ // Do not lint, because this method call is in the loop
+ z.contains(&j);
+ }
+ }
+
+ // Do not lint, because this variable is used.
+ w.contains(&0);
+ }
+
+ fn test_while() {
+ let vec = vec![1, 2];
+ let x: Vec<usize> = vec.iter().map(|i| i * i).collect();
+ let mut n = 0;
+ while n > 1 {
+ // Do not lint, because this method call is in the loop
+ x.contains(&n);
+ n += 1;
+ }
+
+ while n > 2 {
+ let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+ let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+ // Do lint
+ y.contains(&n);
+ n += 1;
+ while n > 4 {
+ // Do not lint, because this method call is in the loop
+ z.contains(&n);
+ n += 1;
+ }
+ }
+ }
+
+ fn test_loop() {
+ let vec = vec![1, 2];
+ let x: Vec<usize> = vec.iter().map(|i| i * i).collect();
+ let mut n = 0;
+ loop {
+ if n < 1 {
+ // Do not lint, because this method call is in the loop
+ x.contains(&n);
+ n += 1;
+ } else {
+ break;
+ }
+ }
+
+ loop {
+ if n < 2 {
+ let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+ let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+ // Do lint
+ y.contains(&n);
+ n += 1;
+ loop {
+ if n < 4 {
+ // Do not lint, because this method call is in the loop
+ z.contains(&n);
+ n += 1;
+ } else {
+ break;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ fn test_while_let() {
+ let vec = vec![1, 2];
+ let x: Vec<usize> = vec.iter().map(|i| i * i).collect();
+ let optional = Some(0);
+ let mut n = 0;
+ while let Some(value) = optional {
+ if n < 1 {
+ // Do not lint, because this method call is in the loop
+ x.contains(&n);
+ n += 1;
+ } else {
+ break;
+ }
+ }
+
+ while let Some(value) = optional {
+ let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+ let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+ if n < 2 {
+ // Do lint
+ y.contains(&n);
+ n += 1;
+ } else {
+ break;
+ }
+
+ while let Some(value) = optional {
+ if n < 4 {
+ // Do not lint, because this method call is in the loop
+ z.contains(&n);
+ n += 1;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ fn test_if_cond() {
+ let vec = vec![1, 2];
+ let v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+ let w = v.iter().collect::<Vec<_>>();
+ // Do lint
+ for _ in 0..w.len() {
+ todo!();
+ }
+ }
+
+ fn test_if_cond_false_case() {
+ let vec = vec![1, 2];
+ let v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+ let w = v.iter().collect::<Vec<_>>();
+ // Do not lint, because w is used.
+ for _ in 0..w.len() {
+ todo!();
+ }
+
+ w.len();
+ }
+
+ fn test_while_cond() {
+ let mut vec = vec![1, 2];
+ let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+ let mut w = v.iter().collect::<Vec<_>>();
+ // Do lint
+ while 1 == w.len() {
+ todo!();
+ }
+ }
+
+ fn test_while_cond_false_case() {
+ let mut vec = vec![1, 2];
+ let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+ let mut w = v.iter().collect::<Vec<_>>();
+ // Do not lint, because w is used.
+ while 1 == w.len() {
+ todo!();
+ }
+
+ w.len();
+ }
+
+ fn test_while_let_cond() {
+ let mut vec = vec![1, 2];
+ let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+ let mut w = v.iter().collect::<Vec<_>>();
+ // Do lint
+ while let Some(i) = Some(w.len()) {
+ todo!();
+ }
+ }
+
+ fn test_while_let_cond_false_case() {
+ let mut vec = vec![1, 2];
+ let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+ let mut w = v.iter().collect::<Vec<_>>();
+ // Do not lint, because w is used.
+ while let Some(i) = Some(w.len()) {
+ todo!();
+ }
+ w.len();
+ }
+}
diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr
index 0f5e78f91..99e1b91d8 100644
--- a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr
+++ b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr
@@ -1,5 +1,5 @@
error: avoid using `collect()` when not needed
- --> $DIR/needless_collect_indirect.rs:5:39
+ --> $DIR/needless_collect_indirect.rs:7:39
|
LL | let indirect_iter = sample.iter().collect::<Vec<_>>();
| ^^^^^^^
@@ -14,7 +14,7 @@ LL ~ sample.iter().map(|x| (x, x + 1)).collect::<HashMap<_, _>>();
|
error: avoid using `collect()` when not needed
- --> $DIR/needless_collect_indirect.rs:7:38
+ --> $DIR/needless_collect_indirect.rs:9:38
|
LL | let indirect_len = sample.iter().collect::<VecDeque<_>>();
| ^^^^^^^
@@ -28,7 +28,7 @@ LL ~ sample.iter().count();
|
error: avoid using `collect()` when not needed
- --> $DIR/needless_collect_indirect.rs:9:40
+ --> $DIR/needless_collect_indirect.rs:11:40
|
LL | let indirect_empty = sample.iter().collect::<VecDeque<_>>();
| ^^^^^^^
@@ -42,7 +42,7 @@ LL ~ sample.iter().next().is_none();
|
error: avoid using `collect()` when not needed
- --> $DIR/needless_collect_indirect.rs:11:43
+ --> $DIR/needless_collect_indirect.rs:13:43
|
LL | let indirect_contains = sample.iter().collect::<VecDeque<_>>();
| ^^^^^^^
@@ -56,7 +56,7 @@ LL ~ sample.iter().any(|x| x == &5);
|
error: avoid using `collect()` when not needed
- --> $DIR/needless_collect_indirect.rs:23:48
+ --> $DIR/needless_collect_indirect.rs:25:48
|
LL | let non_copy_contains = sample.into_iter().collect::<Vec<_>>();
| ^^^^^^^
@@ -70,7 +70,7 @@ LL ~ sample.into_iter().any(|x| x == a);
|
error: avoid using `collect()` when not needed
- --> $DIR/needless_collect_indirect.rs:52:51
+ --> $DIR/needless_collect_indirect.rs:54:51
|
LL | let buffer: Vec<&str> = string.split('/').collect();
| ^^^^^^^
@@ -84,7 +84,7 @@ LL ~ string.split('/').count()
|
error: avoid using `collect()` when not needed
- --> $DIR/needless_collect_indirect.rs:57:55
+ --> $DIR/needless_collect_indirect.rs:59:55
|
LL | let indirect_len: VecDeque<_> = sample.iter().collect();
| ^^^^^^^
@@ -98,7 +98,7 @@ LL ~ sample.iter().count()
|
error: avoid using `collect()` when not needed
- --> $DIR/needless_collect_indirect.rs:62:57
+ --> $DIR/needless_collect_indirect.rs:64:57
|
LL | let indirect_len: LinkedList<_> = sample.iter().collect();
| ^^^^^^^
@@ -112,7 +112,7 @@ LL ~ sample.iter().count()
|
error: avoid using `collect()` when not needed
- --> $DIR/needless_collect_indirect.rs:67:57
+ --> $DIR/needless_collect_indirect.rs:69:57
|
LL | let indirect_len: BinaryHeap<_> = sample.iter().collect();
| ^^^^^^^
@@ -125,5 +125,122 @@ LL ~
LL ~ sample.iter().count()
|
-error: aborting due to 9 previous errors
+error: avoid using `collect()` when not needed
+ --> $DIR/needless_collect_indirect.rs:129:59
+ |
+LL | let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+ | ^^^^^^^
+...
+LL | y.contains(&i);
+ | -------------- the iterator could be used here instead
+ |
+help: check if the original Iterator contains an element instead of collecting then checking
+ |
+LL ~
+LL | let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+LL | // Do lint
+LL ~ vec.iter().map(|k| k * k).any(|x| x == i);
+ |
+
+error: avoid using `collect()` when not needed
+ --> $DIR/needless_collect_indirect.rs:154:59
+ |
+LL | let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+ | ^^^^^^^
+...
+LL | y.contains(&n);
+ | -------------- the iterator could be used here instead
+ |
+help: check if the original Iterator contains an element instead of collecting then checking
+ |
+LL ~
+LL | let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+LL | // Do lint
+LL ~ vec.iter().map(|k| k * k).any(|x| x == n);
+ |
+
+error: avoid using `collect()` when not needed
+ --> $DIR/needless_collect_indirect.rs:183:63
+ |
+LL | let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+ | ^^^^^^^
+...
+LL | y.contains(&n);
+ | -------------- the iterator could be used here instead
+ |
+help: check if the original Iterator contains an element instead of collecting then checking
+ |
+LL ~
+LL | let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+LL | // Do lint
+LL ~ vec.iter().map(|k| k * k).any(|x| x == n);
+ |
+
+error: avoid using `collect()` when not needed
+ --> $DIR/needless_collect_indirect.rs:219:59
+ |
+LL | let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+ | ^^^^^^^
+...
+LL | y.contains(&n);
+ | -------------- the iterator could be used here instead
+ |
+help: check if the original Iterator contains an element instead of collecting then checking
+ |
+LL ~
+LL | let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+LL | if n < 2 {
+LL | // Do lint
+LL ~ vec.iter().map(|k| k * k).any(|x| x == n);
+ |
+
+error: avoid using `collect()` when not needed
+ --> $DIR/needless_collect_indirect.rs:244:26
+ |
+LL | let w = v.iter().collect::<Vec<_>>();
+ | ^^^^^^^
+LL | // Do lint
+LL | for _ in 0..w.len() {
+ | ------- the iterator could be used here instead
+ |
+help: take the original Iterator's count instead of collecting it and finding the length
+ |
+LL ~
+LL | // Do lint
+LL ~ for _ in 0..v.iter().count() {
+ |
+
+error: avoid using `collect()` when not needed
+ --> $DIR/needless_collect_indirect.rs:266:30
+ |
+LL | let mut w = v.iter().collect::<Vec<_>>();
+ | ^^^^^^^
+LL | // Do lint
+LL | while 1 == w.len() {
+ | ------- the iterator could be used here instead
+ |
+help: take the original Iterator's count instead of collecting it and finding the length
+ |
+LL ~
+LL | // Do lint
+LL ~ while 1 == v.iter().count() {
+ |
+
+error: avoid using `collect()` when not needed
+ --> $DIR/needless_collect_indirect.rs:288:30
+ |
+LL | let mut w = v.iter().collect::<Vec<_>>();
+ | ^^^^^^^
+LL | // Do lint
+LL | while let Some(i) = Some(w.len()) {
+ | ------- the iterator could be used here instead
+ |
+help: take the original Iterator's count instead of collecting it and finding the length
+ |
+LL ~
+LL | // Do lint
+LL ~ while let Some(i) = Some(v.iter().count()) {
+ |
+
+error: aborting due to 16 previous errors
diff --git a/src/tools/clippy/tests/ui/needless_continue.rs b/src/tools/clippy/tests/ui/needless_continue.rs
index f105d3d65..c891c9de3 100644
--- a/src/tools/clippy/tests/ui/needless_continue.rs
+++ b/src/tools/clippy/tests/ui/needless_continue.rs
@@ -1,4 +1,5 @@
#![warn(clippy::needless_continue)]
+#![allow(clippy::uninlined_format_args)]
macro_rules! zero {
($x:expr) => {
diff --git a/src/tools/clippy/tests/ui/needless_continue.stderr b/src/tools/clippy/tests/ui/needless_continue.stderr
index b8657c74c..d99989b54 100644
--- a/src/tools/clippy/tests/ui/needless_continue.stderr
+++ b/src/tools/clippy/tests/ui/needless_continue.stderr
@@ -1,5 +1,5 @@
error: this `else` block is redundant
- --> $DIR/needless_continue.rs:29:16
+ --> $DIR/needless_continue.rs:30:16
|
LL | } else {
| ________________^
@@ -7,7 +7,6 @@ LL | | continue;
LL | | }
| |_________^
|
- = note: `-D clippy::needless-continue` implied by `-D warnings`
= help: consider dropping the `else` clause and merging the code that follows (in the loop) with the `if` block
if i % 2 == 0 && i % 3 == 0 {
println!("{}", i);
@@ -33,9 +32,10 @@ LL | | }
}
println!("bleh");
}
+ = note: `-D clippy::needless-continue` implied by `-D warnings`
error: there is no need for an explicit `else` block for this `if` expression
- --> $DIR/needless_continue.rs:44:9
+ --> $DIR/needless_continue.rs:45:9
|
LL | / if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
LL | | continue;
@@ -55,7 +55,7 @@ LL | | }
}
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:57:9
+ --> $DIR/needless_continue.rs:58:9
|
LL | continue; // should lint here
| ^^^^^^^^^
@@ -63,7 +63,7 @@ LL | continue; // should lint here
= help: consider dropping the `continue` expression
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:64:9
+ --> $DIR/needless_continue.rs:65:9
|
LL | continue; // should lint here
| ^^^^^^^^^
@@ -71,7 +71,7 @@ LL | continue; // should lint here
= help: consider dropping the `continue` expression
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:71:9
+ --> $DIR/needless_continue.rs:72:9
|
LL | continue // should lint here
| ^^^^^^^^
@@ -79,7 +79,7 @@ LL | continue // should lint here
= help: consider dropping the `continue` expression
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:79:9
+ --> $DIR/needless_continue.rs:80:9
|
LL | continue // should lint here
| ^^^^^^^^
@@ -87,7 +87,7 @@ LL | continue // should lint here
= help: consider dropping the `continue` expression
error: this `else` block is redundant
- --> $DIR/needless_continue.rs:129:24
+ --> $DIR/needless_continue.rs:130:24
|
LL | } else {
| ________________________^
@@ -110,7 +110,7 @@ LL | | }
}
error: there is no need for an explicit `else` block for this `if` expression
- --> $DIR/needless_continue.rs:135:17
+ --> $DIR/needless_continue.rs:136:17
|
LL | / if condition() {
LL | | continue; // should lint here
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
index c1685f7b6..09e671b88 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
@@ -1,10 +1,11 @@
// run-rustfix
#![warn(clippy::needless_for_each)]
+#![allow(unused)]
#![allow(
- unused,
- clippy::needless_return,
+ clippy::let_unit_value,
clippy::match_single_binding,
- clippy::let_unit_value
+ clippy::needless_return,
+ clippy::uninlined_format_args
)]
use std::collections::HashMap;
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
index ad17b0956..abb4045b9 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
@@ -1,10 +1,11 @@
// run-rustfix
#![warn(clippy::needless_for_each)]
+#![allow(unused)]
#![allow(
- unused,
- clippy::needless_return,
+ clippy::let_unit_value,
clippy::match_single_binding,
- clippy::let_unit_value
+ clippy::needless_return,
+ clippy::uninlined_format_args
)]
use std::collections::HashMap;
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr b/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr
index 08e995851..aebb762cc 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr
@@ -1,5 +1,5 @@
error: needless use of `for_each`
- --> $DIR/needless_for_each_fixable.rs:15:5
+ --> $DIR/needless_for_each_fixable.rs:16:5
|
LL | / v.iter().for_each(|elem| {
LL | | acc += elem;
@@ -15,7 +15,7 @@ LL + }
|
error: needless use of `for_each`
- --> $DIR/needless_for_each_fixable.rs:18:5
+ --> $DIR/needless_for_each_fixable.rs:19:5
|
LL | / v.into_iter().for_each(|elem| {
LL | | acc += elem;
@@ -30,7 +30,7 @@ LL + }
|
error: needless use of `for_each`
- --> $DIR/needless_for_each_fixable.rs:22:5
+ --> $DIR/needless_for_each_fixable.rs:23:5
|
LL | / [1, 2, 3].iter().for_each(|elem| {
LL | | acc += elem;
@@ -45,7 +45,7 @@ LL + }
|
error: needless use of `for_each`
- --> $DIR/needless_for_each_fixable.rs:27:5
+ --> $DIR/needless_for_each_fixable.rs:28:5
|
LL | / hash_map.iter().for_each(|(k, v)| {
LL | | acc += k + v;
@@ -60,7 +60,7 @@ LL + }
|
error: needless use of `for_each`
- --> $DIR/needless_for_each_fixable.rs:30:5
+ --> $DIR/needless_for_each_fixable.rs:31:5
|
LL | / hash_map.iter_mut().for_each(|(k, v)| {
LL | | acc += *k + *v;
@@ -75,7 +75,7 @@ LL + }
|
error: needless use of `for_each`
- --> $DIR/needless_for_each_fixable.rs:33:5
+ --> $DIR/needless_for_each_fixable.rs:34:5
|
LL | / hash_map.keys().for_each(|k| {
LL | | acc += k;
@@ -90,7 +90,7 @@ LL + }
|
error: needless use of `for_each`
- --> $DIR/needless_for_each_fixable.rs:36:5
+ --> $DIR/needless_for_each_fixable.rs:37:5
|
LL | / hash_map.values().for_each(|v| {
LL | | acc += v;
@@ -105,7 +105,7 @@ LL + }
|
error: needless use of `for_each`
- --> $DIR/needless_for_each_fixable.rs:43:5
+ --> $DIR/needless_for_each_fixable.rs:44:5
|
LL | / my_vec().iter().for_each(|elem| {
LL | | acc += elem;
diff --git a/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs b/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs
index d765d7dab..282c72881 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs
+++ b/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs
@@ -1,5 +1,5 @@
#![warn(clippy::needless_for_each)]
-#![allow(clippy::needless_return)]
+#![allow(clippy::needless_return, clippy::uninlined_format_args)]
fn main() {
let v: Vec<i32> = Vec::new();
diff --git a/src/tools/clippy/tests/ui/needless_late_init.fixed b/src/tools/clippy/tests/ui/needless_late_init.fixed
index fee8e3030..17f2227ba 100644
--- a/src/tools/clippy/tests/ui/needless_late_init.fixed
+++ b/src/tools/clippy/tests/ui/needless_late_init.fixed
@@ -1,12 +1,13 @@
// run-rustfix
#![feature(let_chains)]
+#![allow(unused)]
#![allow(
- unused,
clippy::assign_op_pattern,
clippy::blocks_in_if_conditions,
clippy::let_and_return,
clippy::let_unit_value,
- clippy::nonminimal_bool
+ clippy::nonminimal_bool,
+ clippy::uninlined_format_args
)]
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
diff --git a/src/tools/clippy/tests/ui/needless_late_init.rs b/src/tools/clippy/tests/ui/needless_late_init.rs
index 402d9f9ef..d84457a29 100644
--- a/src/tools/clippy/tests/ui/needless_late_init.rs
+++ b/src/tools/clippy/tests/ui/needless_late_init.rs
@@ -1,12 +1,13 @@
// run-rustfix
#![feature(let_chains)]
+#![allow(unused)]
#![allow(
- unused,
clippy::assign_op_pattern,
clippy::blocks_in_if_conditions,
clippy::let_and_return,
clippy::let_unit_value,
- clippy::nonminimal_bool
+ clippy::nonminimal_bool,
+ clippy::uninlined_format_args
)]
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr
index 313cdbbeb..0a256fb4a 100644
--- a/src/tools/clippy/tests/ui/needless_late_init.stderr
+++ b/src/tools/clippy/tests/ui/needless_late_init.stderr
@@ -1,5 +1,5 @@
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:23:5
+ --> $DIR/needless_late_init.rs:24:5
|
LL | let a;
| ^^^^^^ created here
@@ -13,7 +13,7 @@ LL | let a = "zero";
| ~~~~~
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:26:5
+ --> $DIR/needless_late_init.rs:27:5
|
LL | let b;
| ^^^^^^ created here
@@ -27,7 +27,7 @@ LL | let b = 1;
| ~~~~~
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:27:5
+ --> $DIR/needless_late_init.rs:28:5
|
LL | let c;
| ^^^^^^ created here
@@ -41,7 +41,7 @@ LL | let c = 2;
| ~~~~~
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:31:5
+ --> $DIR/needless_late_init.rs:32:5
|
LL | let d: usize;
| ^^^^^^^^^^^^^ created here
@@ -54,7 +54,7 @@ LL | let d: usize = 1;
| ~~~~~~~~~~~~
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:34:5
+ --> $DIR/needless_late_init.rs:35:5
|
LL | let e;
| ^^^^^^ created here
@@ -67,7 +67,7 @@ LL | let e = format!("{}", d);
| ~~~~~
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:39:5
+ --> $DIR/needless_late_init.rs:40:5
|
LL | let a;
| ^^^^^^
@@ -88,7 +88,7 @@ LL | };
| +
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:48:5
+ --> $DIR/needless_late_init.rs:49:5
|
LL | let b;
| ^^^^^^
@@ -109,7 +109,7 @@ LL | };
| +
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:55:5
+ --> $DIR/needless_late_init.rs:56:5
|
LL | let d;
| ^^^^^^
@@ -130,7 +130,7 @@ LL | };
| +
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:63:5
+ --> $DIR/needless_late_init.rs:64:5
|
LL | let e;
| ^^^^^^
@@ -151,7 +151,7 @@ LL | };
| +
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:70:5
+ --> $DIR/needless_late_init.rs:71:5
|
LL | let f;
| ^^^^^^
@@ -167,7 +167,7 @@ LL + 1 => "three",
|
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:76:5
+ --> $DIR/needless_late_init.rs:77:5
|
LL | let g: usize;
| ^^^^^^^^^^^^^
@@ -187,7 +187,7 @@ LL | };
| +
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:84:5
+ --> $DIR/needless_late_init.rs:85:5
|
LL | let x;
| ^^^^^^ created here
@@ -201,7 +201,7 @@ LL | let x = 1;
| ~~~~~
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:88:5
+ --> $DIR/needless_late_init.rs:89:5
|
LL | let x;
| ^^^^^^ created here
@@ -215,7 +215,7 @@ LL | let x = SignificantDrop;
| ~~~~~
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:92:5
+ --> $DIR/needless_late_init.rs:93:5
|
LL | let x;
| ^^^^^^ created here
@@ -229,7 +229,7 @@ LL | let x = SignificantDrop;
| ~~~~~
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:111:5
+ --> $DIR/needless_late_init.rs:112:5
|
LL | let a;
| ^^^^^^
@@ -250,7 +250,7 @@ LL | };
| +
error: unneeded late initialization
- --> $DIR/needless_late_init.rs:128:5
+ --> $DIR/needless_late_init.rs:129:5
|
LL | let a;
| ^^^^^^
diff --git a/src/tools/clippy/tests/ui/needless_match.fixed b/src/tools/clippy/tests/ui/needless_match.fixed
index 0c9178fb8..7e4740679 100644
--- a/src/tools/clippy/tests/ui/needless_match.fixed
+++ b/src/tools/clippy/tests/ui/needless_match.fixed
@@ -207,4 +207,43 @@ impl Tr for Result<i32, i32> {
}
}
+mod issue9084 {
+ fn wildcard_if() {
+ let mut some_bool = true;
+ let e = Some(1);
+
+ // should lint
+ let _ = e;
+
+ // should lint
+ let _ = e;
+
+ // should not lint
+ let _ = match e {
+ _ if some_bool => e,
+ _ => Some(2),
+ };
+
+ // should not lint
+ let _ = match e {
+ Some(i) => Some(i + 1),
+ _ if some_bool => e,
+ _ => e,
+ };
+
+ // should not lint (guard has side effects)
+ let _ = match e {
+ Some(i) => Some(i),
+ _ if {
+ some_bool = false;
+ some_bool
+ } =>
+ {
+ e
+ },
+ _ => e,
+ };
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_match.rs b/src/tools/clippy/tests/ui/needless_match.rs
index f66f01d7c..809c694bf 100644
--- a/src/tools/clippy/tests/ui/needless_match.rs
+++ b/src/tools/clippy/tests/ui/needless_match.rs
@@ -244,4 +244,50 @@ impl Tr for Result<i32, i32> {
}
}
+mod issue9084 {
+ fn wildcard_if() {
+ let mut some_bool = true;
+ let e = Some(1);
+
+ // should lint
+ let _ = match e {
+ _ if some_bool => e,
+ _ => e,
+ };
+
+ // should lint
+ let _ = match e {
+ Some(i) => Some(i),
+ _ if some_bool => e,
+ _ => e,
+ };
+
+ // should not lint
+ let _ = match e {
+ _ if some_bool => e,
+ _ => Some(2),
+ };
+
+ // should not lint
+ let _ = match e {
+ Some(i) => Some(i + 1),
+ _ if some_bool => e,
+ _ => e,
+ };
+
+ // should not lint (guard has side effects)
+ let _ = match e {
+ Some(i) => Some(i),
+ _ if {
+ some_bool = false;
+ some_bool
+ } =>
+ {
+ e
+ },
+ _ => e,
+ };
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_match.stderr b/src/tools/clippy/tests/ui/needless_match.stderr
index 5bc79800a..28e78441c 100644
--- a/src/tools/clippy/tests/ui/needless_match.stderr
+++ b/src/tools/clippy/tests/ui/needless_match.stderr
@@ -109,5 +109,26 @@ LL | | Complex::D(E::VariantB(ea, eb), b) => Complex::D(E::VariantB(
LL | | };
| |_________^ help: replace it with: `ce`
-error: aborting due to 11 previous errors
+error: this match expression is unnecessary
+ --> $DIR/needless_match.rs:253:17
+ |
+LL | let _ = match e {
+ | _________________^
+LL | | _ if some_bool => e,
+LL | | _ => e,
+LL | | };
+ | |_________^ help: replace it with: `e`
+
+error: this match expression is unnecessary
+ --> $DIR/needless_match.rs:259:17
+ |
+LL | let _ = match e {
+ | _________________^
+LL | | Some(i) => Some(i),
+LL | | _ if some_bool => e,
+LL | | _ => e,
+LL | | };
+ | |_________^ help: replace it with: `e`
+
+error: aborting due to 13 previous errors
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_value.rs b/src/tools/clippy/tests/ui/needless_pass_by_value.rs
index 5a35b100a..d79ad86b1 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_value.rs
+++ b/src/tools/clippy/tests/ui/needless_pass_by_value.rs
@@ -1,10 +1,11 @@
#![warn(clippy::needless_pass_by_value)]
+#![allow(dead_code)]
#![allow(
- dead_code,
- clippy::single_match,
- clippy::redundant_pattern_matching,
clippy::option_option,
- clippy::redundant_clone
+ clippy::redundant_clone,
+ clippy::redundant_pattern_matching,
+ clippy::single_match,
+ clippy::uninlined_format_args
)]
use std::borrow::Borrow;
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_value.stderr b/src/tools/clippy/tests/ui/needless_pass_by_value.stderr
index 38f33c53f..0e660a77d 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_value.stderr
+++ b/src/tools/clippy/tests/ui/needless_pass_by_value.stderr
@@ -1,5 +1,5 @@
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:17:23
+ --> $DIR/needless_pass_by_value.rs:18:23
|
LL | fn foo<T: Default>(v: Vec<T>, w: Vec<T>, mut x: Vec<T>, y: Vec<T>) -> Vec<T> {
| ^^^^^^ help: consider changing the type to: `&[T]`
@@ -7,55 +7,55 @@ LL | fn foo<T: Default>(v: Vec<T>, w: Vec<T>, mut x: Vec<T>, y: Vec<T>) -> Vec<T
= note: `-D clippy::needless-pass-by-value` implied by `-D warnings`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:31:11
+ --> $DIR/needless_pass_by_value.rs:32:11
|
LL | fn bar(x: String, y: Wrapper) {
| ^^^^^^ help: consider changing the type to: `&str`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:31:22
+ --> $DIR/needless_pass_by_value.rs:32:22
|
LL | fn bar(x: String, y: Wrapper) {
| ^^^^^^^ help: consider taking a reference instead: `&Wrapper`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:37:71
+ --> $DIR/needless_pass_by_value.rs:38:71
|
LL | fn test_borrow_trait<T: Borrow<str>, U: AsRef<str>, V>(t: T, u: U, v: V) {
| ^ help: consider taking a reference instead: `&V`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:49:18
+ --> $DIR/needless_pass_by_value.rs:50:18
|
LL | fn test_match(x: Option<Option<String>>, y: Option<Option<String>>) {
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&Option<Option<String>>`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:62:24
+ --> $DIR/needless_pass_by_value.rs:63:24
|
LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) {
| ^^^^^^^ help: consider taking a reference instead: `&Wrapper`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:62:36
+ --> $DIR/needless_pass_by_value.rs:63:36
|
LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) {
| ^^^^^^^ help: consider taking a reference instead: `&Wrapper`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:78:49
+ --> $DIR/needless_pass_by_value.rs:79:49
|
LL | fn test_blanket_ref<T: Foo, S: Serialize>(_foo: T, _serializable: S) {}
| ^ help: consider taking a reference instead: `&T`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:80:18
+ --> $DIR/needless_pass_by_value.rs:81:18
|
LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
| ^^^^^^ help: consider taking a reference instead: `&String`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:80:29
+ --> $DIR/needless_pass_by_value.rs:81:29
|
LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
| ^^^^^^
@@ -70,13 +70,13 @@ LL | let _ = t.to_string();
| ~~~~~~~~~~~~~
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:80:40
+ --> $DIR/needless_pass_by_value.rs:81:40
|
LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
| ^^^^^^^^ help: consider taking a reference instead: `&Vec<i32>`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:80:53
+ --> $DIR/needless_pass_by_value.rs:81:53
|
LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
| ^^^^^^^^
@@ -91,85 +91,85 @@ LL | let _ = v.to_owned();
| ~~~~~~~~~~~~
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:93:12
+ --> $DIR/needless_pass_by_value.rs:94:12
|
LL | s: String,
| ^^^^^^ help: consider changing the type to: `&str`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:94:12
+ --> $DIR/needless_pass_by_value.rs:95:12
|
LL | t: String,
| ^^^^^^ help: consider taking a reference instead: `&String`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:103:23
+ --> $DIR/needless_pass_by_value.rs:104:23
|
LL | fn baz(&self, _u: U, _s: Self) {}
| ^ help: consider taking a reference instead: `&U`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:103:30
+ --> $DIR/needless_pass_by_value.rs:104:30
|
LL | fn baz(&self, _u: U, _s: Self) {}
| ^^^^ help: consider taking a reference instead: `&Self`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:125:24
+ --> $DIR/needless_pass_by_value.rs:126:24
|
LL | fn bar_copy(x: u32, y: CopyWrapper) {
| ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
|
help: consider marking this type as `Copy`
- --> $DIR/needless_pass_by_value.rs:123:1
+ --> $DIR/needless_pass_by_value.rs:124:1
|
LL | struct CopyWrapper(u32);
| ^^^^^^^^^^^^^^^^^^
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:131:29
+ --> $DIR/needless_pass_by_value.rs:132:29
|
LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
| ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
|
help: consider marking this type as `Copy`
- --> $DIR/needless_pass_by_value.rs:123:1
+ --> $DIR/needless_pass_by_value.rs:124:1
|
LL | struct CopyWrapper(u32);
| ^^^^^^^^^^^^^^^^^^
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:131:45
+ --> $DIR/needless_pass_by_value.rs:132:45
|
LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
| ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
|
help: consider marking this type as `Copy`
- --> $DIR/needless_pass_by_value.rs:123:1
+ --> $DIR/needless_pass_by_value.rs:124:1
|
LL | struct CopyWrapper(u32);
| ^^^^^^^^^^^^^^^^^^
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:131:61
+ --> $DIR/needless_pass_by_value.rs:132:61
|
LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
| ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
|
help: consider marking this type as `Copy`
- --> $DIR/needless_pass_by_value.rs:123:1
+ --> $DIR/needless_pass_by_value.rs:124:1
|
LL | struct CopyWrapper(u32);
| ^^^^^^^^^^^^^^^^^^
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:143:40
+ --> $DIR/needless_pass_by_value.rs:144:40
|
LL | fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {}
| ^ help: consider taking a reference instead: `&S`
error: this argument is passed by value, but not consumed in the function body
- --> $DIR/needless_pass_by_value.rs:148:20
+ --> $DIR/needless_pass_by_value.rs:149:20
|
LL | fn more_fun(_item: impl Club<'static, i32>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>`
diff --git a/src/tools/clippy/tests/ui/needless_range_loop.rs b/src/tools/clippy/tests/ui/needless_range_loop.rs
index 3fce34367..921801138 100644
--- a/src/tools/clippy/tests/ui/needless_range_loop.rs
+++ b/src/tools/clippy/tests/ui/needless_range_loop.rs
@@ -1,4 +1,5 @@
#![warn(clippy::needless_range_loop)]
+#![allow(clippy::uninlined_format_args)]
static STATIC: [usize; 4] = [0, 1, 8, 16];
const CONST: [usize; 4] = [0, 1, 8, 16];
diff --git a/src/tools/clippy/tests/ui/needless_range_loop.stderr b/src/tools/clippy/tests/ui/needless_range_loop.stderr
index a86cc69df..b31544ec3 100644
--- a/src/tools/clippy/tests/ui/needless_range_loop.stderr
+++ b/src/tools/clippy/tests/ui/needless_range_loop.stderr
@@ -1,5 +1,5 @@
error: the loop variable `i` is only used to index `vec`
- --> $DIR/needless_range_loop.rs:10:14
+ --> $DIR/needless_range_loop.rs:11:14
|
LL | for i in 0..vec.len() {
| ^^^^^^^^^^^^
@@ -11,7 +11,7 @@ LL | for <item> in &vec {
| ~~~~~~ ~~~~
error: the loop variable `i` is only used to index `vec`
- --> $DIR/needless_range_loop.rs:19:14
+ --> $DIR/needless_range_loop.rs:20:14
|
LL | for i in 0..vec.len() {
| ^^^^^^^^^^^^
@@ -22,7 +22,7 @@ LL | for <item> in &vec {
| ~~~~~~ ~~~~
error: the loop variable `j` is only used to index `STATIC`
- --> $DIR/needless_range_loop.rs:24:14
+ --> $DIR/needless_range_loop.rs:25:14
|
LL | for j in 0..4 {
| ^^^^
@@ -33,7 +33,7 @@ LL | for <item> in &STATIC {
| ~~~~~~ ~~~~~~~
error: the loop variable `j` is only used to index `CONST`
- --> $DIR/needless_range_loop.rs:28:14
+ --> $DIR/needless_range_loop.rs:29:14
|
LL | for j in 0..4 {
| ^^^^
@@ -44,7 +44,7 @@ LL | for <item> in &CONST {
| ~~~~~~ ~~~~~~
error: the loop variable `i` is used to index `vec`
- --> $DIR/needless_range_loop.rs:32:14
+ --> $DIR/needless_range_loop.rs:33:14
|
LL | for i in 0..vec.len() {
| ^^^^^^^^^^^^
@@ -55,7 +55,7 @@ LL | for (i, <item>) in vec.iter().enumerate() {
| ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
error: the loop variable `i` is only used to index `vec2`
- --> $DIR/needless_range_loop.rs:40:14
+ --> $DIR/needless_range_loop.rs:41:14
|
LL | for i in 0..vec.len() {
| ^^^^^^^^^^^^
@@ -66,7 +66,7 @@ LL | for <item> in vec2.iter().take(vec.len()) {
| ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: the loop variable `i` is only used to index `vec`
- --> $DIR/needless_range_loop.rs:44:14
+ --> $DIR/needless_range_loop.rs:45:14
|
LL | for i in 5..vec.len() {
| ^^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL | for <item> in vec.iter().skip(5) {
| ~~~~~~ ~~~~~~~~~~~~~~~~~~
error: the loop variable `i` is only used to index `vec`
- --> $DIR/needless_range_loop.rs:48:14
+ --> $DIR/needless_range_loop.rs:49:14
|
LL | for i in 0..MAX_LEN {
| ^^^^^^^^^^
@@ -88,7 +88,7 @@ LL | for <item> in vec.iter().take(MAX_LEN) {
| ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~
error: the loop variable `i` is only used to index `vec`
- --> $DIR/needless_range_loop.rs:52:14
+ --> $DIR/needless_range_loop.rs:53:14
|
LL | for i in 0..=MAX_LEN {
| ^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL | for <item> in vec.iter().take(MAX_LEN + 1) {
| ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: the loop variable `i` is only used to index `vec`
- --> $DIR/needless_range_loop.rs:56:14
+ --> $DIR/needless_range_loop.rs:57:14
|
LL | for i in 5..10 {
| ^^^^^
@@ -110,7 +110,7 @@ LL | for <item> in vec.iter().take(10).skip(5) {
| ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: the loop variable `i` is only used to index `vec`
- --> $DIR/needless_range_loop.rs:60:14
+ --> $DIR/needless_range_loop.rs:61:14
|
LL | for i in 5..=10 {
| ^^^^^^
@@ -121,7 +121,7 @@ LL | for <item> in vec.iter().take(10 + 1).skip(5) {
| ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: the loop variable `i` is used to index `vec`
- --> $DIR/needless_range_loop.rs:64:14
+ --> $DIR/needless_range_loop.rs:65:14
|
LL | for i in 5..vec.len() {
| ^^^^^^^^^^^^
@@ -132,7 +132,7 @@ LL | for (i, <item>) in vec.iter().enumerate().skip(5) {
| ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: the loop variable `i` is used to index `vec`
- --> $DIR/needless_range_loop.rs:68:14
+ --> $DIR/needless_range_loop.rs:69:14
|
LL | for i in 5..10 {
| ^^^^^
@@ -143,7 +143,7 @@ LL | for (i, <item>) in vec.iter().enumerate().take(10).skip(5) {
| ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: the loop variable `i` is used to index `vec`
- --> $DIR/needless_range_loop.rs:73:14
+ --> $DIR/needless_range_loop.rs:74:14
|
LL | for i in 0..vec.len() {
| ^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index 0bc0d0011..d2163b14f 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -1,7 +1,6 @@
// run-rustfix
#![feature(lint_reasons)]
-#![feature(let_else)]
#![allow(unused)]
#![allow(
clippy::if_same_then_else,
@@ -228,13 +227,46 @@ fn needless_return_macro() -> String {
format!("Hello {}", "world!")
}
-fn check_expect() -> bool {
- if true {
- // no error!
- return true;
+fn issue_9361() -> i32 {
+ #[allow(clippy::integer_arithmetic)]
+ return 1 + 2;
+}
+
+fn issue8336(x: i32) -> bool {
+ if x > 0 {
+ println!("something");
+ true
+ } else {
+ false
+ }
+}
+
+fn issue8156(x: u8) -> u64 {
+ match x {
+ 80 => {
+ 10
+ },
+ _ => {
+ 100
+ },
+ }
+}
+
+// Ideally the compiler should throw `unused_braces` in this case
+fn issue9192() -> i32 {
+ {
+ 0
+ }
+}
+
+fn issue9503(x: usize) -> isize {
+ unsafe {
+ if x > 12 {
+ *(x as *const isize)
+ } else {
+ !*(x as *const isize)
+ }
}
- #[expect(clippy::needless_return)]
- return true;
}
fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index eb9f72e8e..114414b5f 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -1,7 +1,6 @@
// run-rustfix
#![feature(lint_reasons)]
-#![feature(let_else)]
#![allow(unused)]
#![allow(
clippy::if_same_then_else,
@@ -228,13 +227,46 @@ fn needless_return_macro() -> String {
return format!("Hello {}", "world!");
}
-fn check_expect() -> bool {
- if true {
- // no error!
+fn issue_9361() -> i32 {
+ #[allow(clippy::integer_arithmetic)]
+ return 1 + 2;
+}
+
+fn issue8336(x: i32) -> bool {
+ if x > 0 {
+ println!("something");
return true;
- }
- #[expect(clippy::needless_return)]
- return true;
+ } else {
+ return false;
+ };
+}
+
+fn issue8156(x: u8) -> u64 {
+ match x {
+ 80 => {
+ return 10;
+ },
+ _ => {
+ return 100;
+ },
+ };
+}
+
+// Ideally the compiler should throw `unused_braces` in this case
+fn issue9192() -> i32 {
+ {
+ return 0;
+ };
+}
+
+fn issue9503(x: usize) -> isize {
+ unsafe {
+ if x > 12 {
+ return *(x as *const isize);
+ } else {
+ return !*(x as *const isize);
+ };
+ };
}
fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr
index 83ff07638..047fb6c23 100644
--- a/src/tools/clippy/tests/ui/needless_return.stderr
+++ b/src/tools/clippy/tests/ui/needless_return.stderr
@@ -1,226 +1,355 @@
error: unneeded `return` statement
- --> $DIR/needless_return.rs:27:5
+ --> $DIR/needless_return.rs:26:5
|
LL | return true;
- | ^^^^^^^^^^^^ help: remove `return`: `true`
+ | ^^^^^^^^^^^
|
= note: `-D clippy::needless-return` implied by `-D warnings`
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:31:5
+ --> $DIR/needless_return.rs:30:5
|
LL | return true;
- | ^^^^^^^^^^^^ help: remove `return`: `true`
+ | ^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:36:9
+ --> $DIR/needless_return.rs:35:9
|
LL | return true;
- | ^^^^^^^^^^^^ help: remove `return`: `true`
+ | ^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:38:9
+ --> $DIR/needless_return.rs:37:9
|
LL | return false;
- | ^^^^^^^^^^^^^ help: remove `return`: `false`
+ | ^^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:44:17
+ --> $DIR/needless_return.rs:43:17
|
LL | true => return false,
- | ^^^^^^^^^^^^ help: remove `return`: `false`
+ | ^^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:46:13
+ --> $DIR/needless_return.rs:45:13
|
LL | return true;
- | ^^^^^^^^^^^^ help: remove `return`: `true`
+ | ^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:53:9
+ --> $DIR/needless_return.rs:52:9
|
LL | return true;
- | ^^^^^^^^^^^^ help: remove `return`: `true`
+ | ^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:55:16
+ --> $DIR/needless_return.rs:54:16
|
LL | let _ = || return true;
- | ^^^^^^^^^^^ help: remove `return`: `true`
+ | ^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:59:5
+ --> $DIR/needless_return.rs:58:5
|
LL | return the_answer!();
- | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `the_answer!()`
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:63:5
+ --> $DIR/needless_return.rs:62:5
|
LL | return;
- | ^^^^^^^ help: remove `return`
+ | ^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:68:9
+ --> $DIR/needless_return.rs:67:9
|
LL | return;
- | ^^^^^^^ help: remove `return`
+ | ^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:70:9
+ --> $DIR/needless_return.rs:69:9
|
LL | return;
- | ^^^^^^^ help: remove `return`
+ | ^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:77:14
+ --> $DIR/needless_return.rs:76:14
|
LL | _ => return,
- | ^^^^^^ help: replace `return` with a unit value: `()`
+ | ^^^^^^
+ |
+ = help: replace `return` with a unit value
error: unneeded `return` statement
- --> $DIR/needless_return.rs:86:13
+ --> $DIR/needless_return.rs:85:13
|
LL | return;
- | ^^^^^^^ help: remove `return`
+ | ^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:88:14
+ --> $DIR/needless_return.rs:87:14
|
LL | _ => return,
- | ^^^^^^ help: replace `return` with a unit value: `()`
+ | ^^^^^^
+ |
+ = help: replace `return` with a unit value
error: unneeded `return` statement
- --> $DIR/needless_return.rs:101:9
+ --> $DIR/needless_return.rs:100:9
|
LL | return String::from("test");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:103:9
+ --> $DIR/needless_return.rs:102:9
|
LL | return String::new();
- | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:125:32
+ --> $DIR/needless_return.rs:124:32
|
LL | bar.unwrap_or_else(|_| return)
- | ^^^^^^ help: replace `return` with an empty block: `{}`
+ | ^^^^^^
+ |
+ = help: replace `return` with an empty block
error: unneeded `return` statement
- --> $DIR/needless_return.rs:130:13
+ --> $DIR/needless_return.rs:129:13
|
LL | return;
- | ^^^^^^^ help: remove `return`
+ | ^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:132:20
+ --> $DIR/needless_return.rs:131:20
|
LL | let _ = || return;
- | ^^^^^^ help: replace `return` with an empty block: `{}`
+ | ^^^^^^
+ |
+ = help: replace `return` with an empty block
error: unneeded `return` statement
- --> $DIR/needless_return.rs:138:32
+ --> $DIR/needless_return.rs:137:32
|
LL | res.unwrap_or_else(|_| return Foo)
- | ^^^^^^^^^^ help: remove `return`: `Foo`
+ | ^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:147:5
+ --> $DIR/needless_return.rs:146:5
|
LL | return true;
- | ^^^^^^^^^^^^ help: remove `return`: `true`
+ | ^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:151:5
+ --> $DIR/needless_return.rs:150:5
|
LL | return true;
- | ^^^^^^^^^^^^ help: remove `return`: `true`
+ | ^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:156:9
+ --> $DIR/needless_return.rs:155:9
|
LL | return true;
- | ^^^^^^^^^^^^ help: remove `return`: `true`
+ | ^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:158:9
+ --> $DIR/needless_return.rs:157:9
|
LL | return false;
- | ^^^^^^^^^^^^^ help: remove `return`: `false`
+ | ^^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:164:17
+ --> $DIR/needless_return.rs:163:17
|
LL | true => return false,
- | ^^^^^^^^^^^^ help: remove `return`: `false`
+ | ^^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:166:13
+ --> $DIR/needless_return.rs:165:13
|
LL | return true;
- | ^^^^^^^^^^^^ help: remove `return`: `true`
+ | ^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:173:9
+ --> $DIR/needless_return.rs:172:9
|
LL | return true;
- | ^^^^^^^^^^^^ help: remove `return`: `true`
+ | ^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:175:16
+ --> $DIR/needless_return.rs:174:16
|
LL | let _ = || return true;
- | ^^^^^^^^^^^ help: remove `return`: `true`
+ | ^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:179:5
+ --> $DIR/needless_return.rs:178:5
|
LL | return the_answer!();
- | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `the_answer!()`
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:183:5
+ --> $DIR/needless_return.rs:182:5
|
LL | return;
- | ^^^^^^^ help: remove `return`
+ | ^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:188:9
+ --> $DIR/needless_return.rs:187:9
|
LL | return;
- | ^^^^^^^ help: remove `return`
+ | ^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:190:9
+ --> $DIR/needless_return.rs:189:9
|
LL | return;
- | ^^^^^^^ help: remove `return`
+ | ^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:197:14
+ --> $DIR/needless_return.rs:196:14
|
LL | _ => return,
- | ^^^^^^ help: replace `return` with a unit value: `()`
+ | ^^^^^^
+ |
+ = help: replace `return` with a unit value
error: unneeded `return` statement
- --> $DIR/needless_return.rs:210:9
+ --> $DIR/needless_return.rs:209:9
|
LL | return String::from("test");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:212:9
+ --> $DIR/needless_return.rs:211:9
|
LL | return String::new();
- | ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:228:5
+ --> $DIR/needless_return.rs:227:5
|
LL | return format!("Hello {}", "world!");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `format!("Hello {}", "world!")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: remove `return`
+
+error: unneeded `return` statement
+ --> $DIR/needless_return.rs:238:9
+ |
+LL | return true;
+ | ^^^^^^^^^^^
+ |
+ = help: remove `return`
+
+error: unneeded `return` statement
+ --> $DIR/needless_return.rs:240:9
+ |
+LL | return false;
+ | ^^^^^^^^^^^^
+ |
+ = help: remove `return`
+
+error: unneeded `return` statement
+ --> $DIR/needless_return.rs:247:13
+ |
+LL | return 10;
+ | ^^^^^^^^^
+ |
+ = help: remove `return`
+
+error: unneeded `return` statement
+ --> $DIR/needless_return.rs:250:13
+ |
+LL | return 100;
+ | ^^^^^^^^^^
+ |
+ = help: remove `return`
+
+error: unneeded `return` statement
+ --> $DIR/needless_return.rs:258:9
+ |
+LL | return 0;
+ | ^^^^^^^^
+ |
+ = help: remove `return`
+
+error: unneeded `return` statement
+ --> $DIR/needless_return.rs:265:13
+ |
+LL | return *(x as *const isize);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: remove `return`
+
+error: unneeded `return` statement
+ --> $DIR/needless_return.rs:267:13
+ |
+LL | return !*(x as *const isize);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: remove `return`
-error: aborting due to 37 previous errors
+error: aborting due to 44 previous errors
diff --git a/src/tools/clippy/tests/ui/never_loop.rs b/src/tools/clippy/tests/ui/never_loop.rs
index 0a21589dd..3dbef1989 100644
--- a/src/tools/clippy/tests/ui/never_loop.rs
+++ b/src/tools/clippy/tests/ui/never_loop.rs
@@ -203,6 +203,32 @@ pub fn test17() {
};
}
+// Issue #9356: `continue` in else branch of let..else
+pub fn test18() {
+ let x = Some(0);
+ let y = 0;
+ // might loop
+ let _ = loop {
+ let Some(x) = x else {
+ if y > 0 {
+ continue;
+ } else {
+ return;
+ }
+ };
+
+ break x;
+ };
+ // never loops
+ let _ = loop {
+ let Some(x) = x else {
+ return;
+ };
+
+ break x;
+ };
+}
+
fn main() {
test1();
test2();
diff --git a/src/tools/clippy/tests/ui/never_loop.stderr b/src/tools/clippy/tests/ui/never_loop.stderr
index f49b23924..3033f0192 100644
--- a/src/tools/clippy/tests/ui/never_loop.stderr
+++ b/src/tools/clippy/tests/ui/never_loop.stderr
@@ -101,5 +101,18 @@ LL | | break 'label;
LL | | }
| |_________^
-error: aborting due to 9 previous errors
+error: this loop never actually loops
+ --> $DIR/never_loop.rs:223:13
+ |
+LL | let _ = loop {
+ | _____________^
+LL | | let Some(x) = x else {
+LL | | return;
+LL | | };
+LL | |
+LL | | break x;
+LL | | };
+ | |_____^
+
+error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs
index fdefb11ae..f08eb092e 100644
--- a/src/tools/clippy/tests/ui/no_effect.rs
+++ b/src/tools/clippy/tests/ui/no_effect.rs
@@ -1,9 +1,7 @@
#![feature(box_syntax, fn_traits, unboxed_closures)]
#![warn(clippy::no_effect_underscore_binding)]
-#![allow(dead_code)]
-#![allow(path_statements)]
-#![allow(clippy::deref_addrof)]
-#![allow(clippy::redundant_field_names)]
+#![allow(dead_code, path_statements)]
+#![allow(clippy::deref_addrof, clippy::redundant_field_names, clippy::uninlined_format_args)]
struct Unit;
struct Tuple(i32);
diff --git a/src/tools/clippy/tests/ui/no_effect.stderr b/src/tools/clippy/tests/ui/no_effect.stderr
index 328d2555c..6a1e636f9 100644
--- a/src/tools/clippy/tests/ui/no_effect.stderr
+++ b/src/tools/clippy/tests/ui/no_effect.stderr
@@ -1,5 +1,5 @@
error: statement with no effect
- --> $DIR/no_effect.rs:94:5
+ --> $DIR/no_effect.rs:92:5
|
LL | 0;
| ^^
@@ -7,157 +7,157 @@ LL | 0;
= note: `-D clippy::no-effect` implied by `-D warnings`
error: statement with no effect
- --> $DIR/no_effect.rs:95:5
+ --> $DIR/no_effect.rs:93:5
|
LL | s2;
| ^^^
error: statement with no effect
- --> $DIR/no_effect.rs:96:5
+ --> $DIR/no_effect.rs:94:5
|
LL | Unit;
| ^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:97:5
+ --> $DIR/no_effect.rs:95:5
|
LL | Tuple(0);
| ^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:98:5
+ --> $DIR/no_effect.rs:96:5
|
LL | Struct { field: 0 };
| ^^^^^^^^^^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:99:5
+ --> $DIR/no_effect.rs:97:5
|
LL | Struct { ..s };
| ^^^^^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:100:5
+ --> $DIR/no_effect.rs:98:5
|
LL | Union { a: 0 };
| ^^^^^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:101:5
+ --> $DIR/no_effect.rs:99:5
|
LL | Enum::Tuple(0);
| ^^^^^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:102:5
+ --> $DIR/no_effect.rs:100:5
|
LL | Enum::Struct { field: 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:103:5
+ --> $DIR/no_effect.rs:101:5
|
LL | 5 + 6;
| ^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:104:5
+ --> $DIR/no_effect.rs:102:5
|
LL | *&42;
| ^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:105:5
+ --> $DIR/no_effect.rs:103:5
|
LL | &6;
| ^^^
error: statement with no effect
- --> $DIR/no_effect.rs:106:5
+ --> $DIR/no_effect.rs:104:5
|
LL | (5, 6, 7);
| ^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:107:5
+ --> $DIR/no_effect.rs:105:5
|
LL | box 42;
| ^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:108:5
+ --> $DIR/no_effect.rs:106:5
|
LL | ..;
| ^^^
error: statement with no effect
- --> $DIR/no_effect.rs:109:5
+ --> $DIR/no_effect.rs:107:5
|
LL | 5..;
| ^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:110:5
+ --> $DIR/no_effect.rs:108:5
|
LL | ..5;
| ^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:111:5
+ --> $DIR/no_effect.rs:109:5
|
LL | 5..6;
| ^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:112:5
+ --> $DIR/no_effect.rs:110:5
|
LL | 5..=6;
| ^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:113:5
+ --> $DIR/no_effect.rs:111:5
|
LL | [42, 55];
| ^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:114:5
+ --> $DIR/no_effect.rs:112:5
|
LL | [42, 55][1];
| ^^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:115:5
+ --> $DIR/no_effect.rs:113:5
|
LL | (42, 55).1;
| ^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:116:5
+ --> $DIR/no_effect.rs:114:5
|
LL | [42; 55];
| ^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:117:5
+ --> $DIR/no_effect.rs:115:5
|
LL | [42; 55][13];
| ^^^^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:119:5
+ --> $DIR/no_effect.rs:117:5
|
LL | || x += 5;
| ^^^^^^^^^^
error: statement with no effect
- --> $DIR/no_effect.rs:121:5
+ --> $DIR/no_effect.rs:119:5
|
LL | FooString { s: s };
| ^^^^^^^^^^^^^^^^^^^
error: binding to `_` prefixed variable with no side-effect
- --> $DIR/no_effect.rs:122:5
+ --> $DIR/no_effect.rs:120:5
|
LL | let _unused = 1;
| ^^^^^^^^^^^^^^^^
@@ -165,19 +165,19 @@ LL | let _unused = 1;
= note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings`
error: binding to `_` prefixed variable with no side-effect
- --> $DIR/no_effect.rs:123:5
+ --> $DIR/no_effect.rs:121:5
|
LL | let _penguin = || println!("Some helpful closure");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: binding to `_` prefixed variable with no side-effect
- --> $DIR/no_effect.rs:124:5
+ --> $DIR/no_effect.rs:122:5
|
LL | let _duck = Struct { field: 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: binding to `_` prefixed variable with no side-effect
- --> $DIR/no_effect.rs:125:5
+ --> $DIR/no_effect.rs:123:5
|
LL | let _cat = [2, 4, 6, 8][2];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr b/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr
index b6c904a14..e912b59a6 100644
--- a/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr
+++ b/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr
@@ -4,13 +4,13 @@ error: some fields in `RingBuffer<T>` are not safe to be sent to another thread
LL | unsafe impl<T> Send for RingBuffer<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings`
note: it is not safe to send field `data` to another thread
--> $DIR/non_send_fields_in_send_ty.rs:12:5
|
LL | data: Vec<UnsafeCell<T>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^
= help: add bounds on type parameter `T` that satisfy `Vec<UnsafeCell<T>>: Send`
+ = note: `-D clippy::non-send-fields-in-send-ty` implied by `-D warnings`
error: some fields in `MvccRwLock<T>` are not safe to be sent to another thread
--> $DIR/non_send_fields_in_send_ty.rs:25:1
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs
index 24ae62bb0..e9b4367ca 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.rs
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs
@@ -57,3 +57,9 @@ fn check_expect() {
#[expect(clippy::nonminimal_bool)]
let _ = !!a;
}
+
+fn issue9428() {
+ if matches!(true, true) && true {
+ println!("foo");
+ }
+}
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.stderr b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
index fc6a5ce1d..91b5805aa 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.stderr
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
@@ -107,5 +107,11 @@ LL | let _ = !(a == b || c == d);
LL | let _ = a != b && c != d;
| ~~~~~~~~~~~~~~~~
-error: aborting due to 12 previous errors
+error: this boolean expression can be simplified
+ --> $DIR/nonminimal_bool.rs:62:8
+ |
+LL | if matches!(true, true) && true {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(true, true)`
+
+error: aborting due to 13 previous errors
diff --git a/src/tools/clippy/tests/ui/octal_escapes.stderr b/src/tools/clippy/tests/ui/octal_escapes.stderr
index 54f5bbb0f..295dc1798 100644
--- a/src/tools/clippy/tests/ui/octal_escapes.stderr
+++ b/src/tools/clippy/tests/ui/octal_escapes.stderr
@@ -4,8 +4,8 @@ error: octal-looking escape in string literal
LL | let _bad1 = "/033[0m";
| ^^^^^^^^^
|
- = note: `-D clippy::octal-escapes` implied by `-D warnings`
= help: octal escapes are not supported, `/0` is always a null character
+ = note: `-D clippy::octal-escapes` implied by `-D warnings`
help: if an octal escape was intended, use the hexadecimal representation instead
|
LL | let _bad1 = "/x1b[0m";
diff --git a/src/tools/clippy/tests/ui/ok_expect.stderr b/src/tools/clippy/tests/ui/ok_expect.stderr
index b02b28e7f..6c40adbb5 100644
--- a/src/tools/clippy/tests/ui/ok_expect.stderr
+++ b/src/tools/clippy/tests/ui/ok_expect.stderr
@@ -4,8 +4,8 @@ error: called `ok().expect()` on a `Result` value
LL | res.ok().expect("disaster!");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::ok-expect` implied by `-D warnings`
= help: you can call `expect()` directly on the `Result`
+ = note: `-D clippy::ok-expect` implied by `-D warnings`
error: called `ok().expect()` on a `Result` value
--> $DIR/ok_expect.rs:20:5
diff --git a/src/tools/clippy/tests/ui/only_used_in_recursion.rs b/src/tools/clippy/tests/ui/only_used_in_recursion.rs
index 5768434f9..f71e8ead5 100644
--- a/src/tools/clippy/tests/ui/only_used_in_recursion.rs
+++ b/src/tools/clippy/tests/ui/only_used_in_recursion.rs
@@ -1,122 +1,113 @@
#![warn(clippy::only_used_in_recursion)]
-fn simple(a: usize, b: usize) -> usize {
- if a == 0 { 1 } else { simple(a - 1, b) }
+fn _simple(x: u32) -> u32 {
+ x
}
-fn with_calc(a: usize, b: isize) -> usize {
- if a == 0 { 1 } else { with_calc(a - 1, -b + 1) }
+fn _simple2(x: u32) -> u32 {
+ _simple(x)
}
-fn tuple((a, b): (usize, usize)) -> usize {
- if a == 0 { 1 } else { tuple((a - 1, b + 1)) }
+fn _one_unused(flag: u32, a: usize) -> usize {
+ if flag == 0 { 0 } else { _one_unused(flag - 1, a) }
}
-fn let_tuple(a: usize, b: usize) -> usize {
- let (c, d) = (a, b);
- if c == 0 { 1 } else { let_tuple(c - 1, d + 1) }
+fn _two_unused(flag: u32, a: u32, b: i32) -> usize {
+ if flag == 0 { 0 } else { _two_unused(flag - 1, a, b) }
}
-fn array([a, b]: [usize; 2]) -> usize {
- if a == 0 { 1 } else { array([a - 1, b + 1]) }
-}
-
-fn index(a: usize, mut b: &[usize], c: usize) -> usize {
- if a == 0 { 1 } else { index(a - 1, b, c + b[0]) }
-}
-
-fn break_(a: usize, mut b: usize, mut c: usize) -> usize {
- let c = loop {
- b += 1;
- c += 1;
- if c == 10 {
- break b;
- }
- };
-
- if a == 0 { 1 } else { break_(a - 1, c, c) }
+fn _with_calc(flag: u32, a: i64) -> usize {
+ if flag == 0 {
+ 0
+ } else {
+ _with_calc(flag - 1, (-a + 10) * 5)
+ }
}
-// this has a side effect
-fn mut_ref(a: usize, b: &mut usize) -> usize {
- *b = 1;
- if a == 0 { 1 } else { mut_ref(a - 1, b) }
+// Don't lint
+fn _used_with_flag(flag: u32, a: u32) -> usize {
+ if flag == 0 { 0 } else { _used_with_flag(flag ^ a, a - 1) }
}
-fn mut_ref2(a: usize, b: &mut usize) -> usize {
- let mut c = *b;
- if a == 0 { 1 } else { mut_ref2(a - 1, &mut c) }
+fn _used_with_unused(flag: u32, a: i32, b: i32) -> usize {
+ if flag == 0 {
+ 0
+ } else {
+ _used_with_unused(flag - 1, -a, a + b)
+ }
}
-fn not_primitive(a: usize, b: String) -> usize {
- if a == 0 { 1 } else { not_primitive(a - 1, b) }
+fn _codependent_unused(flag: u32, a: i32, b: i32) -> usize {
+ if flag == 0 {
+ 0
+ } else {
+ _codependent_unused(flag - 1, a * b, a + b)
+ }
}
-// this doesn't have a side effect,
-// but `String` is not primitive.
-fn not_primitive_op(a: usize, b: String, c: &str) -> usize {
- if a == 1 { 1 } else { not_primitive_op(a, b + c, c) }
+fn _not_primitive(flag: u32, b: String) -> usize {
+ if flag == 0 { 0 } else { _not_primitive(flag - 1, b) }
}
struct A;
impl A {
- fn method(a: usize, b: usize) -> usize {
- if a == 0 { 1 } else { A::method(a - 1, b - 1) }
+ fn _method(flag: usize, a: usize) -> usize {
+ if flag == 0 { 0 } else { Self::_method(flag - 1, a) }
}
- fn method2(&self, a: usize, b: usize) -> usize {
- if a == 0 { 1 } else { self.method2(a - 1, b + 1) }
+ fn _method_self(&self, flag: usize, a: usize) -> usize {
+ if flag == 0 { 0 } else { self._method_self(flag - 1, a) }
}
}
trait B {
- fn hello(a: usize, b: usize) -> usize;
-
- fn hello2(&self, a: usize, b: usize) -> usize;
+ fn method(flag: u32, a: usize) -> usize;
+ fn method_self(&self, flag: u32, a: usize) -> usize;
}
impl B for A {
- fn hello(a: usize, b: usize) -> usize {
- if a == 0 { 1 } else { A::hello(a - 1, b + 1) }
+ fn method(flag: u32, a: usize) -> usize {
+ if flag == 0 { 0 } else { Self::method(flag - 1, a) }
}
- fn hello2(&self, a: usize, b: usize) -> usize {
- if a == 0 { 1 } else { self.hello2(a - 1, b + 1) }
+ fn method_self(&self, flag: u32, a: usize) -> usize {
+ if flag == 0 { 0 } else { self.method_self(flag - 1, a) }
}
}
-trait C {
- fn hello(a: usize, b: usize) -> usize {
- if a == 0 { 1 } else { Self::hello(a - 1, b + 1) }
+impl B for () {
+ fn method(flag: u32, a: usize) -> usize {
+ if flag == 0 { 0 } else { a }
}
- fn hello2(&self, a: usize, b: usize) -> usize {
- if a == 0 { 1 } else { self.hello2(a - 1, b + 1) }
+ fn method_self(&self, flag: u32, a: usize) -> usize {
+ if flag == 0 { 0 } else { a }
}
}
-fn ignore(a: usize, _: usize) -> usize {
- if a == 1 { 1 } else { ignore(a - 1, 0) }
-}
+impl B for u32 {
+ fn method(flag: u32, a: usize) -> usize {
+ if flag == 0 { 0 } else { <() as B>::method(flag, a) }
+ }
-fn ignore2(a: usize, _b: usize) -> usize {
- if a == 1 { 1 } else { ignore2(a - 1, _b) }
+ fn method_self(&self, flag: u32, a: usize) -> usize {
+ if flag == 0 { 0 } else { ().method_self(flag, a) }
+ }
}
-fn f1(a: u32) -> u32 {
- a
-}
+trait C {
+ fn method(flag: u32, a: usize) -> usize {
+ if flag == 0 { 0 } else { Self::method(flag - 1, a) }
+ }
-fn f2(a: u32) -> u32 {
- f1(a)
+ fn method_self(&self, flag: u32, a: usize) -> usize {
+ if flag == 0 { 0 } else { self.method_self(flag - 1, a) }
+ }
}
-fn inner_fn(a: u32) -> u32 {
- fn inner_fn(a: u32) -> u32 {
- a
- }
- inner_fn(a)
+fn _ignore(flag: usize, _a: usize) -> usize {
+ if flag == 0 { 0 } else { _ignore(flag - 1, _a) }
}
fn main() {}
diff --git a/src/tools/clippy/tests/ui/only_used_in_recursion.stderr b/src/tools/clippy/tests/ui/only_used_in_recursion.stderr
index 6fe9361bf..571e5c4b5 100644
--- a/src/tools/clippy/tests/ui/only_used_in_recursion.stderr
+++ b/src/tools/clippy/tests/ui/only_used_in_recursion.stderr
@@ -1,82 +1,195 @@
error: parameter is only used in recursion
- --> $DIR/only_used_in_recursion.rs:3:21
+ --> $DIR/only_used_in_recursion.rs:11:27
|
-LL | fn simple(a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | fn _one_unused(flag: u32, a: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
|
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:12:53
+ |
+LL | if flag == 0 { 0 } else { _one_unused(flag - 1, a) }
+ | ^
= note: `-D clippy::only-used-in-recursion` implied by `-D warnings`
error: parameter is only used in recursion
- --> $DIR/only_used_in_recursion.rs:7:24
+ --> $DIR/only_used_in_recursion.rs:15:27
+ |
+LL | fn _two_unused(flag: u32, a: u32, b: i32) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:16:53
+ |
+LL | if flag == 0 { 0 } else { _two_unused(flag - 1, a, b) }
+ | ^
+
+error: parameter is only used in recursion
+ --> $DIR/only_used_in_recursion.rs:15:35
+ |
+LL | fn _two_unused(flag: u32, a: u32, b: i32) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:16:56
+ |
+LL | if flag == 0 { 0 } else { _two_unused(flag - 1, a, b) }
+ | ^
+
+error: parameter is only used in recursion
+ --> $DIR/only_used_in_recursion.rs:19:26
+ |
+LL | fn _with_calc(flag: u32, a: i64) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:23:32
+ |
+LL | _with_calc(flag - 1, (-a + 10) * 5)
+ | ^
+
+error: parameter is only used in recursion
+ --> $DIR/only_used_in_recursion.rs:32:33
+ |
+LL | fn _used_with_unused(flag: u32, a: i32, b: i32) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:36:38
|
-LL | fn with_calc(a: usize, b: isize) -> usize {
- | ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | _used_with_unused(flag - 1, -a, a + b)
+ | ^ ^
error: parameter is only used in recursion
- --> $DIR/only_used_in_recursion.rs:11:14
+ --> $DIR/only_used_in_recursion.rs:32:41
+ |
+LL | fn _used_with_unused(flag: u32, a: i32, b: i32) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:36:45
|
-LL | fn tuple((a, b): (usize, usize)) -> usize {
- | ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | _used_with_unused(flag - 1, -a, a + b)
+ | ^
error: parameter is only used in recursion
- --> $DIR/only_used_in_recursion.rs:15:24
+ --> $DIR/only_used_in_recursion.rs:40:35
|
-LL | fn let_tuple(a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | fn _codependent_unused(flag: u32, a: i32, b: i32) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:44:39
+ |
+LL | _codependent_unused(flag - 1, a * b, a + b)
+ | ^ ^
error: parameter is only used in recursion
- --> $DIR/only_used_in_recursion.rs:20:14
+ --> $DIR/only_used_in_recursion.rs:40:43
+ |
+LL | fn _codependent_unused(flag: u32, a: i32, b: i32) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
|
-LL | fn array([a, b]: [usize; 2]) -> usize {
- | ^ help: if this is intentional, prefix with an underscore: `_b`
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:44:43
+ |
+LL | _codependent_unused(flag - 1, a * b, a + b)
+ | ^ ^
error: parameter is only used in recursion
- --> $DIR/only_used_in_recursion.rs:24:20
+ --> $DIR/only_used_in_recursion.rs:48:30
+ |
+LL | fn _not_primitive(flag: u32, b: String) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
|
-LL | fn index(a: usize, mut b: &[usize], c: usize) -> usize {
- | ^^^^^ help: if this is intentional, prefix with an underscore: `_b`
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:49:56
+ |
+LL | if flag == 0 { 0 } else { _not_primitive(flag - 1, b) }
+ | ^
error: parameter is only used in recursion
- --> $DIR/only_used_in_recursion.rs:24:37
+ --> $DIR/only_used_in_recursion.rs:55:29
+ |
+LL | fn _method(flag: usize, a: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:56:59
|
-LL | fn index(a: usize, mut b: &[usize], c: usize) -> usize {
- | ^ help: if this is intentional, prefix with an underscore: `_c`
+LL | if flag == 0 { 0 } else { Self::_method(flag - 1, a) }
+ | ^
error: parameter is only used in recursion
- --> $DIR/only_used_in_recursion.rs:28:21
+ --> $DIR/only_used_in_recursion.rs:59:22
+ |
+LL | fn _method_self(&self, flag: usize, a: usize) -> usize {
+ | ^^^^
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:60:35
|
-LL | fn break_(a: usize, mut b: usize, mut c: usize) -> usize {
- | ^^^^^ help: if this is intentional, prefix with an underscore: `_b`
+LL | if flag == 0 { 0 } else { self._method_self(flag - 1, a) }
+ | ^^^^
error: parameter is only used in recursion
- --> $DIR/only_used_in_recursion.rs:46:23
+ --> $DIR/only_used_in_recursion.rs:59:41
|
-LL | fn mut_ref2(a: usize, b: &mut usize) -> usize {
- | ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | fn _method_self(&self, flag: usize, a: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:60:63
+ |
+LL | if flag == 0 { 0 } else { self._method_self(flag - 1, a) }
+ | ^
error: parameter is only used in recursion
- --> $DIR/only_used_in_recursion.rs:51:28
+ --> $DIR/only_used_in_recursion.rs:70:26
+ |
+LL | fn method(flag: u32, a: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
|
-LL | fn not_primitive(a: usize, b: String) -> usize {
- | ^ help: if this is intentional, prefix with an underscore: `_b`
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:71:58
+ |
+LL | if flag == 0 { 0 } else { Self::method(flag - 1, a) }
+ | ^
error: parameter is only used in recursion
- --> $DIR/only_used_in_recursion.rs:68:33
+ --> $DIR/only_used_in_recursion.rs:74:38
+ |
+LL | fn method_self(&self, flag: u32, a: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
|
-LL | fn method2(&self, a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix with an underscore: `_b`
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:75:62
+ |
+LL | if flag == 0 { 0 } else { self.method_self(flag - 1, a) }
+ | ^
error: parameter is only used in recursion
- --> $DIR/only_used_in_recursion.rs:90:24
+ --> $DIR/only_used_in_recursion.rs:100:26
+ |
+LL | fn method(flag: u32, a: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:101:58
|
-LL | fn hello(a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | if flag == 0 { 0 } else { Self::method(flag - 1, a) }
+ | ^
error: parameter is only used in recursion
- --> $DIR/only_used_in_recursion.rs:94:32
+ --> $DIR/only_used_in_recursion.rs:104:38
+ |
+LL | fn method_self(&self, flag: u32, a: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion.rs:105:62
|
-LL | fn hello2(&self, a: usize, b: usize) -> usize {
- | ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | if flag == 0 { 0 } else { self.method_self(flag - 1, a) }
+ | ^
-error: aborting due to 13 previous errors
+error: aborting due to 16 previous errors
diff --git a/src/tools/clippy/tests/ui/only_used_in_recursion2.rs b/src/tools/clippy/tests/ui/only_used_in_recursion2.rs
new file mode 100644
index 000000000..45dd0553f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/only_used_in_recursion2.rs
@@ -0,0 +1,91 @@
+#![warn(clippy::only_used_in_recursion)]
+
+fn _with_inner(flag: u32, a: u32, b: u32) -> usize {
+ fn inner(flag: u32, a: u32) -> u32 {
+ if flag == 0 { 0 } else { inner(flag, a) }
+ }
+
+ let x = inner(flag, a);
+ if flag == 0 { 0 } else { _with_inner(flag, a, b + x) }
+}
+
+fn _with_closure(a: Option<u32>, b: u32, f: impl Fn(u32, u32) -> Option<u32>) -> u32 {
+ if let Some(x) = a.and_then(|x| f(x, x)) {
+ _with_closure(Some(x), b, f)
+ } else {
+ 0
+ }
+}
+
+// Issue #8560
+trait D {
+ fn foo(&mut self, arg: u32) -> u32;
+}
+
+mod m {
+ pub struct S(u32);
+ impl S {
+ pub fn foo(&mut self, arg: u32) -> u32 {
+ arg + self.0
+ }
+ }
+}
+
+impl D for m::S {
+ fn foo(&mut self, arg: u32) -> u32 {
+ self.foo(arg)
+ }
+}
+
+// Issue #8782
+fn only_let(x: u32) {
+ let y = 10u32;
+ let _z = x * y;
+}
+
+trait E<T: E<()>> {
+ fn method(flag: u32, a: usize) -> usize {
+ if flag == 0 {
+ 0
+ } else {
+ <T as E<()>>::method(flag - 1, a)
+ }
+ }
+}
+
+impl E<()> for () {
+ fn method(flag: u32, a: usize) -> usize {
+ if flag == 0 { 0 } else { a }
+ }
+}
+
+fn overwritten_param(flag: u32, mut a: usize) -> usize {
+ if flag == 0 {
+ return 0;
+ } else if flag > 5 {
+ a += flag as usize;
+ } else {
+ a = 5;
+ }
+ overwritten_param(flag, a)
+}
+
+fn field_direct(flag: u32, mut a: (usize,)) -> usize {
+ if flag == 0 {
+ 0
+ } else {
+ a.0 += 5;
+ field_direct(flag - 1, a)
+ }
+}
+
+fn field_deref(flag: u32, a: &mut Box<(usize,)>) -> usize {
+ if flag == 0 {
+ 0
+ } else {
+ a.0 += 5;
+ field_deref(flag - 1, a)
+ }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/only_used_in_recursion2.stderr b/src/tools/clippy/tests/ui/only_used_in_recursion2.stderr
new file mode 100644
index 000000000..8dcbfdd61
--- /dev/null
+++ b/src/tools/clippy/tests/ui/only_used_in_recursion2.stderr
@@ -0,0 +1,63 @@
+error: parameter is only used in recursion
+ --> $DIR/only_used_in_recursion2.rs:3:35
+ |
+LL | fn _with_inner(flag: u32, a: u32, b: u32) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion2.rs:9:52
+ |
+LL | if flag == 0 { 0 } else { _with_inner(flag, a, b + x) }
+ | ^
+ = note: `-D clippy::only-used-in-recursion` implied by `-D warnings`
+
+error: parameter is only used in recursion
+ --> $DIR/only_used_in_recursion2.rs:4:25
+ |
+LL | fn inner(flag: u32, a: u32) -> u32 {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion2.rs:5:47
+ |
+LL | if flag == 0 { 0 } else { inner(flag, a) }
+ | ^
+
+error: parameter is only used in recursion
+ --> $DIR/only_used_in_recursion2.rs:12:34
+ |
+LL | fn _with_closure(a: Option<u32>, b: u32, f: impl Fn(u32, u32) -> Option<u32>) -> u32 {
+ | ^ help: if this is intentional, prefix it with an underscore: `_b`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion2.rs:14:32
+ |
+LL | _with_closure(Some(x), b, f)
+ | ^
+
+error: parameter is only used in recursion
+ --> $DIR/only_used_in_recursion2.rs:62:37
+ |
+LL | fn overwritten_param(flag: u32, mut a: usize) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion2.rs:70:29
+ |
+LL | overwritten_param(flag, a)
+ | ^
+
+error: parameter is only used in recursion
+ --> $DIR/only_used_in_recursion2.rs:73:32
+ |
+LL | fn field_direct(flag: u32, mut a: (usize,)) -> usize {
+ | ^ help: if this is intentional, prefix it with an underscore: `_a`
+ |
+note: parameter used here
+ --> $DIR/only_used_in_recursion2.rs:78:32
+ |
+LL | field_direct(flag - 1, a)
+ | ^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/op_ref.rs b/src/tools/clippy/tests/ui/op_ref.rs
index d8bf66603..07226b0a1 100644
--- a/src/tools/clippy/tests/ui/op_ref.rs
+++ b/src/tools/clippy/tests/ui/op_ref.rs
@@ -1,4 +1,4 @@
-#![allow(unused_variables, clippy::blacklisted_name)]
+#![allow(unused_variables, clippy::disallowed_names)]
#![warn(clippy::op_ref)]
use std::collections::HashSet;
use std::ops::{BitAnd, Mul};
diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.fixed b/src/tools/clippy/tests/ui/option_as_ref_deref.fixed
index 07d7f0b45..bc376d0d7 100644
--- a/src/tools/clippy/tests/ui/option_as_ref_deref.fixed
+++ b/src/tools/clippy/tests/ui/option_as_ref_deref.fixed
@@ -1,6 +1,7 @@
// run-rustfix
-#![allow(unused_imports, clippy::redundant_clone)]
+#![feature(custom_inner_attributes)]
+#![allow(unused, clippy::redundant_clone)]
#![warn(clippy::option_as_ref_deref)]
use std::ffi::{CString, OsString};
@@ -42,3 +43,17 @@ fn main() {
// Issue #5927
let _ = opt.as_deref();
}
+
+fn msrv_1_39() {
+ #![clippy::msrv = "1.39"]
+
+ let opt = Some(String::from("123"));
+ let _ = opt.as_ref().map(String::as_str);
+}
+
+fn msrv_1_40() {
+ #![clippy::msrv = "1.40"]
+
+ let opt = Some(String::from("123"));
+ let _ = opt.as_deref();
+}
diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.rs b/src/tools/clippy/tests/ui/option_as_ref_deref.rs
index 6ae059c94..ba3a2eedc 100644
--- a/src/tools/clippy/tests/ui/option_as_ref_deref.rs
+++ b/src/tools/clippy/tests/ui/option_as_ref_deref.rs
@@ -1,6 +1,7 @@
// run-rustfix
-#![allow(unused_imports, clippy::redundant_clone)]
+#![feature(custom_inner_attributes)]
+#![allow(unused, clippy::redundant_clone)]
#![warn(clippy::option_as_ref_deref)]
use std::ffi::{CString, OsString};
@@ -45,3 +46,17 @@ fn main() {
// Issue #5927
let _ = opt.as_ref().map(std::ops::Deref::deref);
}
+
+fn msrv_1_39() {
+ #![clippy::msrv = "1.39"]
+
+ let opt = Some(String::from("123"));
+ let _ = opt.as_ref().map(String::as_str);
+}
+
+fn msrv_1_40() {
+ #![clippy::msrv = "1.40"]
+
+ let opt = Some(String::from("123"));
+ let _ = opt.as_ref().map(String::as_str);
+}
diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.stderr b/src/tools/clippy/tests/ui/option_as_ref_deref.stderr
index 62f282324..7de8b3b6b 100644
--- a/src/tools/clippy/tests/ui/option_as_ref_deref.stderr
+++ b/src/tools/clippy/tests/ui/option_as_ref_deref.stderr
@@ -1,5 +1,5 @@
error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead
- --> $DIR/option_as_ref_deref.rs:13:13
+ --> $DIR/option_as_ref_deref.rs:14:13
|
LL | let _ = opt.clone().as_ref().map(Deref::deref).map(str::len);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.clone().as_deref()`
@@ -7,7 +7,7 @@ LL | let _ = opt.clone().as_ref().map(Deref::deref).map(str::len);
= note: `-D clippy::option-as-ref-deref` implied by `-D warnings`
error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead
- --> $DIR/option_as_ref_deref.rs:16:13
+ --> $DIR/option_as_ref_deref.rs:17:13
|
LL | let _ = opt.clone()
| _____________^
@@ -17,94 +17,100 @@ LL | | )
| |_________^ help: try using as_deref instead: `opt.clone().as_deref()`
error: called `.as_mut().map(DerefMut::deref_mut)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
- --> $DIR/option_as_ref_deref.rs:22:13
+ --> $DIR/option_as_ref_deref.rs:23:13
|
LL | let _ = opt.as_mut().map(DerefMut::deref_mut);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
- --> $DIR/option_as_ref_deref.rs:24:13
+ --> $DIR/option_as_ref_deref.rs:25:13
|
LL | let _ = opt.as_ref().map(String::as_str);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
error: called `.as_ref().map(|x| x.as_str())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
- --> $DIR/option_as_ref_deref.rs:25:13
+ --> $DIR/option_as_ref_deref.rs:26:13
|
LL | let _ = opt.as_ref().map(|x| x.as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
error: called `.as_mut().map(String::as_mut_str)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
- --> $DIR/option_as_ref_deref.rs:26:13
+ --> $DIR/option_as_ref_deref.rs:27:13
|
LL | let _ = opt.as_mut().map(String::as_mut_str);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
error: called `.as_mut().map(|x| x.as_mut_str())` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
- --> $DIR/option_as_ref_deref.rs:27:13
+ --> $DIR/option_as_ref_deref.rs:28:13
|
LL | let _ = opt.as_mut().map(|x| x.as_mut_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
error: called `.as_ref().map(CString::as_c_str)` on an Option value. This can be done more directly by calling `Some(CString::new(vec![]).unwrap()).as_deref()` instead
- --> $DIR/option_as_ref_deref.rs:28:13
+ --> $DIR/option_as_ref_deref.rs:29:13
|
LL | let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(CString::new(vec![]).unwrap()).as_deref()`
error: called `.as_ref().map(OsString::as_os_str)` on an Option value. This can be done more directly by calling `Some(OsString::new()).as_deref()` instead
- --> $DIR/option_as_ref_deref.rs:29:13
+ --> $DIR/option_as_ref_deref.rs:30:13
|
LL | let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(OsString::new()).as_deref()`
error: called `.as_ref().map(PathBuf::as_path)` on an Option value. This can be done more directly by calling `Some(PathBuf::new()).as_deref()` instead
- --> $DIR/option_as_ref_deref.rs:30:13
+ --> $DIR/option_as_ref_deref.rs:31:13
|
LL | let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(PathBuf::new()).as_deref()`
error: called `.as_ref().map(Vec::as_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref()` instead
- --> $DIR/option_as_ref_deref.rs:31:13
+ --> $DIR/option_as_ref_deref.rs:32:13
|
LL | let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(Vec::<()>::new()).as_deref()`
error: called `.as_mut().map(Vec::as_mut_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref_mut()` instead
- --> $DIR/option_as_ref_deref.rs:32:13
+ --> $DIR/option_as_ref_deref.rs:33:13
|
LL | let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `Some(Vec::<()>::new()).as_deref_mut()`
error: called `.as_ref().map(|x| x.deref())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
- --> $DIR/option_as_ref_deref.rs:34:13
+ --> $DIR/option_as_ref_deref.rs:35:13
|
LL | let _ = opt.as_ref().map(|x| x.deref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
error: called `.as_mut().map(|x| x.deref_mut())` on an Option value. This can be done more directly by calling `opt.clone().as_deref_mut()` instead
- --> $DIR/option_as_ref_deref.rs:35:13
+ --> $DIR/option_as_ref_deref.rs:36:13
|
LL | let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.clone().as_deref_mut()`
error: called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
- --> $DIR/option_as_ref_deref.rs:42:13
+ --> $DIR/option_as_ref_deref.rs:43:13
|
LL | let _ = opt.as_ref().map(|x| &**x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
error: called `.as_mut().map(|x| &mut **x)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
- --> $DIR/option_as_ref_deref.rs:43:13
+ --> $DIR/option_as_ref_deref.rs:44:13
|
LL | let _ = opt.as_mut().map(|x| &mut **x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
error: called `.as_ref().map(std::ops::Deref::deref)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
- --> $DIR/option_as_ref_deref.rs:46:13
+ --> $DIR/option_as_ref_deref.rs:47:13
|
LL | let _ = opt.as_ref().map(std::ops::Deref::deref);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
-error: aborting due to 17 previous errors
+error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
+ --> $DIR/option_as_ref_deref.rs:61:13
+ |
+LL | let _ = opt.as_ref().map(String::as_str);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
+
+error: aborting due to 18 previous errors
diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.stderr b/src/tools/clippy/tests/ui/option_env_unwrap.stderr
index 885ac096c..bc188a07e 100644
--- a/src/tools/clippy/tests/ui/option_env_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/option_env_unwrap.stderr
@@ -4,8 +4,8 @@ error: this will panic at run-time if the environment variable doesn't exist at
LL | let _ = option_env!("PATH").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::option-env-unwrap` implied by `-D warnings`
= help: consider using the `env!` macro instead
+ = note: `-D clippy::option-env-unwrap` implied by `-D warnings`
error: this will panic at run-time if the environment variable doesn't exist at compile-time
--> $DIR/option_env_unwrap.rs:19:13
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index b6d5e106f..f15ac551b 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -179,4 +179,13 @@ fn main() {
let _ = pattern_to_vec("hello world");
let _ = complex_subpat();
+
+ // issue #8492
+ let _ = s.map_or(1, |string| string.len());
+ let _ = Some(10).map_or(5, |a| a + 1);
+
+ let res: Result<i32, i32> = Ok(5);
+ let _ = res.map_or(1, |a| a + 1);
+ let _ = res.map_or(1, |a| a + 1);
+ let _ = res.map_or(5, |a| a + 1);
}
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index 35bae1593..9eeaea12d 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -208,4 +208,25 @@ fn main() {
let _ = pattern_to_vec("hello world");
let _ = complex_subpat();
+
+ // issue #8492
+ let _ = match s {
+ Some(string) => string.len(),
+ None => 1,
+ };
+ let _ = match Some(10) {
+ Some(a) => a + 1,
+ None => 5,
+ };
+
+ let res: Result<i32, i32> = Ok(5);
+ let _ = match res {
+ Ok(a) => a + 1,
+ _ => 1,
+ };
+ let _ = match res {
+ Err(_) => 1,
+ Ok(a) => a + 1,
+ };
+ let _ = if let Ok(a) = res { a + 1 } else { 5 };
}
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index daba60600..a5dbf6e1f 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -206,5 +206,51 @@ LL + s.len() + x
LL ~ });
|
-error: aborting due to 15 previous errors
+error: use Option::map_or instead of an if let/else
+ --> $DIR/option_if_let_else.rs:213:13
+ |
+LL | let _ = match s {
+ | _____________^
+LL | | Some(string) => string.len(),
+LL | | None => 1,
+LL | | };
+ | |_____^ help: try: `s.map_or(1, |string| string.len())`
+
+error: use Option::map_or instead of an if let/else
+ --> $DIR/option_if_let_else.rs:217:13
+ |
+LL | let _ = match Some(10) {
+ | _____________^
+LL | | Some(a) => a + 1,
+LL | | None => 5,
+LL | | };
+ | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
+
+error: use Option::map_or instead of an if let/else
+ --> $DIR/option_if_let_else.rs:223:13
+ |
+LL | let _ = match res {
+ | _____________^
+LL | | Ok(a) => a + 1,
+LL | | _ => 1,
+LL | | };
+ | |_____^ help: try: `res.map_or(1, |a| a + 1)`
+
+error: use Option::map_or instead of an if let/else
+ --> $DIR/option_if_let_else.rs:227:13
+ |
+LL | let _ = match res {
+ | _____________^
+LL | | Err(_) => 1,
+LL | | Ok(a) => a + 1,
+LL | | };
+ | |_____^ help: try: `res.map_or(1, |a| a + 1)`
+
+error: use Option::map_or instead of an if let/else
+ --> $DIR/option_if_let_else.rs:231:13
+ |
+LL | let _ = if let Ok(a) = res { a + 1 } else { 5 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
+
+error: aborting due to 20 previous errors
diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed
index 1290bd8ef..00264dcce 100644
--- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed
+++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed
@@ -1,8 +1,7 @@
// run-rustfix
-
#![warn(clippy::option_map_unit_fn)]
#![allow(unused)]
-#![allow(clippy::unnecessary_wraps)]
+#![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)]
fn do_nothing<T>(_: T) {}
diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs
index f3e5b62c6..f3363ebce 100644
--- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs
+++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs
@@ -1,8 +1,7 @@
// run-rustfix
-
#![warn(clippy::option_map_unit_fn)]
#![allow(unused)]
-#![allow(clippy::unnecessary_wraps)]
+#![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)]
fn do_nothing<T>(_: T) {}
diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr
index ab2a294a0..0305387b9 100644
--- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr
+++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr
@@ -1,5 +1,5 @@
error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:39:5
+ --> $DIR/option_map_unit_fn_fixable.rs:38:5
|
LL | x.field.map(do_nothing);
| ^^^^^^^^^^^^^^^^^^^^^^^-
@@ -9,7 +9,7 @@ LL | x.field.map(do_nothing);
= note: `-D clippy::option-map-unit-fn` implied by `-D warnings`
error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:41:5
+ --> $DIR/option_map_unit_fn_fixable.rs:40:5
|
LL | x.field.map(do_nothing);
| ^^^^^^^^^^^^^^^^^^^^^^^-
@@ -17,7 +17,7 @@ LL | x.field.map(do_nothing);
| help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }`
error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:43:5
+ --> $DIR/option_map_unit_fn_fixable.rs:42:5
|
LL | x.field.map(diverge);
| ^^^^^^^^^^^^^^^^^^^^-
@@ -25,7 +25,7 @@ LL | x.field.map(diverge);
| help: try this: `if let Some(x_field) = x.field { diverge(x_field) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:49:5
+ --> $DIR/option_map_unit_fn_fixable.rs:48:5
|
LL | x.field.map(|value| x.do_option_nothing(value + captured));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -33,7 +33,7 @@ LL | x.field.map(|value| x.do_option_nothing(value + captured));
| help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:51:5
+ --> $DIR/option_map_unit_fn_fixable.rs:50:5
|
LL | x.field.map(|value| { x.do_option_plus_one(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -41,7 +41,7 @@ LL | x.field.map(|value| { x.do_option_plus_one(value + captured); });
| help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:54:5
+ --> $DIR/option_map_unit_fn_fixable.rs:53:5
|
LL | x.field.map(|value| do_nothing(value + captured));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -49,7 +49,7 @@ LL | x.field.map(|value| do_nothing(value + captured));
| help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:56:5
+ --> $DIR/option_map_unit_fn_fixable.rs:55:5
|
LL | x.field.map(|value| { do_nothing(value + captured) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -57,7 +57,7 @@ LL | x.field.map(|value| { do_nothing(value + captured) });
| help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:58:5
+ --> $DIR/option_map_unit_fn_fixable.rs:57:5
|
LL | x.field.map(|value| { do_nothing(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -65,7 +65,7 @@ LL | x.field.map(|value| { do_nothing(value + captured); });
| help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:60:5
+ --> $DIR/option_map_unit_fn_fixable.rs:59:5
|
LL | x.field.map(|value| { { do_nothing(value + captured); } });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -73,7 +73,7 @@ LL | x.field.map(|value| { { do_nothing(value + captured); } });
| help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:63:5
+ --> $DIR/option_map_unit_fn_fixable.rs:62:5
|
LL | x.field.map(|value| diverge(value + captured));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -81,7 +81,7 @@ LL | x.field.map(|value| diverge(value + captured));
| help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:65:5
+ --> $DIR/option_map_unit_fn_fixable.rs:64:5
|
LL | x.field.map(|value| { diverge(value + captured) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -89,7 +89,7 @@ LL | x.field.map(|value| { diverge(value + captured) });
| help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:67:5
+ --> $DIR/option_map_unit_fn_fixable.rs:66:5
|
LL | x.field.map(|value| { diverge(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -97,7 +97,7 @@ LL | x.field.map(|value| { diverge(value + captured); });
| help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:69:5
+ --> $DIR/option_map_unit_fn_fixable.rs:68:5
|
LL | x.field.map(|value| { { diverge(value + captured); } });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -105,7 +105,7 @@ LL | x.field.map(|value| { { diverge(value + captured); } });
| help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:74:5
+ --> $DIR/option_map_unit_fn_fixable.rs:73:5
|
LL | x.field.map(|value| { let y = plus_one(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -113,7 +113,7 @@ LL | x.field.map(|value| { let y = plus_one(value + captured); });
| help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:76:5
+ --> $DIR/option_map_unit_fn_fixable.rs:75:5
|
LL | x.field.map(|value| { plus_one(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -121,7 +121,7 @@ LL | x.field.map(|value| { plus_one(value + captured); });
| help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:78:5
+ --> $DIR/option_map_unit_fn_fixable.rs:77:5
|
LL | x.field.map(|value| { { plus_one(value + captured); } });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -129,7 +129,7 @@ LL | x.field.map(|value| { { plus_one(value + captured); } });
| help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:81:5
+ --> $DIR/option_map_unit_fn_fixable.rs:80:5
|
LL | x.field.map(|ref value| { do_nothing(value + captured) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -137,7 +137,7 @@ LL | x.field.map(|ref value| { do_nothing(value + captured) });
| help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:83:5
+ --> $DIR/option_map_unit_fn_fixable.rs:82:5
|
LL | option().map(do_nothing);
| ^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -145,7 +145,7 @@ LL | option().map(do_nothing);
| help: try this: `if let Some(a) = option() { do_nothing(a) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
- --> $DIR/option_map_unit_fn_fixable.rs:85:5
+ --> $DIR/option_map_unit_fn_fixable.rs:84:5
|
LL | option().map(|value| println!("{:?}", value));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
diff --git a/src/tools/clippy/tests/ui/option_take_on_temporary.fixed b/src/tools/clippy/tests/ui/option_take_on_temporary.fixed
deleted file mode 100644
index 29691e816..000000000
--- a/src/tools/clippy/tests/ui/option_take_on_temporary.fixed
+++ /dev/null
@@ -1,15 +0,0 @@
-// run-rustfix
-
-fn main() {
- println!("Testing non erroneous option_take_on_temporary");
- let mut option = Some(1);
- let _ = Box::new(move || option.take().unwrap());
-
- println!("Testing non erroneous option_take_on_temporary");
- let x = Some(3);
- x.as_ref();
-
- println!("Testing erroneous option_take_on_temporary");
- let x = Some(3);
- x.as_ref();
-}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index fdb08d953..23b1aa8be 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -1,8 +1,7 @@
// run-rustfix
-
#![warn(clippy::or_fun_call)]
#![allow(dead_code)]
-#![allow(clippy::unnecessary_wraps, clippy::borrow_as_ptr)]
+#![allow(clippy::borrow_as_ptr, clippy::uninlined_format_args, clippy::unnecessary_wraps)]
use std::collections::BTreeMap;
use std::collections::HashMap;
@@ -79,19 +78,19 @@ fn or_fun_call() {
without_default.unwrap_or_else(Foo::new);
let mut map = HashMap::<u64, String>::new();
- map.entry(42).or_insert(String::new());
+ map.entry(42).or_default();
let mut map_vec = HashMap::<u64, Vec<i32>>::new();
- map_vec.entry(42).or_insert(vec![]);
+ map_vec.entry(42).or_default();
let mut btree = BTreeMap::<u64, String>::new();
- btree.entry(42).or_insert(String::new());
+ btree.entry(42).or_default();
let mut btree_vec = BTreeMap::<u64, Vec<i32>>::new();
- btree_vec.entry(42).or_insert(vec![]);
+ btree_vec.entry(42).or_default();
- let stringy = Some(String::from(""));
- let _ = stringy.unwrap_or_else(|| "".to_owned());
+ let stringy = Some(String::new());
+ let _ = stringy.unwrap_or_default();
let opt = Some(1);
let hello = "Hello";
@@ -226,4 +225,15 @@ mod issue8239 {
}
}
+mod issue9608 {
+ fn sig_drop() {
+ enum X {
+ X(std::fs::File),
+ Y(u32),
+ }
+
+ let _ = None.unwrap_or(X::Y(0));
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index 57ab5f03e..039998f22 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -1,8 +1,7 @@
// run-rustfix
-
#![warn(clippy::or_fun_call)]
#![allow(dead_code)]
-#![allow(clippy::unnecessary_wraps, clippy::borrow_as_ptr)]
+#![allow(clippy::borrow_as_ptr, clippy::uninlined_format_args, clippy::unnecessary_wraps)]
use std::collections::BTreeMap;
use std::collections::HashMap;
@@ -90,8 +89,8 @@ fn or_fun_call() {
let mut btree_vec = BTreeMap::<u64, Vec<i32>>::new();
btree_vec.entry(42).or_insert(vec![]);
- let stringy = Some(String::from(""));
- let _ = stringy.unwrap_or("".to_owned());
+ let stringy = Some(String::new());
+ let _ = stringy.unwrap_or(String::new());
let opt = Some(1);
let hello = "Hello";
@@ -226,4 +225,15 @@ mod issue8239 {
}
}
+mod issue9608 {
+ fn sig_drop() {
+ enum X {
+ X(std::fs::File),
+ Y(u32),
+ }
+
+ let _ = None.unwrap_or(X::Y(0));
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index 4c5938ab8..113ba150c 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -1,5 +1,5 @@
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:49:22
+ --> $DIR/or_fun_call.rs:48:22
|
LL | with_constructor.unwrap_or(make());
| ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)`
@@ -7,130 +7,154 @@ LL | with_constructor.unwrap_or(make());
= note: `-D clippy::or-fun-call` implied by `-D warnings`
error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:52:14
+ --> $DIR/or_fun_call.rs:51:14
|
LL | with_new.unwrap_or(Vec::new());
| ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:55:21
+ --> $DIR/or_fun_call.rs:54:21
|
LL | with_const_args.unwrap_or(Vec::with_capacity(12));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:58:14
+ --> $DIR/or_fun_call.rs:57:14
|
LL | with_err.unwrap_or(make());
| ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:61:19
+ --> $DIR/or_fun_call.rs:60:19
|
LL | with_err_args.unwrap_or(Vec::with_capacity(12));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))`
error: use of `unwrap_or` followed by a call to `default`
- --> $DIR/or_fun_call.rs:64:24
+ --> $DIR/or_fun_call.rs:63:24
|
LL | with_default_trait.unwrap_or(Default::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
error: use of `unwrap_or` followed by a call to `default`
- --> $DIR/or_fun_call.rs:67:23
+ --> $DIR/or_fun_call.rs:66:23
|
LL | with_default_type.unwrap_or(u64::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:70:18
+ --> $DIR/or_fun_call.rs:69:18
|
LL | self_default.unwrap_or(<FakeDefault>::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(<FakeDefault>::default)`
error: use of `unwrap_or` followed by a call to `default`
- --> $DIR/or_fun_call.rs:73:18
+ --> $DIR/or_fun_call.rs:72:18
|
LL | real_default.unwrap_or(<FakeDefault as Default>::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:76:14
+ --> $DIR/or_fun_call.rs:75:14
|
LL | with_vec.unwrap_or(vec![]);
| ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:79:21
+ --> $DIR/or_fun_call.rs:78:21
|
LL | without_default.unwrap_or(Foo::new());
| ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
-error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:94:21
+error: use of `or_insert` followed by a call to `new`
+ --> $DIR/or_fun_call.rs:81:19
+ |
+LL | map.entry(42).or_insert(String::new());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+
+error: use of `or_insert` followed by a call to `new`
+ --> $DIR/or_fun_call.rs:84:23
+ |
+LL | map_vec.entry(42).or_insert(vec![]);
+ | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+
+error: use of `or_insert` followed by a call to `new`
+ --> $DIR/or_fun_call.rs:87:21
+ |
+LL | btree.entry(42).or_insert(String::new());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+
+error: use of `or_insert` followed by a call to `new`
+ --> $DIR/or_fun_call.rs:90:25
+ |
+LL | btree_vec.entry(42).or_insert(vec![]);
+ | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+
+error: use of `unwrap_or` followed by a call to `new`
+ --> $DIR/or_fun_call.rs:93:21
|
-LL | let _ = stringy.unwrap_or("".to_owned());
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
+LL | let _ = stringy.unwrap_or(String::new());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:102:21
+ --> $DIR/or_fun_call.rs:101:21
|
LL | let _ = Some(1).unwrap_or(map[&1]);
| ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:104:21
+ --> $DIR/or_fun_call.rs:103:21
|
LL | let _ = Some(1).unwrap_or(map[&1]);
| ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])`
error: use of `or` followed by a function call
- --> $DIR/or_fun_call.rs:128:35
+ --> $DIR/or_fun_call.rs:127:35
|
LL | let _ = Some("a".to_string()).or(Some("b".to_string()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:167:14
+ --> $DIR/or_fun_call.rs:166:14
|
LL | None.unwrap_or(ptr_to_ref(s));
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| ptr_to_ref(s))`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:173:14
+ --> $DIR/or_fun_call.rs:172:14
|
LL | None.unwrap_or(unsafe { ptr_to_ref(s) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:175:14
+ --> $DIR/or_fun_call.rs:174:14
|
LL | None.unwrap_or( unsafe { ptr_to_ref(s) } );
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:189:14
+ --> $DIR/or_fun_call.rs:188:14
|
LL | .unwrap_or(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:202:14
+ --> $DIR/or_fun_call.rs:201:14
|
LL | .unwrap_or(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:214:14
+ --> $DIR/or_fun_call.rs:213:14
|
LL | .unwrap_or(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:225:10
+ --> $DIR/or_fun_call.rs:224:10
|
LL | .unwrap_or(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
-error: aborting due to 22 previous errors
+error: aborting due to 26 previous errors
diff --git a/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.rs b/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.rs
index f20a0ede1..edd2123d4 100644
--- a/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.rs
+++ b/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.rs
@@ -1,5 +1,5 @@
#![warn(clippy::out_of_bounds_indexing)]
-#![allow(clippy::no_effect, const_err)]
+#![allow(clippy::no_effect)]
fn main() {
let x = [1, 2, 3, 4];
diff --git a/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.rs b/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.rs
index 590e578d7..4c541c23f 100644
--- a/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.rs
+++ b/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.rs
@@ -1,5 +1,5 @@
#![warn(clippy::out_of_bounds_indexing)]
-#![allow(clippy::no_effect, clippy::unnecessary_operation, const_err)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation)]
fn main() {
let x = [1, 2, 3, 4];
diff --git a/src/tools/clippy/tests/ui/logic_bug.rs b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs
index dd6b1db5f..04a30a832 100644
--- a/src/tools/clippy/tests/ui/logic_bug.rs
+++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs
@@ -1,6 +1,6 @@
#![feature(lint_reasons)]
#![allow(unused, clippy::diverging_sub_expression)]
-#![warn(clippy::logic_bug)]
+#![warn(clippy::overly_complex_bool_expr)]
fn main() {
let a: bool = unimplemented!();
@@ -29,6 +29,6 @@ fn equality_stuff() {
fn check_expect() {
let a: i32 = unimplemented!();
let b: i32 = unimplemented!();
- #[expect(clippy::logic_bug)]
+ #[expect(clippy::overly_complex_bool_expr)]
let _ = a < b && a >= b;
}
diff --git a/src/tools/clippy/tests/ui/logic_bug.stderr b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr
index 4021fbf45..e989f2ece 100644
--- a/src/tools/clippy/tests/ui/logic_bug.stderr
+++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr
@@ -1,60 +1,60 @@
error: this boolean expression contains a logic bug
- --> $DIR/logic_bug.rs:11:13
+ --> $DIR/overly_complex_bool_expr.rs:11:13
|
LL | let _ = a && b || a;
| ^^^^^^^^^^^ help: it would look like the following: `a`
|
- = note: `-D clippy::logic-bug` implied by `-D warnings`
help: this expression can be optimized out by applying boolean operations to the outer expression
- --> $DIR/logic_bug.rs:11:18
+ --> $DIR/overly_complex_bool_expr.rs:11:18
|
LL | let _ = a && b || a;
| ^
+ = note: `-D clippy::overly-complex-bool-expr` implied by `-D warnings`
error: this boolean expression contains a logic bug
- --> $DIR/logic_bug.rs:13:13
+ --> $DIR/overly_complex_bool_expr.rs:13:13
|
LL | let _ = false && a;
| ^^^^^^^^^^ help: it would look like the following: `false`
|
help: this expression can be optimized out by applying boolean operations to the outer expression
- --> $DIR/logic_bug.rs:13:22
+ --> $DIR/overly_complex_bool_expr.rs:13:22
|
LL | let _ = false && a;
| ^
error: this boolean expression contains a logic bug
- --> $DIR/logic_bug.rs:23:13
+ --> $DIR/overly_complex_bool_expr.rs:23:13
|
LL | let _ = a == b && a != b;
| ^^^^^^^^^^^^^^^^ help: it would look like the following: `false`
|
help: this expression can be optimized out by applying boolean operations to the outer expression
- --> $DIR/logic_bug.rs:23:13
+ --> $DIR/overly_complex_bool_expr.rs:23:13
|
LL | let _ = a == b && a != b;
| ^^^^^^
error: this boolean expression contains a logic bug
- --> $DIR/logic_bug.rs:24:13
+ --> $DIR/overly_complex_bool_expr.rs:24:13
|
LL | let _ = a < b && a >= b;
| ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
|
help: this expression can be optimized out by applying boolean operations to the outer expression
- --> $DIR/logic_bug.rs:24:13
+ --> $DIR/overly_complex_bool_expr.rs:24:13
|
LL | let _ = a < b && a >= b;
| ^^^^^
error: this boolean expression contains a logic bug
- --> $DIR/logic_bug.rs:25:13
+ --> $DIR/overly_complex_bool_expr.rs:25:13
|
LL | let _ = a > b && a <= b;
| ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
|
help: this expression can be optimized out by applying boolean operations to the outer expression
- --> $DIR/logic_bug.rs:25:13
+ --> $DIR/overly_complex_bool_expr.rs:25:13
|
LL | let _ = a > b && a <= b;
| ^^^^^
diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn.stderr b/src/tools/clippy/tests/ui/panic_in_result_fn.stderr
index 561503ae5..97787bc84 100644
--- a/src/tools/clippy/tests/ui/panic_in_result_fn.stderr
+++ b/src/tools/clippy/tests/ui/panic_in_result_fn.stderr
@@ -7,13 +7,13 @@ 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
--> $DIR/panic_in_result_fn.rs:8:9
|
LL | panic!("error");
| ^^^^^^^^^^^^^^^
+ = note: `-D clippy::panic-in-result-fn` implied by `-D warnings`
error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
--> $DIR/panic_in_result_fn.rs:11:5
diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.rs b/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.rs
index ffdf8288a..08ab4d868 100644
--- a/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.rs
+++ b/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.rs
@@ -1,5 +1,5 @@
#![warn(clippy::panic_in_result_fn)]
-#![allow(clippy::unnecessary_wraps)]
+#![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)]
struct A;
diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr b/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr
index b6aa005e7..eb0aacbb6 100644
--- a/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr
+++ b/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr
@@ -8,13 +8,13 @@ LL | | Ok(true)
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
--> $DIR/panic_in_result_fn_assertions.rs:9:9
|
LL | assert!(x == 5, "wrong argument");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: `-D clippy::panic-in-result-fn` implied by `-D warnings`
error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
--> $DIR/panic_in_result_fn_assertions.rs:13:5
diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn_debug_assertions.rs b/src/tools/clippy/tests/ui/panic_in_result_fn_debug_assertions.rs
index c4fcd7e70..df89d8c50 100644
--- a/src/tools/clippy/tests/ui/panic_in_result_fn_debug_assertions.rs
+++ b/src/tools/clippy/tests/ui/panic_in_result_fn_debug_assertions.rs
@@ -1,5 +1,5 @@
#![warn(clippy::panic_in_result_fn)]
-#![allow(clippy::unnecessary_wraps)]
+#![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)]
// debug_assert should never trigger the `panic_in_result_fn` lint
diff --git a/src/tools/clippy/tests/ui/partial_pub_fields.rs b/src/tools/clippy/tests/ui/partial_pub_fields.rs
new file mode 100644
index 000000000..668545da8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/partial_pub_fields.rs
@@ -0,0 +1,40 @@
+#![allow(unused)]
+#![warn(clippy::partial_pub_fields)]
+
+fn main() {
+ use std::collections::HashMap;
+
+ #[derive(Default)]
+ pub struct FileSet {
+ files: HashMap<String, u32>,
+ pub paths: HashMap<u32, String>,
+ }
+
+ pub struct Color {
+ pub r: u8,
+ pub g: u8,
+ b: u8,
+ }
+
+ pub struct Point(i32, pub i32);
+
+ pub struct Visibility {
+ r#pub: bool,
+ pub pos: u32,
+ }
+
+ // Don't lint on empty structs;
+ pub struct Empty1;
+ pub struct Empty2();
+ pub struct Empty3 {};
+
+ // Don't lint on structs with one field.
+ pub struct Single1(i32);
+ pub struct Single2(pub i32);
+ pub struct Single3 {
+ v1: i32,
+ }
+ pub struct Single4 {
+ pub v1: i32,
+ }
+}
diff --git a/src/tools/clippy/tests/ui/partial_pub_fields.stderr b/src/tools/clippy/tests/ui/partial_pub_fields.stderr
new file mode 100644
index 000000000..84cfc1a91
--- /dev/null
+++ b/src/tools/clippy/tests/ui/partial_pub_fields.stderr
@@ -0,0 +1,35 @@
+error: mixed usage of pub and non-pub fields
+ --> $DIR/partial_pub_fields.rs:10:9
+ |
+LL | pub paths: HashMap<u32, String>,
+ | ^^^
+ |
+ = help: consider using private field here
+ = note: `-D clippy::partial-pub-fields` implied by `-D warnings`
+
+error: mixed usage of pub and non-pub fields
+ --> $DIR/partial_pub_fields.rs:16:9
+ |
+LL | b: u8,
+ | ^
+ |
+ = help: consider using public field here
+
+error: mixed usage of pub and non-pub fields
+ --> $DIR/partial_pub_fields.rs:19:27
+ |
+LL | pub struct Point(i32, pub i32);
+ | ^^^
+ |
+ = help: consider using private field here
+
+error: mixed usage of pub and non-pub fields
+ --> $DIR/partial_pub_fields.rs:23:9
+ |
+LL | pub pos: u32,
+ | ^^^
+ |
+ = help: consider using private field here
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.fixed b/src/tools/clippy/tests/ui/partialeq_to_none.fixed
new file mode 100644
index 000000000..4644ea8f5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/partialeq_to_none.fixed
@@ -0,0 +1,74 @@
+// run-rustfix
+#![warn(clippy::partialeq_to_none)]
+
+struct Foobar;
+
+impl PartialEq<Option<()>> for Foobar {
+ fn eq(&self, _: &Option<()>) -> bool {
+ false
+ }
+}
+
+#[allow(dead_code)]
+fn foo(f: Option<u32>) -> &'static str {
+ if f.is_some() { "yay" } else { "nay" }
+}
+
+fn foobar() -> Option<()> {
+ None
+}
+
+fn bar() -> Result<(), ()> {
+ Ok(())
+}
+
+fn optref() -> &'static &'static Option<()> {
+ &&None
+}
+
+pub fn macro_expansion() {
+ macro_rules! foo {
+ () => {
+ None::<()>
+ };
+ }
+
+ let _ = foobar() == foo!();
+ let _ = foo!() == foobar();
+ let _ = foo!() == foo!();
+}
+
+fn main() {
+ let x = Some(0);
+
+ let _ = x.is_none();
+ let _ = x.is_some();
+ let _ = x.is_none();
+ let _ = x.is_some();
+
+ if foobar().is_none() {}
+
+ if bar().ok().is_some() {}
+
+ let _ = Some(1 + 2).is_some();
+
+ let _ = { Some(0) }.is_none();
+
+ let _ = {
+ /*
+ This comment runs long
+ */
+ Some(1)
+ }.is_some();
+
+ // Should not trigger, as `Foobar` is not an `Option` and has no `is_none`
+ let _ = Foobar == None;
+
+ let _ = optref().is_none();
+ let _ = optref().is_some();
+ let _ = optref().is_none();
+ let _ = optref().is_some();
+
+ let x = Box::new(Option::<()>::None);
+ let _ = (*x).is_some();
+}
diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.rs b/src/tools/clippy/tests/ui/partialeq_to_none.rs
new file mode 100644
index 000000000..61011b3a8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/partialeq_to_none.rs
@@ -0,0 +1,74 @@
+// run-rustfix
+#![warn(clippy::partialeq_to_none)]
+
+struct Foobar;
+
+impl PartialEq<Option<()>> for Foobar {
+ fn eq(&self, _: &Option<()>) -> bool {
+ false
+ }
+}
+
+#[allow(dead_code)]
+fn foo(f: Option<u32>) -> &'static str {
+ if f != None { "yay" } else { "nay" }
+}
+
+fn foobar() -> Option<()> {
+ None
+}
+
+fn bar() -> Result<(), ()> {
+ Ok(())
+}
+
+fn optref() -> &'static &'static Option<()> {
+ &&None
+}
+
+pub fn macro_expansion() {
+ macro_rules! foo {
+ () => {
+ None::<()>
+ };
+ }
+
+ let _ = foobar() == foo!();
+ let _ = foo!() == foobar();
+ let _ = foo!() == foo!();
+}
+
+fn main() {
+ let x = Some(0);
+
+ let _ = x == None;
+ let _ = x != None;
+ let _ = None == x;
+ let _ = None != x;
+
+ if foobar() == None {}
+
+ if bar().ok() != None {}
+
+ let _ = Some(1 + 2) != None;
+
+ let _ = { Some(0) } == None;
+
+ let _ = {
+ /*
+ This comment runs long
+ */
+ Some(1)
+ } != None;
+
+ // Should not trigger, as `Foobar` is not an `Option` and has no `is_none`
+ let _ = Foobar == None;
+
+ let _ = optref() == &&None;
+ let _ = &&None != optref();
+ let _ = **optref() == None;
+ let _ = &None != *optref();
+
+ let x = Box::new(Option::<()>::None);
+ let _ = None != *x;
+}
diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.stderr b/src/tools/clippy/tests/ui/partialeq_to_none.stderr
new file mode 100644
index 000000000..d06ab7aee
--- /dev/null
+++ b/src/tools/clippy/tests/ui/partialeq_to_none.stderr
@@ -0,0 +1,110 @@
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:14:8
+ |
+LL | if f != None { "yay" } else { "nay" }
+ | ^^^^^^^^^ help: use `Option::is_some()` instead: `f.is_some()`
+ |
+ = note: `-D clippy::partialeq-to-none` implied by `-D warnings`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:44:13
+ |
+LL | let _ = x == None;
+ | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:45:13
+ |
+LL | let _ = x != None;
+ | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:46:13
+ |
+LL | let _ = None == x;
+ | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:47:13
+ |
+LL | let _ = None != x;
+ | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:49:8
+ |
+LL | if foobar() == None {}
+ | ^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `foobar().is_none()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:51:8
+ |
+LL | if bar().ok() != None {}
+ | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `bar().ok().is_some()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:53:13
+ |
+LL | let _ = Some(1 + 2) != None;
+ | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `Some(1 + 2).is_some()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:55:13
+ |
+LL | let _ = { Some(0) } == None;
+ | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `{ Some(0) }.is_none()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:57:13
+ |
+LL | let _ = {
+ | _____________^
+LL | | /*
+LL | | This comment runs long
+LL | | */
+LL | | Some(1)
+LL | | } != None;
+ | |_____________^
+ |
+help: use `Option::is_some()` instead
+ |
+LL ~ let _ = {
+LL + /*
+LL + This comment runs long
+LL + */
+LL + Some(1)
+LL ~ }.is_some();
+ |
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:67:13
+ |
+LL | let _ = optref() == &&None;
+ | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:68:13
+ |
+LL | let _ = &&None != optref();
+ | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:69:13
+ |
+LL | let _ = **optref() == None;
+ | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:70:13
+ |
+LL | let _ = &None != *optref();
+ | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:73:13
+ |
+LL | let _ = None != *x;
+ | ^^^^^^^^^^ help: use `Option::is_some()` instead: `(*x).is_some()`
+
+error: aborting due to 15 previous errors
+
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr
index 3421d5683..87fb243b6 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.stderr
@@ -4,8 +4,8 @@ error: type of pattern does not match the expression type
LL | Some(_) => (),
| ^^^^^^^
|
- = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
= help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+ = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
error: type of pattern does not match the expression type
--> $DIR/mutability.rs:15:9
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr
index d285c9378..a91b5ac6c 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr
@@ -4,8 +4,8 @@ error: type of pattern does not match the expression type
LL | if let Value::B | Value::A(_) = ref_value {}
| ^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
= help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+ = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
error: type of pattern does not match the expression type
--> $DIR/pattern_alternatives.rs:16:34
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr
index d428e85b0..8bc5c63ba 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr
@@ -4,8 +4,8 @@ error: type of pattern does not match the expression type
LL | let Struct { .. } = ref_value;
| ^^^^^^^^^^^^^
|
- = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
= help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+ = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
error: type of pattern does not match the expression type
--> $DIR/pattern_structs.rs:14:33
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr
index edd0074d0..a1ef540d2 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr
@@ -4,8 +4,8 @@ error: type of pattern does not match the expression type
LL | let TupleStruct(_) = ref_value;
| ^^^^^^^^^^^^^^
|
- = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
= help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+ = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
error: type of pattern does not match the expression type
--> $DIR/pattern_tuples.rs:12:25
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr
index 12b3d3a8b..f56a3a893 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr
@@ -4,8 +4,8 @@ error: type of pattern does not match the expression type
LL | Some(_) => (),
| ^^^^^^^
|
- = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
= help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
+ = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings`
error: type of pattern does not match the expression type
--> $DIR/syntax.rs:30:12
diff --git a/src/tools/clippy/tests/ui/patterns.fixed b/src/tools/clippy/tests/ui/patterns.fixed
index f22388154..cd6901432 100644
--- a/src/tools/clippy/tests/ui/patterns.fixed
+++ b/src/tools/clippy/tests/ui/patterns.fixed
@@ -1,6 +1,7 @@
// run-rustfix
-#![allow(unused)]
#![warn(clippy::all)]
+#![allow(unused)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
let v = Some(true);
diff --git a/src/tools/clippy/tests/ui/patterns.rs b/src/tools/clippy/tests/ui/patterns.rs
index 5848ecd38..9128da420 100644
--- a/src/tools/clippy/tests/ui/patterns.rs
+++ b/src/tools/clippy/tests/ui/patterns.rs
@@ -1,6 +1,7 @@
// run-rustfix
-#![allow(unused)]
#![warn(clippy::all)]
+#![allow(unused)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
let v = Some(true);
diff --git a/src/tools/clippy/tests/ui/patterns.stderr b/src/tools/clippy/tests/ui/patterns.stderr
index af0675806..2c46b4eb5 100644
--- a/src/tools/clippy/tests/ui/patterns.stderr
+++ b/src/tools/clippy/tests/ui/patterns.stderr
@@ -1,5 +1,5 @@
error: the `y @ _` pattern can be written as just `y`
- --> $DIR/patterns.rs:10:9
+ --> $DIR/patterns.rs:11:9
|
LL | y @ _ => (),
| ^^^^^ help: try: `y`
@@ -7,13 +7,13 @@ LL | y @ _ => (),
= note: `-D clippy::redundant-pattern` implied by `-D warnings`
error: the `x @ _` pattern can be written as just `x`
- --> $DIR/patterns.rs:25:9
+ --> $DIR/patterns.rs:26:9
|
LL | ref mut x @ _ => {
| ^^^^^^^^^^^^^ help: try: `ref mut x`
error: the `x @ _` pattern can be written as just `x`
- --> $DIR/patterns.rs:33:9
+ --> $DIR/patterns.rs:34:9
|
LL | ref x @ _ => println!("vec: {:?}", x),
| ^^^^^^^^^ help: try: `ref x`
diff --git a/src/tools/clippy/tests/ui/print_literal.rs b/src/tools/clippy/tests/ui/print_literal.rs
index 8665a3bb2..86f908f66 100644
--- a/src/tools/clippy/tests/ui/print_literal.rs
+++ b/src/tools/clippy/tests/ui/print_literal.rs
@@ -1,4 +1,5 @@
#![warn(clippy::print_literal)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
// these should be fine
@@ -20,11 +21,13 @@ fn main() {
println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
println!("10 / 4 is {}", 2.5);
println!("2 + 1 = {}", 3);
+ println!("From expansion {}", stringify!(not a string literal));
// these should throw warnings
print!("Hello {}", "world");
println!("Hello {} {}", world, "world");
println!("Hello {}", "world");
+ println!("{} {:.4}", "a literal", 5);
// positional args don't change the fact
// that we're using a literal -- this should
diff --git a/src/tools/clippy/tests/ui/print_literal.stderr b/src/tools/clippy/tests/ui/print_literal.stderr
index 72aae0756..6404dacda 100644
--- a/src/tools/clippy/tests/ui/print_literal.stderr
+++ b/src/tools/clippy/tests/ui/print_literal.stderr
@@ -1,5 +1,5 @@
error: literal with an empty format string
- --> $DIR/print_literal.rs:25:24
+ --> $DIR/print_literal.rs:27:24
|
LL | print!("Hello {}", "world");
| ^^^^^^^
@@ -12,7 +12,7 @@ LL + print!("Hello world");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:26:36
+ --> $DIR/print_literal.rs:28:36
|
LL | println!("Hello {} {}", world, "world");
| ^^^^^^^
@@ -24,7 +24,7 @@ LL + println!("Hello {} world", world);
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:27:26
+ --> $DIR/print_literal.rs:29:26
|
LL | println!("Hello {}", "world");
| ^^^^^^^
@@ -36,7 +36,19 @@ LL + println!("Hello world");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:32:25
+ --> $DIR/print_literal.rs:30:26
+ |
+LL | println!("{} {:.4}", "a literal", 5);
+ | ^^^^^^^^^^^
+ |
+help: try this
+ |
+LL - println!("{} {:.4}", "a literal", 5);
+LL + println!("a literal {:.4}", 5);
+ |
+
+error: literal with an empty format string
+ --> $DIR/print_literal.rs:35:25
|
LL | println!("{0} {1}", "hello", "world");
| ^^^^^^^
@@ -48,7 +60,7 @@ LL + println!("hello {1}", "world");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:32:34
+ --> $DIR/print_literal.rs:35:34
|
LL | println!("{0} {1}", "hello", "world");
| ^^^^^^^
@@ -60,34 +72,34 @@ LL + println!("{0} world", "hello");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:33:25
+ --> $DIR/print_literal.rs:36:34
|
LL | println!("{1} {0}", "hello", "world");
- | ^^^^^^^
+ | ^^^^^^^
|
help: try this
|
LL - println!("{1} {0}", "hello", "world");
-LL + println!("{1} hello", "world");
+LL + println!("world {0}", "hello");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:33:34
+ --> $DIR/print_literal.rs:36:25
|
LL | println!("{1} {0}", "hello", "world");
- | ^^^^^^^
+ | ^^^^^^^
|
help: try this
|
LL - println!("{1} {0}", "hello", "world");
-LL + println!("world {0}", "hello");
+LL + println!("{1} hello", "world");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:36:29
+ --> $DIR/print_literal.rs:39:35
|
LL | println!("{foo} {bar}", foo = "hello", bar = "world");
- | ^^^^^^^^^^^^^
+ | ^^^^^^^
|
help: try this
|
@@ -96,10 +108,10 @@ LL + println!("hello {bar}", bar = "world");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:36:44
+ --> $DIR/print_literal.rs:39:50
|
LL | println!("{foo} {bar}", foo = "hello", bar = "world");
- | ^^^^^^^^^^^^^
+ | ^^^^^^^
|
help: try this
|
@@ -108,28 +120,28 @@ LL + println!("{foo} world", foo = "hello");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:37:29
+ --> $DIR/print_literal.rs:40:50
|
LL | println!("{bar} {foo}", foo = "hello", bar = "world");
- | ^^^^^^^^^^^^^
+ | ^^^^^^^
|
help: try this
|
LL - println!("{bar} {foo}", foo = "hello", bar = "world");
-LL + println!("{bar} hello", bar = "world");
+LL + println!("world {foo}", foo = "hello");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:37:44
+ --> $DIR/print_literal.rs:40:35
|
LL | println!("{bar} {foo}", foo = "hello", bar = "world");
- | ^^^^^^^^^^^^^
+ | ^^^^^^^
|
help: try this
|
LL - println!("{bar} {foo}", foo = "hello", bar = "world");
-LL + println!("world {foo}", foo = "hello");
+LL + println!("{bar} hello", bar = "world");
|
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/print_with_newline.rs b/src/tools/clippy/tests/ui/print_with_newline.rs
index a43a1fc4f..b8c29d207 100644
--- a/src/tools/clippy/tests/ui/print_with_newline.rs
+++ b/src/tools/clippy/tests/ui/print_with_newline.rs
@@ -48,5 +48,13 @@ fn main() {
print!("\r\n");
print!("foo\r\n");
print!("\\r\n"); //~ ERROR
- print!("foo\rbar\n") // ~ ERROR
+ print!("foo\rbar\n");
+
+ // Ignore expanded format strings
+ macro_rules! newline {
+ () => {
+ "\n"
+ };
+ }
+ print!(newline!());
}
diff --git a/src/tools/clippy/tests/ui/print_with_newline.stderr b/src/tools/clippy/tests/ui/print_with_newline.stderr
index edbaa1cdf..b9f5675fa 100644
--- a/src/tools/clippy/tests/ui/print_with_newline.stderr
+++ b/src/tools/clippy/tests/ui/print_with_newline.stderr
@@ -83,7 +83,7 @@ LL | | );
help: use `println!` instead
|
LL ~ println!(
-LL ~ ""
+LL ~
|
error: using `print!()` with a format string that ends in a single newline
@@ -98,7 +98,7 @@ LL | | );
help: use `println!` instead
|
LL ~ println!(
-LL ~ r""
+LL ~
|
error: using `print!()` with a format string that ends in a single newline
@@ -113,17 +113,5 @@ LL - print!("/r/n"); //~ ERROR
LL + println!("/r"); //~ ERROR
|
-error: using `print!()` with a format string that ends in a single newline
- --> $DIR/print_with_newline.rs:51:5
- |
-LL | print!("foo/rbar/n") // ~ ERROR
- | ^^^^^^^^^^^^^^^^^^^^
- |
-help: use `println!` instead
- |
-LL - print!("foo/rbar/n") // ~ ERROR
-LL + println!("foo/rbar") // ~ ERROR
- |
-
-error: aborting due to 10 previous errors
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/println_empty_string.stderr b/src/tools/clippy/tests/ui/println_empty_string.stderr
index 17fe4ea74..3cc8bb947 100644
--- a/src/tools/clippy/tests/ui/println_empty_string.stderr
+++ b/src/tools/clippy/tests/ui/println_empty_string.stderr
@@ -1,28 +1,36 @@
-error: using `println!("")`
+error: empty string literal in `println!`
--> $DIR/println_empty_string.rs:6:5
|
LL | println!("");
- | ^^^^^^^^^^^^ help: replace it with: `println!()`
+ | ^^^^^^^^^--^
+ | |
+ | help: remove the empty string
|
= note: `-D clippy::println-empty-string` implied by `-D warnings`
-error: using `println!("")`
+error: empty string literal in `println!`
--> $DIR/println_empty_string.rs:9:14
|
LL | _ => println!(""),
- | ^^^^^^^^^^^^ help: replace it with: `println!()`
+ | ^^^^^^^^^--^
+ | |
+ | help: remove the empty string
-error: using `eprintln!("")`
+error: empty string literal in `eprintln!`
--> $DIR/println_empty_string.rs:13:5
|
LL | eprintln!("");
- | ^^^^^^^^^^^^^ help: replace it with: `eprintln!()`
+ | ^^^^^^^^^^--^
+ | |
+ | help: remove the empty string
-error: using `eprintln!("")`
+error: empty string literal in `eprintln!`
--> $DIR/println_empty_string.rs:16:14
|
LL | _ => eprintln!(""),
- | ^^^^^^^^^^^^^ help: replace it with: `eprintln!()`
+ | ^^^^^^^^^^--^
+ | |
+ | help: remove the empty string
error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/proc_macro.stderr b/src/tools/clippy/tests/ui/proc_macro.stderr
index 48fd58c9a..c795f6ad0 100644
--- a/src/tools/clippy/tests/ui/proc_macro.stderr
+++ b/src/tools/clippy/tests/ui/proc_macro.stderr
@@ -4,8 +4,8 @@ error: approximate value of `f{32, 64}::consts::PI` found
LL | let _x = 3.14;
| ^^^^
|
- = note: `#[deny(clippy::approx_constant)]` on by default
= help: consider using the constant directly
+ = note: `#[deny(clippy::approx_constant)]` on by default
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
index fd15001e5..5f54101ca 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.rs
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -3,7 +3,7 @@
#![warn(clippy::ptr_arg)]
use std::borrow::Cow;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
fn do_vec(x: &Vec<i64>) {
//Nothing here
@@ -207,3 +207,31 @@ fn cow_conditional_to_mut(a: &mut Cow<str>) {
a.to_mut().push_str("foo");
}
}
+
+// Issue #9542
+fn dyn_trait_ok(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
+ trait T {}
+ impl<U> T for Vec<U> {}
+ impl T for String {}
+ impl T for PathBuf {}
+ fn takes_dyn(_: &mut dyn T) {}
+
+ takes_dyn(a);
+ takes_dyn(b);
+ takes_dyn(c);
+}
+
+fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
+ trait T {}
+ impl<U> T for Vec<U> {}
+ impl<U> T for [U] {}
+ impl T for String {}
+ impl T for str {}
+ impl T for PathBuf {}
+ impl T for Path {}
+ fn takes_dyn(_: &mut dyn T) {}
+
+ takes_dyn(a);
+ takes_dyn(b);
+ takes_dyn(c);
+}
diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr
index d64b5f454..6b4de98ce 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.stderr
+++ b/src/tools/clippy/tests/ui/ptr_arg.stderr
@@ -162,5 +162,23 @@ error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a sl
LL | fn mut_vec_slice_methods(v: &mut Vec<u32>) {
| ^^^^^^^^^^^^^ help: change this to: `&mut [u32]`
-error: aborting due to 17 previous errors
+error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
+ --> $DIR/ptr_arg.rs:224:17
+ |
+LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
+ | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]`
+
+error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do
+ --> $DIR/ptr_arg.rs:224:35
+ |
+LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
+ | ^^^^^^^^^^^ help: change this to: `&mut str`
+
+error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do
+ --> $DIR/ptr_arg.rs:224:51
+ |
+LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
+ | ^^^^^^^^^^^^ help: change this to: `&mut Path`
+
+error: aborting due to 20 previous errors
diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed b/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed
index 718e391e8..c57e2990f 100644
--- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed
+++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed
@@ -1,4 +1,5 @@
// run-rustfix
+#![allow(clippy::unnecessary_cast)]
fn main() {
let vec = vec![b'a', b'b', b'c'];
diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs b/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs
index f613742c7..3de7997ac 100644
--- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs
@@ -1,4 +1,5 @@
// run-rustfix
+#![allow(clippy::unnecessary_cast)]
fn main() {
let vec = vec![b'a', b'b', b'c'];
diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr b/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr
index fd45224ca..3ba40593d 100644
--- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr
+++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr
@@ -1,5 +1,5 @@
error: use of `offset` with a `usize` casted to an `isize`
- --> $DIR/ptr_offset_with_cast.rs:12:17
+ --> $DIR/ptr_offset_with_cast.rs:13:17
|
LL | let _ = ptr.offset(offset_usize as isize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.add(offset_usize)`
@@ -7,7 +7,7 @@ LL | let _ = ptr.offset(offset_usize as isize);
= note: `-D clippy::ptr-offset-with-cast` implied by `-D warnings`
error: use of `wrapping_offset` with a `usize` casted to an `isize`
- --> $DIR/ptr_offset_with_cast.rs:16:17
+ --> $DIR/ptr_offset_with_cast.rs:17:17
|
LL | let _ = ptr.wrapping_offset(offset_usize as isize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.wrapping_add(offset_usize)`
diff --git a/src/tools/clippy/tests/ui/pub_use.stderr b/src/tools/clippy/tests/ui/pub_use.stderr
index 9ab710df8..ba4ee732c 100644
--- a/src/tools/clippy/tests/ui/pub_use.stderr
+++ b/src/tools/clippy/tests/ui/pub_use.stderr
@@ -4,8 +4,8 @@ error: using `pub use`
LL | pub use inner::Test;
| ^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::pub-use` implied by `-D warnings`
= help: move the exported item to a public module instead
+ = note: `-D clippy::pub-use` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index c4c9c8214..993389232 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -207,4 +207,28 @@ fn option_map() -> Option<bool> {
}
}
+pub struct PatternedError {
+ flag: bool,
+}
+
+// No warning
+fn pattern() -> Result<(), PatternedError> {
+ let res = Ok(());
+
+ if let Err(err @ PatternedError { flag: true }) = res {
+ return Err(err);
+ }
+
+ res
+}
+
fn main() {}
+
+// should not lint, `?` operator not available in const context
+const fn issue9175(option: Option<()>) -> Option<()> {
+ if option.is_none() {
+ return None;
+ }
+ //stuff
+ Some(())
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index cdbc7b160..9ae0d8882 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -243,4 +243,28 @@ fn option_map() -> Option<bool> {
}
}
+pub struct PatternedError {
+ flag: bool,
+}
+
+// No warning
+fn pattern() -> Result<(), PatternedError> {
+ let res = Ok(());
+
+ if let Err(err @ PatternedError { flag: true }) = res {
+ return Err(err);
+ }
+
+ res
+}
+
fn main() {}
+
+// should not lint, `?` operator not available in const context
+const fn issue9175(option: Option<()>) -> Option<()> {
+ if option.is_none() {
+ return None;
+ }
+ //stuff
+ Some(())
+}
diff --git a/src/tools/clippy/tests/ui/range_contains.fixed b/src/tools/clippy/tests/ui/range_contains.fixed
index 85d021b2f..824f00cb9 100644
--- a/src/tools/clippy/tests/ui/range_contains.fixed
+++ b/src/tools/clippy/tests/ui/range_contains.fixed
@@ -1,10 +1,12 @@
// run-rustfix
-#[warn(clippy::manual_range_contains)]
-#[allow(unused)]
-#[allow(clippy::no_effect)]
-#[allow(clippy::short_circuit_statement)]
-#[allow(clippy::unnecessary_operation)]
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_range_contains)]
+#![allow(unused)]
+#![allow(clippy::no_effect)]
+#![allow(clippy::short_circuit_statement)]
+#![allow(clippy::unnecessary_operation)]
+
fn main() {
let x = 9_i32;
@@ -62,3 +64,17 @@ fn main() {
pub const fn in_range(a: i32) -> bool {
3 <= a && a <= 20
}
+
+fn msrv_1_34() {
+ #![clippy::msrv = "1.34"]
+
+ let x = 5;
+ x >= 8 && x < 34;
+}
+
+fn msrv_1_35() {
+ #![clippy::msrv = "1.35"]
+
+ let x = 5;
+ (8..35).contains(&x);
+}
diff --git a/src/tools/clippy/tests/ui/range_contains.rs b/src/tools/clippy/tests/ui/range_contains.rs
index 9a7a75dc1..df925eead 100644
--- a/src/tools/clippy/tests/ui/range_contains.rs
+++ b/src/tools/clippy/tests/ui/range_contains.rs
@@ -1,10 +1,12 @@
// run-rustfix
-#[warn(clippy::manual_range_contains)]
-#[allow(unused)]
-#[allow(clippy::no_effect)]
-#[allow(clippy::short_circuit_statement)]
-#[allow(clippy::unnecessary_operation)]
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_range_contains)]
+#![allow(unused)]
+#![allow(clippy::no_effect)]
+#![allow(clippy::short_circuit_statement)]
+#![allow(clippy::unnecessary_operation)]
+
fn main() {
let x = 9_i32;
@@ -62,3 +64,17 @@ fn main() {
pub const fn in_range(a: i32) -> bool {
3 <= a && a <= 20
}
+
+fn msrv_1_34() {
+ #![clippy::msrv = "1.34"]
+
+ let x = 5;
+ x >= 8 && x < 34;
+}
+
+fn msrv_1_35() {
+ #![clippy::msrv = "1.35"]
+
+ let x = 5;
+ x >= 8 && x < 35;
+}
diff --git a/src/tools/clippy/tests/ui/range_contains.stderr b/src/tools/clippy/tests/ui/range_contains.stderr
index 936859db5..9689e665b 100644
--- a/src/tools/clippy/tests/ui/range_contains.stderr
+++ b/src/tools/clippy/tests/ui/range_contains.stderr
@@ -1,5 +1,5 @@
error: manual `Range::contains` implementation
- --> $DIR/range_contains.rs:12:5
+ --> $DIR/range_contains.rs:14:5
|
LL | x >= 8 && x < 12;
| ^^^^^^^^^^^^^^^^ help: use: `(8..12).contains(&x)`
@@ -7,118 +7,124 @@ LL | x >= 8 && x < 12;
= note: `-D clippy::manual-range-contains` implied by `-D warnings`
error: manual `Range::contains` implementation
- --> $DIR/range_contains.rs:13:5
+ --> $DIR/range_contains.rs:15:5
|
LL | x < 42 && x >= 21;
| ^^^^^^^^^^^^^^^^^ help: use: `(21..42).contains(&x)`
error: manual `Range::contains` implementation
- --> $DIR/range_contains.rs:14:5
+ --> $DIR/range_contains.rs:16:5
|
LL | 100 > x && 1 <= x;
| ^^^^^^^^^^^^^^^^^ help: use: `(1..100).contains(&x)`
error: manual `RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:17:5
+ --> $DIR/range_contains.rs:19:5
|
LL | x >= 9 && x <= 99;
| ^^^^^^^^^^^^^^^^^ help: use: `(9..=99).contains(&x)`
error: manual `RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:18:5
+ --> $DIR/range_contains.rs:20:5
|
LL | x <= 33 && x >= 1;
| ^^^^^^^^^^^^^^^^^ help: use: `(1..=33).contains(&x)`
error: manual `RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:19:5
+ --> $DIR/range_contains.rs:21:5
|
LL | 999 >= x && 1 <= x;
| ^^^^^^^^^^^^^^^^^^ help: use: `(1..=999).contains(&x)`
error: manual `!Range::contains` implementation
- --> $DIR/range_contains.rs:22:5
+ --> $DIR/range_contains.rs:24:5
|
LL | x < 8 || x >= 12;
| ^^^^^^^^^^^^^^^^ help: use: `!(8..12).contains(&x)`
error: manual `!Range::contains` implementation
- --> $DIR/range_contains.rs:23:5
+ --> $DIR/range_contains.rs:25:5
|
LL | x >= 42 || x < 21;
| ^^^^^^^^^^^^^^^^^ help: use: `!(21..42).contains(&x)`
error: manual `!Range::contains` implementation
- --> $DIR/range_contains.rs:24:5
+ --> $DIR/range_contains.rs:26:5
|
LL | 100 <= x || 1 > x;
| ^^^^^^^^^^^^^^^^^ help: use: `!(1..100).contains(&x)`
error: manual `!RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:27:5
+ --> $DIR/range_contains.rs:29:5
|
LL | x < 9 || x > 99;
| ^^^^^^^^^^^^^^^ help: use: `!(9..=99).contains(&x)`
error: manual `!RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:28:5
+ --> $DIR/range_contains.rs:30:5
|
LL | x > 33 || x < 1;
| ^^^^^^^^^^^^^^^ help: use: `!(1..=33).contains(&x)`
error: manual `!RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:29:5
+ --> $DIR/range_contains.rs:31:5
|
LL | 999 < x || 1 > x;
| ^^^^^^^^^^^^^^^^ help: use: `!(1..=999).contains(&x)`
error: manual `Range::contains` implementation
- --> $DIR/range_contains.rs:44:5
+ --> $DIR/range_contains.rs:46:5
|
LL | y >= 0. && y < 1.;
| ^^^^^^^^^^^^^^^^^ help: use: `(0. ..1.).contains(&y)`
error: manual `!RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:45:5
+ --> $DIR/range_contains.rs:47:5
|
LL | y < 0. || y > 1.;
| ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)`
error: manual `RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:48:5
+ --> $DIR/range_contains.rs:50:5
|
LL | x >= -10 && x <= 10;
| ^^^^^^^^^^^^^^^^^^^ help: use: `(-10..=10).contains(&x)`
error: manual `RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:50:5
+ --> $DIR/range_contains.rs:52:5
|
LL | y >= -3. && y <= 3.;
| ^^^^^^^^^^^^^^^^^^^ help: use: `(-3. ..=3.).contains(&y)`
error: manual `RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:55:30
+ --> $DIR/range_contains.rs:57:30
|
LL | (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
| ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&z)`
error: manual `RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:55:5
+ --> $DIR/range_contains.rs:57:5
|
LL | (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
| ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&x)`
error: manual `!Range::contains` implementation
- --> $DIR/range_contains.rs:56:29
+ --> $DIR/range_contains.rs:58:29
|
LL | (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
| ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&z)`
error: manual `!Range::contains` implementation
- --> $DIR/range_contains.rs:56:5
+ --> $DIR/range_contains.rs:58:5
|
LL | (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
| ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&x)`
-error: aborting due to 20 previous errors
+error: manual `Range::contains` implementation
+ --> $DIR/range_contains.rs:79:5
+ |
+LL | x >= 8 && x < 35;
+ | ^^^^^^^^^^^^^^^^ help: use: `(8..35).contains(&x)`
+
+error: aborting due to 21 previous errors
diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.fixed b/src/tools/clippy/tests/ui/range_plus_minus_one.fixed
index 40d7791df..a16a3e54d 100644
--- a/src/tools/clippy/tests/ui/range_plus_minus_one.fixed
+++ b/src/tools/clippy/tests/ui/range_plus_minus_one.fixed
@@ -6,6 +6,22 @@ fn f() -> usize {
42
}
+macro_rules! macro_plus_one {
+ ($m: literal) => {
+ for i in 0..$m + 1 {
+ println!("{}", i);
+ }
+ };
+}
+
+macro_rules! macro_minus_one {
+ ($m: literal) => {
+ for i in 0..=$m - 1 {
+ println!("{}", i);
+ }
+ };
+}
+
#[warn(clippy::range_plus_one)]
#[warn(clippy::range_minus_one)]
fn main() {
@@ -39,4 +55,7 @@ fn main() {
let mut vec: Vec<()> = std::vec::Vec::new();
vec.drain(..);
+
+ macro_plus_one!(5);
+ macro_minus_one!(5);
}
diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.rs b/src/tools/clippy/tests/ui/range_plus_minus_one.rs
index a8ddd9b5f..bd6cb4d21 100644
--- a/src/tools/clippy/tests/ui/range_plus_minus_one.rs
+++ b/src/tools/clippy/tests/ui/range_plus_minus_one.rs
@@ -6,6 +6,22 @@ fn f() -> usize {
42
}
+macro_rules! macro_plus_one {
+ ($m: literal) => {
+ for i in 0..$m + 1 {
+ println!("{}", i);
+ }
+ };
+}
+
+macro_rules! macro_minus_one {
+ ($m: literal) => {
+ for i in 0..=$m - 1 {
+ println!("{}", i);
+ }
+ };
+}
+
#[warn(clippy::range_plus_one)]
#[warn(clippy::range_minus_one)]
fn main() {
@@ -39,4 +55,7 @@ fn main() {
let mut vec: Vec<()> = std::vec::Vec::new();
vec.drain(..);
+
+ macro_plus_one!(5);
+ macro_minus_one!(5);
}
diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr
index fb4f16585..022369624 100644
--- a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr
+++ b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr
@@ -1,5 +1,5 @@
error: an inclusive range would be more readable
- --> $DIR/range_plus_minus_one.rs:15:14
+ --> $DIR/range_plus_minus_one.rs:31:14
|
LL | for _ in 0..3 + 1 {}
| ^^^^^^^^ help: use: `0..=3`
@@ -7,25 +7,25 @@ LL | for _ in 0..3 + 1 {}
= note: `-D clippy::range-plus-one` implied by `-D warnings`
error: an inclusive range would be more readable
- --> $DIR/range_plus_minus_one.rs:18:14
+ --> $DIR/range_plus_minus_one.rs:34:14
|
LL | for _ in 0..1 + 5 {}
| ^^^^^^^^ help: use: `0..=5`
error: an inclusive range would be more readable
- --> $DIR/range_plus_minus_one.rs:21:14
+ --> $DIR/range_plus_minus_one.rs:37:14
|
LL | for _ in 1..1 + 1 {}
| ^^^^^^^^ help: use: `1..=1`
error: an inclusive range would be more readable
- --> $DIR/range_plus_minus_one.rs:27:14
+ --> $DIR/range_plus_minus_one.rs:43:14
|
LL | for _ in 0..(1 + f()) {}
| ^^^^^^^^^^^^ help: use: `0..=f()`
error: an exclusive range would be more readable
- --> $DIR/range_plus_minus_one.rs:31:13
+ --> $DIR/range_plus_minus_one.rs:47:13
|
LL | let _ = ..=11 - 1;
| ^^^^^^^^^ help: use: `..11`
@@ -33,25 +33,25 @@ LL | let _ = ..=11 - 1;
= note: `-D clippy::range-minus-one` implied by `-D warnings`
error: an exclusive range would be more readable
- --> $DIR/range_plus_minus_one.rs:32:13
+ --> $DIR/range_plus_minus_one.rs:48:13
|
LL | let _ = ..=(11 - 1);
| ^^^^^^^^^^^ help: use: `..11`
error: an inclusive range would be more readable
- --> $DIR/range_plus_minus_one.rs:33:13
+ --> $DIR/range_plus_minus_one.rs:49:13
|
LL | let _ = (1..11 + 1);
| ^^^^^^^^^^^ help: use: `(1..=11)`
error: an inclusive range would be more readable
- --> $DIR/range_plus_minus_one.rs:34:13
+ --> $DIR/range_plus_minus_one.rs:50:13
|
LL | let _ = (f() + 1)..(f() + 1);
| ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())`
error: an inclusive range would be more readable
- --> $DIR/range_plus_minus_one.rs:38:14
+ --> $DIR/range_plus_minus_one.rs:54:14
|
LL | for _ in 1..ONE + ONE {}
| ^^^^^^^^^^^^ help: use: `1..=ONE`
diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr
index cd7d91e12..7814f5b54 100644
--- a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr
+++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr
@@ -4,8 +4,8 @@ error: initializing a reference-counted pointer in `vec![elem; len]`
LL | let v = vec![Arc::new("x".to_string()); 2];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings`
= note: each element will point to the same `Arc` instance
+ = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings`
help: consider initializing each `Arc` element individually
|
LL ~ let v = {
diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr
index fe861afe0..80deb7cb9 100644
--- a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr
+++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr
@@ -4,8 +4,8 @@ error: initializing a reference-counted pointer in `vec![elem; len]`
LL | let v = vec![Rc::new("x".to_string()); 2];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings`
= note: each element will point to the same `Rc` instance
+ = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings`
help: consider initializing each `Rc` element individually
|
LL ~ let v = {
diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.stderr b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.stderr
index 4a21946cc..789e14a30 100644
--- a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.stderr
+++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.stderr
@@ -4,8 +4,8 @@ error: initializing a reference-counted pointer in `vec![elem; len]`
LL | let v = vec![SyncWeak::<u32>::new(); 2];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings`
= note: each element will point to the same `Weak` instance
+ = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings`
help: consider initializing each `Weak` element individually
|
LL ~ let v = {
diff --git a/src/tools/clippy/tests/ui/rc_mutex.rs b/src/tools/clippy/tests/ui/rc_mutex.rs
index 18e8a2e01..432972bbc 100644
--- a/src/tools/clippy/tests/ui/rc_mutex.rs
+++ b/src/tools/clippy/tests/ui/rc_mutex.rs
@@ -1,5 +1,5 @@
#![warn(clippy::rc_mutex)]
-#![allow(unused, clippy::blacklisted_name)]
+#![allow(unused, clippy::disallowed_names)]
use std::rc::Rc;
use std::sync::Mutex;
diff --git a/src/tools/clippy/tests/ui/rc_mutex.stderr b/src/tools/clippy/tests/ui/rc_mutex.stderr
index fe84361d7..cee3bd8b2 100644
--- a/src/tools/clippy/tests/ui/rc_mutex.stderr
+++ b/src/tools/clippy/tests/ui/rc_mutex.stderr
@@ -4,8 +4,8 @@ error: usage of `Rc<Mutex<_>>`
LL | foo: Rc<Mutex<i32>>,
| ^^^^^^^^^^^^^^
|
- = note: `-D clippy::rc-mutex` implied by `-D warnings`
= help: consider using `Rc<RefCell<_>>` or `Arc<Mutex<_>>` instead
+ = note: `-D clippy::rc-mutex` implied by `-D warnings`
error: usage of `Rc<Mutex<_>>`
--> $DIR/rc_mutex.rs:26:18
diff --git a/src/tools/clippy/tests/ui/recursive_format_impl.rs b/src/tools/clippy/tests/ui/recursive_format_impl.rs
index cb6ba36b1..b92490b4c 100644
--- a/src/tools/clippy/tests/ui/recursive_format_impl.rs
+++ b/src/tools/clippy/tests/ui/recursive_format_impl.rs
@@ -1,9 +1,10 @@
#![warn(clippy::recursive_format_impl)]
#![allow(
+ clippy::borrow_deref_ref,
+ clippy::deref_addrof,
clippy::inherent_to_string_shadow_display,
clippy::to_string_in_format_args,
- clippy::deref_addrof,
- clippy::borrow_deref_ref
+ clippy::uninlined_format_args
)]
use std::fmt;
diff --git a/src/tools/clippy/tests/ui/recursive_format_impl.stderr b/src/tools/clippy/tests/ui/recursive_format_impl.stderr
index 84ce69df5..8a58b9a3b 100644
--- a/src/tools/clippy/tests/ui/recursive_format_impl.stderr
+++ b/src/tools/clippy/tests/ui/recursive_format_impl.stderr
@@ -1,5 +1,5 @@
error: using `self.to_string` in `fmt::Display` implementation will cause infinite recursion
- --> $DIR/recursive_format_impl.rs:30:25
+ --> $DIR/recursive_format_impl.rs:31:25
|
LL | write!(f, "{}", self.to_string())
| ^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | write!(f, "{}", self.to_string())
= note: `-D clippy::recursive-format-impl` implied by `-D warnings`
error: using `self` as `Display` in `impl Display` will cause infinite recursion
- --> $DIR/recursive_format_impl.rs:74:9
+ --> $DIR/recursive_format_impl.rs:75:9
|
LL | write!(f, "{}", self)
| ^^^^^^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | write!(f, "{}", self)
= note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
error: using `self` as `Display` in `impl Display` will cause infinite recursion
- --> $DIR/recursive_format_impl.rs:83:9
+ --> $DIR/recursive_format_impl.rs:84:9
|
LL | write!(f, "{}", &self)
| ^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL | write!(f, "{}", &self)
= note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
error: using `self` as `Debug` in `impl Debug` will cause infinite recursion
- --> $DIR/recursive_format_impl.rs:89:9
+ --> $DIR/recursive_format_impl.rs:90:9
|
LL | write!(f, "{:?}", &self)
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -31,7 +31,7 @@ LL | write!(f, "{:?}", &self)
= note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
error: using `self` as `Display` in `impl Display` will cause infinite recursion
- --> $DIR/recursive_format_impl.rs:98:9
+ --> $DIR/recursive_format_impl.rs:99:9
|
LL | write!(f, "{}", &&&self)
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -39,7 +39,7 @@ LL | write!(f, "{}", &&&self)
= note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
error: using `self` as `Display` in `impl Display` will cause infinite recursion
- --> $DIR/recursive_format_impl.rs:172:9
+ --> $DIR/recursive_format_impl.rs:173:9
|
LL | write!(f, "{}", &*self)
| ^^^^^^^^^^^^^^^^^^^^^^^
@@ -47,7 +47,7 @@ LL | write!(f, "{}", &*self)
= note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
error: using `self` as `Debug` in `impl Debug` will cause infinite recursion
- --> $DIR/recursive_format_impl.rs:178:9
+ --> $DIR/recursive_format_impl.rs:179:9
|
LL | write!(f, "{:?}", &*self)
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -55,7 +55,7 @@ LL | write!(f, "{:?}", &*self)
= note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
error: using `self` as `Display` in `impl Display` will cause infinite recursion
- --> $DIR/recursive_format_impl.rs:194:9
+ --> $DIR/recursive_format_impl.rs:195:9
|
LL | write!(f, "{}", *self)
| ^^^^^^^^^^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ LL | write!(f, "{}", *self)
= note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
error: using `self` as `Display` in `impl Display` will cause infinite recursion
- --> $DIR/recursive_format_impl.rs:210:9
+ --> $DIR/recursive_format_impl.rs:211:9
|
LL | write!(f, "{}", **&&*self)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -71,7 +71,7 @@ LL | write!(f, "{}", **&&*self)
= note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
error: using `self` as `Display` in `impl Display` will cause infinite recursion
- --> $DIR/recursive_format_impl.rs:226:9
+ --> $DIR/recursive_format_impl.rs:227:9
|
LL | write!(f, "{}", &&**&&*self)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/redundant_allocation.rs b/src/tools/clippy/tests/ui/redundant_allocation.rs
index cf7d8c6e3..574d34aed 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation.rs
+++ b/src/tools/clippy/tests/ui/redundant_allocation.rs
@@ -1,7 +1,5 @@
#![warn(clippy::all)]
-#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
-#![allow(unused_imports)]
+#![allow(clippy::boxed_local, clippy::disallowed_names)]
pub struct MyStruct;
@@ -9,13 +7,7 @@ pub struct SubT<T> {
foo: T,
}
-pub enum MyEnum {
- One,
- Two,
-}
-
mod outer_box {
- use crate::MyEnum;
use crate::MyStruct;
use crate::SubT;
use std::boxed::Box;
@@ -36,7 +28,6 @@ mod outer_box {
}
mod outer_rc {
- use crate::MyEnum;
use crate::MyStruct;
use crate::SubT;
use std::boxed::Box;
@@ -57,7 +48,6 @@ mod outer_rc {
}
mod outer_arc {
- use crate::MyEnum;
use crate::MyStruct;
use crate::SubT;
use std::boxed::Box;
diff --git a/src/tools/clippy/tests/ui/redundant_allocation.stderr b/src/tools/clippy/tests/ui/redundant_allocation.stderr
index fab1b069f..e0826fefa 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation.stderr
+++ b/src/tools/clippy/tests/ui/redundant_allocation.stderr
@@ -1,15 +1,15 @@
error: usage of `Box<Rc<T>>`
- --> $DIR/redundant_allocation.rs:25:30
+ --> $DIR/redundant_allocation.rs:17:30
|
LL | pub fn box_test6<T>(foo: Box<Rc<T>>) {}
| ^^^^^^^^^^
|
- = note: `-D clippy::redundant-allocation` implied by `-D warnings`
= note: `Rc<T>` is already on the heap, `Box<Rc<T>>` makes an extra allocation
= help: consider using just `Box<T>` or `Rc<T>`
+ = note: `-D clippy::redundant-allocation` implied by `-D warnings`
error: usage of `Box<Arc<T>>`
- --> $DIR/redundant_allocation.rs:27:30
+ --> $DIR/redundant_allocation.rs:19:30
|
LL | pub fn box_test7<T>(foo: Box<Arc<T>>) {}
| ^^^^^^^^^^^
@@ -18,7 +18,7 @@ LL | pub fn box_test7<T>(foo: Box<Arc<T>>) {}
= help: consider using just `Box<T>` or `Arc<T>`
error: usage of `Box<Rc<SubT<usize>>>`
- --> $DIR/redundant_allocation.rs:29:27
+ --> $DIR/redundant_allocation.rs:21:27
|
LL | pub fn box_test8() -> Box<Rc<SubT<usize>>> {
| ^^^^^^^^^^^^^^^^^^^^
@@ -27,7 +27,7 @@ LL | pub fn box_test8() -> Box<Rc<SubT<usize>>> {
= help: consider using just `Box<SubT<usize>>` or `Rc<SubT<usize>>`
error: usage of `Box<Arc<T>>`
- --> $DIR/redundant_allocation.rs:33:30
+ --> $DIR/redundant_allocation.rs:25:30
|
LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
| ^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
= help: consider using just `Box<T>` or `Arc<T>`
error: usage of `Box<Arc<SubT<T>>>`
- --> $DIR/redundant_allocation.rs:33:46
+ --> $DIR/redundant_allocation.rs:25:46
|
LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
| ^^^^^^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
= help: consider using just `Box<SubT<T>>` or `Arc<SubT<T>>`
error: usage of `Rc<Box<bool>>`
- --> $DIR/redundant_allocation.rs:46:24
+ --> $DIR/redundant_allocation.rs:37:24
|
LL | pub fn rc_test5(a: Rc<Box<bool>>) {}
| ^^^^^^^^^^^^^
@@ -54,7 +54,7 @@ LL | pub fn rc_test5(a: Rc<Box<bool>>) {}
= help: consider using just `Rc<bool>` or `Box<bool>`
error: usage of `Rc<Arc<bool>>`
- --> $DIR/redundant_allocation.rs:48:24
+ --> $DIR/redundant_allocation.rs:39:24
|
LL | pub fn rc_test7(a: Rc<Arc<bool>>) {}
| ^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ LL | pub fn rc_test7(a: Rc<Arc<bool>>) {}
= help: consider using just `Rc<bool>` or `Arc<bool>`
error: usage of `Rc<Box<SubT<usize>>>`
- --> $DIR/redundant_allocation.rs:50:26
+ --> $DIR/redundant_allocation.rs:41:26
|
LL | pub fn rc_test8() -> Rc<Box<SubT<usize>>> {
| ^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL | pub fn rc_test8() -> Rc<Box<SubT<usize>>> {
= help: consider using just `Rc<SubT<usize>>` or `Box<SubT<usize>>`
error: usage of `Rc<Arc<T>>`
- --> $DIR/redundant_allocation.rs:54:29
+ --> $DIR/redundant_allocation.rs:45:29
|
LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
| ^^^^^^^^^^
@@ -81,7 +81,7 @@ LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
= help: consider using just `Rc<T>` or `Arc<T>`
error: usage of `Rc<Arc<SubT<T>>>`
- --> $DIR/redundant_allocation.rs:54:44
+ --> $DIR/redundant_allocation.rs:45:44
|
LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
| ^^^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
= help: consider using just `Rc<SubT<T>>` or `Arc<SubT<T>>`
error: usage of `Arc<Box<bool>>`
- --> $DIR/redundant_allocation.rs:67:25
+ --> $DIR/redundant_allocation.rs:57:25
|
LL | pub fn arc_test5(a: Arc<Box<bool>>) {}
| ^^^^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL | pub fn arc_test5(a: Arc<Box<bool>>) {}
= help: consider using just `Arc<bool>` or `Box<bool>`
error: usage of `Arc<Rc<bool>>`
- --> $DIR/redundant_allocation.rs:69:25
+ --> $DIR/redundant_allocation.rs:59:25
|
LL | pub fn arc_test6(a: Arc<Rc<bool>>) {}
| ^^^^^^^^^^^^^
@@ -108,7 +108,7 @@ LL | pub fn arc_test6(a: Arc<Rc<bool>>) {}
= help: consider using just `Arc<bool>` or `Rc<bool>`
error: usage of `Arc<Box<SubT<usize>>>`
- --> $DIR/redundant_allocation.rs:71:27
+ --> $DIR/redundant_allocation.rs:61:27
|
LL | pub fn arc_test8() -> Arc<Box<SubT<usize>>> {
| ^^^^^^^^^^^^^^^^^^^^^
@@ -117,7 +117,7 @@ LL | pub fn arc_test8() -> Arc<Box<SubT<usize>>> {
= help: consider using just `Arc<SubT<usize>>` or `Box<SubT<usize>>`
error: usage of `Arc<Rc<T>>`
- --> $DIR/redundant_allocation.rs:75:30
+ --> $DIR/redundant_allocation.rs:65:30
|
LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
| ^^^^^^^^^^
@@ -126,7 +126,7 @@ LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
= help: consider using just `Arc<T>` or `Rc<T>`
error: usage of `Arc<Rc<SubT<T>>>`
- --> $DIR/redundant_allocation.rs:75:45
+ --> $DIR/redundant_allocation.rs:65:45
|
LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
| ^^^^^^^^^^^^^^^^
@@ -135,7 +135,7 @@ LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
= help: consider using just `Arc<SubT<T>>` or `Rc<SubT<T>>`
error: usage of `Rc<Box<Box<dyn T>>>`
- --> $DIR/redundant_allocation.rs:97:27
+ --> $DIR/redundant_allocation.rs:87:27
|
LL | pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {}
| ^^^^^^^^^^^^^^^^^^^
@@ -144,7 +144,7 @@ LL | pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {}
= help: consider using just `Rc<Box<dyn T>>` or `Box<Box<dyn T>>`
error: usage of `Rc<Box<Box<str>>>`
- --> $DIR/redundant_allocation.rs:129:31
+ --> $DIR/redundant_allocation.rs:119:31
|
LL | pub fn test_rc_box_str(_: Rc<Box<Box<str>>>) {}
| ^^^^^^^^^^^^^^^^^
@@ -153,7 +153,7 @@ LL | pub fn test_rc_box_str(_: Rc<Box<Box<str>>>) {}
= help: consider using just `Rc<Box<str>>` or `Box<Box<str>>`
error: usage of `Rc<Box<Box<[usize]>>>`
- --> $DIR/redundant_allocation.rs:130:33
+ --> $DIR/redundant_allocation.rs:120:33
|
LL | pub fn test_rc_box_slice(_: Rc<Box<Box<[usize]>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^
@@ -162,7 +162,7 @@ LL | pub fn test_rc_box_slice(_: Rc<Box<Box<[usize]>>>) {}
= help: consider using just `Rc<Box<[usize]>>` or `Box<Box<[usize]>>`
error: usage of `Rc<Box<Box<Path>>>`
- --> $DIR/redundant_allocation.rs:131:32
+ --> $DIR/redundant_allocation.rs:121:32
|
LL | pub fn test_rc_box_path(_: Rc<Box<Box<Path>>>) {}
| ^^^^^^^^^^^^^^^^^^
@@ -171,7 +171,7 @@ LL | pub fn test_rc_box_path(_: Rc<Box<Box<Path>>>) {}
= help: consider using just `Rc<Box<Path>>` or `Box<Box<Path>>`
error: usage of `Rc<Box<Box<DynSized>>>`
- --> $DIR/redundant_allocation.rs:132:34
+ --> $DIR/redundant_allocation.rs:122:34
|
LL | pub fn test_rc_box_custom(_: Rc<Box<Box<DynSized>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed b/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed
index e7ed84731..6db02718c 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed
+++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed
@@ -1,7 +1,7 @@
// run-rustfix
#![warn(clippy::all)]
#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
+#![allow(clippy::disallowed_names, unused_variables, dead_code)]
#![allow(unused_imports)]
pub struct MyStruct;
diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs b/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs
index de763f98b..c15806f30 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs
+++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs
@@ -1,7 +1,7 @@
// run-rustfix
#![warn(clippy::all)]
#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
+#![allow(clippy::disallowed_names, unused_variables, dead_code)]
#![allow(unused_imports)]
pub struct MyStruct;
diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr b/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr
index fdd76ef17..8dd4a6a26 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr
+++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr
@@ -4,8 +4,8 @@ error: usage of `Box<&T>`
LL | pub fn box_test1<T>(foo: Box<&T>) {}
| ^^^^^^^ help: try: `&T`
|
- = note: `-D clippy::redundant-allocation` implied by `-D warnings`
= note: `&T` is already a pointer, `Box<&T>` allocates a pointer on the heap
+ = note: `-D clippy::redundant-allocation` implied by `-D warnings`
error: usage of `Box<&MyStruct>`
--> $DIR/redundant_allocation_fixable.rs:28:27
diff --git a/src/tools/clippy/tests/ui/redundant_clone.fixed b/src/tools/clippy/tests/ui/redundant_clone.fixed
index da52c0acf..00b427450 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.fixed
+++ b/src/tools/clippy/tests/ui/redundant_clone.fixed
@@ -1,8 +1,8 @@
// run-rustfix
// rustfix-only-machine-applicable
-
#![feature(lint_reasons)]
-#![allow(clippy::implicit_clone, clippy::drop_non_drop)]
+#![allow(clippy::drop_non_drop, clippy::implicit_clone, clippy::uninlined_format_args)]
+
use std::ffi::OsString;
use std::path::Path;
diff --git a/src/tools/clippy/tests/ui/redundant_clone.rs b/src/tools/clippy/tests/ui/redundant_clone.rs
index 5867d019d..f899127db 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.rs
+++ b/src/tools/clippy/tests/ui/redundant_clone.rs
@@ -1,8 +1,8 @@
// run-rustfix
// rustfix-only-machine-applicable
-
#![feature(lint_reasons)]
-#![allow(clippy::implicit_clone, clippy::drop_non_drop)]
+#![allow(clippy::drop_non_drop, clippy::implicit_clone, clippy::uninlined_format_args)]
+
use std::ffi::OsString;
use std::path::Path;
diff --git a/src/tools/clippy/tests/ui/redundant_clone.stderr b/src/tools/clippy/tests/ui/redundant_clone.stderr
index aa1dd7cbb..782590034 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.stderr
+++ b/src/tools/clippy/tests/ui/redundant_clone.stderr
@@ -4,12 +4,12 @@ error: redundant clone
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:10:14
|
LL | let _s = ["lorem", "ipsum"].join(" ").to_string();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: `-D clippy::redundant-clone` implied by `-D warnings`
error: redundant clone
--> $DIR/redundant_clone.rs:13:15
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed
index 0abca6fca..7cd687c95 100644
--- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed
+++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed
@@ -1,8 +1,28 @@
// run-rustfix
+#![feature(async_closure)]
#![warn(clippy::redundant_closure_call)]
#![allow(unused)]
+async fn something() -> u32 {
+ 21
+}
+
+async fn something_else() -> u32 {
+ 2
+}
+
fn main() {
let a = 42;
+ let b = async {
+ let x = something().await;
+ let y = something_else().await;
+ x * y
+ };
+ let c = {
+ let x = 21;
+ let y = 2;
+ x * y
+ };
+ let d = async { something().await };
}
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs
index f8b9d37a5..37e4d2238 100644
--- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs
+++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs
@@ -1,8 +1,28 @@
// run-rustfix
+#![feature(async_closure)]
#![warn(clippy::redundant_closure_call)]
#![allow(unused)]
+async fn something() -> u32 {
+ 21
+}
+
+async fn something_else() -> u32 {
+ 2
+}
+
fn main() {
let a = (|| 42)();
+ let b = (async || {
+ let x = something().await;
+ let y = something_else().await;
+ x * y
+ })();
+ let c = (|| {
+ let x = 21;
+ let y = 2;
+ x * y
+ })();
+ let d = (async || something().await)();
}
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr
index afd704ef1..56a8e57c0 100644
--- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr
+++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr
@@ -1,10 +1,56 @@
error: try not to call a closure in the expression where it is declared
- --> $DIR/redundant_closure_call_fixable.rs:7:13
+ --> $DIR/redundant_closure_call_fixable.rs:16:13
|
LL | let a = (|| 42)();
| ^^^^^^^^^ help: try doing something like: `42`
|
= note: `-D clippy::redundant-closure-call` implied by `-D warnings`
-error: aborting due to previous error
+error: try not to call a closure in the expression where it is declared
+ --> $DIR/redundant_closure_call_fixable.rs:17:13
+ |
+LL | let b = (async || {
+ | _____________^
+LL | | let x = something().await;
+LL | | let y = something_else().await;
+LL | | x * y
+LL | | })();
+ | |________^
+ |
+help: try doing something like
+ |
+LL ~ let b = async {
+LL + let x = something().await;
+LL + let y = something_else().await;
+LL + x * y
+LL ~ };
+ |
+
+error: try not to call a closure in the expression where it is declared
+ --> $DIR/redundant_closure_call_fixable.rs:22:13
+ |
+LL | let c = (|| {
+ | _____________^
+LL | | let x = 21;
+LL | | let y = 2;
+LL | | x * y
+LL | | })();
+ | |________^
+ |
+help: try doing something like
+ |
+LL ~ let c = {
+LL + let x = 21;
+LL + let y = 2;
+LL + x * y
+LL ~ };
+ |
+
+error: try not to call a closure in the expression where it is declared
+ --> $DIR/redundant_closure_call_fixable.rs:27:13
+ |
+LL | let d = (async || something().await)();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { something().await }`
+
+error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/redundant_else.stderr b/src/tools/clippy/tests/ui/redundant_else.stderr
index 9000cdc81..de9d00a60 100644
--- a/src/tools/clippy/tests/ui/redundant_else.stderr
+++ b/src/tools/clippy/tests/ui/redundant_else.stderr
@@ -7,8 +7,8 @@ LL | | println!("yet don't pull down your hedge.");
LL | | }
| |_________^
|
- = note: `-D clippy::redundant-else` implied by `-D warnings`
= help: remove the `else` block and move the contents out
+ = note: `-D clippy::redundant-else` implied by `-D warnings`
error: redundant else block
--> $DIR/redundant_else.rs:17:16
diff --git a/src/tools/clippy/tests/ui/redundant_field_names.fixed b/src/tools/clippy/tests/ui/redundant_field_names.fixed
index 5b4b8eeed..34ab552cb 100644
--- a/src/tools/clippy/tests/ui/redundant_field_names.fixed
+++ b/src/tools/clippy/tests/ui/redundant_field_names.fixed
@@ -1,4 +1,6 @@
// run-rustfix
+
+#![feature(custom_inner_attributes)]
#![warn(clippy::redundant_field_names)]
#![allow(clippy::no_effect, dead_code, unused_variables)]
@@ -69,3 +71,17 @@ fn issue_3476() {
S { foo: foo::<i32> };
}
+
+fn msrv_1_16() {
+ #![clippy::msrv = "1.16"]
+
+ let start = 0;
+ let _ = RangeFrom { start: start };
+}
+
+fn msrv_1_17() {
+ #![clippy::msrv = "1.17"]
+
+ let start = 0;
+ let _ = RangeFrom { start };
+}
diff --git a/src/tools/clippy/tests/ui/redundant_field_names.rs b/src/tools/clippy/tests/ui/redundant_field_names.rs
index 3f97b80c5..a051b1f96 100644
--- a/src/tools/clippy/tests/ui/redundant_field_names.rs
+++ b/src/tools/clippy/tests/ui/redundant_field_names.rs
@@ -1,4 +1,6 @@
// run-rustfix
+
+#![feature(custom_inner_attributes)]
#![warn(clippy::redundant_field_names)]
#![allow(clippy::no_effect, dead_code, unused_variables)]
@@ -69,3 +71,17 @@ fn issue_3476() {
S { foo: foo::<i32> };
}
+
+fn msrv_1_16() {
+ #![clippy::msrv = "1.16"]
+
+ let start = 0;
+ let _ = RangeFrom { start: start };
+}
+
+fn msrv_1_17() {
+ #![clippy::msrv = "1.17"]
+
+ let start = 0;
+ let _ = RangeFrom { start: start };
+}
diff --git a/src/tools/clippy/tests/ui/redundant_field_names.stderr b/src/tools/clippy/tests/ui/redundant_field_names.stderr
index 7976292df..8b82e062b 100644
--- a/src/tools/clippy/tests/ui/redundant_field_names.stderr
+++ b/src/tools/clippy/tests/ui/redundant_field_names.stderr
@@ -1,5 +1,5 @@
error: redundant field names in struct initialization
- --> $DIR/redundant_field_names.rs:34:9
+ --> $DIR/redundant_field_names.rs:36:9
|
LL | gender: gender,
| ^^^^^^^^^^^^^^ help: replace it with: `gender`
@@ -7,40 +7,46 @@ LL | gender: gender,
= note: `-D clippy::redundant-field-names` implied by `-D warnings`
error: redundant field names in struct initialization
- --> $DIR/redundant_field_names.rs:35:9
+ --> $DIR/redundant_field_names.rs:37:9
|
LL | age: age,
| ^^^^^^^^ help: replace it with: `age`
error: redundant field names in struct initialization
- --> $DIR/redundant_field_names.rs:56:25
+ --> $DIR/redundant_field_names.rs:58:25
|
LL | let _ = RangeFrom { start: start };
| ^^^^^^^^^^^^ help: replace it with: `start`
error: redundant field names in struct initialization
- --> $DIR/redundant_field_names.rs:57:23
+ --> $DIR/redundant_field_names.rs:59:23
|
LL | let _ = RangeTo { end: end };
| ^^^^^^^^ help: replace it with: `end`
error: redundant field names in struct initialization
- --> $DIR/redundant_field_names.rs:58:21
+ --> $DIR/redundant_field_names.rs:60:21
|
LL | let _ = Range { start: start, end: end };
| ^^^^^^^^^^^^ help: replace it with: `start`
error: redundant field names in struct initialization
- --> $DIR/redundant_field_names.rs:58:35
+ --> $DIR/redundant_field_names.rs:60:35
|
LL | let _ = Range { start: start, end: end };
| ^^^^^^^^ help: replace it with: `end`
error: redundant field names in struct initialization
- --> $DIR/redundant_field_names.rs:60:32
+ --> $DIR/redundant_field_names.rs:62:32
|
LL | let _ = RangeToInclusive { end: end };
| ^^^^^^^^ help: replace it with: `end`
-error: aborting due to 7 previous errors
+error: redundant field names in struct initialization
+ --> $DIR/redundant_field_names.rs:86:25
+ |
+LL | let _ = RangeFrom { start: start };
+ | ^^^^^^^^^^^^ help: replace it with: `start`
+
+error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr
index eb7aa70ee..23f08103f 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr
@@ -4,9 +4,9 @@ error: redundant pattern matching, consider using `is_ok()`
LL | if let Ok(_) = m.lock() {}
| -------^^^^^----------- help: try this: `if m.lock().is_ok()`
|
- = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
= note: this will change drop order of the result, as well as all temporaries
= note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important
+ = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_drop_order.rs:13:12
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed
index acc8de5f4..21bae9095 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed
@@ -1,8 +1,11 @@
// run-rustfix
-
-#![warn(clippy::all)]
-#![warn(clippy::redundant_pattern_matching)]
-#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)]
+#![warn(clippy::all, clippy::redundant_pattern_matching)]
+#![allow(unused_must_use)]
+#![allow(
+ clippy::match_like_matches_macro,
+ clippy::needless_bool,
+ clippy::uninlined_format_args
+)]
use std::net::{
IpAddr::{self, V4, V6},
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs
index 678d91ce9..4dd917167 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs
@@ -1,8 +1,11 @@
// run-rustfix
-
-#![warn(clippy::all)]
-#![warn(clippy::redundant_pattern_matching)]
-#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)]
+#![warn(clippy::all, clippy::redundant_pattern_matching)]
+#![allow(unused_must_use)]
+#![allow(
+ clippy::match_like_matches_macro,
+ clippy::needless_bool,
+ clippy::uninlined_format_args
+)]
use std::net::{
IpAddr::{self, V4, V6},
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr
index caf458cd8..536b589de 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr
@@ -1,5 +1,5 @@
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:14:12
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:17:12
|
LL | if let V4(_) = &ipaddr {}
| -------^^^^^---------- help: try this: `if ipaddr.is_ipv4()`
@@ -7,31 +7,31 @@ LL | if let V4(_) = &ipaddr {}
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:16:12
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:19:12
|
LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
| -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:18:12
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:21:12
|
LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
| -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:20:15
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:23:15
|
LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
| ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:22:15
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:25:15
|
LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
| ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:32:5
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:35:5
|
LL | / match V4(Ipv4Addr::LOCALHOST) {
LL | | V4(_) => true,
@@ -40,7 +40,7 @@ LL | | };
| |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:37:5
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:40:5
|
LL | / match V4(Ipv4Addr::LOCALHOST) {
LL | | V4(_) => false,
@@ -49,7 +49,7 @@ LL | | };
| |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:42:5
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:45:5
|
LL | / match V6(Ipv6Addr::LOCALHOST) {
LL | | V4(_) => false,
@@ -58,7 +58,7 @@ LL | | };
| |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:47:5
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:50:5
|
LL | / match V6(Ipv6Addr::LOCALHOST) {
LL | | V4(_) => true,
@@ -67,49 +67,49 @@ LL | | };
| |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:52:20
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:55:20
|
LL | let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) {
| -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:60:20
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:63:20
|
LL | let _ = if let V4(_) = gen_ipaddr() {
| -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:62:19
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:65:19
|
LL | } else if let V6(_) = gen_ipaddr() {
| -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:74:12
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:77:12
|
LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
| -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:76:12
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:79:12
|
LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
| -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:78:15
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:81:15
|
LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
| ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:80:15
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:83:15
|
LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
| ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:82:5
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:85:5
|
LL | / match V4(Ipv4Addr::LOCALHOST) {
LL | | V4(_) => true,
@@ -118,7 +118,7 @@ LL | | };
| |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:87:5
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:90:5
|
LL | / match V6(Ipv6Addr::LOCALHOST) {
LL | | V4(_) => false,
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed
index 83c783385..b88c5d0be 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed
@@ -1,14 +1,13 @@
// run-rustfix
-
#![warn(clippy::all)]
#![warn(clippy::redundant_pattern_matching)]
+#![allow(deprecated, unused_must_use)]
#![allow(
- unused_must_use,
- clippy::needless_bool,
+ clippy::if_same_then_else,
clippy::match_like_matches_macro,
- clippy::unnecessary_wraps,
- deprecated,
- clippy::if_same_then_else
+ clippy::needless_bool,
+ clippy::uninlined_format_args,
+ clippy::unnecessary_wraps
)]
fn main() {
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs
index e06d4485a..5949cb227 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs
@@ -1,14 +1,13 @@
// run-rustfix
-
#![warn(clippy::all)]
#![warn(clippy::redundant_pattern_matching)]
+#![allow(deprecated, unused_must_use)]
#![allow(
- unused_must_use,
- clippy::needless_bool,
+ clippy::if_same_then_else,
clippy::match_like_matches_macro,
- clippy::unnecessary_wraps,
- deprecated,
- clippy::if_same_then_else
+ clippy::needless_bool,
+ clippy::uninlined_format_args,
+ clippy::unnecessary_wraps
)]
fn main() {
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
index d674d061e..e6afe9eb7 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
@@ -1,5 +1,5 @@
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching_result.rs:16:12
+ --> $DIR/redundant_pattern_matching_result.rs:15:12
|
LL | if let Ok(_) = &result {}
| -------^^^^^---------- help: try this: `if result.is_ok()`
@@ -7,31 +7,31 @@ LL | if let Ok(_) = &result {}
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching_result.rs:18:12
+ --> $DIR/redundant_pattern_matching_result.rs:17:12
|
LL | if let Ok(_) = Ok::<i32, i32>(42) {}
| -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching_result.rs:20:12
+ --> $DIR/redundant_pattern_matching_result.rs:19:12
|
LL | if let Err(_) = Err::<i32, i32>(42) {}
| -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching_result.rs:22:15
+ --> $DIR/redundant_pattern_matching_result.rs:21:15
|
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching_result.rs:24:15
+ --> $DIR/redundant_pattern_matching_result.rs:23:15
|
LL | while let Err(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching_result.rs:34:5
+ --> $DIR/redundant_pattern_matching_result.rs:33:5
|
LL | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => true,
@@ -40,7 +40,7 @@ LL | | };
| |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching_result.rs:39:5
+ --> $DIR/redundant_pattern_matching_result.rs:38:5
|
LL | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => false,
@@ -49,7 +49,7 @@ LL | | };
| |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching_result.rs:44:5
+ --> $DIR/redundant_pattern_matching_result.rs:43:5
|
LL | / match Err::<i32, i32>(42) {
LL | | Ok(_) => false,
@@ -58,7 +58,7 @@ LL | | };
| |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching_result.rs:49:5
+ --> $DIR/redundant_pattern_matching_result.rs:48:5
|
LL | / match Err::<i32, i32>(42) {
LL | | Ok(_) => true,
@@ -67,73 +67,73 @@ LL | | };
| |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching_result.rs:54:20
+ --> $DIR/redundant_pattern_matching_result.rs:53:20
|
LL | let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
| -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching_result.rs:60:20
+ --> $DIR/redundant_pattern_matching_result.rs:59:20
|
LL | let _ = if let Ok(_) = gen_res() {
| -------^^^^^------------ help: try this: `if gen_res().is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching_result.rs:62:19
+ --> $DIR/redundant_pattern_matching_result.rs:61:19
|
LL | } else if let Err(_) = gen_res() {
| -------^^^^^^------------ help: try this: `if gen_res().is_err()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_result.rs:85:19
+ --> $DIR/redundant_pattern_matching_result.rs:84:19
|
LL | while let Some(_) = r#try!(result_opt()) {}
| ----------^^^^^^^----------------------- help: try this: `while (r#try!(result_opt())).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_result.rs:86:16
+ --> $DIR/redundant_pattern_matching_result.rs:85:16
|
LL | if let Some(_) = r#try!(result_opt()) {}
| -------^^^^^^^----------------------- help: try this: `if (r#try!(result_opt())).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_result.rs:92:12
+ --> $DIR/redundant_pattern_matching_result.rs:91:12
|
LL | if let Some(_) = m!() {}
| -------^^^^^^^------- help: try this: `if m!().is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_result.rs:93:15
+ --> $DIR/redundant_pattern_matching_result.rs:92:15
|
LL | while let Some(_) = m!() {}
| ----------^^^^^^^------- help: try this: `while m!().is_some()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching_result.rs:111:12
+ --> $DIR/redundant_pattern_matching_result.rs:110:12
|
LL | if let Ok(_) = Ok::<i32, i32>(42) {}
| -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching_result.rs:113:12
+ --> $DIR/redundant_pattern_matching_result.rs:112:12
|
LL | if let Err(_) = Err::<i32, i32>(42) {}
| -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching_result.rs:115:15
+ --> $DIR/redundant_pattern_matching_result.rs:114:15
|
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching_result.rs:117:15
+ --> $DIR/redundant_pattern_matching_result.rs:116:15
|
LL | while let Err(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching_result.rs:119:5
+ --> $DIR/redundant_pattern_matching_result.rs:118:5
|
LL | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => true,
@@ -142,7 +142,7 @@ LL | | };
| |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching_result.rs:124:5
+ --> $DIR/redundant_pattern_matching_result.rs:123:5
|
LL | / match Err::<i32, i32>(42) {
LL | | Ok(_) => false,
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed b/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
index acc8f1e25..42110dbe8 100644
--- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
@@ -1,5 +1,6 @@
// run-rustfix
+#![feature(custom_inner_attributes)]
#![allow(unused)]
#[derive(Debug)]
@@ -54,3 +55,15 @@ impl Foo {
impl Bar for Foo {
const TRAIT_VAR: &'static str = "foo";
}
+
+fn msrv_1_16() {
+ #![clippy::msrv = "1.16"]
+
+ static V: &'static u8 = &16;
+}
+
+fn msrv_1_17() {
+ #![clippy::msrv = "1.17"]
+
+ static V: &u8 = &17;
+}
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs b/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
index f2f0f7865..bc5200bc8 100644
--- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
@@ -1,5 +1,6 @@
// run-rustfix
+#![feature(custom_inner_attributes)]
#![allow(unused)]
#[derive(Debug)]
@@ -54,3 +55,15 @@ impl Foo {
impl Bar for Foo {
const TRAIT_VAR: &'static str = "foo";
}
+
+fn msrv_1_16() {
+ #![clippy::msrv = "1.16"]
+
+ static V: &'static u8 = &16;
+}
+
+fn msrv_1_17() {
+ #![clippy::msrv = "1.17"]
+
+ static V: &'static u8 = &17;
+}
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr b/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
index 649831f9c..735113460 100644
--- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
@@ -1,5 +1,5 @@
error: constants have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:8:17
+ --> $DIR/redundant_static_lifetimes.rs:9:17
|
LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static.
| -^^^^^^^---- help: consider removing `'static`: `&str`
@@ -7,94 +7,100 @@ LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removin
= note: `-D clippy::redundant-static-lifetimes` implied by `-D warnings`
error: constants have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:12:21
+ --> $DIR/redundant_static_lifetimes.rs:13:21
|
LL | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
| -^^^^^^^---- help: consider removing `'static`: `&str`
error: constants have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:14:32
+ --> $DIR/redundant_static_lifetimes.rs:15:32
|
LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
| -^^^^^^^---- help: consider removing `'static`: `&str`
error: constants have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:14:47
+ --> $DIR/redundant_static_lifetimes.rs:15:47
|
LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
| -^^^^^^^---- help: consider removing `'static`: `&str`
error: constants have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:16:17
+ --> $DIR/redundant_static_lifetimes.rs:17:17
|
LL | const VAR_SIX: &'static u8 = &5;
| -^^^^^^^--- help: consider removing `'static`: `&u8`
error: constants have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:18:20
+ --> $DIR/redundant_static_lifetimes.rs:19:20
|
LL | const VAR_HEIGHT: &'static Foo = &Foo {};
| -^^^^^^^---- help: consider removing `'static`: `&Foo`
error: constants have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:20:19
+ --> $DIR/redundant_static_lifetimes.rs:21:19
|
LL | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static.
| -^^^^^^^----- help: consider removing `'static`: `&[u8]`
error: constants have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:22:19
+ --> $DIR/redundant_static_lifetimes.rs:23:19
|
LL | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
| -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
error: constants have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:24:19
+ --> $DIR/redundant_static_lifetimes.rs:25:19
|
LL | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
| -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
error: statics have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:26:25
+ --> $DIR/redundant_static_lifetimes.rs:27:25
|
LL | static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static.
| -^^^^^^^---- help: consider removing `'static`: `&str`
error: statics have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:30:29
+ --> $DIR/redundant_static_lifetimes.rs:31:29
|
LL | static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
| -^^^^^^^---- help: consider removing `'static`: `&str`
error: statics have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:32:25
+ --> $DIR/redundant_static_lifetimes.rs:33:25
|
LL | static STATIC_VAR_SIX: &'static u8 = &5;
| -^^^^^^^--- help: consider removing `'static`: `&u8`
error: statics have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:34:28
+ --> $DIR/redundant_static_lifetimes.rs:35:28
|
LL | static STATIC_VAR_HEIGHT: &'static Foo = &Foo {};
| -^^^^^^^---- help: consider removing `'static`: `&Foo`
error: statics have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:36:27
+ --> $DIR/redundant_static_lifetimes.rs:37:27
|
LL | static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static.
| -^^^^^^^----- help: consider removing `'static`: `&[u8]`
error: statics have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:38:27
+ --> $DIR/redundant_static_lifetimes.rs:39:27
|
LL | static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
| -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
error: statics have by default a `'static` lifetime
- --> $DIR/redundant_static_lifetimes.rs:40:27
+ --> $DIR/redundant_static_lifetimes.rs:41:27
|
LL | static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
| -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
-error: aborting due to 16 previous errors
+error: statics have by default a `'static` lifetime
+ --> $DIR/redundant_static_lifetimes.rs:68:16
+ |
+LL | static V: &'static u8 = &17;
+ | -^^^^^^^--- help: consider removing `'static`: `&u8`
+
+error: aborting due to 17 previous errors
diff --git a/src/tools/clippy/tests/ui/ref_option_ref.rs b/src/tools/clippy/tests/ui/ref_option_ref.rs
index 2df45c927..e487799e1 100644
--- a/src/tools/clippy/tests/ui/ref_option_ref.rs
+++ b/src/tools/clippy/tests/ui/ref_option_ref.rs
@@ -45,3 +45,8 @@ impl RefOptTrait for u32 {
fn main() {
let x: &Option<&u32> = &None;
}
+
+fn issue9682(arg: &Option<&mut String>) {
+ // Should not lint, as the inner ref is mutable making it non `Copy`
+ println!("{arg:?}");
+}
diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs
index f7f3b195c..f0e1a8128 100644
--- a/src/tools/clippy/tests/ui/regex.rs
+++ b/src/tools/clippy/tests/ui/regex.rs
@@ -1,4 +1,4 @@
-#![allow(unused)]
+#![allow(unused, clippy::needless_borrow)]
#![warn(clippy::invalid_regex, clippy::trivial_regex)]
extern crate regex;
diff --git a/src/tools/clippy/tests/ui/regex.stderr b/src/tools/clippy/tests/ui/regex.stderr
index 1394a9b63..2424644c6 100644
--- a/src/tools/clippy/tests/ui/regex.stderr
+++ b/src/tools/clippy/tests/ui/regex.stderr
@@ -4,8 +4,8 @@ error: trivial regex
LL | let pipe_in_wrong_position = Regex::new("|");
| ^^^
|
- = note: `-D clippy::trivial-regex` implied by `-D warnings`
= help: the regex is unlikely to be useful as it is
+ = note: `-D clippy::trivial-regex` implied by `-D warnings`
error: trivial regex
--> $DIR/regex.rs:14:60
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 53288be94..8beae8dee 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -4,6 +4,7 @@
// run-rustfix
+#![allow(clippy::disallowed_names)]
#![allow(clippy::blocks_in_if_conditions)]
#![allow(clippy::box_collection)]
#![allow(clippy::redundant_static_lifetimes)]
@@ -11,9 +12,10 @@
#![allow(clippy::disallowed_methods)]
#![allow(clippy::disallowed_types)]
#![allow(clippy::mixed_read_write_in_expression)]
-#![allow(clippy::for_loops_over_fallibles)]
+#![allow(for_loops_over_fallibles)]
#![allow(clippy::useless_conversion)]
#![allow(clippy::match_result_ok)]
+#![allow(clippy::overly_complex_bool_expr)]
#![allow(clippy::new_without_default)]
#![allow(clippy::bind_instead_of_map)]
#![allow(clippy::expect_used)]
@@ -30,9 +32,11 @@
#![allow(invalid_value)]
#![allow(enum_intrinsics_non_enums)]
#![allow(non_fmt_panics)]
+#![allow(named_arguments_used_positionally)]
#![allow(temporary_cstring_as_ptr)]
#![allow(unknown_lints)]
#![allow(unused_labels)]
+#![warn(clippy::disallowed_names)]
#![warn(clippy::blocks_in_if_conditions)]
#![warn(clippy::blocks_in_if_conditions)]
#![warn(clippy::box_collection)]
@@ -41,10 +45,11 @@
#![warn(clippy::disallowed_methods)]
#![warn(clippy::disallowed_types)]
#![warn(clippy::mixed_read_write_in_expression)]
-#![warn(clippy::for_loops_over_fallibles)]
-#![warn(clippy::for_loops_over_fallibles)]
+#![warn(for_loops_over_fallibles)]
+#![warn(for_loops_over_fallibles)]
#![warn(clippy::useless_conversion)]
#![warn(clippy::match_result_ok)]
+#![warn(clippy::overly_complex_bool_expr)]
#![warn(clippy::new_without_default)]
#![warn(clippy::bind_instead_of_map)]
#![warn(clippy::expect_used)]
@@ -60,11 +65,13 @@
#![warn(clippy::recursive_format_impl)]
#![warn(clippy::invisible_characters)]
#![warn(drop_bounds)]
+#![warn(for_loops_over_fallibles)]
#![warn(array_into_iter)]
#![warn(invalid_atomic_ordering)]
#![warn(invalid_value)]
#![warn(enum_intrinsics_non_enums)]
#![warn(non_fmt_panics)]
+#![warn(named_arguments_used_positionally)]
#![warn(temporary_cstring_as_ptr)]
#![warn(unknown_lints)]
#![warn(unused_labels)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 539f34f84..9e665047b 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -4,6 +4,7 @@
// run-rustfix
+#![allow(clippy::disallowed_names)]
#![allow(clippy::blocks_in_if_conditions)]
#![allow(clippy::box_collection)]
#![allow(clippy::redundant_static_lifetimes)]
@@ -11,9 +12,10 @@
#![allow(clippy::disallowed_methods)]
#![allow(clippy::disallowed_types)]
#![allow(clippy::mixed_read_write_in_expression)]
-#![allow(clippy::for_loops_over_fallibles)]
+#![allow(for_loops_over_fallibles)]
#![allow(clippy::useless_conversion)]
#![allow(clippy::match_result_ok)]
+#![allow(clippy::overly_complex_bool_expr)]
#![allow(clippy::new_without_default)]
#![allow(clippy::bind_instead_of_map)]
#![allow(clippy::expect_used)]
@@ -30,9 +32,11 @@
#![allow(invalid_value)]
#![allow(enum_intrinsics_non_enums)]
#![allow(non_fmt_panics)]
+#![allow(named_arguments_used_positionally)]
#![allow(temporary_cstring_as_ptr)]
#![allow(unknown_lints)]
#![allow(unused_labels)]
+#![warn(clippy::blacklisted_name)]
#![warn(clippy::block_in_if_condition_expr)]
#![warn(clippy::block_in_if_condition_stmt)]
#![warn(clippy::box_vec)]
@@ -45,6 +49,7 @@
#![warn(clippy::for_loop_over_result)]
#![warn(clippy::identity_conversion)]
#![warn(clippy::if_let_some_result)]
+#![warn(clippy::logic_bug)]
#![warn(clippy::new_without_default_derive)]
#![warn(clippy::option_and_then_some)]
#![warn(clippy::option_expect_used)]
@@ -60,11 +65,13 @@
#![warn(clippy::to_string_in_display)]
#![warn(clippy::zero_width_space)]
#![warn(clippy::drop_bounds)]
+#![warn(clippy::for_loops_over_fallibles)]
#![warn(clippy::into_iter_on_array)]
#![warn(clippy::invalid_atomic_ordering)]
#![warn(clippy::invalid_ref)]
#![warn(clippy::mem_discriminant_non_enum)]
#![warn(clippy::panic_params)]
+#![warn(clippy::positional_named_format_parameters)]
#![warn(clippy::temporary_cstring_as_ptr)]
#![warn(clippy::unknown_clippy_lints)]
#![warn(clippy::unused_label)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 8ea46b580..63eb56518 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,214 +1,238 @@
+error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
+ --> $DIR/rename.rs:39:9
+ |
+LL | #![warn(clippy::blacklisted_name)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
+ |
+ = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+
error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
- --> $DIR/rename.rs:36:9
+ --> $DIR/rename.rs:40:9
|
LL | #![warn(clippy::block_in_if_condition_expr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
- |
- = note: `-D renamed-and-removed-lints` implied by `-D warnings`
error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
- --> $DIR/rename.rs:37:9
+ --> $DIR/rename.rs:41:9
|
LL | #![warn(clippy::block_in_if_condition_stmt)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
- --> $DIR/rename.rs:38:9
+ --> $DIR/rename.rs:42:9
|
LL | #![warn(clippy::box_vec)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
- --> $DIR/rename.rs:39:9
+ --> $DIR/rename.rs:43: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`
- --> $DIR/rename.rs:40:9
+ --> $DIR/rename.rs:44:9
|
LL | #![warn(clippy::cyclomatic_complexity)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
- --> $DIR/rename.rs:41:9
+ --> $DIR/rename.rs:45:9
|
LL | #![warn(clippy::disallowed_method)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
- --> $DIR/rename.rs:42:9
+ --> $DIR/rename.rs:46:9
|
LL | #![warn(clippy::disallowed_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
- --> $DIR/rename.rs:43:9
+ --> $DIR/rename.rs:47:9
|
LL | #![warn(clippy::eval_order_dependence)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
-error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
- --> $DIR/rename.rs:44:9
+error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
+ --> $DIR/rename.rs:48:9
|
LL | #![warn(clippy::for_loop_over_option)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
-error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
- --> $DIR/rename.rs:45:9
+error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
+ --> $DIR/rename.rs:49:9
|
LL | #![warn(clippy::for_loop_over_result)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
- --> $DIR/rename.rs:46:9
+ --> $DIR/rename.rs:50:9
|
LL | #![warn(clippy::identity_conversion)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
- --> $DIR/rename.rs:47:9
+ --> $DIR/rename.rs:51:9
|
LL | #![warn(clippy::if_let_some_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
+error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
+ --> $DIR/rename.rs:52:9
+ |
+LL | #![warn(clippy::logic_bug)]
+ | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
+
error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
- --> $DIR/rename.rs:48:9
+ --> $DIR/rename.rs:53:9
|
LL | #![warn(clippy::new_without_default_derive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
- --> $DIR/rename.rs:49:9
+ --> $DIR/rename.rs:54:9
|
LL | #![warn(clippy::option_and_then_some)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
- --> $DIR/rename.rs:50:9
+ --> $DIR/rename.rs:55:9
|
LL | #![warn(clippy::option_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
- --> $DIR/rename.rs:51:9
+ --> $DIR/rename.rs:56: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:52:9
+ --> $DIR/rename.rs:57:9
|
LL | #![warn(clippy::option_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:53:9
+ --> $DIR/rename.rs:58:9
|
LL | #![warn(clippy::option_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
- --> $DIR/rename.rs:54:9
+ --> $DIR/rename.rs:59:9
|
LL | #![warn(clippy::ref_in_deref)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
- --> $DIR/rename.rs:55:9
+ --> $DIR/rename.rs:60:9
|
LL | #![warn(clippy::result_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
- --> $DIR/rename.rs:56:9
+ --> $DIR/rename.rs:61:9
|
LL | #![warn(clippy::result_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
- --> $DIR/rename.rs:57:9
+ --> $DIR/rename.rs:62:9
|
LL | #![warn(clippy::result_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
- --> $DIR/rename.rs:58:9
+ --> $DIR/rename.rs:63:9
|
LL | #![warn(clippy::single_char_push_str)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
- --> $DIR/rename.rs:59:9
+ --> $DIR/rename.rs:64:9
|
LL | #![warn(clippy::stutter)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
- --> $DIR/rename.rs:60:9
+ --> $DIR/rename.rs:65:9
|
LL | #![warn(clippy::to_string_in_display)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
- --> $DIR/rename.rs:61:9
+ --> $DIR/rename.rs:66:9
|
LL | #![warn(clippy::zero_width_space)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
- --> $DIR/rename.rs:62:9
+ --> $DIR/rename.rs:67:9
|
LL | #![warn(clippy::drop_bounds)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
+error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
+ --> $DIR/rename.rs:68:9
+ |
+LL | #![warn(clippy::for_loops_over_fallibles)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
+
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
- --> $DIR/rename.rs:63:9
+ --> $DIR/rename.rs:69:9
|
LL | #![warn(clippy::into_iter_on_array)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
- --> $DIR/rename.rs:64:9
+ --> $DIR/rename.rs:70:9
|
LL | #![warn(clippy::invalid_atomic_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
- --> $DIR/rename.rs:65:9
+ --> $DIR/rename.rs:71:9
|
LL | #![warn(clippy::invalid_ref)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
- --> $DIR/rename.rs:66:9
+ --> $DIR/rename.rs:72:9
|
LL | #![warn(clippy::mem_discriminant_non_enum)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
- --> $DIR/rename.rs:67:9
+ --> $DIR/rename.rs:73:9
|
LL | #![warn(clippy::panic_params)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
+error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
+ --> $DIR/rename.rs:74:9
+ |
+LL | #![warn(clippy::positional_named_format_parameters)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
+
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
- --> $DIR/rename.rs:68:9
+ --> $DIR/rename.rs:75:9
|
LL | #![warn(clippy::temporary_cstring_as_ptr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
- --> $DIR/rename.rs:69:9
+ --> $DIR/rename.rs:76:9
|
LL | #![warn(clippy::unknown_clippy_lints)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
error: lint `clippy::unused_label` has been renamed to `unused_labels`
- --> $DIR/rename.rs:70:9
+ --> $DIR/rename.rs:77:9
|
LL | #![warn(clippy::unused_label)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
-error: aborting due to 35 previous errors
+error: aborting due to 39 previous errors
diff --git a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
index 57ebd47f8..e15633fb1 100644
--- a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
+++ b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
@@ -4,8 +4,8 @@ error: unnecessary use of `..` pattern in struct binding. All fields were alread
LL | A { a: 5, b: 42, c: "", .. } => {}, // Lint
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::rest-pat-in-fully-bound-structs` implied by `-D warnings`
= help: consider removing `..` from this binding
+ = note: `-D clippy::rest-pat-in-fully-bound-structs` implied by `-D warnings`
error: unnecessary use of `..` pattern in struct binding. All fields were already bound
--> $DIR/rest_pat_in_fully_bound_structs.rs:23:9
diff --git a/src/tools/clippy/tests/ui/result_large_err.rs b/src/tools/clippy/tests/ui/result_large_err.rs
new file mode 100644
index 000000000..f7df3b856
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_large_err.rs
@@ -0,0 +1,99 @@
+#![warn(clippy::result_large_err)]
+#![allow(clippy::large_enum_variant)]
+
+pub fn small_err() -> Result<(), u128> {
+ Ok(())
+}
+
+pub fn large_err() -> Result<(), [u8; 512]> {
+ Ok(())
+}
+
+pub struct FullyDefinedLargeError {
+ _foo: u128,
+ _bar: [u8; 100],
+ _foobar: [u8; 120],
+}
+
+impl FullyDefinedLargeError {
+ pub fn ret() -> Result<(), Self> {
+ Ok(())
+ }
+}
+
+pub fn struct_error() -> Result<(), FullyDefinedLargeError> {
+ Ok(())
+}
+
+type Fdlr<T> = std::result::Result<T, FullyDefinedLargeError>;
+pub fn large_err_via_type_alias<T>(x: T) -> Fdlr<T> {
+ Ok(x)
+}
+
+pub fn param_small_error<R>() -> Result<(), (R, u128)> {
+ Ok(())
+}
+
+pub fn param_large_error<R>() -> Result<(), (u128, R, FullyDefinedLargeError)> {
+ Ok(())
+}
+
+pub enum LargeErrorVariants<T> {
+ _Small(u8),
+ _Omg([u8; 512]),
+ _Param(T),
+}
+
+impl LargeErrorVariants<()> {
+ pub fn large_enum_error() -> Result<(), Self> {
+ Ok(())
+ }
+}
+
+trait TraitForcesLargeError {
+ fn large_error() -> Result<(), [u8; 512]> {
+ Ok(())
+ }
+}
+
+struct TraitImpl;
+
+impl TraitForcesLargeError for TraitImpl {
+ // Should not lint
+ fn large_error() -> Result<(), [u8; 512]> {
+ Ok(())
+ }
+}
+
+pub union FullyDefinedUnionError {
+ _maybe: u8,
+ _or_even: [[u8; 16]; 32],
+}
+
+pub fn large_union_err() -> Result<(), FullyDefinedUnionError> {
+ Ok(())
+}
+
+pub union UnionError<T: Copy> {
+ _maybe: T,
+ _or_perhaps_even: (T, [u8; 512]),
+}
+
+pub fn param_large_union<T: Copy>() -> Result<(), UnionError<T>> {
+ Ok(())
+}
+
+pub struct ArrayError<T, U> {
+ _large_array: [T; 32],
+ _other_stuff: U,
+}
+
+pub fn array_error_subst<U>() -> Result<(), ArrayError<i32, U>> {
+ Ok(())
+}
+
+pub fn array_error<T, U>() -> Result<(), ArrayError<(i32, T), U>> {
+ Ok(())
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/result_large_err.stderr b/src/tools/clippy/tests/ui/result_large_err.stderr
new file mode 100644
index 000000000..bea101fe2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_large_err.stderr
@@ -0,0 +1,91 @@
+error: the `Err`-variant returned from this function is very large
+ --> $DIR/result_large_err.rs:8:23
+ |
+LL | pub fn large_err() -> Result<(), [u8; 512]> {
+ | ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
+ |
+ = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>`
+ = note: `-D clippy::result-large-err` implied by `-D warnings`
+
+error: the `Err`-variant returned from this function is very large
+ --> $DIR/result_large_err.rs:19:21
+ |
+LL | pub fn ret() -> Result<(), Self> {
+ | ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes
+ |
+ = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
+
+error: the `Err`-variant returned from this function is very large
+ --> $DIR/result_large_err.rs:24:26
+ |
+LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes
+ |
+ = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
+
+error: the `Err`-variant returned from this function is very large
+ --> $DIR/result_large_err.rs:29:45
+ |
+LL | pub fn large_err_via_type_alias<T>(x: T) -> Fdlr<T> {
+ | ^^^^^^^ the `Err`-variant is at least 240 bytes
+ |
+ = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
+
+error: the `Err`-variant returned from this function is very large
+ --> $DIR/result_large_err.rs:37:34
+ |
+LL | pub fn param_large_error<R>() -> Result<(), (u128, R, FullyDefinedLargeError)> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 256 bytes
+ |
+ = help: try reducing the size of `(u128, R, FullyDefinedLargeError)`, for example by boxing large elements or replacing it with `Box<(u128, R, FullyDefinedLargeError)>`
+
+error: the `Err`-variant returned from this function is very large
+ --> $DIR/result_large_err.rs:48:34
+ |
+LL | pub fn large_enum_error() -> Result<(), Self> {
+ | ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 513 bytes
+ |
+ = help: try reducing the size of `LargeErrorVariants<()>`, for example by boxing large elements or replacing it with `Box<LargeErrorVariants<()>>`
+
+error: the `Err`-variant returned from this function is very large
+ --> $DIR/result_large_err.rs:54:25
+ |
+LL | fn large_error() -> Result<(), [u8; 512]> {
+ | ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
+ |
+ = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>`
+
+error: the `Err`-variant returned from this function is very large
+ --> $DIR/result_large_err.rs:73:29
+ |
+LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
+ |
+ = help: try reducing the size of `FullyDefinedUnionError`, for example by boxing large elements or replacing it with `Box<FullyDefinedUnionError>`
+
+error: the `Err`-variant returned from this function is very large
+ --> $DIR/result_large_err.rs:82:40
+ |
+LL | pub fn param_large_union<T: Copy>() -> Result<(), UnionError<T>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
+ |
+ = help: try reducing the size of `UnionError<T>`, for example by boxing large elements or replacing it with `Box<UnionError<T>>`
+
+error: the `Err`-variant returned from this function is very large
+ --> $DIR/result_large_err.rs:91:34
+ |
+LL | pub fn array_error_subst<U>() -> Result<(), ArrayError<i32, U>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes
+ |
+ = help: try reducing the size of `ArrayError<i32, U>`, for example by boxing large elements or replacing it with `Box<ArrayError<i32, U>>`
+
+error: the `Err`-variant returned from this function is very large
+ --> $DIR/result_large_err.rs:95:31
+ |
+LL | pub fn array_error<T, U>() -> Result<(), ArrayError<(i32, T), U>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes
+ |
+ = help: try reducing the size of `ArrayError<(i32, T), U>`, for example by boxing large elements or replacing it with `Box<ArrayError<(i32, T), U>>`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed
index 14c331f67..d8b56237e 100644
--- a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed
+++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed
@@ -1,7 +1,7 @@
// run-rustfix
-
#![warn(clippy::result_map_unit_fn)]
#![allow(unused)]
+#![allow(clippy::uninlined_format_args)]
fn do_nothing<T>(_: T) {}
diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs
index 8b0fca9ec..44f50d211 100644
--- a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs
+++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs
@@ -1,7 +1,7 @@
// run-rustfix
-
#![warn(clippy::result_map_unit_fn)]
#![allow(unused)]
+#![allow(clippy::uninlined_format_args)]
fn do_nothing<T>(_: T) {}
diff --git a/src/tools/clippy/tests/ui/result_unit_error.stderr b/src/tools/clippy/tests/ui/result_unit_error.stderr
index 8c7573eab..8393a4bf0 100644
--- a/src/tools/clippy/tests/ui/result_unit_error.stderr
+++ b/src/tools/clippy/tests/ui/result_unit_error.stderr
@@ -4,8 +4,8 @@ error: this returns a `Result<_, ()>`
LL | pub fn returns_unit_error() -> Result<u32, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::result-unit-err` implied by `-D warnings`
= help: use a custom `Error` type instead
+ = note: `-D clippy::result-unit-err` implied by `-D warnings`
error: this returns a `Result<_, ()>`
--> $DIR/result_unit_error.rs:12:5
diff --git a/src/tools/clippy/tests/ui/return_self_not_must_use.stderr b/src/tools/clippy/tests/ui/return_self_not_must_use.stderr
index 94be87dfa..34932fe1c 100644
--- a/src/tools/clippy/tests/ui/return_self_not_must_use.stderr
+++ b/src/tools/clippy/tests/ui/return_self_not_must_use.stderr
@@ -4,8 +4,8 @@ error: missing `#[must_use]` attribute on a method returning `Self`
LL | fn what(&self) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::return-self-not-must-use` implied by `-D warnings`
= help: consider adding the `#[must_use]` attribute to the method or directly to the `Self` type
+ = note: `-D clippy::return-self-not-must-use` implied by `-D warnings`
error: missing `#[must_use]` attribute on a method returning `Self`
--> $DIR/return_self_not_must_use.rs:18:5
diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed
index 79e482eec..c67edb36c 100644
--- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed
+++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed
@@ -1,5 +1,6 @@
// run-rustfix
#![warn(clippy::reversed_empty_ranges)]
+#![allow(clippy::uninlined_format_args)]
const ANSWER: i32 = 42;
diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs
index b2e8bf337..0a4fef5bf 100644
--- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs
+++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs
@@ -1,5 +1,6 @@
// run-rustfix
#![warn(clippy::reversed_empty_ranges)]
+#![allow(clippy::uninlined_format_args)]
const ANSWER: i32 = 42;
diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr
index 2d1bfe62c..c2495ea95 100644
--- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr
+++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr
@@ -1,5 +1,5 @@
error: this range is empty so it will yield no values
- --> $DIR/reversed_empty_ranges_fixable.rs:9:5
+ --> $DIR/reversed_empty_ranges_fixable.rs:10:5
|
LL | (42..=21).for_each(|x| println!("{}", x));
| ^^^^^^^^^
@@ -11,7 +11,7 @@ LL | (21..=42).rev().for_each(|x| println!("{}", x));
| ~~~~~~~~~~~~~~~
error: this range is empty so it will yield no values
- --> $DIR/reversed_empty_ranges_fixable.rs:10:13
+ --> $DIR/reversed_empty_ranges_fixable.rs:11:13
|
LL | let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>();
| ^^^^^^^^^^^^
@@ -22,7 +22,7 @@ LL | let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect::<Ve
| ~~~~~~~~~~~~~~~~~~
error: this range is empty so it will yield no values
- --> $DIR/reversed_empty_ranges_fixable.rs:12:14
+ --> $DIR/reversed_empty_ranges_fixable.rs:13:14
|
LL | for _ in -21..=-42 {}
| ^^^^^^^^^
@@ -33,7 +33,7 @@ LL | for _ in (-42..=-21).rev() {}
| ~~~~~~~~~~~~~~~~~
error: this range is empty so it will yield no values
- --> $DIR/reversed_empty_ranges_fixable.rs:13:14
+ --> $DIR/reversed_empty_ranges_fixable.rs:14:14
|
LL | for _ in 42u32..21u32 {}
| ^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed
index f1503ed6d..78401e463 100644
--- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed
+++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed
@@ -1,5 +1,6 @@
// run-rustfix
#![warn(clippy::reversed_empty_ranges)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
const MAX_LEN: usize = 42;
diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.rs b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.rs
index a733788dc..f9e0f7fcd 100644
--- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.rs
+++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.rs
@@ -1,5 +1,6 @@
// run-rustfix
#![warn(clippy::reversed_empty_ranges)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
const MAX_LEN: usize = 42;
diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr
index a135da488..dfc52e64c 100644
--- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr
+++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr
@@ -1,5 +1,5 @@
error: this range is empty so it will yield no values
- --> $DIR/reversed_empty_ranges_loops_fixable.rs:7:14
+ --> $DIR/reversed_empty_ranges_loops_fixable.rs:8:14
|
LL | for i in 10..0 {
| ^^^^^
@@ -11,7 +11,7 @@ LL | for i in (0..10).rev() {
| ~~~~~~~~~~~~~
error: this range is empty so it will yield no values
- --> $DIR/reversed_empty_ranges_loops_fixable.rs:11:14
+ --> $DIR/reversed_empty_ranges_loops_fixable.rs:12:14
|
LL | for i in 10..=0 {
| ^^^^^^
@@ -22,7 +22,7 @@ LL | for i in (0..=10).rev() {
| ~~~~~~~~~~~~~~
error: this range is empty so it will yield no values
- --> $DIR/reversed_empty_ranges_loops_fixable.rs:15:14
+ --> $DIR/reversed_empty_ranges_loops_fixable.rs:16:14
|
LL | for i in MAX_LEN..0 {
| ^^^^^^^^^^
@@ -33,7 +33,7 @@ LL | for i in (0..MAX_LEN).rev() {
| ~~~~~~~~~~~~~~~~~~
error: this range is empty so it will yield no values
- --> $DIR/reversed_empty_ranges_loops_fixable.rs:34:14
+ --> $DIR/reversed_empty_ranges_loops_fixable.rs:35:14
|
LL | for i in (10..0).map(|x| x * 2) {
| ^^^^^^^
@@ -44,7 +44,7 @@ LL | for i in (0..10).rev().map(|x| x * 2) {
| ~~~~~~~~~~~~~
error: this range is empty so it will yield no values
- --> $DIR/reversed_empty_ranges_loops_fixable.rs:39:14
+ --> $DIR/reversed_empty_ranges_loops_fixable.rs:40:14
|
LL | for i in 10..5 + 4 {
| ^^^^^^^^^
@@ -55,7 +55,7 @@ LL | for i in (5 + 4..10).rev() {
| ~~~~~~~~~~~~~~~~~
error: this range is empty so it will yield no values
- --> $DIR/reversed_empty_ranges_loops_fixable.rs:43:14
+ --> $DIR/reversed_empty_ranges_loops_fixable.rs:44:14
|
LL | for i in (5 + 2)..(3 - 1) {
| ^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.rs b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.rs
index c4c572244..50264ef68 100644
--- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.rs
+++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.rs
@@ -1,4 +1,5 @@
#![warn(clippy::reversed_empty_ranges)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
for i in 5..5 {
diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.stderr
index 30095d20c..4490ff35f 100644
--- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.stderr
@@ -1,5 +1,5 @@
error: this range is empty so it will yield no values
- --> $DIR/reversed_empty_ranges_loops_unfixable.rs:4:14
+ --> $DIR/reversed_empty_ranges_loops_unfixable.rs:5:14
|
LL | for i in 5..5 {
| ^^^^
@@ -7,7 +7,7 @@ LL | for i in 5..5 {
= note: `-D clippy::reversed-empty-ranges` implied by `-D warnings`
error: this range is empty so it will yield no values
- --> $DIR/reversed_empty_ranges_loops_unfixable.rs:8:14
+ --> $DIR/reversed_empty_ranges_loops_unfixable.rs:9:14
|
LL | for i in (5 + 2)..(8 - 1) {
| ^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
index 3d2295912..e6198a1bc 100644
--- a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
+++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
@@ -1,8 +1,14 @@
#![feature(adt_const_params)]
-#![allow(incomplete_features)]
#![warn(clippy::same_functions_in_if_condition)]
-#![allow(clippy::ifs_same_cond)] // This warning is different from `ifs_same_cond`.
-#![allow(clippy::if_same_then_else, clippy::comparison_chain)] // all empty blocks
+// ifs_same_cond warning is different from `ifs_same_cond`.
+// clippy::if_same_then_else, clippy::comparison_chain -- all empty blocks
+#![allow(incomplete_features)]
+#![allow(
+ clippy::comparison_chain,
+ clippy::if_same_then_else,
+ clippy::ifs_same_cond,
+ clippy::uninlined_format_args
+)]
fn function() -> bool {
true
@@ -48,9 +54,9 @@ fn ifs_same_cond_fn() {
}
let mut v = vec![1];
- if v.pop() == None {
+ if v.pop().is_none() {
//~ ERROR ifs same condition
- } else if v.pop() == None {
+ } else if v.pop().is_none() {
}
if v.len() == 42 {
diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr b/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
index 71e82910e..f352ade15 100644
--- a/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
+++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
@@ -1,72 +1,72 @@
error: this `if` has the same function call as a previous `if`
- --> $DIR/same_functions_in_if_condition.rs:31:15
+ --> $DIR/same_functions_in_if_condition.rs:37:15
|
LL | } else if function() {
| ^^^^^^^^^^
|
- = note: `-D clippy::same-functions-in-if-condition` implied by `-D warnings`
note: same as this
- --> $DIR/same_functions_in_if_condition.rs:30:8
+ --> $DIR/same_functions_in_if_condition.rs:36:8
|
LL | if function() {
| ^^^^^^^^^^
+ = note: `-D clippy::same-functions-in-if-condition` implied by `-D warnings`
error: this `if` has the same function call as a previous `if`
- --> $DIR/same_functions_in_if_condition.rs:36:15
+ --> $DIR/same_functions_in_if_condition.rs:42:15
|
LL | } else if fn_arg(a) {
| ^^^^^^^^^
|
note: same as this
- --> $DIR/same_functions_in_if_condition.rs:35:8
+ --> $DIR/same_functions_in_if_condition.rs:41:8
|
LL | if fn_arg(a) {
| ^^^^^^^^^
error: this `if` has the same function call as a previous `if`
- --> $DIR/same_functions_in_if_condition.rs:41:15
+ --> $DIR/same_functions_in_if_condition.rs:47:15
|
LL | } else if obj.method() {
| ^^^^^^^^^^^^
|
note: same as this
- --> $DIR/same_functions_in_if_condition.rs:40:8
+ --> $DIR/same_functions_in_if_condition.rs:46:8
|
LL | if obj.method() {
| ^^^^^^^^^^^^
error: this `if` has the same function call as a previous `if`
- --> $DIR/same_functions_in_if_condition.rs:46:15
+ --> $DIR/same_functions_in_if_condition.rs:52:15
|
LL | } else if obj.method_arg(a) {
| ^^^^^^^^^^^^^^^^^
|
note: same as this
- --> $DIR/same_functions_in_if_condition.rs:45:8
+ --> $DIR/same_functions_in_if_condition.rs:51:8
|
LL | if obj.method_arg(a) {
| ^^^^^^^^^^^^^^^^^
error: this `if` has the same function call as a previous `if`
- --> $DIR/same_functions_in_if_condition.rs:53:15
+ --> $DIR/same_functions_in_if_condition.rs:59:15
|
-LL | } else if v.pop() == None {
- | ^^^^^^^^^^^^^^^
+LL | } else if v.pop().is_none() {
+ | ^^^^^^^^^^^^^^^^^
|
note: same as this
- --> $DIR/same_functions_in_if_condition.rs:51:8
+ --> $DIR/same_functions_in_if_condition.rs:57:8
|
-LL | if v.pop() == None {
- | ^^^^^^^^^^^^^^^
+LL | if v.pop().is_none() {
+ | ^^^^^^^^^^^^^^^^^
error: this `if` has the same function call as a previous `if`
- --> $DIR/same_functions_in_if_condition.rs:58:15
+ --> $DIR/same_functions_in_if_condition.rs:64:15
|
LL | } else if v.len() == 42 {
| ^^^^^^^^^^^^^
|
note: same as this
- --> $DIR/same_functions_in_if_condition.rs:56:8
+ --> $DIR/same_functions_in_if_condition.rs:62:8
|
LL | if v.len() == 42 {
| ^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/same_item_push.rs b/src/tools/clippy/tests/ui/same_item_push.rs
index 99964f0de..af01a8df7 100644
--- a/src/tools/clippy/tests/ui/same_item_push.rs
+++ b/src/tools/clippy/tests/ui/same_item_push.rs
@@ -151,6 +151,7 @@ fn main() {
// Fix #6987
let mut vec = Vec::new();
+ #[allow(clippy::needless_borrow)]
for _ in 0..10 {
vec.push(1);
vec.extend(&[2]);
diff --git a/src/tools/clippy/tests/ui/same_item_push.stderr b/src/tools/clippy/tests/ui/same_item_push.stderr
index d9ffa1578..1d1254d9f 100644
--- a/src/tools/clippy/tests/ui/same_item_push.stderr
+++ b/src/tools/clippy/tests/ui/same_item_push.stderr
@@ -4,8 +4,8 @@ error: it looks like the same item is being pushed into this Vec
LL | vec.push(item);
| ^^^
|
- = note: `-D clippy::same-item-push` implied by `-D warnings`
= help: try using vec![item;SIZE] or vec.resize(NEW_SIZE, item)
+ = note: `-D clippy::same-item-push` implied by `-D warnings`
error: it looks like the same item is being pushed into this Vec
--> $DIR/same_item_push.rs:29:9
diff --git a/src/tools/clippy/tests/ui/same_name_method.stderr b/src/tools/clippy/tests/ui/same_name_method.stderr
index f55ec9f3c..0c6908c09 100644
--- a/src/tools/clippy/tests/ui/same_name_method.stderr
+++ b/src/tools/clippy/tests/ui/same_name_method.stderr
@@ -4,12 +4,12 @@ error: method's name is the same as an existing method in a trait
LL | fn foo() {}
| ^^^^^^^^^^^
|
- = note: `-D clippy::same-name-method` implied by `-D warnings`
note: existing `foo` defined here
--> $DIR/same_name_method.rs:25:13
|
LL | fn foo() {}
| ^^^^^^^^^^^
+ = note: `-D clippy::same-name-method` implied by `-D warnings`
error: method's name is the same as an existing method in a trait
--> $DIR/same_name_method.rs:35:13
diff --git a/src/tools/clippy/tests/ui/search_is_some.stderr b/src/tools/clippy/tests/ui/search_is_some.stderr
index 54760545b..6bea8c674 100644
--- a/src/tools/clippy/tests/ui/search_is_some.stderr
+++ b/src/tools/clippy/tests/ui/search_is_some.stderr
@@ -8,8 +8,8 @@ LL | | }
LL | | ).is_some();
| |______________________________^
|
- = note: `-D clippy::search-is-some` implied by `-D warnings`
= help: this is more succinctly expressed by calling `any()`
+ = note: `-D clippy::search-is-some` implied by `-D warnings`
error: called `is_some()` after searching an `Iterator` with `position`
--> $DIR/search_is_some.rs:20:13
diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
index 91916e748..4ab7dbab5 100644
--- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
@@ -1,7 +1,5 @@
#![warn(clippy::semicolon_if_nothing_returned)]
-#![allow(clippy::redundant_closure)]
-#![feature(label_break_value)]
-#![feature(let_else)]
+#![allow(clippy::redundant_closure, clippy::uninlined_format_args)]
fn get_unit() {}
diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
index 41d2c1cfb..8d9a67585 100644
--- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
+++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
@@ -1,5 +1,5 @@
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:10:5
+ --> $DIR/semicolon_if_nothing_returned.rs:8:5
|
LL | println!("Hello")
| ^^^^^^^^^^^^^^^^^ help: add a `;` here: `println!("Hello");`
@@ -7,25 +7,25 @@ LL | println!("Hello")
= note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings`
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:14:5
+ --> $DIR/semicolon_if_nothing_returned.rs:12:5
|
LL | get_unit()
| ^^^^^^^^^^ help: add a `;` here: `get_unit();`
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:19:5
+ --> $DIR/semicolon_if_nothing_returned.rs:17:5
|
LL | y = x + 1
| ^^^^^^^^^ help: add a `;` here: `y = x + 1;`
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:25:9
+ --> $DIR/semicolon_if_nothing_returned.rs:23:9
|
LL | hello()
| ^^^^^^^ help: add a `;` here: `hello();`
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:36:9
+ --> $DIR/semicolon_if_nothing_returned.rs:34:9
|
LL | ptr::drop_in_place(s.as_mut_ptr())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `ptr::drop_in_place(s.as_mut_ptr());`
diff --git a/src/tools/clippy/tests/ui/shadow.stderr b/src/tools/clippy/tests/ui/shadow.stderr
index 43d76094d..c3d7bc2a5 100644
--- a/src/tools/clippy/tests/ui/shadow.stderr
+++ b/src/tools/clippy/tests/ui/shadow.stderr
@@ -4,12 +4,12 @@ error: `x` is shadowed by itself in `x`
LL | let x = x;
| ^
|
- = note: `-D clippy::shadow-same` implied by `-D warnings`
note: previous binding is here
--> $DIR/shadow.rs:5:9
|
LL | let x = 1;
| ^
+ = note: `-D clippy::shadow-same` implied by `-D warnings`
error: `mut x` is shadowed by itself in `&x`
--> $DIR/shadow.rs:7:13
@@ -53,12 +53,12 @@ error: `x` is shadowed
LL | let x = x.0;
| ^
|
- = note: `-D clippy::shadow-reuse` implied by `-D warnings`
note: previous binding is here
--> $DIR/shadow.rs:13:9
|
LL | let x = ([[0]], ());
| ^
+ = note: `-D clippy::shadow-reuse` implied by `-D warnings`
error: `x` is shadowed
--> $DIR/shadow.rs:15:9
@@ -150,12 +150,12 @@ error: `x` shadows a previous, unrelated binding
LL | let x = 2;
| ^
|
- = note: `-D clippy::shadow-unrelated` implied by `-D warnings`
note: previous binding is here
--> $DIR/shadow.rs:30:9
|
LL | let x = 1;
| ^
+ = note: `-D clippy::shadow-unrelated` implied by `-D warnings`
error: `x` shadows a previous, unrelated binding
--> $DIR/shadow.rs:36:13
diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr
index 2b7d4628c..161dd66b0 100644
--- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr
+++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr
@@ -6,8 +6,8 @@ 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
+ = note: `-D clippy::should-implement-trait` implied by `-D warnings`
error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut`
--> $DIR/method_list_1.rs:29:5
@@ -99,6 +99,16 @@ LL | | }
|
= help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name
+error: method `default` can be confused for the standard trait method `std::default::Default::default`
+ --> $DIR/method_list_1.rs:65:5
+ |
+LL | / pub fn default() -> Self {
+LL | | unimplemented!()
+LL | | }
+ | |_____^
+ |
+ = help: consider implementing the trait `std::default::Default` or choosing a less ambiguous method name
+
error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref`
--> $DIR/method_list_1.rs:69:5
|
@@ -139,5 +149,5 @@ LL | | }
|
= help: consider implementing the trait `std::ops::Drop` or choosing a less ambiguous method name
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
index b6fd43569..10bfea68f 100644
--- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
+++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
@@ -6,8 +6,8 @@ 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
+ = note: `-D clippy::should-implement-trait` implied by `-D warnings`
error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter`
--> $DIR/method_list_2.rs:30:5
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
index 84ecf1ea5..c65df9ece 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
@@ -1,11 +1,8 @@
// FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934
// // run-rustfix
-
#![warn(clippy::significant_drop_in_scrutinee)]
-#![allow(clippy::single_match)]
-#![allow(clippy::match_single_binding)]
-#![allow(unused_assignments)]
-#![allow(dead_code)]
+#![allow(dead_code, unused_assignments)]
+#![allow(clippy::match_single_binding, clippy::single_match, clippy::uninlined_format_args)]
use std::num::ParseIntError;
use std::ops::Deref;
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
index 88ea6bce2..75063a8c9 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
@@ -1,5 +1,5 @@
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:59:11
+ --> $DIR/significant_drop_in_scrutinee.rs:56:11
|
LL | match mutex.lock().unwrap().foo() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -10,8 +10,8 @@ LL | mutex.lock().unwrap().bar();
LL | };
| - temporary lives until here
|
- = note: `-D clippy::significant-drop-in-scrutinee` implied by `-D warnings`
= note: this might lead to deadlocks or other unexpected behavior
+ = note: `-D clippy::significant-drop-in-scrutinee` implied by `-D warnings`
help: try moving the temporary above the match
|
LL ~ let value = mutex.lock().unwrap().foo();
@@ -19,7 +19,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:145:11
+ --> $DIR/significant_drop_in_scrutinee.rs:142:11
|
LL | match s.lock_m().get_the_value() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -38,7 +38,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:166:11
+ --> $DIR/significant_drop_in_scrutinee.rs:163:11
|
LL | match s.lock_m_m().get_the_value() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -57,7 +57,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:214:11
+ --> $DIR/significant_drop_in_scrutinee.rs:211:11
|
LL | match counter.temp_increment().len() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:237:16
+ --> $DIR/significant_drop_in_scrutinee.rs:234:16
|
LL | match (mutex1.lock().unwrap().s.len(), true) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -92,7 +92,7 @@ LL ~ match (value, true) {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:246:22
+ --> $DIR/significant_drop_in_scrutinee.rs:243:22
|
LL | match (true, mutex1.lock().unwrap().s.len(), true) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -111,7 +111,7 @@ LL ~ match (true, value, true) {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:256:16
+ --> $DIR/significant_drop_in_scrutinee.rs:253:16
|
LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -132,7 +132,7 @@ LL ~ match (value, true, mutex2.lock().unwrap().s.len()) {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:256:54
+ --> $DIR/significant_drop_in_scrutinee.rs:253:54
|
LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -153,7 +153,7 @@ LL ~ match (mutex1.lock().unwrap().s.len(), true, value) {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:267:15
+ --> $DIR/significant_drop_in_scrutinee.rs:264:15
|
LL | match mutex3.lock().unwrap().s.as_str() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +169,7 @@ LL | };
= note: this might lead to deadlocks or other unexpected behavior
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:277:22
+ --> $DIR/significant_drop_in_scrutinee.rs:274:22
|
LL | match (true, mutex3.lock().unwrap().s.as_str()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -185,7 +185,7 @@ LL | };
= note: this might lead to deadlocks or other unexpected behavior
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:296:11
+ --> $DIR/significant_drop_in_scrutinee.rs:293:11
|
LL | match mutex.lock().unwrap().s.len() > 1 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -204,7 +204,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:303:11
+ --> $DIR/significant_drop_in_scrutinee.rs:300:11
|
LL | match 1 < mutex.lock().unwrap().s.len() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -223,7 +223,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:321:11
+ --> $DIR/significant_drop_in_scrutinee.rs:318:11
|
LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -244,7 +244,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:332:11
+ --> $DIR/significant_drop_in_scrutinee.rs:329:11
|
LL | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -265,7 +265,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:367:11
+ --> $DIR/significant_drop_in_scrutinee.rs:364:11
|
LL | match get_mutex_guard().s.len() > 1 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -284,7 +284,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:384:11
+ --> $DIR/significant_drop_in_scrutinee.rs:381:11
|
LL | match match i {
| ___________^
@@ -316,7 +316,7 @@ LL ~ match value
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:410:11
+ --> $DIR/significant_drop_in_scrutinee.rs:407:11
|
LL | match if i > 1 {
| ___________^
@@ -349,7 +349,7 @@ LL ~ match value
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:464:11
+ --> $DIR/significant_drop_in_scrutinee.rs:461:11
|
LL | match s.lock().deref().deref() {
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -367,7 +367,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:492:11
+ --> $DIR/significant_drop_in_scrutinee.rs:489:11
|
LL | match s.lock().deref().deref() {
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -380,7 +380,7 @@ LL | };
= note: this might lead to deadlocks or other unexpected behavior
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:511:11
+ --> $DIR/significant_drop_in_scrutinee.rs:508:11
|
LL | match mutex.lock().unwrap().i = i {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -399,7 +399,7 @@ LL ~ match () {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:517:11
+ --> $DIR/significant_drop_in_scrutinee.rs:514:11
|
LL | match i = mutex.lock().unwrap().i {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -418,7 +418,7 @@ LL ~ match () {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:523:11
+ --> $DIR/significant_drop_in_scrutinee.rs:520:11
|
LL | match mutex.lock().unwrap().i += 1 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -437,7 +437,7 @@ LL ~ match () {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:529:11
+ --> $DIR/significant_drop_in_scrutinee.rs:526:11
|
LL | match i += mutex.lock().unwrap().i {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -456,7 +456,7 @@ LL ~ match () {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:592:11
+ --> $DIR/significant_drop_in_scrutinee.rs:589:11
|
LL | match rwlock.read().unwrap().to_number() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -467,7 +467,7 @@ LL | };
= note: this might lead to deadlocks or other unexpected behavior
error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression
- --> $DIR/significant_drop_in_scrutinee.rs:602:14
+ --> $DIR/significant_drop_in_scrutinee.rs:599:14
|
LL | for s in rwlock.read().unwrap().iter() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -478,7 +478,7 @@ LL | }
= note: this might lead to deadlocks or other unexpected behavior
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:617:11
+ --> $DIR/significant_drop_in_scrutinee.rs:614:11
|
LL | match mutex.lock().unwrap().foo() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/similar_names.stderr b/src/tools/clippy/tests/ui/similar_names.stderr
index 6e7726938..43c5cee4b 100644
--- a/src/tools/clippy/tests/ui/similar_names.stderr
+++ b/src/tools/clippy/tests/ui/similar_names.stderr
@@ -4,12 +4,12 @@ error: binding's name is too similar to existing binding
LL | let bpple: i32;
| ^^^^^
|
- = note: `-D clippy::similar-names` implied by `-D warnings`
note: existing binding defined here
--> $DIR/similar_names.rs:19:9
|
LL | let apple: i32;
| ^^^^^
+ = note: `-D clippy::similar-names` implied by `-D warnings`
error: binding's name is too similar to existing binding
--> $DIR/similar_names.rs:23:9
diff --git a/src/tools/clippy/tests/ui/single_char_lifetime_names.stderr b/src/tools/clippy/tests/ui/single_char_lifetime_names.stderr
index 1438b3999..bfe6d44b5 100644
--- a/src/tools/clippy/tests/ui/single_char_lifetime_names.stderr
+++ b/src/tools/clippy/tests/ui/single_char_lifetime_names.stderr
@@ -4,8 +4,8 @@ error: single-character lifetime names are likely uninformative
LL | struct DiagnosticCtx<'a, 'b>
| ^^
|
- = note: `-D clippy::single-char-lifetime-names` implied by `-D warnings`
= help: use a more informative name
+ = note: `-D clippy::single-char-lifetime-names` implied by `-D warnings`
error: single-character lifetime names are likely uninformative
--> $DIR/single_char_lifetime_names.rs:5:26
diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr
index cf990be1b..633546f64 100644
--- a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr
+++ b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr
@@ -4,8 +4,8 @@ error: this import is redundant
LL | use {regex, serde};
| ^^^^^
|
- = note: `-D clippy::single-component-path-imports` implied by `-D warnings`
= help: remove this import
+ = note: `-D clippy::single-component-path-imports` implied by `-D warnings`
error: this import is redundant
--> $DIR/single_component_path_imports_nested_first.rs:13:17
diff --git a/src/tools/clippy/tests/ui/single_match.rs b/src/tools/clippy/tests/ui/single_match.rs
index dd148edf5..d0c9b7b56 100644
--- a/src/tools/clippy/tests/ui/single_match.rs
+++ b/src/tools/clippy/tests/ui/single_match.rs
@@ -1,4 +1,5 @@
#![warn(clippy::single_match)]
+#![allow(clippy::uninlined_format_args)]
fn dummy() {}
diff --git a/src/tools/clippy/tests/ui/single_match.stderr b/src/tools/clippy/tests/ui/single_match.stderr
index 4d2b9ec5f..7cecc1b73 100644
--- a/src/tools/clippy/tests/ui/single_match.stderr
+++ b/src/tools/clippy/tests/ui/single_match.stderr
@@ -1,5 +1,5 @@
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:8:5
+ --> $DIR/single_match.rs:9:5
|
LL | / match x {
LL | | Some(y) => {
@@ -18,7 +18,7 @@ LL ~ };
|
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:16:5
+ --> $DIR/single_match.rs:17:5
|
LL | / match x {
LL | | // Note the missing block braces.
@@ -30,7 +30,7 @@ LL | | }
| |_____^ help: try this: `if let Some(y) = x { println!("{:?}", y) }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:25:5
+ --> $DIR/single_match.rs:26:5
|
LL | / match z {
LL | | (2..=3, 7..=9) => dummy(),
@@ -39,7 +39,7 @@ LL | | };
| |_____^ help: try this: `if let (2..=3, 7..=9) = z { dummy() }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:54:5
+ --> $DIR/single_match.rs:55:5
|
LL | / match x {
LL | | Some(y) => dummy(),
@@ -48,7 +48,7 @@ LL | | };
| |_____^ help: try this: `if let Some(y) = x { dummy() }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:59:5
+ --> $DIR/single_match.rs:60:5
|
LL | / match y {
LL | | Ok(y) => dummy(),
@@ -57,7 +57,7 @@ LL | | };
| |_____^ help: try this: `if let Ok(y) = y { dummy() }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:66:5
+ --> $DIR/single_match.rs:67:5
|
LL | / match c {
LL | | Cow::Borrowed(..) => dummy(),
@@ -66,7 +66,7 @@ LL | | };
| |_____^ help: try this: `if let Cow::Borrowed(..) = c { dummy() }`
error: you seem to be trying to use `match` for an equality check. Consider using `if`
- --> $DIR/single_match.rs:87:5
+ --> $DIR/single_match.rs:88:5
|
LL | / match x {
LL | | "test" => println!(),
@@ -75,7 +75,7 @@ LL | | }
| |_____^ help: try this: `if x == "test" { println!() }`
error: you seem to be trying to use `match` for an equality check. Consider using `if`
- --> $DIR/single_match.rs:100:5
+ --> $DIR/single_match.rs:101:5
|
LL | / match x {
LL | | Foo::A => println!(),
@@ -84,7 +84,7 @@ LL | | }
| |_____^ help: try this: `if x == Foo::A { println!() }`
error: you seem to be trying to use `match` for an equality check. Consider using `if`
- --> $DIR/single_match.rs:106:5
+ --> $DIR/single_match.rs:107:5
|
LL | / match x {
LL | | FOO_C => println!(),
@@ -93,7 +93,7 @@ LL | | }
| |_____^ help: try this: `if x == FOO_C { println!() }`
error: you seem to be trying to use `match` for an equality check. Consider using `if`
- --> $DIR/single_match.rs:111:5
+ --> $DIR/single_match.rs:112:5
|
LL | / match &&x {
LL | | Foo::A => println!(),
@@ -102,7 +102,7 @@ LL | | }
| |_____^ help: try this: `if x == Foo::A { println!() }`
error: you seem to be trying to use `match` for an equality check. Consider using `if`
- --> $DIR/single_match.rs:117:5
+ --> $DIR/single_match.rs:118:5
|
LL | / match &x {
LL | | Foo::A => println!(),
@@ -111,7 +111,7 @@ LL | | }
| |_____^ help: try this: `if x == &Foo::A { println!() }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:134:5
+ --> $DIR/single_match.rs:135:5
|
LL | / match x {
LL | | Bar::A => println!(),
@@ -120,7 +120,7 @@ LL | | }
| |_____^ help: try this: `if let Bar::A = x { println!() }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:142:5
+ --> $DIR/single_match.rs:143:5
|
LL | / match x {
LL | | None => println!(),
@@ -129,7 +129,7 @@ LL | | };
| |_____^ help: try this: `if let None = x { println!() }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:164:5
+ --> $DIR/single_match.rs:165:5
|
LL | / match x {
LL | | (Some(_), _) => {},
@@ -138,7 +138,7 @@ LL | | }
| |_____^ help: try this: `if let (Some(_), _) = x {}`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:170:5
+ --> $DIR/single_match.rs:171:5
|
LL | / match x {
LL | | (Some(E::V), _) => todo!(),
@@ -147,7 +147,7 @@ LL | | }
| |_____^ help: try this: `if let (Some(E::V), _) = x { todo!() }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:176:5
+ --> $DIR/single_match.rs:177:5
|
LL | / match (Some(42), Some(E::V), Some(42)) {
LL | | (.., Some(E::V), _) => {},
diff --git a/src/tools/clippy/tests/ui/single_match_else.rs b/src/tools/clippy/tests/ui/single_match_else.rs
index 70d6febb7..5d03f77e9 100644
--- a/src/tools/clippy/tests/ui/single_match_else.rs
+++ b/src/tools/clippy/tests/ui/single_match_else.rs
@@ -1,8 +1,6 @@
// aux-build: proc_macro_with_span.rs
-
#![warn(clippy::single_match_else)]
-#![allow(clippy::needless_return)]
-#![allow(clippy::no_effect)]
+#![allow(clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)]
extern crate proc_macro_with_span;
use proc_macro_with_span::with_span;
diff --git a/src/tools/clippy/tests/ui/single_match_else.stderr b/src/tools/clippy/tests/ui/single_match_else.stderr
index 38fd9c6a6..62876a55d 100644
--- a/src/tools/clippy/tests/ui/single_match_else.stderr
+++ b/src/tools/clippy/tests/ui/single_match_else.stderr
@@ -1,5 +1,5 @@
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match_else.rs:19:13
+ --> $DIR/single_match_else.rs:17:13
|
LL | let _ = match ExprNode::Butterflies {
| _____________^
@@ -21,7 +21,7 @@ LL ~ };
|
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match_else.rs:84:5
+ --> $DIR/single_match_else.rs:82:5
|
LL | / match Some(1) {
LL | | Some(a) => println!("${:?}", a),
@@ -41,7 +41,7 @@ LL + }
|
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match_else.rs:93:5
+ --> $DIR/single_match_else.rs:91:5
|
LL | / match Some(1) {
LL | | Some(a) => println!("${:?}", a),
@@ -61,7 +61,7 @@ LL + }
|
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match_else.rs:103:5
+ --> $DIR/single_match_else.rs:101:5
|
LL | / match Result::<i32, Infallible>::Ok(1) {
LL | | Ok(a) => println!("${:?}", a),
@@ -81,7 +81,7 @@ LL + }
|
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match_else.rs:112:5
+ --> $DIR/single_match_else.rs:110:5
|
LL | / match Cow::from("moo") {
LL | | Cow::Owned(a) => println!("${:?}", a),
diff --git a/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.stderr b/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.stderr
index 0f0dff57f..037f695f3 100644
--- a/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.stderr
+++ b/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.stderr
@@ -4,8 +4,8 @@ error: found a count of bytes instead of a count of elements of `T`
LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>() * SIZE) };
| ^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::size-of-in-element-count` implied by `-D warnings`
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
+ = note: `-D clippy::size-of-in-element-count` implied by `-D warnings`
error: found a count of bytes instead of a count of elements of `T`
--> $DIR/expressions.rs:18:62
diff --git a/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr b/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr
index c1e824167..4351e6a14 100644
--- a/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr
+++ b/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr
@@ -4,8 +4,8 @@ error: found a count of bytes instead of a count of elements of `T`
LL | unsafe { copy_nonoverlapping::<u8>(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>()) };
| ^^^^^^^^^^^^^^^
|
- = note: `-D clippy::size-of-in-element-count` implied by `-D warnings`
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
+ = note: `-D clippy::size-of-in-element-count` implied by `-D warnings`
error: found a count of bytes instead of a count of elements of `T`
--> $DIR/functions.rs:19:62
diff --git a/src/tools/clippy/tests/ui/skip_while_next.rs b/src/tools/clippy/tests/ui/skip_while_next.rs
index a522c0f08..a551c19d9 100644
--- a/src/tools/clippy/tests/ui/skip_while_next.rs
+++ b/src/tools/clippy/tests/ui/skip_while_next.rs
@@ -1,7 +1,7 @@
// aux-build:option_helpers.rs
#![warn(clippy::skip_while_next)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
extern crate option_helpers;
use option_helpers::IteratorFalsePositives;
diff --git a/src/tools/clippy/tests/ui/skip_while_next.stderr b/src/tools/clippy/tests/ui/skip_while_next.stderr
index 269cc1346..7308ab4e5 100644
--- a/src/tools/clippy/tests/ui/skip_while_next.stderr
+++ b/src/tools/clippy/tests/ui/skip_while_next.stderr
@@ -4,8 +4,8 @@ error: called `skip_while(<p>).next()` on an `Iterator`
LL | let _ = v.iter().skip_while(|&x| *x < 0).next();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::skip-while-next` implied by `-D warnings`
= help: this is more succinctly expressed by calling `.find(!<p>)` instead
+ = note: `-D clippy::skip-while-next` implied by `-D warnings`
error: called `skip_while(<p>).next()` on an `Iterator`
--> $DIR/skip_while_next.rs:17:13
diff --git a/src/tools/clippy/tests/ui/stable_sort_primitive.stderr b/src/tools/clippy/tests/ui/stable_sort_primitive.stderr
index c35e0c22a..1432fdcff 100644
--- a/src/tools/clippy/tests/ui/stable_sort_primitive.stderr
+++ b/src/tools/clippy/tests/ui/stable_sort_primitive.stderr
@@ -4,8 +4,8 @@ error: used `sort` on primitive type `i32`
LL | vec.sort();
| ^^^^^^^^^^ help: try: `vec.sort_unstable()`
|
- = note: `-D clippy::stable-sort-primitive` implied by `-D warnings`
= note: an unstable sort typically performs faster without any observable difference for this data type
+ = note: `-D clippy::stable-sort-primitive` implied by `-D warnings`
error: used `sort` on primitive type `bool`
--> $DIR/stable_sort_primitive.rs:9:5
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.rs b/src/tools/clippy/tests/ui/std_instead_of_core.rs
index 6b27475de..75b114ba0 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.rs
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs
@@ -24,6 +24,12 @@ fn std_instead_of_core() {
let cell_absolute = ::std::cell::Cell::new(8u32);
let _ = std::env!("PATH");
+
+ // do not lint until `error_in_core` is stable
+ use std::error::Error;
+
+ // lint items re-exported from private modules, `core::iter::traits::iterator::Iterator`
+ use std::iter::Iterator;
}
#[warn(clippy::std_instead_of_alloc)]
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.stderr b/src/tools/clippy/tests/ui/std_instead_of_core.stderr
index bc49dabf5..d21024973 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.stderr
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.stderr
@@ -4,8 +4,8 @@ error: used import from `std` instead of `core`
LL | use std::hash::Hasher;
| ^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::std-instead-of-core` implied by `-D warnings`
= help: consider importing the item from `core`
+ = note: `-D clippy::std-instead-of-core` implied by `-D warnings`
error: used import from `std` instead of `core`
--> $DIR/std_instead_of_core.rs:11:9
@@ -63,17 +63,25 @@ LL | let cell_absolute = ::std::cell::Cell::new(8u32);
|
= help: consider importing the item from `core`
-error: used import from `std` instead of `alloc`
+error: used import from `std` instead of `core`
--> $DIR/std_instead_of_core.rs:32:9
|
+LL | use std::iter::Iterator;
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider importing the item from `core`
+
+error: used import from `std` instead of `alloc`
+ --> $DIR/std_instead_of_core.rs:38:9
+ |
LL | use std::vec;
| ^^^^^^^^
|
- = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings`
= help: consider importing the item from `alloc`
+ = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings`
error: used import from `std` instead of `alloc`
- --> $DIR/std_instead_of_core.rs:33:9
+ --> $DIR/std_instead_of_core.rs:39:9
|
LL | use std::vec::Vec;
| ^^^^^^^^^^^^^
@@ -81,13 +89,13 @@ LL | use std::vec::Vec;
= help: consider importing the item from `alloc`
error: used import from `alloc` instead of `core`
- --> $DIR/std_instead_of_core.rs:38:9
+ --> $DIR/std_instead_of_core.rs:44:9
|
LL | use alloc::slice::from_ref;
| ^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings`
= help: consider importing the item from `core`
+ = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings`
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/str_to_string.stderr b/src/tools/clippy/tests/ui/str_to_string.stderr
index b1f73eda5..1d47da571 100644
--- a/src/tools/clippy/tests/ui/str_to_string.stderr
+++ b/src/tools/clippy/tests/ui/str_to_string.stderr
@@ -4,8 +4,8 @@ error: `to_string()` called on a `&str`
LL | let hello = "hello world".to_string();
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::str-to-string` implied by `-D warnings`
= help: consider using `.to_owned()`
+ = note: `-D clippy::str-to-string` implied by `-D warnings`
error: `to_string()` called on a `&str`
--> $DIR/str_to_string.rs:6:5
diff --git a/src/tools/clippy/tests/ui/string_add.rs b/src/tools/clippy/tests/ui/string_add.rs
index 30fd17c59..16673c01e 100644
--- a/src/tools/clippy/tests/ui/string_add.rs
+++ b/src/tools/clippy/tests/ui/string_add.rs
@@ -7,13 +7,13 @@ extern crate macro_rules;
#[allow(clippy::string_add_assign, unused)]
fn main() {
// ignores assignment distinction
- let mut x = "".to_owned();
+ let mut x = String::new();
for _ in 1..3 {
x = x + ".";
}
- let y = "".to_owned();
+ let y = String::new();
let z = y + "...";
assert_eq!(&x, &z);
diff --git a/src/tools/clippy/tests/ui/string_add_assign.fixed b/src/tools/clippy/tests/ui/string_add_assign.fixed
index db71bab1e..b687f43b2 100644
--- a/src/tools/clippy/tests/ui/string_add_assign.fixed
+++ b/src/tools/clippy/tests/ui/string_add_assign.fixed
@@ -4,13 +4,13 @@
#[warn(clippy::string_add_assign)]
fn main() {
// ignores assignment distinction
- let mut x = "".to_owned();
+ let mut x = String::new();
for _ in 1..3 {
x += ".";
}
- let y = "".to_owned();
+ let y = String::new();
let z = y + "...";
assert_eq!(&x, &z);
diff --git a/src/tools/clippy/tests/ui/string_add_assign.rs b/src/tools/clippy/tests/ui/string_add_assign.rs
index 644991945..e5dbde108 100644
--- a/src/tools/clippy/tests/ui/string_add_assign.rs
+++ b/src/tools/clippy/tests/ui/string_add_assign.rs
@@ -4,13 +4,13 @@
#[warn(clippy::string_add_assign)]
fn main() {
// ignores assignment distinction
- let mut x = "".to_owned();
+ let mut x = String::new();
for _ in 1..3 {
x = x + ".";
}
- let y = "".to_owned();
+ let y = String::new();
let z = y + "...";
assert_eq!(&x, &z);
diff --git a/src/tools/clippy/tests/ui/string_to_string.stderr b/src/tools/clippy/tests/ui/string_to_string.stderr
index 1ebd17999..e304c3e34 100644
--- a/src/tools/clippy/tests/ui/string_to_string.stderr
+++ b/src/tools/clippy/tests/ui/string_to_string.stderr
@@ -4,8 +4,8 @@ error: `to_string()` called on a `String`
LL | let mut v = message.to_string();
| ^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::string-to-string` implied by `-D warnings`
= help: consider using `.clone()`
+ = note: `-D clippy::string-to-string` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/struct_excessive_bools.stderr b/src/tools/clippy/tests/ui/struct_excessive_bools.stderr
index 2941bf298..e4d50043a 100644
--- a/src/tools/clippy/tests/ui/struct_excessive_bools.stderr
+++ b/src/tools/clippy/tests/ui/struct_excessive_bools.stderr
@@ -9,8 +9,8 @@ LL | | d: bool,
LL | | }
| |_^
|
- = note: `-D clippy::struct-excessive-bools` implied by `-D warnings`
= help: consider using a state machine or refactoring bools into two-variant enums
+ = note: `-D clippy::struct-excessive-bools` implied by `-D warnings`
error: more than 3 bools in a struct
--> $DIR/struct_excessive_bools.rs:38:5
diff --git a/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr b/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr
index ee68eb5a7..2e512b47f 100644
--- a/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr
@@ -4,8 +4,8 @@ error: this looks like an `else {..}` but the `else` is missing
LL | } {
| ^
|
- = note: `-D clippy::suspicious-else-formatting` implied by `-D warnings`
= note: to remove this lint, add the missing `else` or add a new line before the next block
+ = note: `-D clippy::suspicious-else-formatting` implied by `-D warnings`
error: this looks like an `else if` but the `else` is missing
--> $DIR/suspicious_else_formatting.rs:21:6
diff --git a/src/tools/clippy/tests/ui/suspicious_map.stderr b/src/tools/clippy/tests/ui/suspicious_map.stderr
index 3ffcd1a90..e25167481 100644
--- a/src/tools/clippy/tests/ui/suspicious_map.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_map.stderr
@@ -4,8 +4,8 @@ error: this call to `map()` won't have an effect on the call to `count()`
LL | let _ = (0..3).map(|x| x + 2).count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::suspicious-map` implied by `-D warnings`
= help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect`
+ = note: `-D clippy::suspicious-map` implied by `-D warnings`
error: this call to `map()` won't have an effect on the call to `count()`
--> $DIR/suspicious_map.rs:7:13
diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.stderr b/src/tools/clippy/tests/ui/suspicious_splitn.stderr
index 3bcd681fa..55ce63d4f 100644
--- a/src/tools/clippy/tests/ui/suspicious_splitn.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_splitn.stderr
@@ -4,8 +4,8 @@ error: `splitn` called with `0` splits
LL | let _ = "a,b".splitn(0, ',');
| ^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::suspicious-splitn` implied by `-D warnings`
= note: the resulting iterator will always return `None`
+ = note: `-D clippy::suspicious-splitn` implied by `-D warnings`
error: `rsplitn` called with `0` splits
--> $DIR/suspicious_splitn.rs:11:13
diff --git a/src/tools/clippy/tests/ui/suspicious_to_owned.rs b/src/tools/clippy/tests/ui/suspicious_to_owned.rs
new file mode 100644
index 000000000..cba21bf4a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_to_owned.rs
@@ -0,0 +1,62 @@
+#![warn(clippy::suspicious_to_owned)]
+#![warn(clippy::implicit_clone)]
+#![allow(clippy::redundant_clone)]
+use std::borrow::Cow;
+use std::ffi::{c_char, CStr};
+
+fn main() {
+ let moo = "Moooo";
+ let c_moo = b"Moooo\0";
+ let c_moo_ptr = c_moo.as_ptr() as *const c_char;
+ let moos = ['M', 'o', 'o'];
+ let moos_vec = moos.to_vec();
+
+ // we expect this to be linted
+ let cow = Cow::Borrowed(moo);
+ let _ = cow.to_owned();
+ // we expect no lints for this
+ let cow = Cow::Borrowed(moo);
+ let _ = cow.into_owned();
+ // we expect no lints for this
+ let cow = Cow::Borrowed(moo);
+ let _ = cow.clone();
+
+ // we expect this to be linted
+ let cow = Cow::Borrowed(&moos);
+ let _ = cow.to_owned();
+ // we expect no lints for this
+ let cow = Cow::Borrowed(&moos);
+ let _ = cow.into_owned();
+ // we expect no lints for this
+ let cow = Cow::Borrowed(&moos);
+ let _ = cow.clone();
+
+ // we expect this to be linted
+ let cow = Cow::Borrowed(&moos_vec);
+ let _ = cow.to_owned();
+ // we expect no lints for this
+ let cow = Cow::Borrowed(&moos_vec);
+ let _ = cow.into_owned();
+ // we expect no lints for this
+ let cow = Cow::Borrowed(&moos_vec);
+ let _ = cow.clone();
+
+ // we expect this to be linted
+ let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy();
+ let _ = cow.to_owned();
+ // we expect no lints for this
+ let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy();
+ let _ = cow.into_owned();
+ // we expect no lints for this
+ let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy();
+ let _ = cow.clone();
+
+ // we expect no lints for these
+ let _ = moo.to_owned();
+ let _ = c_moo.to_owned();
+ let _ = moos.to_owned();
+
+ // we expect implicit_clone lints for these
+ let _ = String::from(moo).to_owned();
+ let _ = moos_vec.to_owned();
+}
diff --git a/src/tools/clippy/tests/ui/suspicious_to_owned.stderr b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr
new file mode 100644
index 000000000..ae1aec34d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr
@@ -0,0 +1,42 @@
+error: this `to_owned` call clones the std::borrow::Cow<'_, str> itself and does not cause the std::borrow::Cow<'_, str> contents to become owned
+ --> $DIR/suspicious_to_owned.rs:16:13
+ |
+LL | let _ = cow.to_owned();
+ | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+ |
+ = note: `-D clippy::suspicious-to-owned` implied by `-D warnings`
+
+error: this `to_owned` call clones the std::borrow::Cow<'_, [char; 3]> itself and does not cause the std::borrow::Cow<'_, [char; 3]> contents to become owned
+ --> $DIR/suspicious_to_owned.rs:26:13
+ |
+LL | let _ = cow.to_owned();
+ | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+
+error: this `to_owned` call clones the std::borrow::Cow<'_, std::vec::Vec<char>> itself and does not cause the std::borrow::Cow<'_, std::vec::Vec<char>> contents to become owned
+ --> $DIR/suspicious_to_owned.rs:36:13
+ |
+LL | let _ = cow.to_owned();
+ | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+
+error: this `to_owned` call clones the std::borrow::Cow<'_, str> itself and does not cause the std::borrow::Cow<'_, str> contents to become owned
+ --> $DIR/suspicious_to_owned.rs:46:13
+ |
+LL | let _ = cow.to_owned();
+ | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+
+error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type
+ --> $DIR/suspicious_to_owned.rs:60:13
+ |
+LL | let _ = String::from(moo).to_owned();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::from(moo).clone()`
+ |
+ = note: `-D clippy::implicit-clone` implied by `-D warnings`
+
+error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type
+ --> $DIR/suspicious_to_owned.rs:61:13
+ |
+LL | let _ = moos_vec.to_owned();
+ | ^^^^^^^^^^^^^^^^^^^ help: consider using: `moos_vec.clone()`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr b/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr
index 581527dcf..9f1289ccb 100644
--- a/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr
@@ -4,8 +4,8 @@ error: by not having a space between `>` and `-` it looks like `>-` is a single
LL | if a >- 30 {}
| ^^^^
|
- = note: `-D clippy::suspicious-unary-op-formatting` implied by `-D warnings`
= help: put a space between `>` and `-` and remove the space after `-`
+ = note: `-D clippy::suspicious-unary-op-formatting` implied by `-D warnings`
error: by not having a space between `>=` and `-` it looks like `>=-` is a single operator
--> $DIR/suspicious_unary_op_formatting.rs:9:9
diff --git a/src/tools/clippy/tests/ui/swap.fixed b/src/tools/clippy/tests/ui/swap.fixed
index 3329efbd4..24b229235 100644
--- a/src/tools/clippy/tests/ui/swap.fixed
+++ b/src/tools/clippy/tests/ui/swap.fixed
@@ -2,7 +2,7 @@
#![warn(clippy::all)]
#![allow(
- clippy::blacklisted_name,
+ clippy::disallowed_names,
clippy::no_effect,
clippy::redundant_clone,
redundant_semicolons,
diff --git a/src/tools/clippy/tests/ui/swap.rs b/src/tools/clippy/tests/ui/swap.rs
index 8179ac1f2..a318c2791 100644
--- a/src/tools/clippy/tests/ui/swap.rs
+++ b/src/tools/clippy/tests/ui/swap.rs
@@ -2,7 +2,7 @@
#![warn(clippy::all)]
#![allow(
- clippy::blacklisted_name,
+ clippy::disallowed_names,
clippy::no_effect,
clippy::redundant_clone,
redundant_semicolons,
diff --git a/src/tools/clippy/tests/ui/swap.stderr b/src/tools/clippy/tests/ui/swap.stderr
index 2b556b475..ee4b7a508 100644
--- a/src/tools/clippy/tests/ui/swap.stderr
+++ b/src/tools/clippy/tests/ui/swap.stderr
@@ -6,8 +6,8 @@ LL | | bar.a = bar.b;
LL | | bar.b = temp;
| |________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b)`
|
- = note: `-D clippy::manual-swap` implied by `-D warnings`
= note: or maybe you should use `std::mem::replace`?
+ = note: `-D clippy::manual-swap` implied by `-D warnings`
error: this looks like you are swapping elements of `foo` manually
--> $DIR/swap.rs:36:5
@@ -96,8 +96,8 @@ LL | / a = b;
LL | | b = a;
| |_________^ help: try: `std::mem::swap(&mut a, &mut b)`
|
- = note: `-D clippy::almost-swapped` implied by `-D warnings`
= note: or maybe you should use `std::mem::replace`?
+ = note: `-D clippy::almost-swapped` implied by `-D warnings`
error: this looks like you are trying to swap `c.0` and `a`
--> $DIR/swap.rs:140:5
diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed b/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed
index b129d95c5..09fb66ca3 100644
--- a/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed
+++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed
@@ -1,7 +1,7 @@
// run-rustfix
// aux-build:macro_rules.rs
-
#![warn(clippy::toplevel_ref_arg)]
+#![allow(clippy::uninlined_format_args)]
#[macro_use]
extern crate macro_rules;
diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.rs b/src/tools/clippy/tests/ui/toplevel_ref_arg.rs
index 73eb4ff73..9d1f2f810 100644
--- a/src/tools/clippy/tests/ui/toplevel_ref_arg.rs
+++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.rs
@@ -1,7 +1,7 @@
// run-rustfix
// aux-build:macro_rules.rs
-
#![warn(clippy::toplevel_ref_arg)]
+#![allow(clippy::uninlined_format_args)]
#[macro_use]
extern crate macro_rules;
diff --git a/src/tools/clippy/tests/ui/trailing_empty_array.stderr b/src/tools/clippy/tests/ui/trailing_empty_array.stderr
index 9e2bd31d9..2e1484400 100644
--- a/src/tools/clippy/tests/ui/trailing_empty_array.stderr
+++ b/src/tools/clippy/tests/ui/trailing_empty_array.stderr
@@ -7,8 +7,8 @@ LL | | last: [usize; 0],
LL | | }
| |_^
|
- = note: `-D clippy::trailing-empty-array` implied by `-D warnings`
= help: consider annotating `RarelyUseful` with `#[repr(C)]` or another `repr` attribute
+ = note: `-D clippy::trailing-empty-array` implied by `-D warnings`
error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
--> $DIR/trailing_empty_array.rs:10:1
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed
new file mode 100644
index 000000000..4ce5d4217
--- /dev/null
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed
@@ -0,0 +1,112 @@
+// run-rustfix
+#![deny(clippy::trait_duplication_in_bounds)]
+#![allow(unused)]
+
+fn bad_foo<T: Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
+ unimplemented!();
+}
+
+fn bad_bar<T, U>(arg0: T, arg1: U)
+where
+ T: Clone + Copy,
+ U: Clone + Copy,
+{
+ unimplemented!();
+}
+
+fn good_bar<T: Clone + Copy, U: Clone + Copy>(arg0: T, arg1: U) {
+ unimplemented!();
+}
+
+fn good_foo<T, U>(arg0: T, arg1: U)
+where
+ T: Clone + Copy,
+ U: Clone + Copy,
+{
+ unimplemented!();
+}
+
+trait GoodSelfTraitBound: Clone + Copy {
+ fn f();
+}
+
+trait GoodSelfWhereClause {
+ fn f()
+ where
+ Self: Clone + Copy;
+}
+
+trait BadSelfTraitBound: Clone {
+ fn f();
+}
+
+trait BadSelfWhereClause {
+ fn f()
+ where
+ Self: Clone;
+}
+
+trait GoodTraitBound<T: Clone + Copy, U: Clone + Copy> {
+ fn f();
+}
+
+trait GoodWhereClause<T, U> {
+ fn f()
+ where
+ T: Clone + Copy,
+ U: Clone + Copy;
+}
+
+trait BadTraitBound<T: Clone + Copy, U: Clone + Copy> {
+ fn f();
+}
+
+trait BadWhereClause<T, U> {
+ fn f()
+ where
+ T: Clone + Copy,
+ U: Clone + Copy;
+}
+
+struct GoodStructBound<T: Clone + Copy, U: Clone + Copy> {
+ t: T,
+ u: U,
+}
+
+impl<T: Clone + Copy, U: Clone + Copy> GoodTraitBound<T, U> for GoodStructBound<T, U> {
+ // this should not warn
+ fn f() {}
+}
+
+struct GoodStructWhereClause;
+
+impl<T, U> GoodTraitBound<T, U> for GoodStructWhereClause
+where
+ T: Clone + Copy,
+ U: Clone + Copy,
+{
+ // this should not warn
+ fn f() {}
+}
+
+fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {}
+
+trait GenericTrait<T> {}
+
+fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
+ unimplemented!();
+}
+
+fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
+ unimplemented!();
+}
+
+mod foo {
+ pub trait Clone {}
+}
+
+fn qualified_path<T: std::clone::Clone + foo::Clone>(arg0: T) {
+ unimplemented!();
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
index a5751c58a..7f2e96a22 100644
--- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
@@ -1,212 +1,112 @@
+// run-rustfix
#![deny(clippy::trait_duplication_in_bounds)]
#![allow(unused)]
-use std::collections::BTreeMap;
-use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
+fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
+ unimplemented!();
+}
-fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+fn bad_bar<T, U>(arg0: T, arg1: U)
where
- T: Clone,
- T: Default,
+ T: Clone + Clone + Clone + Copy,
+ U: Clone + Copy,
{
unimplemented!();
}
-fn good_bar<T: Clone + Default>(arg: T) {
+fn good_bar<T: Clone + Copy, U: Clone + Copy>(arg0: T, arg1: U) {
unimplemented!();
}
-fn good_foo<T>(arg: T)
+fn good_foo<T, U>(arg0: T, arg1: U)
where
- T: Clone + Default,
+ T: Clone + Copy,
+ U: Clone + Copy,
{
unimplemented!();
}
-fn good_foobar<T: Default>(arg: T)
-where
- T: Clone,
-{
- unimplemented!();
+trait GoodSelfTraitBound: Clone + Copy {
+ fn f();
}
-trait T: Default {
+trait GoodSelfWhereClause {
fn f()
where
- Self: Default;
+ Self: Clone + Copy;
}
-trait U: Default {
+trait BadSelfTraitBound: Clone + Clone + Clone {
+ fn f();
+}
+
+trait BadSelfWhereClause {
fn f()
where
- Self: Clone;
+ Self: Clone + Clone + Clone;
+}
+
+trait GoodTraitBound<T: Clone + Copy, U: Clone + Copy> {
+ fn f();
}
-trait ZZ: Default {
- fn g();
- fn h();
+trait GoodWhereClause<T, U> {
fn f()
where
- Self: Default + Clone;
+ T: Clone + Copy,
+ U: Clone + Copy;
}
-trait BadTrait: Default + Clone {
+trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
+ fn f();
+}
+
+trait BadWhereClause<T, U> {
fn f()
where
- Self: Default + Clone;
- fn g()
- where
- Self: Default;
- fn h()
- where
- Self: Copy;
+ T: Clone + Clone + Clone + Copy,
+ U: Clone + Copy;
}
-#[derive(Default, Clone)]
-struct Life;
+struct GoodStructBound<T: Clone + Copy, U: Clone + Copy> {
+ t: T,
+ u: U,
+}
-impl T for Life {
+impl<T: Clone + Copy, U: Clone + Copy> GoodTraitBound<T, U> for GoodStructBound<T, U> {
// this should not warn
fn f() {}
}
-impl U for Life {
+struct GoodStructWhereClause;
+
+impl<T, U> GoodTraitBound<T, U> for GoodStructWhereClause
+where
+ T: Clone + Copy,
+ U: Clone + Copy,
+{
// this should not warn
fn f() {}
}
-// should not warn
-trait Iter: Iterator {
- fn into_group_btreemap<K, V>(self) -> BTreeMap<K, Vec<V>>
- where
- Self: Iterator<Item = (K, V)> + Sized,
- K: Ord + Eq,
- {
- unimplemented!();
- }
-}
+fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {}
-struct Foo;
+trait GenericTrait<T> {}
-trait FooIter: Iterator<Item = Foo> {
- fn bar()
- where
- Self: Iterator<Item = Foo>,
- {
- }
+fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
+ unimplemented!();
}
-// This should not lint
-fn impl_trait(_: impl AsRef<str>, _: impl AsRef<str>) {}
-
-mod repeated_where_clauses_or_trait_bounds {
- fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
- unimplemented!();
- }
-
- fn bad_bar<T, U>(arg0: T, arg1: U)
- where
- T: Clone + Clone + Clone + Copy,
- U: Clone + Copy,
- {
- unimplemented!();
- }
-
- fn good_bar<T: Clone + Copy, U: Clone + Copy>(arg0: T, arg1: U) {
- unimplemented!();
- }
-
- fn good_foo<T, U>(arg0: T, arg1: U)
- where
- T: Clone + Copy,
- U: Clone + Copy,
- {
- unimplemented!();
- }
-
- trait GoodSelfTraitBound: Clone + Copy {
- fn f();
- }
-
- trait GoodSelfWhereClause {
- fn f()
- where
- Self: Clone + Copy;
- }
-
- trait BadSelfTraitBound: Clone + Clone + Clone {
- fn f();
- }
-
- trait BadSelfWhereClause {
- fn f()
- where
- Self: Clone + Clone + Clone;
- }
-
- trait GoodTraitBound<T: Clone + Copy, U: Clone + Copy> {
- fn f();
- }
-
- trait GoodWhereClause<T, U> {
- fn f()
- where
- T: Clone + Copy,
- U: Clone + Copy;
- }
-
- trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
- fn f();
- }
-
- trait BadWhereClause<T, U> {
- fn f()
- where
- T: Clone + Clone + Clone + Copy,
- U: Clone + Copy;
- }
-
- struct GoodStructBound<T: Clone + Copy, U: Clone + Copy> {
- t: T,
- u: U,
- }
-
- impl<T: Clone + Copy, U: Clone + Copy> GoodTraitBound<T, U> for GoodStructBound<T, U> {
- // this should not warn
- fn f() {}
- }
-
- struct GoodStructWhereClause;
-
- impl<T, U> GoodTraitBound<T, U> for GoodStructWhereClause
- where
- T: Clone + Copy,
- U: Clone + Copy,
- {
- // this should not warn
- fn f() {}
- }
-
- fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {}
-
- trait GenericTrait<T> {}
-
- // This should not warn but currently does see #8757
- fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
- unimplemented!();
- }
-
- fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
- unimplemented!();
- }
+fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
+ unimplemented!();
+}
- mod foo {
- pub trait Clone {}
- }
+mod foo {
+ pub trait Clone {}
+}
- fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
- unimplemented!();
- }
+fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
+ unimplemented!();
}
fn main() {}
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
index 7ef04e527..af800ba78 100644
--- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
@@ -1,167 +1,56 @@
-error: this trait bound is already specified in the where clause
- --> $DIR/trait_duplication_in_bounds.rs:7:15
+error: these bounds contain repeated elements
+ --> $DIR/trait_duplication_in_bounds.rs:5:15
|
-LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
- | ^^^^^
+LL | fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
|
note: the lint level is defined here
- --> $DIR/trait_duplication_in_bounds.rs:1:9
+ --> $DIR/trait_duplication_in_bounds.rs:2:9
|
LL | #![deny(clippy::trait_duplication_in_bounds)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: consider removing this trait bound
-
-error: this trait bound is already specified in the where clause
- --> $DIR/trait_duplication_in_bounds.rs:7:23
- |
-LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
- | ^^^^^^^
- |
- = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
- --> $DIR/trait_duplication_in_bounds.rs:36:15
- |
-LL | Self: Default;
- | ^^^^^^^
- |
- = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
- --> $DIR/trait_duplication_in_bounds.rs:50:15
- |
-LL | Self: Default + Clone;
- | ^^^^^^^
- |
- = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
- --> $DIR/trait_duplication_in_bounds.rs:56:15
- |
-LL | Self: Default + Clone;
- | ^^^^^^^
- |
- = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
- --> $DIR/trait_duplication_in_bounds.rs:56:25
- |
-LL | Self: Default + Clone;
- | ^^^^^
- |
- = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
- --> $DIR/trait_duplication_in_bounds.rs:59:15
- |
-LL | Self: Default;
- | ^^^^^^^
- |
- = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
- --> $DIR/trait_duplication_in_bounds.rs:94:15
- |
-LL | Self: Iterator<Item = Foo>,
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider removing this trait bound
-
-error: this trait bound is already specified in the where clause
- --> $DIR/trait_duplication_in_bounds.rs:103:19
- |
-LL | fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
- | ^^^^^
- |
- = help: consider removing this trait bound
-
-error: these bounds contain repeated elements
- --> $DIR/trait_duplication_in_bounds.rs:103:19
- |
-LL | fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
-
-error: this trait bound is already specified in the where clause
- --> $DIR/trait_duplication_in_bounds.rs:109:12
- |
-LL | T: Clone + Clone + Clone + Copy,
- | ^^^^^
- |
- = help: consider removing this trait bound
error: these where clauses contain repeated elements
- --> $DIR/trait_duplication_in_bounds.rs:109:12
+ --> $DIR/trait_duplication_in_bounds.rs:11:8
|
-LL | T: Clone + Clone + Clone + Copy,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
+LL | T: Clone + Clone + Clone + Copy,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
error: these bounds contain repeated elements
- --> $DIR/trait_duplication_in_bounds.rs:137:30
+ --> $DIR/trait_duplication_in_bounds.rs:39:26
|
-LL | trait BadSelfTraitBound: Clone + Clone + Clone {
- | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
+LL | trait BadSelfTraitBound: Clone + Clone + Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
error: these where clauses contain repeated elements
- --> $DIR/trait_duplication_in_bounds.rs:144:19
- |
-LL | Self: Clone + Clone + Clone;
- | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
-
-error: this trait bound is already specified in the where clause
- --> $DIR/trait_duplication_in_bounds.rs:158:28
+ --> $DIR/trait_duplication_in_bounds.rs:46:15
|
-LL | trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
- | ^^^^^
- |
- = help: consider removing this trait bound
+LL | Self: Clone + Clone + Clone;
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
error: these bounds contain repeated elements
- --> $DIR/trait_duplication_in_bounds.rs:158:28
+ --> $DIR/trait_duplication_in_bounds.rs:60:24
|
-LL | trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
+LL | trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
error: these where clauses contain repeated elements
- --> $DIR/trait_duplication_in_bounds.rs:165:16
- |
-LL | T: Clone + Clone + Clone + Copy,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
-
-error: this trait bound is already specified in the where clause
- --> $DIR/trait_duplication_in_bounds.rs:195:24
- |
-LL | fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
- | ^^^^^^^^^^^^^^^^^
- |
- = help: consider removing this trait bound
-
-error: this trait bound is already specified in the where clause
- --> $DIR/trait_duplication_in_bounds.rs:199:23
+ --> $DIR/trait_duplication_in_bounds.rs:67:12
|
-LL | fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
- | ^^^^^^^^^^^^^^^^^
- |
- = help: consider removing this trait bound
+LL | T: Clone + Clone + Clone + Copy,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
error: these bounds contain repeated elements
- --> $DIR/trait_duplication_in_bounds.rs:199:23
- |
-LL | fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait<u32> + GenericTrait<u64>`
-
-error: this trait bound is already specified in the where clause
- --> $DIR/trait_duplication_in_bounds.rs:207:26
- |
-LL | fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
- | ^^^^^^^^^^^^^^^^^
+ --> $DIR/trait_duplication_in_bounds.rs:100:19
|
- = help: consider removing this trait bound
+LL | fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait<u64> + GenericTrait<u32>`
error: these bounds contain repeated elements
- --> $DIR/trait_duplication_in_bounds.rs:207:26
+ --> $DIR/trait_duplication_in_bounds.rs:108:22
|
-LL | fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + foo::Clone`
+LL | fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::clone::Clone + foo::Clone`
-error: aborting due to 22 previous errors
+error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.rs
new file mode 100644
index 000000000..5630a0345
--- /dev/null
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.rs
@@ -0,0 +1,166 @@
+#![deny(clippy::trait_duplication_in_bounds)]
+
+use std::collections::BTreeMap;
+use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
+
+fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+where
+ T: Clone,
+ T: Default,
+{
+ unimplemented!();
+}
+
+fn good_bar<T: Clone + Default>(arg: T) {
+ unimplemented!();
+}
+
+fn good_foo<T>(arg: T)
+where
+ T: Clone + Default,
+{
+ unimplemented!();
+}
+
+fn good_foobar<T: Default>(arg: T)
+where
+ T: Clone,
+{
+ unimplemented!();
+}
+
+trait T: Default {
+ fn f()
+ where
+ Self: Default;
+}
+
+trait U: Default {
+ fn f()
+ where
+ Self: Clone;
+}
+
+trait ZZ: Default {
+ fn g();
+ fn h();
+ fn f()
+ where
+ Self: Default + Clone;
+}
+
+trait BadTrait: Default + Clone {
+ fn f()
+ where
+ Self: Default + Clone;
+ fn g()
+ where
+ Self: Default;
+ fn h()
+ where
+ Self: Copy;
+}
+
+#[derive(Default, Clone)]
+struct Life;
+
+impl T for Life {
+ // this should not warn
+ fn f() {}
+}
+
+impl U for Life {
+ // this should not warn
+ fn f() {}
+}
+
+// should not warn
+trait Iter: Iterator {
+ fn into_group_btreemap<K, V>(self) -> BTreeMap<K, Vec<V>>
+ where
+ Self: Iterator<Item = (K, V)> + Sized,
+ K: Ord + Eq,
+ {
+ unimplemented!();
+ }
+}
+
+struct Foo;
+
+trait FooIter: Iterator<Item = Foo> {
+ fn bar()
+ where
+ Self: Iterator<Item = Foo>,
+ {
+ }
+}
+
+// The below should not lint and exist to guard against false positives
+fn impl_trait(_: impl AsRef<str>, _: impl AsRef<str>) {}
+
+pub mod one {
+ #[derive(Clone, Debug)]
+ struct MultiProductIter<I>
+ where
+ I: Iterator + Clone,
+ I::Item: Clone,
+ {
+ _marker: I,
+ }
+
+ pub struct MultiProduct<I>(Vec<MultiProductIter<I>>)
+ where
+ I: Iterator + Clone,
+ I::Item: Clone;
+
+ pub fn multi_cartesian_product<H>(_: H) -> MultiProduct<<H::Item as IntoIterator>::IntoIter>
+ where
+ H: Iterator,
+ H::Item: IntoIterator,
+ <H::Item as IntoIterator>::IntoIter: Clone,
+ <H::Item as IntoIterator>::Item: Clone,
+ {
+ todo!()
+ }
+}
+
+pub mod two {
+ use std::iter::Peekable;
+
+ pub struct MergeBy<I, J, F>
+ where
+ I: Iterator,
+ J: Iterator<Item = I::Item>,
+ {
+ _i: Peekable<I>,
+ _j: Peekable<J>,
+ _f: F,
+ }
+
+ impl<I, J, F> Clone for MergeBy<I, J, F>
+ where
+ I: Iterator,
+ J: Iterator<Item = I::Item>,
+ std::iter::Peekable<I>: Clone,
+ std::iter::Peekable<J>: Clone,
+ F: Clone,
+ {
+ fn clone(&self) -> Self {
+ Self {
+ _i: self._i.clone(),
+ _j: self._j.clone(),
+ _f: self._f.clone(),
+ }
+ }
+ }
+}
+
+pub trait Trait {}
+
+pub fn f(_a: impl Trait, _b: impl Trait) {}
+
+pub trait ImplTrait<T> {}
+
+impl<A, B> ImplTrait<(A, B)> for Foo where Foo: ImplTrait<A> + ImplTrait<B> {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.stderr
new file mode 100644
index 000000000..4d56a9464
--- /dev/null
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.stderr
@@ -0,0 +1,71 @@
+error: this trait bound is already specified in the where clause
+ --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:15
+ |
+LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+ | ^^^^^
+ |
+ = help: consider removing this trait bound
+note: the lint level is defined here
+ --> $DIR/trait_duplication_in_bounds_unfixable.rs:1:9
+ |
+LL | #![deny(clippy::trait_duplication_in_bounds)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this trait bound is already specified in the where clause
+ --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:23
+ |
+LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+ | ^^^^^^^
+ |
+ = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+ --> $DIR/trait_duplication_in_bounds_unfixable.rs:35:15
+ |
+LL | Self: Default;
+ | ^^^^^^^
+ |
+ = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+ --> $DIR/trait_duplication_in_bounds_unfixable.rs:49:15
+ |
+LL | Self: Default + Clone;
+ | ^^^^^^^
+ |
+ = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+ --> $DIR/trait_duplication_in_bounds_unfixable.rs:55:15
+ |
+LL | Self: Default + Clone;
+ | ^^^^^^^
+ |
+ = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+ --> $DIR/trait_duplication_in_bounds_unfixable.rs:55:25
+ |
+LL | Self: Default + Clone;
+ | ^^^^^
+ |
+ = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+ --> $DIR/trait_duplication_in_bounds_unfixable.rs:58:15
+ |
+LL | Self: Default;
+ | ^^^^^^^
+ |
+ = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+ --> $DIR/trait_duplication_in_bounds_unfixable.rs:93:15
+ |
+LL | Self: Iterator<Item = Foo>,
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider removing this trait bound
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
index 2993e5e7b..10117ee91 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
@@ -42,13 +42,13 @@ error: transmute from a pointer type (`*mut U`) to a reference type (`&T`)
LL | let _: &T = std::mem::transmute(om);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)`
-error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<u8>`)
+error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, u8>`)
--> $DIR/transmute_ptr_to_ref.rs:36:32
|
LL | let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<_>>()`
-error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<&u8>`)
+error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, &u8>`)
--> $DIR/transmute_ptr_to_ref.rs:38:33
|
LL | let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) };
diff --git a/src/tools/clippy/tests/ui/transmute_undefined_repr.rs b/src/tools/clippy/tests/ui/transmute_undefined_repr.rs
index ebcaa7a84..5aad0b442 100644
--- a/src/tools/clippy/tests/ui/transmute_undefined_repr.rs
+++ b/src/tools/clippy/tests/ui/transmute_undefined_repr.rs
@@ -4,6 +4,7 @@
use core::any::TypeId;
use core::ffi::c_void;
use core::mem::{size_of, transmute, MaybeUninit};
+use core::ptr::NonNull;
fn value<T>() -> T {
unimplemented!()
@@ -109,6 +110,17 @@ fn main() {
let _: Ty2<u32, u32> = transmute(value::<MaybeUninit<Ty2<u32, u32>>>()); // Ok
let _: Ty<&[u32]> = transmute::<&[u32], _>(value::<&Vec<u32>>()); // Ok
+
+ let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<Ty2<u32, u32>, u32>>()); // Ok
+ let _: *const Ty2C<Ty2<u32, u32>, u32> = transmute(value::<*const Ty2<u32, u32>>()); // Ok
+ let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<(), Ty2<u32, u32>>>()); // Ok
+ let _: *const Ty2C<(), Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Ok
+
+ let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<u32, Ty2<u32, u32>>>()); // Err
+ let _: *const Ty2C<u32, Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Err
+
+ let _: NonNull<u8> = transmute(value::<NonNull<(String, String)>>()); // Ok
+ let _: NonNull<(String, String)> = transmute(value::<NonNull<u8>>()); // Ok
}
}
diff --git a/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr b/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr
index 28bfba6c7..e50a77329 100644
--- a/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr
+++ b/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr
@@ -1,5 +1,5 @@
error: transmute from `Ty2<u32, i32>` which has an undefined layout
- --> $DIR/transmute_undefined_repr.rs:27:33
+ --> $DIR/transmute_undefined_repr.rs:28:33
|
LL | let _: Ty2C<u32, i32> = transmute(value::<Ty2<u32, i32>>()); // Lint, Ty2 is unordered
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,13 +7,13 @@ LL | let _: Ty2C<u32, i32> = transmute(value::<Ty2<u32, i32>>()); // Lin
= note: `-D clippy::transmute-undefined-repr` implied by `-D warnings`
error: transmute into `Ty2<u32, i32>` which has an undefined layout
- --> $DIR/transmute_undefined_repr.rs:28:32
+ --> $DIR/transmute_undefined_repr.rs:29:32
|
LL | let _: Ty2<u32, i32> = transmute(value::<Ty2C<u32, i32>>()); // Lint, Ty2 is unordered
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from `Ty<Ty2<u32, i32>>` to `Ty2<u32, f32>`, both of which have an undefined layout
- --> $DIR/transmute_undefined_repr.rs:33:32
+ --> $DIR/transmute_undefined_repr.rs:34:32
|
LL | let _: Ty2<u32, f32> = transmute(value::<Ty<Ty2<u32, i32>>>()); // Lint, different Ty2 instances
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -21,7 +21,7 @@ LL | let _: Ty2<u32, f32> = transmute(value::<Ty<Ty2<u32, i32>>>()); //
= note: two instances of the same generic type (`Ty2`) may have different layouts
error: transmute from `Ty2<u32, f32>` to `Ty<Ty2<u32, i32>>`, both of which have an undefined layout
- --> $DIR/transmute_undefined_repr.rs:34:36
+ --> $DIR/transmute_undefined_repr.rs:35:36
|
LL | let _: Ty<Ty2<u32, i32>> = transmute(value::<Ty2<u32, f32>>()); // Lint, different Ty2 instances
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -29,7 +29,7 @@ LL | let _: Ty<Ty2<u32, i32>> = transmute(value::<Ty2<u32, f32>>()); //
= note: two instances of the same generic type (`Ty2`) may have different layouts
error: transmute from `Ty<&Ty2<u32, i32>>` to `&Ty2<u32, f32>`, both of which have an undefined layout
- --> $DIR/transmute_undefined_repr.rs:39:33
+ --> $DIR/transmute_undefined_repr.rs:40:33
|
LL | let _: &Ty2<u32, f32> = transmute(value::<Ty<&Ty2<u32, i32>>>()); // Lint, different Ty2 instances
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL | let _: &Ty2<u32, f32> = transmute(value::<Ty<&Ty2<u32, i32>>>()); /
= note: two instances of the same generic type (`Ty2`) may have different layouts
error: transmute from `&Ty2<u32, f32>` to `Ty<&Ty2<u32, i32>>`, both of which have an undefined layout
- --> $DIR/transmute_undefined_repr.rs:40:37
+ --> $DIR/transmute_undefined_repr.rs:41:37
|
LL | let _: Ty<&Ty2<u32, i32>> = transmute(value::<&Ty2<u32, f32>>()); // Lint, different Ty2 instances
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL | let _: Ty<&Ty2<u32, i32>> = transmute(value::<&Ty2<u32, f32>>()); /
= note: two instances of the same generic type (`Ty2`) may have different layouts
error: transmute from `std::boxed::Box<Ty2<u32, u32>>` to `&mut Ty2<u32, f32>`, both of which have an undefined layout
- --> $DIR/transmute_undefined_repr.rs:57:45
+ --> $DIR/transmute_undefined_repr.rs:58:45
|
LL | let _: &'static mut Ty2<u32, f32> = transmute(value::<Box<Ty2<u32, u32>>>()); // Lint, different Ty2 instances
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -53,15 +53,31 @@ LL | let _: &'static mut Ty2<u32, f32> = transmute(value::<Box<Ty2<u32,
= note: two instances of the same generic type (`Ty2`) may have different layouts
error: transmute from `&mut Ty2<u32, f32>` to `std::boxed::Box<Ty2<u32, u32>>`, both of which have an undefined layout
- --> $DIR/transmute_undefined_repr.rs:58:37
+ --> $DIR/transmute_undefined_repr.rs:59:37
|
LL | let _: Box<Ty2<u32, u32>> = transmute(value::<&'static mut Ty2<u32, f32>>()); // Lint, different Ty2 instances
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: two instances of the same generic type (`Ty2`) may have different layouts
+error: transmute into `*const Ty2<u32, u32>` which has an undefined layout
+ --> $DIR/transmute_undefined_repr.rs:119:39
+ |
+LL | let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<u32, Ty2<u32, u32>>>()); // Err
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the contained type `Ty2<u32, u32>` has an undefined layout
+
+error: transmute from `*const Ty2<u32, u32>` which has an undefined layout
+ --> $DIR/transmute_undefined_repr.rs:120:50
+ |
+LL | let _: *const Ty2C<u32, Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Err
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the contained type `Ty2<u32, u32>` has an undefined layout
+
error: transmute from `std::vec::Vec<Ty2<U, i32>>` to `std::vec::Vec<Ty2<T, u32>>`, both of which have an undefined layout
- --> $DIR/transmute_undefined_repr.rs:138:35
+ --> $DIR/transmute_undefined_repr.rs:150:35
|
LL | let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); // Err
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -69,12 +85,12 @@ LL | let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); /
= note: two instances of the same generic type (`Vec`) may have different layouts
error: transmute from `std::vec::Vec<Ty2<T, u32>>` to `std::vec::Vec<Ty2<U, i32>>`, both of which have an undefined layout
- --> $DIR/transmute_undefined_repr.rs:139:35
+ --> $DIR/transmute_undefined_repr.rs:151:35
|
LL | let _: Vec<Ty2<U, i32>> = transmute(value::<Vec<Ty2<T, u32>>>()); // Err
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: two instances of the same generic type (`Vec`) may have different layouts
-error: aborting due to 10 previous errors
+error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
index 539239fc1..7263abac1 100644
--- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
+++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
@@ -8,7 +8,7 @@
use std::mem::{size_of, transmute};
-// rustc_typeck::check::cast contains documentation about when a cast `e as U` is
+// rustc_hir_analysis::check::cast contains documentation about when a cast `e as U` is
// valid, which we quote from below.
fn main() {
// We should see an error message for each transmute, and no error messages for
diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
index b9e446dc8..d8e4421d4 100644
--- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
+++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
@@ -8,7 +8,7 @@
use std::mem::{size_of, transmute};
-// rustc_typeck::check::cast contains documentation about when a cast `e as U` is
+// rustc_hir_analysis::check::cast contains documentation about when a cast `e as U` is
// valid, which we quote from below.
fn main() {
// We should see an error message for each transmute, and no error messages for
diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
index 8f78f16a0..af4f3b184 100644
--- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
+++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
@@ -1,8 +1,11 @@
// normalize-stderr-test "\(\d+ byte\)" -> "(N byte)"
// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)"
-
#![deny(clippy::trivially_copy_pass_by_ref)]
-#![allow(clippy::blacklisted_name, clippy::redundant_field_names)]
+#![allow(
+ clippy::disallowed_names,
+ clippy::redundant_field_names,
+ clippy::uninlined_format_args
+)]
#[derive(Copy, Clone)]
struct Foo(u32);
diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
index 66ecb3d8e..6a8eca965 100644
--- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
+++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
@@ -1,113 +1,113 @@
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:47:11
+ --> $DIR/trivially_copy_pass_by_ref.rs:50:11
|
LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `u32`
|
note: the lint level is defined here
- --> $DIR/trivially_copy_pass_by_ref.rs:4:9
+ --> $DIR/trivially_copy_pass_by_ref.rs:3:9
|
LL | #![deny(clippy::trivially_copy_pass_by_ref)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:47:20
+ --> $DIR/trivially_copy_pass_by_ref.rs:50:20
|
LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Foo`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:47:29
+ --> $DIR/trivially_copy_pass_by_ref.rs:50:29
|
LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Baz`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:54:12
+ --> $DIR/trivially_copy_pass_by_ref.rs:57:12
|
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
| ^^^^^ help: consider passing by value instead: `self`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:54:22
+ --> $DIR/trivially_copy_pass_by_ref.rs:57:22
|
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `u32`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:54:31
+ --> $DIR/trivially_copy_pass_by_ref.rs:57:31
|
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Foo`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:54:40
+ --> $DIR/trivially_copy_pass_by_ref.rs:57:40
|
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Baz`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:56:16
+ --> $DIR/trivially_copy_pass_by_ref.rs:59:16
|
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `u32`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:56:25
+ --> $DIR/trivially_copy_pass_by_ref.rs:59:25
|
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Foo`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:56:34
+ --> $DIR/trivially_copy_pass_by_ref.rs:59:34
|
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Baz`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:58:35
+ --> $DIR/trivially_copy_pass_by_ref.rs:61:35
|
LL | fn bad_issue7518(self, other: &Self) {}
| ^^^^^ help: consider passing by value instead: `Self`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:70:16
+ --> $DIR/trivially_copy_pass_by_ref.rs:73:16
|
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `u32`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:70:25
+ --> $DIR/trivially_copy_pass_by_ref.rs:73:25
|
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Foo`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:70:34
+ --> $DIR/trivially_copy_pass_by_ref.rs:73:34
|
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Baz`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:74:34
+ --> $DIR/trivially_copy_pass_by_ref.rs:77:34
|
LL | fn trait_method(&self, _foo: &Foo);
| ^^^^ help: consider passing by value instead: `Foo`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:106:21
+ --> $DIR/trivially_copy_pass_by_ref.rs:109:21
|
LL | fn foo_never(x: &i32) {
| ^^^^ help: consider passing by value instead: `i32`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:111:15
+ --> $DIR/trivially_copy_pass_by_ref.rs:114:15
|
LL | fn foo(x: &i32) {
| ^^^^ help: consider passing by value instead: `i32`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:138:37
+ --> $DIR/trivially_copy_pass_by_ref.rs:141:37
|
LL | fn _unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 {
| ^^^^^^^ help: consider passing by value instead: `u32`
diff --git a/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr b/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
index 1d8871481..70d700c1c 100644
--- a/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
+++ b/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
@@ -4,12 +4,12 @@ error: this type has already been used as a bound predicate
LL | T: Clone,
| ^^^^^^^^
|
+ = help: consider combining the bounds: `T: Copy + Clone`
note: the lint level is defined here
--> $DIR/type_repetition_in_bounds.rs:1:9
|
LL | #![deny(clippy::type_repetition_in_bounds)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: consider combining the bounds: `T: Copy + Clone`
error: this type has already been used as a bound predicate
--> $DIR/type_repetition_in_bounds.rs:25:5
diff --git a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr
index c6a212744..2c466ff5c 100644
--- a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr
+++ b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.stderr
@@ -4,8 +4,8 @@ error: unsafe block missing a safety comment
LL | /* Safety: */ unsafe {}
| ^^^^^^^^^
|
- = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
= help: consider adding a safety comment on the preceding line
+ = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
error: unsafe block missing a safety comment
--> $DIR/undocumented_unsafe_blocks.rs:266:5
diff --git a/src/tools/clippy/tests/ui/undropped_manually_drops.stderr b/src/tools/clippy/tests/ui/undropped_manually_drops.stderr
index 2ac0fe986..92611a9b7 100644
--- a/src/tools/clippy/tests/ui/undropped_manually_drops.stderr
+++ b/src/tools/clippy/tests/ui/undropped_manually_drops.stderr
@@ -4,8 +4,8 @@ error: the inner value of this ManuallyDrop will not be dropped
LL | drop(std::mem::ManuallyDrop::new(S));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::undropped-manually-drops` implied by `-D warnings`
= help: to drop a `ManuallyDrop<T>`, use std::mem::ManuallyDrop::drop
+ = note: `-D clippy::undropped-manually-drops` implied by `-D warnings`
error: the inner value of this ManuallyDrop will not be dropped
--> $DIR/undropped_manually_drops.rs:15:5
diff --git a/src/tools/clippy/tests/ui/unicode.fixed b/src/tools/clippy/tests/ui/unicode.fixed
index 328cda369..94b472345 100644
--- a/src/tools/clippy/tests/ui/unicode.fixed
+++ b/src/tools/clippy/tests/ui/unicode.fixed
@@ -1,4 +1,7 @@
// run-rustfix
+// compile-flags: --test
+#![allow(dead_code)]
+
#[warn(clippy::invisible_characters)]
fn zero() {
print!("Here >\u{200B}< is a ZWS, and \u{200B}another");
@@ -15,22 +18,43 @@ fn canon() {
print!("a\u{0300}h?"); // also ok
}
-#[warn(clippy::non_ascii_literal)]
-fn uni() {
- print!("\u{dc}ben!");
- print!("\u{DC}ben!"); // this is ok
-}
+mod non_ascii_literal {
+ #![deny(clippy::non_ascii_literal)]
+
+ fn uni() {
+ print!("\u{dc}ben!");
+ print!("\u{DC}ben!"); // this is ok
+ }
+
+ // issue 8013
+ fn single_quote() {
+ const _EMPTY_BLOCK: char = '\u{25b1}';
+ const _FULL_BLOCK: char = '\u{25b0}';
+ }
+
+ #[test]
+ pub fn issue_7739() {
+ // Ryū crate: https://github.com/dtolnay/ryu
+ }
+
+ mod issue_8263 {
+ #![deny(clippy::non_ascii_literal)]
+
+ // Re-allow for a single test
+ #[test]
+ #[allow(clippy::non_ascii_literal)]
+ fn allowed() {
+ let _ = "悲しいかな、ここに日本語を書くことはできない。";
+ }
-// issue 8013
-#[warn(clippy::non_ascii_literal)]
-fn single_quote() {
- const _EMPTY_BLOCK: char = '\u{25b1}';
- const _FULL_BLOCK: char = '\u{25b0}';
+ #[test]
+ fn denied() {
+ let _ = "\u{60b2}\u{3057}\u{3044}\u{304b}\u{306a}\u{3001}\u{3053}\u{3053}\u{306b}\u{65e5}\u{672c}\u{8a9e}\u{3092}\u{66f8}\u{304f}\u{3053}\u{3068}\u{306f}\u{3067}\u{304d}\u{306a}\u{3044}\u{3002}";
+ }
+ }
}
fn main() {
zero();
- uni();
canon();
- single_quote();
}
diff --git a/src/tools/clippy/tests/ui/unicode.rs b/src/tools/clippy/tests/ui/unicode.rs
index 7828d6bcb..6ad0b255b 100644
--- a/src/tools/clippy/tests/ui/unicode.rs
+++ b/src/tools/clippy/tests/ui/unicode.rs
@@ -1,4 +1,7 @@
// run-rustfix
+// compile-flags: --test
+#![allow(dead_code)]
+
#[warn(clippy::invisible_characters)]
fn zero() {
print!("Here >​< is a ZWS, and ​another");
@@ -15,22 +18,43 @@ fn canon() {
print!("a\u{0300}h?"); // also ok
}
-#[warn(clippy::non_ascii_literal)]
-fn uni() {
- print!("Üben!");
- print!("\u{DC}ben!"); // this is ok
-}
+mod non_ascii_literal {
+ #![deny(clippy::non_ascii_literal)]
+
+ fn uni() {
+ print!("Üben!");
+ print!("\u{DC}ben!"); // this is ok
+ }
+
+ // issue 8013
+ fn single_quote() {
+ const _EMPTY_BLOCK: char = '▱';
+ const _FULL_BLOCK: char = '▰';
+ }
+
+ #[test]
+ pub fn issue_7739() {
+ // Ryū crate: https://github.com/dtolnay/ryu
+ }
+
+ mod issue_8263 {
+ #![deny(clippy::non_ascii_literal)]
+
+ // Re-allow for a single test
+ #[test]
+ #[allow(clippy::non_ascii_literal)]
+ fn allowed() {
+ let _ = "悲しいかな、ここに日本語を書くことはできない。";
+ }
-// issue 8013
-#[warn(clippy::non_ascii_literal)]
-fn single_quote() {
- const _EMPTY_BLOCK: char = '▱';
- const _FULL_BLOCK: char = '▰';
+ #[test]
+ fn denied() {
+ let _ = "悲しいかな、ここに日本語を書くことはできない。";
+ }
+ }
}
fn main() {
zero();
- uni();
canon();
- single_quote();
}
diff --git a/src/tools/clippy/tests/ui/unicode.stderr b/src/tools/clippy/tests/ui/unicode.stderr
index 01d3f3c02..ea74a8145 100644
--- a/src/tools/clippy/tests/ui/unicode.stderr
+++ b/src/tools/clippy/tests/ui/unicode.stderr
@@ -1,5 +1,5 @@
error: invisible character detected
- --> $DIR/unicode.rs:4:12
+ --> $DIR/unicode.rs:7:12
|
LL | print!("Here >​< is a ZWS, and ​another");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{200B}< is a ZWS, and /u{200B}another"`
@@ -7,19 +7,19 @@ LL | print!("Here >​< is a ZWS, and ​another");
= note: `-D clippy::invisible-characters` implied by `-D warnings`
error: invisible character detected
- --> $DIR/unicode.rs:6:12
+ --> $DIR/unicode.rs:9:12
|
LL | print!("Here >­< is a SHY, and ­another");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{AD}< is a SHY, and /u{AD}another"`
error: invisible character detected
- --> $DIR/unicode.rs:8:12
+ --> $DIR/unicode.rs:11:12
|
LL | print!("Here >⁠< is a WJ, and ⁠another");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{2060}< is a WJ, and /u{2060}another"`
error: non-NFC Unicode sequence detected
- --> $DIR/unicode.rs:14:12
+ --> $DIR/unicode.rs:17:12
|
LL | print!("̀àh?");
| ^^^^^ help: consider replacing the string with: `"̀àh?"`
@@ -27,24 +27,40 @@ LL | print!("̀àh?");
= note: `-D clippy::unicode-not-nfc` implied by `-D warnings`
error: literal non-ASCII character detected
- --> $DIR/unicode.rs:20:12
+ --> $DIR/unicode.rs:25:16
|
-LL | print!("Üben!");
- | ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"`
+LL | print!("Üben!");
+ | ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"`
|
- = note: `-D clippy::non-ascii-literal` implied by `-D warnings`
+note: the lint level is defined here
+ --> $DIR/unicode.rs:22:13
+ |
+LL | #![deny(clippy::non_ascii_literal)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: literal non-ASCII character detected
+ --> $DIR/unicode.rs:31:36
+ |
+LL | const _EMPTY_BLOCK: char = '▱';
+ | ^^^ help: consider replacing the string with: `'/u{25b1}'`
error: literal non-ASCII character detected
- --> $DIR/unicode.rs:27:32
+ --> $DIR/unicode.rs:32:35
|
-LL | const _EMPTY_BLOCK: char = '▱';
- | ^^^ help: consider replacing the string with: `'/u{25b1}'`
+LL | const _FULL_BLOCK: char = '▰';
+ | ^^^ help: consider replacing the string with: `'/u{25b0}'`
error: literal non-ASCII character detected
- --> $DIR/unicode.rs:28:31
+ --> $DIR/unicode.rs:52:21
+ |
+LL | let _ = "悲しいかな、ここに日本語を書くことはできない。";
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"/u{60b2}/u{3057}/u{3044}/u{304b}/u{306a}/u{3001}/u{3053}/u{3053}/u{306b}/u{65e5}/u{672c}/u{8a9e}/u{3092}/u{66f8}/u{304f}/u{3053}/u{3068}/u{306f}/u{3067}/u{304d}/u{306a}/u{3044}/u{3002}"`
+ |
+note: the lint level is defined here
+ --> $DIR/unicode.rs:41:17
|
-LL | const _FULL_BLOCK: char = '▰';
- | ^^^ help: consider replacing the string with: `'/u{25b0}'`
+LL | #![deny(clippy::non_ascii_literal)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/uninit.rs b/src/tools/clippy/tests/ui/uninit.rs
index dac5ce272..211317317 100644
--- a/src/tools/clippy/tests/ui/uninit.rs
+++ b/src/tools/clippy/tests/ui/uninit.rs
@@ -1,5 +1,5 @@
#![feature(stmt_expr_attributes)]
-#![allow(clippy::let_unit_value)]
+#![allow(clippy::let_unit_value, invalid_value)]
use std::mem::{self, MaybeUninit};
diff --git a/src/tools/clippy/tests/ui/uninit_vec.rs b/src/tools/clippy/tests/ui/uninit_vec.rs
index dc150cf28..194e4fc15 100644
--- a/src/tools/clippy/tests/ui/uninit_vec.rs
+++ b/src/tools/clippy/tests/ui/uninit_vec.rs
@@ -91,4 +91,10 @@ fn main() {
vec1.set_len(200);
vec2.set_len(200);
}
+
+ // set_len(0) should not be detected
+ let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ unsafe {
+ vec.set_len(0);
+ }
}
diff --git a/src/tools/clippy/tests/ui/uninit_vec.stderr b/src/tools/clippy/tests/ui/uninit_vec.stderr
index 520bfb26b..77fc689f0 100644
--- a/src/tools/clippy/tests/ui/uninit_vec.stderr
+++ b/src/tools/clippy/tests/ui/uninit_vec.stderr
@@ -7,8 +7,8 @@ LL | unsafe {
LL | vec.set_len(200);
| ^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::uninit-vec` implied by `-D warnings`
= help: initialize the buffer or wrap the content in `MaybeUninit`
+ = note: `-D clippy::uninit-vec` implied by `-D warnings`
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
--> $DIR/uninit_vec.rs:18:5
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.fixed b/src/tools/clippy/tests/ui/uninlined_format_args.fixed
new file mode 100644
index 000000000..106274479
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninlined_format_args.fixed
@@ -0,0 +1,182 @@
+// aux-build:proc_macro_with_span.rs
+// run-rustfix
+#![feature(custom_inner_attributes)]
+#![warn(clippy::uninlined_format_args)]
+#![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)]
+#![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)]
+
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
+macro_rules! no_param_str {
+ () => {
+ "{}"
+ };
+}
+
+macro_rules! my_println {
+ ($($args:tt),*) => {{
+ println!($($args),*)
+ }};
+}
+
+macro_rules! my_println_args {
+ ($($args:tt),*) => {{
+ println!("foo: {}", format_args!($($args),*))
+ }};
+}
+
+fn tester(fn_arg: i32) {
+ let local_i32 = 1;
+ let local_f64 = 2.0;
+ let local_opt: Option<i32> = Some(3);
+ let width = 4;
+ let prec = 5;
+ let val = 6;
+
+ // make sure this file hasn't been corrupted with tabs converted to spaces
+ // let _ = ' '; // <- this is a single tab character
+ let _: &[u8; 3] = b" "; // <- <tab><space><tab>
+
+ println!("val='{local_i32}'");
+ println!("val='{local_i32}'"); // 3 spaces
+ println!("val='{local_i32}'"); // tab
+ println!("val='{local_i32}'"); // space+tab
+ println!("val='{local_i32}'"); // tab+space
+ println!(
+ "val='{
+ }'",
+ local_i32
+ );
+ println!("{local_i32}");
+ println!("{fn_arg}");
+ println!("{local_i32:?}");
+ println!("{local_i32:#?}");
+ println!("{local_i32:4}");
+ println!("{local_i32:04}");
+ println!("{local_i32:<3}");
+ println!("{local_i32:#010x}");
+ println!("{local_f64:.1}");
+ println!("Hello {} is {local_f64:.local_i32$}", "x");
+ println!("Hello {local_i32} is {local_f64:.*}", 5);
+ println!("Hello {local_i32} is {local_f64:.*}", 5);
+ println!("{local_i32} {local_f64}");
+ println!("{local_i32}, {}", local_opt.unwrap());
+ println!("{val}");
+ println!("{val}");
+ println!("{} {1}", local_i32, 42);
+ println!("val='{local_i32}'");
+ println!("val='{local_i32}'");
+ println!("val='{local_i32}'");
+ println!("val='{fn_arg}'");
+ println!("{local_i32}");
+ println!("{local_i32:?}");
+ println!("{local_i32:#?}");
+ println!("{local_i32:04}");
+ println!("{local_i32:<3}");
+ println!("{local_i32:#010x}");
+ println!("{local_f64:.1}");
+ println!("{local_i32} {local_i32}");
+ println!("{local_f64} {local_i32} {local_i32} {local_f64}");
+ println!("{local_i32} {local_f64}");
+ println!("{local_f64} {local_i32}");
+ println!("{local_f64} {local_i32} {local_f64} {local_i32}");
+ println!("{1} {0}", "str", local_i32);
+ println!("{local_i32}");
+ println!("{local_i32:width$}");
+ println!("{local_i32:width$}");
+ println!("{local_i32:.prec$}");
+ println!("{local_i32:.prec$}");
+ println!("{val:val$}");
+ println!("{val:val$}");
+ println!("{val:val$.val$}");
+ println!("{val:val$.val$}");
+ println!("{val:val$.val$}");
+ println!("{val:val$.val$}");
+ println!("{val:val$.val$}");
+ println!("{val:val$.val$}");
+ println!("{val:val$.val$}");
+ println!("{val:val$.val$}");
+ println!("{width:width$}");
+ println!("{local_i32:width$}");
+ println!("{width:width$}");
+ println!("{local_i32:width$}");
+ println!("{prec:.prec$}");
+ println!("{local_i32:.prec$}");
+ println!("{prec:.prec$}");
+ println!("{local_i32:.prec$}");
+ println!("{width:width$.prec$}");
+ println!("{width:width$.prec$}");
+ println!("{local_f64:width$.prec$}");
+ println!("{local_f64:width$.prec$} {local_f64} {width} {prec}");
+ println!(
+ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}",
+ local_i32, width, prec,
+ );
+ println!(
+ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$} {3}",
+ local_i32,
+ width,
+ prec,
+ 1 + 2
+ );
+ println!("Width = {local_i32}, value with width = {local_f64:local_i32$}");
+ println!("{local_i32:width$.prec$}");
+ println!("{width:width$.prec$}");
+ println!("{}", format!("{local_i32}"));
+ my_println!("{}", local_i32);
+ my_println_args!("{}", local_i32);
+
+ // these should NOT be modified by the lint
+ println!(concat!("nope ", "{}"), local_i32);
+ println!("val='{local_i32}'");
+ println!("val='{local_i32 }'");
+ println!("val='{local_i32 }'"); // with tab
+ println!("val='{local_i32\n}'");
+ println!("{}", usize::MAX);
+ println!("{}", local_opt.unwrap());
+ println!(
+ "val='{local_i32
+ }'"
+ );
+ println!(no_param_str!(), local_i32);
+
+ println!(
+ "{}",
+ // comment with a comma , in it
+ val,
+ );
+ println!("{val}");
+
+ println!(with_span!("{0} {1}" "{1} {0}"), local_i32, local_f64);
+ println!("{}", with_span!(span val));
+
+ if local_i32 > 0 {
+ panic!("p1 {local_i32}");
+ }
+ if local_i32 > 0 {
+ panic!("p2 {local_i32}");
+ }
+ if local_i32 > 0 {
+ panic!("p3 {local_i32}");
+ }
+ if local_i32 > 0 {
+ panic!("p4 {local_i32}");
+ }
+}
+
+fn main() {
+ tester(42);
+}
+
+fn _under_msrv() {
+ #![clippy::msrv = "1.57"]
+ let local_i32 = 1;
+ println!("don't expand='{}'", local_i32);
+}
+
+fn _meets_msrv() {
+ #![clippy::msrv = "1.58"]
+ let local_i32 = 1;
+ println!("expand='{local_i32}'");
+}
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.rs b/src/tools/clippy/tests/ui/uninlined_format_args.rs
new file mode 100644
index 000000000..8e495ebd0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninlined_format_args.rs
@@ -0,0 +1,182 @@
+// aux-build:proc_macro_with_span.rs
+// run-rustfix
+#![feature(custom_inner_attributes)]
+#![warn(clippy::uninlined_format_args)]
+#![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)]
+#![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)]
+
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
+macro_rules! no_param_str {
+ () => {
+ "{}"
+ };
+}
+
+macro_rules! my_println {
+ ($($args:tt),*) => {{
+ println!($($args),*)
+ }};
+}
+
+macro_rules! my_println_args {
+ ($($args:tt),*) => {{
+ println!("foo: {}", format_args!($($args),*))
+ }};
+}
+
+fn tester(fn_arg: i32) {
+ let local_i32 = 1;
+ let local_f64 = 2.0;
+ let local_opt: Option<i32> = Some(3);
+ let width = 4;
+ let prec = 5;
+ let val = 6;
+
+ // make sure this file hasn't been corrupted with tabs converted to spaces
+ // let _ = ' '; // <- this is a single tab character
+ let _: &[u8; 3] = b" "; // <- <tab><space><tab>
+
+ println!("val='{}'", local_i32);
+ println!("val='{ }'", local_i32); // 3 spaces
+ println!("val='{ }'", local_i32); // tab
+ println!("val='{ }'", local_i32); // space+tab
+ println!("val='{ }'", local_i32); // tab+space
+ println!(
+ "val='{
+ }'",
+ local_i32
+ );
+ println!("{}", local_i32);
+ println!("{}", fn_arg);
+ println!("{:?}", local_i32);
+ println!("{:#?}", local_i32);
+ println!("{:4}", local_i32);
+ println!("{:04}", local_i32);
+ println!("{:<3}", local_i32);
+ println!("{:#010x}", local_i32);
+ println!("{:.1}", local_f64);
+ println!("Hello {} is {:.*}", "x", local_i32, local_f64);
+ println!("Hello {} is {:.*}", local_i32, 5, local_f64);
+ println!("Hello {} is {2:.*}", local_i32, 5, local_f64);
+ println!("{} {}", local_i32, local_f64);
+ println!("{}, {}", local_i32, local_opt.unwrap());
+ println!("{}", val);
+ println!("{}", v = val);
+ println!("{} {1}", local_i32, 42);
+ println!("val='{\t }'", local_i32);
+ println!("val='{\n }'", local_i32);
+ println!("val='{local_i32}'", local_i32 = local_i32);
+ println!("val='{local_i32}'", local_i32 = fn_arg);
+ println!("{0}", local_i32);
+ println!("{0:?}", local_i32);
+ println!("{0:#?}", local_i32);
+ println!("{0:04}", local_i32);
+ println!("{0:<3}", local_i32);
+ println!("{0:#010x}", local_i32);
+ println!("{0:.1}", local_f64);
+ println!("{0} {0}", local_i32);
+ println!("{1} {} {0} {}", local_i32, local_f64);
+ println!("{0} {1}", local_i32, local_f64);
+ println!("{1} {0}", local_i32, local_f64);
+ println!("{1} {0} {1} {0}", local_i32, local_f64);
+ println!("{1} {0}", "str", local_i32);
+ println!("{v}", v = local_i32);
+ println!("{local_i32:0$}", width);
+ println!("{local_i32:w$}", w = width);
+ println!("{local_i32:.0$}", prec);
+ println!("{local_i32:.p$}", p = prec);
+ println!("{:0$}", v = val);
+ println!("{0:0$}", v = val);
+ println!("{:0$.0$}", v = val);
+ println!("{0:0$.0$}", v = val);
+ println!("{0:0$.v$}", v = val);
+ println!("{0:v$.0$}", v = val);
+ println!("{v:0$.0$}", v = val);
+ println!("{v:v$.0$}", v = val);
+ println!("{v:0$.v$}", v = val);
+ println!("{v:v$.v$}", v = val);
+ println!("{:0$}", width);
+ println!("{:1$}", local_i32, width);
+ println!("{:w$}", w = width);
+ println!("{:w$}", local_i32, w = width);
+ println!("{:.0$}", prec);
+ println!("{:.1$}", local_i32, prec);
+ println!("{:.p$}", p = prec);
+ println!("{:.p$}", local_i32, p = prec);
+ println!("{:0$.1$}", width, prec);
+ println!("{:0$.w$}", width, w = prec);
+ println!("{:1$.2$}", local_f64, width, prec);
+ println!("{:1$.2$} {0} {1} {2}", local_f64, width, prec);
+ println!(
+ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}",
+ local_i32, width, prec,
+ );
+ println!(
+ "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$} {3}",
+ local_i32,
+ width,
+ prec,
+ 1 + 2
+ );
+ println!("Width = {}, value with width = {:0$}", local_i32, local_f64);
+ println!("{:w$.p$}", local_i32, w = width, p = prec);
+ println!("{:w$.p$}", w = width, p = prec);
+ println!("{}", format!("{}", local_i32));
+ my_println!("{}", local_i32);
+ my_println_args!("{}", local_i32);
+
+ // these should NOT be modified by the lint
+ println!(concat!("nope ", "{}"), local_i32);
+ println!("val='{local_i32}'");
+ println!("val='{local_i32 }'");
+ println!("val='{local_i32 }'"); // with tab
+ println!("val='{local_i32\n}'");
+ println!("{}", usize::MAX);
+ println!("{}", local_opt.unwrap());
+ println!(
+ "val='{local_i32
+ }'"
+ );
+ println!(no_param_str!(), local_i32);
+
+ println!(
+ "{}",
+ // comment with a comma , in it
+ val,
+ );
+ println!("{}", /* comment with a comma , in it */ val);
+
+ println!(with_span!("{0} {1}" "{1} {0}"), local_i32, local_f64);
+ println!("{}", with_span!(span val));
+
+ if local_i32 > 0 {
+ panic!("p1 {}", local_i32);
+ }
+ if local_i32 > 0 {
+ panic!("p2 {0}", local_i32);
+ }
+ if local_i32 > 0 {
+ panic!("p3 {local_i32}", local_i32 = local_i32);
+ }
+ if local_i32 > 0 {
+ panic!("p4 {local_i32}");
+ }
+}
+
+fn main() {
+ tester(42);
+}
+
+fn _under_msrv() {
+ #![clippy::msrv = "1.57"]
+ let local_i32 = 1;
+ println!("don't expand='{}'", local_i32);
+}
+
+fn _meets_msrv() {
+ #![clippy::msrv = "1.58"]
+ let local_i32 = 1;
+ println!("expand='{}'", local_i32);
+}
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.stderr b/src/tools/clippy/tests/ui/uninlined_format_args.stderr
new file mode 100644
index 000000000..2ce3b7fa9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninlined_format_args.stderr
@@ -0,0 +1,879 @@
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:41:5
+ |
+LL | println!("val='{}'", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::uninlined-format-args` implied by `-D warnings`
+help: change this to
+ |
+LL - println!("val='{}'", local_i32);
+LL + println!("val='{local_i32}'");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:42:5
+ |
+LL | println!("val='{ }'", local_i32); // 3 spaces
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("val='{ }'", local_i32); // 3 spaces
+LL + println!("val='{local_i32}'"); // 3 spaces
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:43:5
+ |
+LL | println!("val='{ }'", local_i32); // tab
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("val='{ }'", local_i32); // tab
+LL + println!("val='{local_i32}'"); // tab
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:44:5
+ |
+LL | println!("val='{ }'", local_i32); // space+tab
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("val='{ }'", local_i32); // space+tab
+LL + println!("val='{local_i32}'"); // space+tab
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:45:5
+ |
+LL | println!("val='{ }'", local_i32); // tab+space
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("val='{ }'", local_i32); // tab+space
+LL + println!("val='{local_i32}'"); // tab+space
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:51:5
+ |
+LL | println!("{}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{}", local_i32);
+LL + println!("{local_i32}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:52:5
+ |
+LL | println!("{}", fn_arg);
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{}", fn_arg);
+LL + println!("{fn_arg}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:53:5
+ |
+LL | println!("{:?}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:?}", local_i32);
+LL + println!("{local_i32:?}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:54:5
+ |
+LL | println!("{:#?}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:#?}", local_i32);
+LL + println!("{local_i32:#?}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:55:5
+ |
+LL | println!("{:4}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:4}", local_i32);
+LL + println!("{local_i32:4}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:56:5
+ |
+LL | println!("{:04}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:04}", local_i32);
+LL + println!("{local_i32:04}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:57:5
+ |
+LL | println!("{:<3}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:<3}", local_i32);
+LL + println!("{local_i32:<3}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:58:5
+ |
+LL | println!("{:#010x}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:#010x}", local_i32);
+LL + println!("{local_i32:#010x}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:59:5
+ |
+LL | println!("{:.1}", local_f64);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:.1}", local_f64);
+LL + println!("{local_f64:.1}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:60:5
+ |
+LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("Hello {} is {:.*}", "x", local_i32, local_f64);
+LL + println!("Hello {} is {local_f64:.local_i32$}", "x");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:61:5
+ |
+LL | println!("Hello {} is {:.*}", local_i32, 5, local_f64);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("Hello {} is {:.*}", local_i32, 5, local_f64);
+LL + println!("Hello {local_i32} is {local_f64:.*}", 5);
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:62:5
+ |
+LL | println!("Hello {} is {2:.*}", local_i32, 5, local_f64);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("Hello {} is {2:.*}", local_i32, 5, local_f64);
+LL + println!("Hello {local_i32} is {local_f64:.*}", 5);
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:63:5
+ |
+LL | println!("{} {}", local_i32, local_f64);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{} {}", local_i32, local_f64);
+LL + println!("{local_i32} {local_f64}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:64:5
+ |
+LL | println!("{}, {}", local_i32, local_opt.unwrap());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{}, {}", local_i32, local_opt.unwrap());
+LL + println!("{local_i32}, {}", local_opt.unwrap());
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:65:5
+ |
+LL | println!("{}", val);
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{}", val);
+LL + println!("{val}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:66:5
+ |
+LL | println!("{}", v = val);
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{}", v = val);
+LL + println!("{val}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:68:5
+ |
+LL | println!("val='{/t }'", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("val='{/t }'", local_i32);
+LL + println!("val='{local_i32}'");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:69:5
+ |
+LL | println!("val='{/n }'", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("val='{/n }'", local_i32);
+LL + println!("val='{local_i32}'");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:70:5
+ |
+LL | println!("val='{local_i32}'", local_i32 = local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("val='{local_i32}'", local_i32 = local_i32);
+LL + println!("val='{local_i32}'");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:71:5
+ |
+LL | println!("val='{local_i32}'", local_i32 = fn_arg);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("val='{local_i32}'", local_i32 = fn_arg);
+LL + println!("val='{fn_arg}'");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:72:5
+ |
+LL | println!("{0}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{0}", local_i32);
+LL + println!("{local_i32}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:73:5
+ |
+LL | println!("{0:?}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{0:?}", local_i32);
+LL + println!("{local_i32:?}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:74:5
+ |
+LL | println!("{0:#?}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{0:#?}", local_i32);
+LL + println!("{local_i32:#?}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:75:5
+ |
+LL | println!("{0:04}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{0:04}", local_i32);
+LL + println!("{local_i32:04}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:76:5
+ |
+LL | println!("{0:<3}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{0:<3}", local_i32);
+LL + println!("{local_i32:<3}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:77:5
+ |
+LL | println!("{0:#010x}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{0:#010x}", local_i32);
+LL + println!("{local_i32:#010x}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:78:5
+ |
+LL | println!("{0:.1}", local_f64);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{0:.1}", local_f64);
+LL + println!("{local_f64:.1}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:79:5
+ |
+LL | println!("{0} {0}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{0} {0}", local_i32);
+LL + println!("{local_i32} {local_i32}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:80:5
+ |
+LL | println!("{1} {} {0} {}", local_i32, local_f64);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{1} {} {0} {}", local_i32, local_f64);
+LL + println!("{local_f64} {local_i32} {local_i32} {local_f64}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:81:5
+ |
+LL | println!("{0} {1}", local_i32, local_f64);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{0} {1}", local_i32, local_f64);
+LL + println!("{local_i32} {local_f64}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:82:5
+ |
+LL | println!("{1} {0}", local_i32, local_f64);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{1} {0}", local_i32, local_f64);
+LL + println!("{local_f64} {local_i32}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:83:5
+ |
+LL | println!("{1} {0} {1} {0}", local_i32, local_f64);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{1} {0} {1} {0}", local_i32, local_f64);
+LL + println!("{local_f64} {local_i32} {local_f64} {local_i32}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:85:5
+ |
+LL | println!("{v}", v = local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{v}", v = local_i32);
+LL + println!("{local_i32}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:86:5
+ |
+LL | println!("{local_i32:0$}", width);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{local_i32:0$}", width);
+LL + println!("{local_i32:width$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:87:5
+ |
+LL | println!("{local_i32:w$}", w = width);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{local_i32:w$}", w = width);
+LL + println!("{local_i32:width$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:88:5
+ |
+LL | println!("{local_i32:.0$}", prec);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{local_i32:.0$}", prec);
+LL + println!("{local_i32:.prec$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:89:5
+ |
+LL | println!("{local_i32:.p$}", p = prec);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{local_i32:.p$}", p = prec);
+LL + println!("{local_i32:.prec$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:90:5
+ |
+LL | println!("{:0$}", v = val);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:0$}", v = val);
+LL + println!("{val:val$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:91:5
+ |
+LL | println!("{0:0$}", v = val);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{0:0$}", v = val);
+LL + println!("{val:val$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:92:5
+ |
+LL | println!("{:0$.0$}", v = val);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:0$.0$}", v = val);
+LL + println!("{val:val$.val$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:93:5
+ |
+LL | println!("{0:0$.0$}", v = val);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{0:0$.0$}", v = val);
+LL + println!("{val:val$.val$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:94:5
+ |
+LL | println!("{0:0$.v$}", v = val);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{0:0$.v$}", v = val);
+LL + println!("{val:val$.val$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:95:5
+ |
+LL | println!("{0:v$.0$}", v = val);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{0:v$.0$}", v = val);
+LL + println!("{val:val$.val$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:96:5
+ |
+LL | println!("{v:0$.0$}", v = val);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{v:0$.0$}", v = val);
+LL + println!("{val:val$.val$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:97:5
+ |
+LL | println!("{v:v$.0$}", v = val);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{v:v$.0$}", v = val);
+LL + println!("{val:val$.val$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:98:5
+ |
+LL | println!("{v:0$.v$}", v = val);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{v:0$.v$}", v = val);
+LL + println!("{val:val$.val$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:99:5
+ |
+LL | println!("{v:v$.v$}", v = val);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{v:v$.v$}", v = val);
+LL + println!("{val:val$.val$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:100:5
+ |
+LL | println!("{:0$}", width);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:0$}", width);
+LL + println!("{width:width$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:101:5
+ |
+LL | println!("{:1$}", local_i32, width);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:1$}", local_i32, width);
+LL + println!("{local_i32:width$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:102:5
+ |
+LL | println!("{:w$}", w = width);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:w$}", w = width);
+LL + println!("{width:width$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:103:5
+ |
+LL | println!("{:w$}", local_i32, w = width);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:w$}", local_i32, w = width);
+LL + println!("{local_i32:width$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:104:5
+ |
+LL | println!("{:.0$}", prec);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:.0$}", prec);
+LL + println!("{prec:.prec$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:105:5
+ |
+LL | println!("{:.1$}", local_i32, prec);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:.1$}", local_i32, prec);
+LL + println!("{local_i32:.prec$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:106:5
+ |
+LL | println!("{:.p$}", p = prec);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:.p$}", p = prec);
+LL + println!("{prec:.prec$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:107:5
+ |
+LL | println!("{:.p$}", local_i32, p = prec);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:.p$}", local_i32, p = prec);
+LL + println!("{local_i32:.prec$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:108:5
+ |
+LL | println!("{:0$.1$}", width, prec);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:0$.1$}", width, prec);
+LL + println!("{width:width$.prec$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:109:5
+ |
+LL | println!("{:0$.w$}", width, w = prec);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:0$.w$}", width, w = prec);
+LL + println!("{width:width$.prec$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:110:5
+ |
+LL | println!("{:1$.2$}", local_f64, width, prec);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:1$.2$}", local_f64, width, prec);
+LL + println!("{local_f64:width$.prec$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:111:5
+ |
+LL | println!("{:1$.2$} {0} {1} {2}", local_f64, width, prec);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:1$.2$} {0} {1} {2}", local_f64, width, prec);
+LL + println!("{local_f64:width$.prec$} {local_f64} {width} {prec}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:123:5
+ |
+LL | println!("Width = {}, value with width = {:0$}", local_i32, local_f64);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("Width = {}, value with width = {:0$}", local_i32, local_f64);
+LL + println!("Width = {local_i32}, value with width = {local_f64:local_i32$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:124:5
+ |
+LL | println!("{:w$.p$}", local_i32, w = width, p = prec);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:w$.p$}", local_i32, w = width, p = prec);
+LL + println!("{local_i32:width$.prec$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:125:5
+ |
+LL | println!("{:w$.p$}", w = width, p = prec);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{:w$.p$}", w = width, p = prec);
+LL + println!("{width:width$.prec$}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:126:20
+ |
+LL | println!("{}", format!("{}", local_i32));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{}", format!("{}", local_i32));
+LL + println!("{}", format!("{local_i32}"));
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:149:5
+ |
+LL | println!("{}", /* comment with a comma , in it */ val);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("{}", /* comment with a comma , in it */ val);
+LL + println!("{val}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:155:9
+ |
+LL | panic!("p1 {}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - panic!("p1 {}", local_i32);
+LL + panic!("p1 {local_i32}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:158:9
+ |
+LL | panic!("p2 {0}", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - panic!("p2 {0}", local_i32);
+LL + panic!("p2 {local_i32}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:161:9
+ |
+LL | panic!("p3 {local_i32}", local_i32 = local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - panic!("p3 {local_i32}", local_i32 = local_i32);
+LL + panic!("p3 {local_i32}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args.rs:181:5
+ |
+LL | println!("expand='{}'", local_i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - println!("expand='{}'", local_i32);
+LL + println!("expand='{local_i32}'");
+ |
+
+error: aborting due to 73 previous errors
+
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed
new file mode 100644
index 000000000..96cc08779
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed
@@ -0,0 +1,29 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+
+#![warn(clippy::uninlined_format_args)]
+
+fn main() {
+ let var = 1;
+
+ println!("val='{var}'");
+
+ if var > 0 {
+ panic!("p1 {}", var);
+ }
+ if var > 0 {
+ panic!("p2 {0}", var);
+ }
+ if var > 0 {
+ panic!("p3 {var}", var = var);
+ }
+
+ #[allow(non_fmt_panics)]
+ {
+ if var > 0 {
+ panic!("p4 {var}");
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.stderr b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.stderr
new file mode 100644
index 000000000..2c8061259
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.stderr
@@ -0,0 +1,15 @@
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args_panic.rs:11:5
+ |
+LL | println!("val='{}'", var);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::uninlined-format-args` implied by `-D warnings`
+help: change this to
+ |
+LL - println!("val='{}'", var);
+LL + println!("val='{var}'");
+ |
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed
new file mode 100644
index 000000000..faf8ca4d3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed
@@ -0,0 +1,29 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+
+#![warn(clippy::uninlined_format_args)]
+
+fn main() {
+ let var = 1;
+
+ println!("val='{var}'");
+
+ if var > 0 {
+ panic!("p1 {var}");
+ }
+ if var > 0 {
+ panic!("p2 {var}");
+ }
+ if var > 0 {
+ panic!("p3 {var}");
+ }
+
+ #[allow(non_fmt_panics)]
+ {
+ if var > 0 {
+ panic!("p4 {var}");
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr
new file mode 100644
index 000000000..0f09c45f4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr
@@ -0,0 +1,51 @@
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args_panic.rs:11:5
+ |
+LL | println!("val='{}'", var);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::uninlined-format-args` implied by `-D warnings`
+help: change this to
+ |
+LL - println!("val='{}'", var);
+LL + println!("val='{var}'");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args_panic.rs:14:9
+ |
+LL | panic!("p1 {}", var);
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - panic!("p1 {}", var);
+LL + panic!("p1 {var}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args_panic.rs:17:9
+ |
+LL | panic!("p2 {0}", var);
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - panic!("p2 {0}", var);
+LL + panic!("p2 {var}");
+ |
+
+error: variables can be used directly in the `format!` string
+ --> $DIR/uninlined_format_args_panic.rs:20:9
+ |
+LL | panic!("p3 {var}", var = var);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: change this to
+ |
+LL - panic!("p3 {var}", var = var);
+LL + panic!("p3 {var}");
+ |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs b/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs
new file mode 100644
index 000000000..6421c5bbe
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs
@@ -0,0 +1,29 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+
+#![warn(clippy::uninlined_format_args)]
+
+fn main() {
+ let var = 1;
+
+ println!("val='{}'", var);
+
+ if var > 0 {
+ panic!("p1 {}", var);
+ }
+ if var > 0 {
+ panic!("p2 {0}", var);
+ }
+ if var > 0 {
+ panic!("p3 {var}", var = var);
+ }
+
+ #[allow(non_fmt_panics)]
+ {
+ if var > 0 {
+ panic!("p4 {var}");
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs
index 38be87bdd..07e70873a 100644
--- a/src/tools/clippy/tests/ui/unit_arg.rs
+++ b/src/tools/clippy/tests/ui/unit_arg.rs
@@ -1,16 +1,21 @@
+// aux-build: proc_macro_with_span.rs
#![warn(clippy::unit_arg)]
+#![allow(unused_must_use, unused_variables)]
#![allow(
+ clippy::let_unit_value,
+ clippy::needless_question_mark,
+ clippy::never_loop,
clippy::no_effect,
- unused_must_use,
- unused_variables,
- clippy::unused_unit,
- clippy::unnecessary_wraps,
clippy::or_fun_call,
- clippy::needless_question_mark,
clippy::self_named_constructors,
- clippy::let_unit_value
+ clippy::uninlined_format_args,
+ clippy::unnecessary_wraps,
+ clippy::unused_unit
)]
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
use std::fmt::Debug;
fn foo<T: Debug>(t: T) {
@@ -127,6 +132,10 @@ fn returning_expr() -> Option<()> {
fn taking_multiple_units(a: (), b: ()) {}
+fn proc_macro() {
+ with_span!(span taking_multiple_units(unsafe { (); }, 'x: loop { break 'x (); }));
+}
+
fn main() {
bad();
ok();
diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr
index 11cfe66a3..74d4d2f40 100644
--- a/src/tools/clippy/tests/ui/unit_arg.stderr
+++ b/src/tools/clippy/tests/ui/unit_arg.stderr
@@ -1,5 +1,5 @@
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:57:5
+ --> $DIR/unit_arg.rs:62:5
|
LL | / foo({
LL | | 1;
@@ -20,7 +20,7 @@ LL ~ foo(());
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:60:5
+ --> $DIR/unit_arg.rs:65:5
|
LL | foo(foo(1));
| ^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL ~ foo(());
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:61:5
+ --> $DIR/unit_arg.rs:66:5
|
LL | / foo({
LL | | foo(1);
@@ -54,7 +54,7 @@ LL ~ foo(());
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:66:5
+ --> $DIR/unit_arg.rs:71:5
|
LL | / b.bar({
LL | | 1;
@@ -74,7 +74,7 @@ LL ~ b.bar(());
|
error: passing unit values to a function
- --> $DIR/unit_arg.rs:69:5
+ --> $DIR/unit_arg.rs:74:5
|
LL | taking_multiple_units(foo(0), foo(1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -87,7 +87,7 @@ LL ~ taking_multiple_units((), ());
|
error: passing unit values to a function
- --> $DIR/unit_arg.rs:70:5
+ --> $DIR/unit_arg.rs:75:5
|
LL | / taking_multiple_units(foo(0), {
LL | | foo(1);
@@ -110,7 +110,7 @@ LL ~ taking_multiple_units((), ());
|
error: passing unit values to a function
- --> $DIR/unit_arg.rs:74:5
+ --> $DIR/unit_arg.rs:79:5
|
LL | / taking_multiple_units(
LL | | {
@@ -146,7 +146,7 @@ LL ~ );
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:85:13
+ --> $DIR/unit_arg.rs:90:13
|
LL | None.or(Some(foo(2)));
| ^^^^^^^^^^^^
@@ -160,7 +160,7 @@ LL ~ });
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:88:5
+ --> $DIR/unit_arg.rs:93:5
|
LL | foo(foo(()));
| ^^^^^^^^^^^^
@@ -172,7 +172,7 @@ LL ~ foo(());
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:125:5
+ --> $DIR/unit_arg.rs:130:5
|
LL | Some(foo(1))
| ^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed
index 9400e93ca..5787471a3 100644
--- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed
+++ b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed
@@ -1,6 +1,7 @@
// run-rustfix
#![warn(clippy::unit_arg)]
-#![allow(clippy::no_effect, unused_must_use, unused_variables)]
+#![allow(unused_must_use, unused_variables)]
+#![allow(clippy::no_effect, clippy::uninlined_format_args)]
use std::fmt::Debug;
diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs
index 5f52b6c53..6a42c2ccf 100644
--- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs
+++ b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs
@@ -1,6 +1,7 @@
// run-rustfix
#![warn(clippy::unit_arg)]
-#![allow(clippy::no_effect, unused_must_use, unused_variables)]
+#![allow(unused_must_use, unused_variables)]
+#![allow(clippy::no_effect, clippy::uninlined_format_args)]
use std::fmt::Debug;
diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr
index d35e93169..c697dfb1e 100644
--- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr
+++ b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr
@@ -1,5 +1,5 @@
error: passing a unit value to a function
- --> $DIR/unit_arg_empty_blocks.rs:16:5
+ --> $DIR/unit_arg_empty_blocks.rs:17:5
|
LL | foo({});
| ^^^^--^
@@ -9,7 +9,7 @@ LL | foo({});
= note: `-D clippy::unit-arg` implied by `-D warnings`
error: passing a unit value to a function
- --> $DIR/unit_arg_empty_blocks.rs:17:5
+ --> $DIR/unit_arg_empty_blocks.rs:18:5
|
LL | foo3({}, 2, 2);
| ^^^^^--^^^^^^^
@@ -17,7 +17,7 @@ LL | foo3({}, 2, 2);
| help: use a unit literal instead: `()`
error: passing unit values to a function
- --> $DIR/unit_arg_empty_blocks.rs:18:5
+ --> $DIR/unit_arg_empty_blocks.rs:19:5
|
LL | taking_two_units({}, foo(0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -29,7 +29,7 @@ LL ~ taking_two_units((), ());
|
error: passing unit values to a function
- --> $DIR/unit_arg_empty_blocks.rs:19:5
+ --> $DIR/unit_arg_empty_blocks.rs:20:5
|
LL | taking_three_units({}, foo(0), foo(1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/unit_hash.stderr b/src/tools/clippy/tests/ui/unit_hash.stderr
index 050fa55a1..089d1212d 100644
--- a/src/tools/clippy/tests/ui/unit_hash.stderr
+++ b/src/tools/clippy/tests/ui/unit_hash.stderr
@@ -4,8 +4,8 @@ error: this call to `hash` on the unit type will do nothing
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
+ = note: `-D clippy::unit-hash` implied by `-D warnings`
error: this call to `hash` on the unit type will do nothing
--> $DIR/unit_hash.rs:24:5
diff --git a/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr b/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr
index e63d58746..1d9564ce2 100644
--- a/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr
+++ b/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr
@@ -4,12 +4,12 @@ error: this closure returns the unit type which also implements Ord
LL | structs.sort_by_key(|s| {
| ^^^
|
- = note: `-D clippy::unit-return-expecting-ord` implied by `-D warnings`
help: probably caused by this trailing semicolon
--> $DIR/unit_return_expecting_ord.rs:19:24
|
LL | double(s.field);
| ^
+ = note: `-D clippy::unit-return-expecting-ord` implied by `-D warnings`
error: this closure returns the unit type which also implements PartialOrd
--> $DIR/unit_return_expecting_ord.rs:22:30
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.fixed b/src/tools/clippy/tests/ui/unnecessary_cast.fixed
index b352b285c..ec8c6abfa 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.fixed
@@ -88,4 +88,31 @@ mod fixable {
}
type I32Alias = i32;
+
+ fn issue_9380() {
+ let _: i32 = -1_i32;
+ let _: f32 = -(1) as f32;
+ let _: i64 = -1_i64;
+ let _: i64 = -(1.0) as i64;
+
+ let _ = -(1 + 1) as i64;
+ }
+
+ fn issue_9563() {
+ let _: f64 = (-8.0_f64).exp();
+ #[allow(clippy::precedence)]
+ let _: f64 = -8.0_f64.exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior
+ }
+
+ fn issue_9562_non_literal() {
+ fn foo() -> f32 {
+ 0.
+ }
+
+ let _num = foo();
+ }
+
+ fn issue_9603() {
+ let _: f32 = -0x400 as f32;
+ }
}
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs
index 6c8cc3eff..5213cdc26 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs
@@ -88,4 +88,31 @@ mod fixable {
}
type I32Alias = i32;
+
+ fn issue_9380() {
+ let _: i32 = -(1) as i32;
+ let _: f32 = -(1) as f32;
+ let _: i64 = -(1) as i64;
+ let _: i64 = -(1.0) as i64;
+
+ let _ = -(1 + 1) as i64;
+ }
+
+ fn issue_9563() {
+ let _: f64 = (-8.0 as f64).exp();
+ #[allow(clippy::precedence)]
+ let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior
+ }
+
+ fn issue_9562_non_literal() {
+ fn foo() -> f32 {
+ 0.
+ }
+
+ let _num = foo() as f32;
+ }
+
+ fn issue_9603() {
+ let _: f32 = -0x400 as f32;
+ }
}
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
index bad45f002..e5c3dd5e5 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
@@ -150,5 +150,35 @@ error: casting float literal to `f32` is unnecessary
LL | let _ = -1.0 as f32;
| ^^^^^^^^^^^ help: try: `-1.0_f32`
-error: aborting due to 25 previous errors
+error: casting integer literal to `i32` is unnecessary
+ --> $DIR/unnecessary_cast.rs:93:22
+ |
+LL | let _: i32 = -(1) as i32;
+ | ^^^^^^^^^^^ help: try: `-1_i32`
+
+error: casting integer literal to `i64` is unnecessary
+ --> $DIR/unnecessary_cast.rs:95:22
+ |
+LL | let _: i64 = -(1) as i64;
+ | ^^^^^^^^^^^ help: try: `-1_i64`
+
+error: casting float literal to `f64` is unnecessary
+ --> $DIR/unnecessary_cast.rs:102:22
+ |
+LL | let _: f64 = (-8.0 as f64).exp();
+ | ^^^^^^^^^^^^^ help: try: `(-8.0_f64)`
+
+error: casting float literal to `f64` is unnecessary
+ --> $DIR/unnecessary_cast.rs:104:23
+ |
+LL | let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior
+ | ^^^^^^^^^^^^ help: try: `8.0_f64`
+
+error: casting to the same type is unnecessary (`f32` -> `f32`)
+ --> $DIR/unnecessary_cast.rs:112:20
+ |
+LL | let _num = foo() as f32;
+ | ^^^^^^^^^^^^ help: try: `foo()`
+
+error: aborting due to 30 previous errors
diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.rs b/src/tools/clippy/tests/ui/unnecessary_clone.rs
index 6770a7fac..8b1629b19 100644
--- a/src/tools/clippy/tests/ui/unnecessary_clone.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_clone.rs
@@ -1,7 +1,7 @@
// does not test any rustfixable lints
-
#![warn(clippy::clone_on_ref_ptr)]
-#![allow(unused, clippy::redundant_clone, clippy::unnecessary_wraps)]
+#![allow(unused)]
+#![allow(clippy::redundant_clone, clippy::uninlined_format_args, clippy::unnecessary_wraps)]
use std::cell::RefCell;
use std::rc::{self, Rc};
diff --git a/src/tools/clippy/tests/ui/unnecessary_join.fixed b/src/tools/clippy/tests/ui/unnecessary_join.fixed
index 7e12c6ae4..347953960 100644
--- a/src/tools/clippy/tests/ui/unnecessary_join.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_join.fixed
@@ -1,6 +1,6 @@
// run-rustfix
-
#![warn(clippy::unnecessary_join)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
// should be linted
diff --git a/src/tools/clippy/tests/ui/unnecessary_join.rs b/src/tools/clippy/tests/ui/unnecessary_join.rs
index 0a21656a7..344918cd2 100644
--- a/src/tools/clippy/tests/ui/unnecessary_join.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_join.rs
@@ -1,6 +1,6 @@
// run-rustfix
-
#![warn(clippy::unnecessary_join)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
// should be linted
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
index eed817968..ce4a82e02 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
@@ -1,9 +1,13 @@
// run-rustfix
+// aux-build: proc_macro_with_span.rs
#![warn(clippy::unnecessary_lazy_evaluations)]
#![allow(clippy::redundant_closure)]
#![allow(clippy::bind_instead_of_map)]
#![allow(clippy::map_identity)]
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
struct Deep(Option<usize>);
#[derive(Copy, Clone)]
@@ -21,6 +25,14 @@ fn some_call<T: Default>() -> T {
T::default()
}
+struct Issue9427(i32);
+
+impl Drop for Issue9427 {
+ fn drop(&mut self) {
+ println!("{}", self.0);
+ }
+}
+
fn main() {
let astronomers_pi = 10;
let ext_arr: [usize; 1] = [2];
@@ -73,6 +85,9 @@ fn main() {
let _ = deep.0.or_else(|| some_call());
let _ = opt.ok_or_else(|| ext_arr[0]);
+ // Should not lint - bool
+ let _ = (0 == 1).then(|| Issue9427(0)); // Issue9427 has a significant drop
+
// should not lint, bind_instead_of_map takes priority
let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
let _ = Some(10).and_then(|idx| Some(idx));
@@ -130,3 +145,9 @@ fn main() {
let _: Result<usize, usize> = res.and_then(|x| Err(x));
let _: Result<usize, usize> = res.or_else(|err| Ok(err));
}
+
+#[allow(unused)]
+fn issue9485() {
+ // should not lint, is in proc macro
+ with_span!(span Some(42).unwrap_or_else(|| 2););
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
index 1588db79b..59cdf6628 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
@@ -1,9 +1,13 @@
// run-rustfix
+// aux-build: proc_macro_with_span.rs
#![warn(clippy::unnecessary_lazy_evaluations)]
#![allow(clippy::redundant_closure)]
#![allow(clippy::bind_instead_of_map)]
#![allow(clippy::map_identity)]
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
struct Deep(Option<usize>);
#[derive(Copy, Clone)]
@@ -21,6 +25,14 @@ fn some_call<T: Default>() -> T {
T::default()
}
+struct Issue9427(i32);
+
+impl Drop for Issue9427 {
+ fn drop(&mut self) {
+ println!("{}", self.0);
+ }
+}
+
fn main() {
let astronomers_pi = 10;
let ext_arr: [usize; 1] = [2];
@@ -73,6 +85,9 @@ fn main() {
let _ = deep.0.or_else(|| some_call());
let _ = opt.ok_or_else(|| ext_arr[0]);
+ // Should not lint - bool
+ let _ = (0 == 1).then(|| Issue9427(0)); // Issue9427 has a significant drop
+
// should not lint, bind_instead_of_map takes priority
let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
let _ = Some(10).and_then(|idx| Some(idx));
@@ -130,3 +145,9 @@ fn main() {
let _: Result<usize, usize> = res.and_then(|x| Err(x));
let _: Result<usize, usize> = res.or_else(|err| Ok(err));
}
+
+#[allow(unused)]
+fn issue9485() {
+ // should not lint, is in proc macro
+ with_span!(span Some(42).unwrap_or_else(|| 2););
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr
index 83dc7fd83..8a9ece4aa 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr
@@ -1,5 +1,5 @@
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:36:13
+ --> $DIR/unnecessary_lazy_eval.rs:48:13
|
LL | let _ = opt.unwrap_or_else(|| 2);
| ^^^^--------------------
@@ -9,7 +9,7 @@ LL | let _ = opt.unwrap_or_else(|| 2);
= note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:37:13
+ --> $DIR/unnecessary_lazy_eval.rs:49:13
|
LL | let _ = opt.unwrap_or_else(|| astronomers_pi);
| ^^^^---------------------------------
@@ -17,7 +17,7 @@ LL | let _ = opt.unwrap_or_else(|| astronomers_pi);
| help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:38:13
+ --> $DIR/unnecessary_lazy_eval.rs:50:13
|
LL | let _ = opt.unwrap_or_else(|| ext_str.some_field);
| ^^^^-------------------------------------
@@ -25,7 +25,7 @@ LL | let _ = opt.unwrap_or_else(|| ext_str.some_field);
| help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:40:13
+ --> $DIR/unnecessary_lazy_eval.rs:52:13
|
LL | let _ = opt.and_then(|_| ext_opt);
| ^^^^---------------------
@@ -33,7 +33,7 @@ LL | let _ = opt.and_then(|_| ext_opt);
| help: use `and(..)` instead: `and(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:41:13
+ --> $DIR/unnecessary_lazy_eval.rs:53:13
|
LL | let _ = opt.or_else(|| ext_opt);
| ^^^^-------------------
@@ -41,7 +41,7 @@ LL | let _ = opt.or_else(|| ext_opt);
| help: use `or(..)` instead: `or(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:42:13
+ --> $DIR/unnecessary_lazy_eval.rs:54:13
|
LL | let _ = opt.or_else(|| None);
| ^^^^----------------
@@ -49,7 +49,7 @@ LL | let _ = opt.or_else(|| None);
| help: use `or(..)` instead: `or(None)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:43:13
+ --> $DIR/unnecessary_lazy_eval.rs:55:13
|
LL | let _ = opt.get_or_insert_with(|| 2);
| ^^^^------------------------
@@ -57,7 +57,7 @@ LL | let _ = opt.get_or_insert_with(|| 2);
| help: use `get_or_insert(..)` instead: `get_or_insert(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:44:13
+ --> $DIR/unnecessary_lazy_eval.rs:56:13
|
LL | let _ = opt.ok_or_else(|| 2);
| ^^^^----------------
@@ -65,7 +65,7 @@ LL | let _ = opt.ok_or_else(|| 2);
| help: use `ok_or(..)` instead: `ok_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:45:13
+ --> $DIR/unnecessary_lazy_eval.rs:57:13
|
LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
| ^^^^^^^^^^^^^^^^^-------------------------------
@@ -73,7 +73,7 @@ LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
| help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))`
error: unnecessary closure used with `bool::then`
- --> $DIR/unnecessary_lazy_eval.rs:46:13
+ --> $DIR/unnecessary_lazy_eval.rs:58:13
|
LL | let _ = cond.then(|| astronomers_pi);
| ^^^^^-----------------------
@@ -81,7 +81,7 @@ LL | let _ = cond.then(|| astronomers_pi);
| help: use `then_some(..)` instead: `then_some(astronomers_pi)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:49:13
+ --> $DIR/unnecessary_lazy_eval.rs:61:13
|
LL | let _ = Some(10).unwrap_or_else(|| 2);
| ^^^^^^^^^--------------------
@@ -89,7 +89,7 @@ LL | let _ = Some(10).unwrap_or_else(|| 2);
| help: use `unwrap_or(..)` instead: `unwrap_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:50:13
+ --> $DIR/unnecessary_lazy_eval.rs:62:13
|
LL | let _ = Some(10).and_then(|_| ext_opt);
| ^^^^^^^^^---------------------
@@ -97,7 +97,7 @@ LL | let _ = Some(10).and_then(|_| ext_opt);
| help: use `and(..)` instead: `and(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:51:28
+ --> $DIR/unnecessary_lazy_eval.rs:63:28
|
LL | let _: Option<usize> = None.or_else(|| ext_opt);
| ^^^^^-------------------
@@ -105,7 +105,7 @@ LL | let _: Option<usize> = None.or_else(|| ext_opt);
| help: use `or(..)` instead: `or(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:52:13
+ --> $DIR/unnecessary_lazy_eval.rs:64:13
|
LL | let _ = None.get_or_insert_with(|| 2);
| ^^^^^------------------------
@@ -113,7 +113,7 @@ LL | let _ = None.get_or_insert_with(|| 2);
| help: use `get_or_insert(..)` instead: `get_or_insert(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:53:35
+ --> $DIR/unnecessary_lazy_eval.rs:65:35
|
LL | let _: Result<usize, usize> = None.ok_or_else(|| 2);
| ^^^^^----------------
@@ -121,7 +121,7 @@ LL | let _: Result<usize, usize> = None.ok_or_else(|| 2);
| help: use `ok_or(..)` instead: `ok_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:54:28
+ --> $DIR/unnecessary_lazy_eval.rs:66:28
|
LL | let _: Option<usize> = None.or_else(|| None);
| ^^^^^----------------
@@ -129,7 +129,7 @@ LL | let _: Option<usize> = None.or_else(|| None);
| help: use `or(..)` instead: `or(None)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:57:13
+ --> $DIR/unnecessary_lazy_eval.rs:69:13
|
LL | let _ = deep.0.unwrap_or_else(|| 2);
| ^^^^^^^--------------------
@@ -137,7 +137,7 @@ LL | let _ = deep.0.unwrap_or_else(|| 2);
| help: use `unwrap_or(..)` instead: `unwrap_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:58:13
+ --> $DIR/unnecessary_lazy_eval.rs:70:13
|
LL | let _ = deep.0.and_then(|_| ext_opt);
| ^^^^^^^---------------------
@@ -145,7 +145,7 @@ LL | let _ = deep.0.and_then(|_| ext_opt);
| help: use `and(..)` instead: `and(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:59:13
+ --> $DIR/unnecessary_lazy_eval.rs:71:13
|
LL | let _ = deep.0.or_else(|| None);
| ^^^^^^^----------------
@@ -153,7 +153,7 @@ LL | let _ = deep.0.or_else(|| None);
| help: use `or(..)` instead: `or(None)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:60:13
+ --> $DIR/unnecessary_lazy_eval.rs:72:13
|
LL | let _ = deep.0.get_or_insert_with(|| 2);
| ^^^^^^^------------------------
@@ -161,7 +161,7 @@ LL | let _ = deep.0.get_or_insert_with(|| 2);
| help: use `get_or_insert(..)` instead: `get_or_insert(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:61:13
+ --> $DIR/unnecessary_lazy_eval.rs:73:13
|
LL | let _ = deep.0.ok_or_else(|| 2);
| ^^^^^^^----------------
@@ -169,7 +169,7 @@ LL | let _ = deep.0.ok_or_else(|| 2);
| help: use `ok_or(..)` instead: `ok_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:81:28
+ --> $DIR/unnecessary_lazy_eval.rs:96:28
|
LL | let _: Option<usize> = None.or_else(|| Some(3));
| ^^^^^-------------------
@@ -177,7 +177,7 @@ LL | let _: Option<usize> = None.or_else(|| Some(3));
| help: use `or(..)` instead: `or(Some(3))`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:82:13
+ --> $DIR/unnecessary_lazy_eval.rs:97:13
|
LL | let _ = deep.0.or_else(|| Some(3));
| ^^^^^^^-------------------
@@ -185,7 +185,7 @@ LL | let _ = deep.0.or_else(|| Some(3));
| help: use `or(..)` instead: `or(Some(3))`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:83:13
+ --> $DIR/unnecessary_lazy_eval.rs:98:13
|
LL | let _ = opt.or_else(|| Some(3));
| ^^^^-------------------
@@ -193,7 +193,7 @@ LL | let _ = opt.or_else(|| Some(3));
| help: use `or(..)` instead: `or(Some(3))`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:89:13
+ --> $DIR/unnecessary_lazy_eval.rs:104:13
|
LL | let _ = res2.unwrap_or_else(|_| 2);
| ^^^^^---------------------
@@ -201,7 +201,7 @@ LL | let _ = res2.unwrap_or_else(|_| 2);
| help: use `unwrap_or(..)` instead: `unwrap_or(2)`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:90:13
+ --> $DIR/unnecessary_lazy_eval.rs:105:13
|
LL | let _ = res2.unwrap_or_else(|_| astronomers_pi);
| ^^^^^----------------------------------
@@ -209,7 +209,7 @@ LL | let _ = res2.unwrap_or_else(|_| astronomers_pi);
| help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:91:13
+ --> $DIR/unnecessary_lazy_eval.rs:106:13
|
LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field);
| ^^^^^--------------------------------------
@@ -217,7 +217,7 @@ LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field);
| help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:113:35
+ --> $DIR/unnecessary_lazy_eval.rs:128:35
|
LL | let _: Result<usize, usize> = res.and_then(|_| Err(2));
| ^^^^--------------------
@@ -225,7 +225,7 @@ LL | let _: Result<usize, usize> = res.and_then(|_| Err(2));
| help: use `and(..)` instead: `and(Err(2))`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:114:35
+ --> $DIR/unnecessary_lazy_eval.rs:129:35
|
LL | let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
| ^^^^---------------------------------
@@ -233,7 +233,7 @@ LL | let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
| help: use `and(..)` instead: `and(Err(astronomers_pi))`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:115:35
+ --> $DIR/unnecessary_lazy_eval.rs:130:35
|
LL | let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
| ^^^^-------------------------------------
@@ -241,7 +241,7 @@ LL | let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field))
| help: use `and(..)` instead: `and(Err(ext_str.some_field))`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:117:35
+ --> $DIR/unnecessary_lazy_eval.rs:132:35
|
LL | let _: Result<usize, usize> = res.or_else(|_| Ok(2));
| ^^^^------------------
@@ -249,7 +249,7 @@ LL | let _: Result<usize, usize> = res.or_else(|_| Ok(2));
| help: use `or(..)` instead: `or(Ok(2))`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:118:35
+ --> $DIR/unnecessary_lazy_eval.rs:133:35
|
LL | let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
| ^^^^-------------------------------
@@ -257,7 +257,7 @@ LL | let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
| help: use `or(..)` instead: `or(Ok(astronomers_pi))`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:119:35
+ --> $DIR/unnecessary_lazy_eval.rs:134:35
|
LL | let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
| ^^^^-----------------------------------
@@ -265,7 +265,7 @@ LL | let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
| help: use `or(..)` instead: `or(Ok(ext_str.some_field))`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:120:35
+ --> $DIR/unnecessary_lazy_eval.rs:135:35
|
LL | let _: Result<usize, usize> = res.
| ___________________________________^
diff --git a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.fixed b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.fixed
index f95f91329..40052c410 100644
--- a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.fixed
@@ -12,6 +12,7 @@ fn main() {
ref_str_argument("");
// should be linted
+ #[allow(clippy::manual_string_new)]
ref_str_argument("");
// should not be linted
diff --git a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.rs b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.rs
index 0cbdc151e..2304dff51 100644
--- a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.rs
@@ -12,6 +12,7 @@ fn main() {
ref_str_argument(&String::new());
// should be linted
+ #[allow(clippy::manual_string_new)]
ref_str_argument(&String::from(""));
// should not be linted
diff --git a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.stderr b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.stderr
index 46bc4597b..1eb198a86 100644
--- a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.stderr
@@ -7,7 +7,7 @@ LL | ref_str_argument(&String::new());
= note: `-D clippy::unnecessary-owned-empty-strings` implied by `-D warnings`
error: usage of `&String::from("")` for a function expecting a `&str` argument
- --> $DIR/unnecessary_owned_empty_strings.rs:15:22
+ --> $DIR/unnecessary_owned_empty_strings.rs:16:22
|
LL | ref_str_argument(&String::from(""));
| ^^^^^^^^^^^^^^^^^ help: try: `""`
diff --git a/src/tools/clippy/tests/ui/unnecessary_self_imports.stderr b/src/tools/clippy/tests/ui/unnecessary_self_imports.stderr
index 83a5618c9..db805eb36 100644
--- a/src/tools/clippy/tests/ui/unnecessary_self_imports.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_self_imports.stderr
@@ -6,8 +6,8 @@ LL | use std::fs::{self as alias};
| |
| help: consider omitting `::{self}`: `fs as alias;`
|
- = note: `-D clippy::unnecessary-self-imports` implied by `-D warnings`
= note: this will slightly change semantics; any non-module items at the same path will also be imported
+ = note: `-D clippy::unnecessary-self-imports` implied by `-D warnings`
error: import ending with `::{self}`
--> $DIR/unnecessary_self_imports.rs:8:1
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
index f4f76cd3d..fe09aad06 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
@@ -1,6 +1,6 @@
// run-rustfix
-#![allow(clippy::ptr_arg)]
+#![allow(clippy::needless_borrow, clippy::ptr_arg)]
#![warn(clippy::unnecessary_to_owned)]
#![feature(custom_inner_attributes)]
@@ -329,3 +329,100 @@ mod issue_8759_variant {
rw.set_view(&rw.default_view().to_owned());
}
}
+
+mod issue_9317 {
+ #![allow(dead_code)]
+
+ struct Bytes {}
+
+ impl ToString for Bytes {
+ fn to_string(&self) -> String {
+ "123".to_string()
+ }
+ }
+
+ impl AsRef<[u8]> for Bytes {
+ fn as_ref(&self) -> &[u8] {
+ &[1, 2, 3]
+ }
+ }
+
+ fn consume<C: AsRef<[u8]>>(c: C) {
+ let _ = c;
+ }
+
+ pub fn main() {
+ let b = Bytes {};
+ // Should not lint.
+ consume(b.to_string());
+ }
+}
+
+mod issue_9351 {
+ #![allow(dead_code)]
+
+ use std::ops::Deref;
+ use std::path::{Path, PathBuf};
+
+ fn require_deref_path<T: Deref<Target = std::path::Path>>(x: T) -> T {
+ x
+ }
+
+ fn generic_arg_used_elsewhere<T: AsRef<Path>>(_x: T, _y: T) {}
+
+ fn id<T: AsRef<str>>(x: T) -> T {
+ x
+ }
+
+ fn predicates_are_satisfied(_x: impl std::fmt::Write) {}
+
+ // Should lint
+ fn single_return() -> impl AsRef<str> {
+ id("abc")
+ }
+
+ // Should not lint
+ fn multiple_returns(b: bool) -> impl AsRef<str> {
+ if b {
+ return String::new();
+ }
+
+ id("abc".to_string())
+ }
+
+ struct S1(String);
+
+ // Should not lint
+ fn fields1() -> S1 {
+ S1(id("abc".to_string()))
+ }
+
+ struct S2 {
+ s: String,
+ }
+
+ // Should not lint
+ fn fields2() {
+ let mut s = S2 { s: "abc".into() };
+ s.s = id("abc".to_string());
+ }
+
+ pub fn main() {
+ let path = std::path::Path::new("x");
+ let path_buf = path.to_owned();
+
+ // Should not lint.
+ let _x: PathBuf = require_deref_path(path.to_owned());
+ generic_arg_used_elsewhere(path.to_owned(), path_buf);
+ predicates_are_satisfied(id("abc".to_string()));
+ }
+}
+
+mod issue_9504 {
+ #![allow(dead_code)]
+
+ async fn foo<S: AsRef<str>>(_: S) {}
+ async fn bar() {
+ foo(std::path::PathBuf::new().to_string_lossy().to_string()).await;
+ }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
index fe09a489a..3de6d0903 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
@@ -1,6 +1,6 @@
// run-rustfix
-#![allow(clippy::ptr_arg)]
+#![allow(clippy::needless_borrow, clippy::ptr_arg)]
#![warn(clippy::unnecessary_to_owned)]
#![feature(custom_inner_attributes)]
@@ -329,3 +329,100 @@ mod issue_8759_variant {
rw.set_view(&rw.default_view().to_owned());
}
}
+
+mod issue_9317 {
+ #![allow(dead_code)]
+
+ struct Bytes {}
+
+ impl ToString for Bytes {
+ fn to_string(&self) -> String {
+ "123".to_string()
+ }
+ }
+
+ impl AsRef<[u8]> for Bytes {
+ fn as_ref(&self) -> &[u8] {
+ &[1, 2, 3]
+ }
+ }
+
+ fn consume<C: AsRef<[u8]>>(c: C) {
+ let _ = c;
+ }
+
+ pub fn main() {
+ let b = Bytes {};
+ // Should not lint.
+ consume(b.to_string());
+ }
+}
+
+mod issue_9351 {
+ #![allow(dead_code)]
+
+ use std::ops::Deref;
+ use std::path::{Path, PathBuf};
+
+ fn require_deref_path<T: Deref<Target = std::path::Path>>(x: T) -> T {
+ x
+ }
+
+ fn generic_arg_used_elsewhere<T: AsRef<Path>>(_x: T, _y: T) {}
+
+ fn id<T: AsRef<str>>(x: T) -> T {
+ x
+ }
+
+ fn predicates_are_satisfied(_x: impl std::fmt::Write) {}
+
+ // Should lint
+ fn single_return() -> impl AsRef<str> {
+ id("abc".to_string())
+ }
+
+ // Should not lint
+ fn multiple_returns(b: bool) -> impl AsRef<str> {
+ if b {
+ return String::new();
+ }
+
+ id("abc".to_string())
+ }
+
+ struct S1(String);
+
+ // Should not lint
+ fn fields1() -> S1 {
+ S1(id("abc".to_string()))
+ }
+
+ struct S2 {
+ s: String,
+ }
+
+ // Should not lint
+ fn fields2() {
+ let mut s = S2 { s: "abc".into() };
+ s.s = id("abc".to_string());
+ }
+
+ pub fn main() {
+ let path = std::path::Path::new("x");
+ let path_buf = path.to_owned();
+
+ // Should not lint.
+ let _x: PathBuf = require_deref_path(path.to_owned());
+ generic_arg_used_elsewhere(path.to_owned(), path_buf);
+ predicates_are_satisfied(id("abc".to_string()));
+ }
+}
+
+mod issue_9504 {
+ #![allow(dead_code)]
+
+ async fn foo<S: AsRef<str>>(_: S) {}
+ async fn bar() {
+ foo(std::path::PathBuf::new().to_string_lossy().to_string()).await;
+ }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
index 243b4599d..02bf45a33 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
@@ -4,12 +4,12 @@ error: redundant clone
LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
| ^^^^^^^^^^^ help: remove this
|
- = note: `-D clippy::redundant-clone` implied by `-D warnings`
note: this value is dropped without further use
--> $DIR/unnecessary_to_owned.rs:151:20
|
LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: `-D clippy::redundant-clone` implied by `-D warnings`
error: redundant clone
--> $DIR/unnecessary_to_owned.rs:152:40
@@ -509,5 +509,11 @@ error: unnecessary use of `to_string`
LL | Box::new(build(y.to_string()))
| ^^^^^^^^^^^^^ help: use: `y`
-error: aborting due to 78 previous errors
+error: unnecessary use of `to_string`
+ --> $DIR/unnecessary_to_owned.rs:381:12
+ |
+LL | id("abc".to_string())
+ | ^^^^^^^^^^^^^^^^^ help: use: `"abc"`
+
+error: aborting due to 79 previous errors
diff --git a/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr b/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr
index b8d3c2945..6f7c31545 100644
--- a/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr
+++ b/src/tools/clippy/tests/ui/unneeded_field_pattern.stderr
@@ -4,8 +4,8 @@ error: you matched a field with a wildcard pattern, consider using `..` instead
LL | Foo { a: _, b: 0, .. } => {},
| ^^^^
|
- = note: `-D clippy::unneeded-field-pattern` implied by `-D warnings`
= help: try with `Foo { b: 0, .. }`
+ = note: `-D clippy::unneeded-field-pattern` implied by `-D warnings`
error: all the struct fields are matched to a wildcard pattern, consider using `..`
--> $DIR/unneeded_field_pattern.rs:16:9
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed
index c223b5bc7..9786c7b12 100644
--- a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed
@@ -1,9 +1,9 @@
// run-rustfix
-#![feature(box_patterns)]
+#![feature(box_patterns, custom_inner_attributes)]
#![warn(clippy::unnested_or_patterns)]
#![allow(clippy::cognitive_complexity, clippy::match_ref_pats, clippy::upper_case_acronyms)]
-#![allow(unreachable_patterns, irrefutable_let_patterns, unused_variables)]
+#![allow(unreachable_patterns, irrefutable_let_patterns, unused)]
fn main() {
// Should be ignored by this lint, as nesting requires more characters.
@@ -33,3 +33,15 @@ fn main() {
if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {}
if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
}
+
+fn msrv_1_52() {
+ #![clippy::msrv = "1.52"]
+
+ if let [1] | [52] = [0] {}
+}
+
+fn msrv_1_53() {
+ #![clippy::msrv = "1.53"]
+
+ if let [1 | 53] = [0] {}
+}
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.rs b/src/tools/clippy/tests/ui/unnested_or_patterns.rs
index 04cd11036..f57322396 100644
--- a/src/tools/clippy/tests/ui/unnested_or_patterns.rs
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.rs
@@ -1,9 +1,9 @@
// run-rustfix
-#![feature(box_patterns)]
+#![feature(box_patterns, custom_inner_attributes)]
#![warn(clippy::unnested_or_patterns)]
#![allow(clippy::cognitive_complexity, clippy::match_ref_pats, clippy::upper_case_acronyms)]
-#![allow(unreachable_patterns, irrefutable_let_patterns, unused_variables)]
+#![allow(unreachable_patterns, irrefutable_let_patterns, unused)]
fn main() {
// Should be ignored by this lint, as nesting requires more characters.
@@ -33,3 +33,15 @@ fn main() {
if let S { x: 0, y } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
}
+
+fn msrv_1_52() {
+ #![clippy::msrv = "1.52"]
+
+ if let [1] | [52] = [0] {}
+}
+
+fn msrv_1_53() {
+ #![clippy::msrv = "1.53"]
+
+ if let [1] | [53] = [0] {}
+}
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr
index 453c66cbb..fbc12fff0 100644
--- a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr
@@ -175,5 +175,16 @@ help: nest the patterns
LL | if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {}
| ~~~~~~~~~~~~~~~~~
-error: aborting due to 16 previous errors
+error: unnested or-patterns
+ --> $DIR/unnested_or_patterns.rs:46:12
+ |
+LL | if let [1] | [53] = [0] {}
+ | ^^^^^^^^^^
+ |
+help: nest the patterns
+ |
+LL | if let [1 | 53] = [0] {}
+ | ~~~~~~~~
+
+error: aborting due to 17 previous errors
diff --git a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr
index 18c4276c6..8aaae2d7f 100644
--- a/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr
+++ b/src/tools/clippy/tests/ui/unsafe_derive_deserialize.stderr
@@ -4,8 +4,8 @@ error: you are deriving `serde::Deserialize` on a type that has methods using `u
LL | #[derive(Deserialize)]
| ^^^^^^^^^^^
|
- = note: `-D clippy::unsafe-derive-deserialize` implied by `-D warnings`
= help: consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html
+ = note: `-D clippy::unsafe-derive-deserialize` implied by `-D warnings`
= note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are deriving `serde::Deserialize` on a type that has methods using `unsafe`
diff --git a/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs b/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs
index cde4e96d6..d29888ac6 100644
--- a/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs
+++ b/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs
@@ -24,4 +24,7 @@ use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety;
use mod_with_some_unsafe_things::Safe as IPromiseItsSafeThisTime;
use mod_with_some_unsafe_things::Unsafe as SuperUnsafeModThing;
+#[allow(clippy::unsafe_removed_from_name)]
+use mod_with_some_unsafe_things::Unsafe as SuperSafeThing;
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr
index 8b8ad065a..cff3eccbd 100644
--- a/src/tools/clippy/tests/ui/unused_async.stderr
+++ b/src/tools/clippy/tests/ui/unused_async.stderr
@@ -6,8 +6,8 @@ LL | | 4
LL | | }
| |_^
|
- = note: `-D clippy::unused-async` implied by `-D warnings`
= help: consider removing the `async` from this function
+ = note: `-D clippy::unused-async` implied by `-D warnings`
error: unused `async` for function with no await statements
--> $DIR/unused_async.rs:17:5
diff --git a/src/tools/clippy/tests/ui/unused_format_specs.fixed b/src/tools/clippy/tests/ui/unused_format_specs.fixed
new file mode 100644
index 000000000..2930722b4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_format_specs.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+
+#![warn(clippy::unused_format_specs)]
+#![allow(unused)]
+
+fn main() {
+ let f = 1.0f64;
+ println!("{}", 1.0);
+ println!("{f} {f:?}");
+
+ println!("{}", 1);
+}
+
+fn should_not_lint() {
+ let f = 1.0f64;
+ println!("{:.1}", 1.0);
+ println!("{f:.w$} {f:.*?}", 3, w = 2);
+}
diff --git a/src/tools/clippy/tests/ui/unused_format_specs.rs b/src/tools/clippy/tests/ui/unused_format_specs.rs
new file mode 100644
index 000000000..ee192a000
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_format_specs.rs
@@ -0,0 +1,18 @@
+// run-rustfix
+
+#![warn(clippy::unused_format_specs)]
+#![allow(unused)]
+
+fn main() {
+ let f = 1.0f64;
+ println!("{:.}", 1.0);
+ println!("{f:.} {f:.?}");
+
+ println!("{:.}", 1);
+}
+
+fn should_not_lint() {
+ let f = 1.0f64;
+ println!("{:.1}", 1.0);
+ println!("{f:.w$} {f:.*?}", 3, w = 2);
+}
diff --git a/src/tools/clippy/tests/ui/unused_format_specs.stderr b/src/tools/clippy/tests/ui/unused_format_specs.stderr
new file mode 100644
index 000000000..7231c17e7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_format_specs.stderr
@@ -0,0 +1,54 @@
+error: empty precision specifier has no effect
+ --> $DIR/unused_format_specs.rs:8:17
+ |
+LL | println!("{:.}", 1.0);
+ | ^
+ |
+ = note: a precision specifier is not required to format floats
+ = note: `-D clippy::unused-format-specs` implied by `-D warnings`
+help: remove the `.`
+ |
+LL - println!("{:.}", 1.0);
+LL + println!("{}", 1.0);
+ |
+
+error: empty precision specifier has no effect
+ --> $DIR/unused_format_specs.rs:9:18
+ |
+LL | println!("{f:.} {f:.?}");
+ | ^
+ |
+ = note: a precision specifier is not required to format floats
+help: remove the `.`
+ |
+LL - println!("{f:.} {f:.?}");
+LL + println!("{f} {f:.?}");
+ |
+
+error: empty precision specifier has no effect
+ --> $DIR/unused_format_specs.rs:9:24
+ |
+LL | println!("{f:.} {f:.?}");
+ | ^
+ |
+ = note: a precision specifier is not required to format floats
+help: remove the `.`
+ |
+LL - println!("{f:.} {f:.?}");
+LL + println!("{f:.} {f:?}");
+ |
+
+error: empty precision specifier has no effect
+ --> $DIR/unused_format_specs.rs:11:17
+ |
+LL | println!("{:.}", 1);
+ | ^
+ |
+help: remove the `.`
+ |
+LL - println!("{:.}", 1);
+LL + println!("{}", 1);
+ |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unused_format_specs_unfixable.rs b/src/tools/clippy/tests/ui/unused_format_specs_unfixable.rs
new file mode 100644
index 000000000..78601a348
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_format_specs_unfixable.rs
@@ -0,0 +1,30 @@
+#![warn(clippy::unused_format_specs)]
+#![allow(unused)]
+
+macro_rules! format_args_from_macro {
+ () => {
+ format_args!("from macro")
+ };
+}
+
+fn main() {
+ // prints `.`, not ` .`
+ println!("{:5}.", format_args!(""));
+ //prints `abcde`, not `abc`
+ println!("{:.3}", format_args!("abcde"));
+
+ println!("{:5}.", format_args_from_macro!());
+
+ let args = format_args!("");
+ println!("{args:5}");
+}
+
+fn should_not_lint() {
+ println!("{}", format_args!(""));
+ // Technically the same as `{}`, but the `format_args` docs specifically mention that you can use
+ // debug formatting so allow it
+ println!("{:?}", format_args!(""));
+
+ let args = format_args!("");
+ println!("{args}");
+}
diff --git a/src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr b/src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr
new file mode 100644
index 000000000..9f1890282
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr
@@ -0,0 +1,69 @@
+error: format specifiers have no effect on `format_args!()`
+ --> $DIR/unused_format_specs_unfixable.rs:12:15
+ |
+LL | println!("{:5}.", format_args!(""));
+ | ^^^^
+ |
+ = note: `-D clippy::unused-format-specs` implied by `-D warnings`
+help: for the width to apply consider using `format!()`
+ |
+LL | println!("{:5}.", format!(""));
+ | ~~~~~~
+help: if the current behavior is intentional, remove the format specifiers
+ |
+LL - println!("{:5}.", format_args!(""));
+LL + println!("{}.", format_args!(""));
+ |
+
+error: format specifiers have no effect on `format_args!()`
+ --> $DIR/unused_format_specs_unfixable.rs:14:15
+ |
+LL | println!("{:.3}", format_args!("abcde"));
+ | ^^^^^
+ |
+help: for the precision to apply consider using `format!()`
+ |
+LL | println!("{:.3}", format!("abcde"));
+ | ~~~~~~
+help: if the current behavior is intentional, remove the format specifiers
+ |
+LL - println!("{:.3}", format_args!("abcde"));
+LL + println!("{}", format_args!("abcde"));
+ |
+
+error: format specifiers have no effect on `format_args!()`
+ --> $DIR/unused_format_specs_unfixable.rs:16:15
+ |
+LL | println!("{:5}.", format_args_from_macro!());
+ | ^^^^
+ |
+help: for the width to apply consider using `format!()`
+ --> $DIR/unused_format_specs_unfixable.rs:16:17
+ |
+LL | println!("{:5}.", format_args_from_macro!());
+ | ^
+help: if the current behavior is intentional, remove the format specifiers
+ |
+LL - println!("{:5}.", format_args_from_macro!());
+LL + println!("{}.", format_args_from_macro!());
+ |
+
+error: format specifiers have no effect on `format_args!()`
+ --> $DIR/unused_format_specs_unfixable.rs:19:15
+ |
+LL | println!("{args:5}");
+ | ^^^^^^^^
+ |
+help: for the width to apply consider using `format!()`
+ --> $DIR/unused_format_specs_unfixable.rs:19:21
+ |
+LL | println!("{args:5}");
+ | ^
+help: if the current behavior is intentional, remove the format specifiers
+ |
+LL - println!("{args:5}");
+LL + println!("{args}");
+ |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unused_io_amount.stderr b/src/tools/clippy/tests/ui/unused_io_amount.stderr
index e5bdd993a..7ba7e09c0 100644
--- a/src/tools/clippy/tests/ui/unused_io_amount.stderr
+++ b/src/tools/clippy/tests/ui/unused_io_amount.stderr
@@ -4,8 +4,8 @@ error: written amount is not handled
LL | s.write(b"test")?;
| ^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::unused-io-amount` implied by `-D warnings`
= help: use `Write::write_all` instead, or handle partial writes
+ = note: `-D clippy::unused-io-amount` implied by `-D warnings`
error: read amount is not handled
--> $DIR/unused_io_amount.rs:11:5
diff --git a/src/tools/clippy/tests/ui/unused_peekable.rs b/src/tools/clippy/tests/ui/unused_peekable.rs
new file mode 100644
index 000000000..7374dfdf9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_peekable.rs
@@ -0,0 +1,169 @@
+#![warn(clippy::unused_peekable)]
+#![allow(clippy::no_effect)]
+
+use std::iter::Empty;
+use std::iter::Peekable;
+
+fn main() {
+ invalid();
+ valid();
+}
+
+#[allow(clippy::unused_unit)]
+fn invalid() {
+ let peekable = std::iter::empty::<u32>().peekable();
+
+ // Only lint `new_local`
+ let old_local = std::iter::empty::<u32>().peekable();
+ let new_local = old_local;
+
+ // Behind mut ref
+ let mut by_mut_ref_test = std::iter::empty::<u32>().peekable();
+ let by_mut_ref = &mut by_mut_ref_test;
+
+ // Explicitly returns `Peekable`
+ fn returns_peekable() -> Peekable<Empty<u32>> {
+ std::iter::empty().peekable()
+ }
+
+ let peekable_from_fn = returns_peekable();
+
+ // Using a method not exclusive to `Peekable`
+ let mut peekable_using_iterator_method = std::iter::empty::<u32>().peekable();
+ peekable_using_iterator_method.next();
+
+ // Passed by ref to another function
+ fn takes_ref(_peek: &Peekable<Empty<u32>>) {}
+ let passed_along_ref = std::iter::empty::<u32>().peekable();
+ takes_ref(&passed_along_ref);
+
+ // `by_ref` without `peek`
+ let mut by_ref_test = std::iter::empty::<u32>().peekable();
+ let _by_ref = by_ref_test.by_ref();
+
+ let mut peekable_in_for_loop = std::iter::empty::<u32>().peekable();
+ for x in peekable_in_for_loop {}
+}
+
+fn valid() {
+ fn takes_peekable(_peek: Peekable<Empty<u32>>) {}
+
+ // Passed to another function
+ let passed_along = std::iter::empty::<u32>().peekable();
+ takes_peekable(passed_along);
+
+ // Passed to another method
+ struct PeekableConsumer;
+ impl PeekableConsumer {
+ fn consume(&self, _: Peekable<Empty<u32>>) {}
+ fn consume_mut_ref(&self, _: &mut Peekable<Empty<u32>>) {}
+ fn consume_assoc(_: Peekable<Empty<u32>>) {}
+ fn consume_assoc_mut_ref(_: &mut Peekable<Empty<u32>>) {}
+ }
+ let peekable_consumer = PeekableConsumer;
+
+ let peekable = std::iter::empty::<u32>().peekable();
+ peekable_consumer.consume(peekable);
+
+ let mut peekable = std::iter::empty::<u32>().peekable();
+ peekable_consumer.consume_mut_ref(&mut peekable);
+
+ let peekable = std::iter::empty::<u32>().peekable();
+ PeekableConsumer::consume_assoc(peekable);
+
+ let mut peekable = std::iter::empty::<u32>().peekable();
+ PeekableConsumer::consume_assoc_mut_ref(&mut peekable);
+
+ // `peek` called in another block
+ let mut peekable_in_block = std::iter::empty::<u32>().peekable();
+ {
+ peekable_in_block.peek();
+ }
+
+ // Check the other `Peekable` methods :)
+ {
+ let mut peekable_with_peek_mut = std::iter::empty::<u32>().peekable();
+ peekable_with_peek_mut.peek_mut();
+
+ let mut peekable_with_next_if = std::iter::empty::<u32>().peekable();
+ peekable_with_next_if.next_if(|_| true);
+
+ let mut peekable_with_next_if_eq = std::iter::empty::<u32>().peekable();
+ peekable_with_next_if_eq.next_if_eq(&3);
+ }
+
+ let mut peekable_in_closure = std::iter::empty::<u32>().peekable();
+ let call_peek = |p: &mut Peekable<Empty<u32>>| {
+ p.peek();
+ };
+ call_peek(&mut peekable_in_closure);
+
+ // From a macro
+ macro_rules! make_me_a_peekable_please {
+ () => {
+ std::iter::empty::<u32>().peekable()
+ };
+ }
+
+ let _unsuspecting_macro_user = make_me_a_peekable_please!();
+
+ // Generic Iterator returned
+ fn return_an_iter() -> impl Iterator<Item = u32> {
+ std::iter::empty::<u32>().peekable()
+ }
+
+ let _unsuspecting_user = return_an_iter();
+
+ // Call `peek` in a macro
+ macro_rules! peek_iter {
+ ($iter:ident) => {
+ $iter.peek();
+ };
+ }
+
+ let mut peek_in_macro = std::iter::empty::<u32>().peekable();
+ peek_iter!(peek_in_macro);
+
+ // Behind mut ref
+ let mut by_mut_ref_test = std::iter::empty::<u32>().peekable();
+ let by_mut_ref = &mut by_mut_ref_test;
+ by_mut_ref.peek();
+
+ // Behind ref
+ let mut by_ref_test = std::iter::empty::<u32>().peekable();
+ let by_ref = &by_ref_test;
+ by_ref_test.peek();
+
+ // In struct
+ struct PeekableWrapper {
+ f: Peekable<Empty<u32>>,
+ }
+
+ let struct_test = std::iter::empty::<u32>().peekable();
+ PeekableWrapper { f: struct_test };
+
+ // `by_ref` before `peek`
+ let mut by_ref_test = std::iter::empty::<u32>().peekable();
+ let peeked_val = by_ref_test.by_ref().peek();
+
+ // `peek` called in another block as the last expression
+ let mut peekable_last_expr = std::iter::empty::<u32>().peekable();
+ {
+ peekable_last_expr.peek();
+ }
+
+ let mut peek_in_closure = std::iter::empty::<u32>().peekable();
+ let _ = || {
+ let _ = peek_in_closure.peek();
+ };
+
+ trait PeekTrait {}
+ impl<I> PeekTrait for Peekable<I> where I: Iterator {}
+
+ let mut peekable = std::iter::empty::<u32>().peekable();
+ let _dyn = &mut peekable as &mut dyn PeekTrait;
+
+ fn takes_dyn(_: &mut dyn PeekTrait) {}
+ let mut peekable = std::iter::empty::<u32>().peekable();
+ takes_dyn(&mut peekable);
+}
diff --git a/src/tools/clippy/tests/ui/unused_peekable.stderr b/src/tools/clippy/tests/ui/unused_peekable.stderr
new file mode 100644
index 000000000..54788f2fa
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_peekable.stderr
@@ -0,0 +1,67 @@
+error: `peek` never called on `Peekable` iterator
+ --> $DIR/unused_peekable.rs:14:9
+ |
+LL | let peekable = std::iter::empty::<u32>().peekable();
+ | ^^^^^^^^
+ |
+ = help: consider removing the call to `peekable`
+ = note: `-D clippy::unused-peekable` implied by `-D warnings`
+
+error: `peek` never called on `Peekable` iterator
+ --> $DIR/unused_peekable.rs:18:9
+ |
+LL | let new_local = old_local;
+ | ^^^^^^^^^
+ |
+ = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+ --> $DIR/unused_peekable.rs:22:9
+ |
+LL | let by_mut_ref = &mut by_mut_ref_test;
+ | ^^^^^^^^^^
+ |
+ = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+ --> $DIR/unused_peekable.rs:29:9
+ |
+LL | let peekable_from_fn = returns_peekable();
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+ --> $DIR/unused_peekable.rs:32:13
+ |
+LL | let mut peekable_using_iterator_method = std::iter::empty::<u32>().peekable();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+ --> $DIR/unused_peekable.rs:37:9
+ |
+LL | let passed_along_ref = std::iter::empty::<u32>().peekable();
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+ --> $DIR/unused_peekable.rs:42:9
+ |
+LL | let _by_ref = by_ref_test.by_ref();
+ | ^^^^^^^
+ |
+ = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+ --> $DIR/unused_peekable.rs:44:13
+ |
+LL | let mut peekable_in_for_loop = std::iter::empty::<u32>().peekable();
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider removing the call to `peekable`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unused_self.stderr b/src/tools/clippy/tests/ui/unused_self.stderr
index 0534b40ea..23186122a 100644
--- a/src/tools/clippy/tests/ui/unused_self.stderr
+++ b/src/tools/clippy/tests/ui/unused_self.stderr
@@ -4,8 +4,8 @@ error: unused `self` argument
LL | fn unused_self_move(self) {}
| ^^^^
|
- = note: `-D clippy::unused-self` implied by `-D warnings`
= help: consider refactoring to a associated function
+ = note: `-D clippy::unused-self` implied by `-D warnings`
error: unused `self` argument
--> $DIR/unused_self.rs:12:28
diff --git a/src/tools/clippy/tests/ui/unwrap.rs b/src/tools/clippy/tests/ui/unwrap.rs
index a4a3cd1d3..d9fd402e7 100644
--- a/src/tools/clippy/tests/ui/unwrap.rs
+++ b/src/tools/clippy/tests/ui/unwrap.rs
@@ -6,8 +6,9 @@ fn unwrap_option() {
}
fn unwrap_result() {
- let res: Result<u8, ()> = Ok(0);
+ let res: Result<u8, u8> = Ok(0);
let _ = res.unwrap();
+ let _ = res.unwrap_err();
}
fn main() {
diff --git a/src/tools/clippy/tests/ui/unwrap.stderr b/src/tools/clippy/tests/ui/unwrap.stderr
index 4f0858005..e88d580f7 100644
--- a/src/tools/clippy/tests/ui/unwrap.stderr
+++ b/src/tools/clippy/tests/ui/unwrap.stderr
@@ -4,8 +4,8 @@ error: used `unwrap()` on `an Option` value
LL | let _ = opt.unwrap();
| ^^^^^^^^^^^^
|
- = note: `-D clippy::unwrap-used` implied by `-D warnings`
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: `-D clippy::unwrap-used` implied by `-D warnings`
error: used `unwrap()` on `a Result` value
--> $DIR/unwrap.rs:10:13
@@ -15,5 +15,13 @@ LL | let _ = res.unwrap();
|
= help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message
-error: aborting due to 2 previous errors
+error: used `unwrap_err()` on `a Result` value
+ --> $DIR/unwrap.rs:11:13
+ |
+LL | let _ = res.unwrap_err();
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: if you don't want to handle the `Ok` case gracefully, consider using `expect_err()` to provide a better panic message
+
+error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.rs b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
new file mode 100644
index 000000000..9f27fef82
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
@@ -0,0 +1,35 @@
+#![warn(clippy::unwrap_used, clippy::expect_used)]
+
+trait OptionExt {
+ type Item;
+
+ fn unwrap_err(self) -> Self::Item;
+
+ fn expect_err(self, msg: &str) -> Self::Item;
+}
+
+impl<T> OptionExt for Option<T> {
+ type Item = T;
+ fn unwrap_err(self) -> T {
+ panic!();
+ }
+
+ fn expect_err(self, msg: &str) -> T {
+ panic!();
+ }
+}
+
+fn main() {
+ Some(3).unwrap();
+ Some(3).expect("Hello world!");
+
+ // Don't trigger on unwrap_err on an option
+ Some(3).unwrap_err();
+ Some(3).expect_err("Hellow none!");
+
+ let a: Result<i32, i32> = Ok(3);
+ a.unwrap();
+ a.expect("Hello world!");
+ a.unwrap_err();
+ a.expect_err("Hello error!");
+}
diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.stderr b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr
new file mode 100644
index 000000000..211d2be18
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr
@@ -0,0 +1,52 @@
+error: used `unwrap()` on `an Option` value
+ --> $DIR/unwrap_expect_used.rs:23:5
+ |
+LL | Some(3).unwrap();
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: if this value is `None`, it will panic
+ = note: `-D clippy::unwrap-used` implied by `-D warnings`
+
+error: used `expect()` on `an Option` value
+ --> $DIR/unwrap_expect_used.rs:24:5
+ |
+LL | Some(3).expect("Hello world!");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: if this value is `None`, it will panic
+ = note: `-D clippy::expect-used` implied by `-D warnings`
+
+error: used `unwrap()` on `a Result` value
+ --> $DIR/unwrap_expect_used.rs:31:5
+ |
+LL | a.unwrap();
+ | ^^^^^^^^^^
+ |
+ = help: if this value is an `Err`, it will panic
+
+error: used `expect()` on `a Result` value
+ --> $DIR/unwrap_expect_used.rs:32:5
+ |
+LL | a.expect("Hello world!");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: if this value is an `Err`, it will panic
+
+error: used `unwrap_err()` on `a Result` value
+ --> $DIR/unwrap_expect_used.rs:33:5
+ |
+LL | a.unwrap_err();
+ | ^^^^^^^^^^^^^^
+ |
+ = help: if this value is an `Ok`, it will panic
+
+error: used `expect_err()` on `a Result` value
+ --> $DIR/unwrap_expect_used.rs:34:5
+ |
+LL | a.expect_err("Hello error!");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: if this value is an `Ok`, it will panic
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unwrap_in_result.stderr b/src/tools/clippy/tests/ui/unwrap_in_result.stderr
index 56bc2f2d1..40e6bfe08 100644
--- a/src/tools/clippy/tests/ui/unwrap_in_result.stderr
+++ b/src/tools/clippy/tests/ui/unwrap_in_result.stderr
@@ -10,13 +10,13 @@ LL | | }
LL | | }
| |_____^
|
- = note: `-D clippy::unwrap-in-result` implied by `-D warnings`
= help: unwrap and expect should not be used in a function that returns result or option
note: potential non-recoverable error(s)
--> $DIR/unwrap_in_result.rs:24:17
|
LL | let i = i_str.parse::<i32>().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: `-D clippy::unwrap-in-result` implied by `-D warnings`
error: used unwrap or expect in a function that returns result or option
--> $DIR/unwrap_in_result.rs:32:5
diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed b/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed
index c2b9bd2c8..84f779569 100644
--- a/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed
+++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed
@@ -69,6 +69,9 @@ fn unwrap_or_else_default() {
let with_default_type: Option<Vec<u64>> = None;
with_default_type.unwrap_or_default();
+
+ let empty_string = None::<String>;
+ empty_string.unwrap_or_default();
}
fn main() {}
diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.rs b/src/tools/clippy/tests/ui/unwrap_or_else_default.rs
index d55664990..1735bd580 100644
--- a/src/tools/clippy/tests/ui/unwrap_or_else_default.rs
+++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.rs
@@ -69,6 +69,9 @@ fn unwrap_or_else_default() {
let with_default_type: Option<Vec<u64>> = None;
with_default_type.unwrap_or_else(Vec::new);
+
+ let empty_string = None::<String>;
+ empty_string.unwrap_or_else(|| "".to_string());
}
fn main() {}
diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr b/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr
index 53e31d85e..d2b921222 100644
--- a/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr
+++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr
@@ -30,5 +30,11 @@ error: use of `.unwrap_or_else(..)` to construct default value
LL | with_default_type.unwrap_or_else(Vec::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
-error: aborting due to 5 previous errors
+error: use of `.unwrap_or_else(..)` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:74:5
+ |
+LL | empty_string.unwrap_or_else(|| "".to_string());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `empty_string.unwrap_or_default()`
+
+error: aborting due to 6 previous errors
diff --git a/src/tools/clippy/tests/ui/upper_case_acronyms.rs b/src/tools/clippy/tests/ui/upper_case_acronyms.rs
index 48bb9e54b..9b7c2f28e 100644
--- a/src/tools/clippy/tests/ui/upper_case_acronyms.rs
+++ b/src/tools/clippy/tests/ui/upper_case_acronyms.rs
@@ -38,4 +38,13 @@ enum ParseErrorPrivate<T> {
Parse(T, String),
}
+// do lint here
+struct JSON;
+
+// do lint here
+enum YAML {
+ Num(u32),
+ Str(String),
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/upper_case_acronyms.stderr b/src/tools/clippy/tests/ui/upper_case_acronyms.stderr
index 250b196a9..74082ec16 100644
--- a/src/tools/clippy/tests/ui/upper_case_acronyms.stderr
+++ b/src/tools/clippy/tests/ui/upper_case_acronyms.stderr
@@ -54,5 +54,17 @@ error: name `WASD` contains a capitalized acronym
LL | WASD(u8),
| ^^^^ help: consider making the acronym lowercase, except the initial letter: `Wasd`
-error: aborting due to 9 previous errors
+error: name `JSON` contains a capitalized acronym
+ --> $DIR/upper_case_acronyms.rs:42:8
+ |
+LL | struct JSON;
+ | ^^^^ help: consider making the acronym lowercase, except the initial letter: `Json`
+
+error: name `YAML` contains a capitalized acronym
+ --> $DIR/upper_case_acronyms.rs:45:6
+ |
+LL | enum YAML {
+ | ^^^^ help: consider making the acronym lowercase, except the initial letter: `Yaml`
+
+error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed
index 4f80aaecc..3b54fe9d5 100644
--- a/src/tools/clippy/tests/ui/use_self.fixed
+++ b/src/tools/clippy/tests/ui/use_self.fixed
@@ -1,6 +1,7 @@
// run-rustfix
// aux-build:proc_macro_derive.rs
+#![feature(custom_inner_attributes)]
#![warn(clippy::use_self)]
#![allow(dead_code, unreachable_code)]
#![allow(
@@ -608,3 +609,44 @@ mod issue8845 {
}
}
}
+
+mod issue6902 {
+ use serde::Serialize;
+
+ #[derive(Serialize)]
+ pub enum Foo {
+ Bar = 1,
+ }
+}
+
+fn msrv_1_36() {
+ #![clippy::msrv = "1.36"]
+
+ enum E {
+ A,
+ }
+
+ impl E {
+ fn foo(self) {
+ match self {
+ E::A => {},
+ }
+ }
+ }
+}
+
+fn msrv_1_37() {
+ #![clippy::msrv = "1.37"]
+
+ enum E {
+ A,
+ }
+
+ impl E {
+ fn foo(self) {
+ match self {
+ Self::A => {},
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs
index 52da72db5..bf87633cd 100644
--- a/src/tools/clippy/tests/ui/use_self.rs
+++ b/src/tools/clippy/tests/ui/use_self.rs
@@ -1,6 +1,7 @@
// run-rustfix
// aux-build:proc_macro_derive.rs
+#![feature(custom_inner_attributes)]
#![warn(clippy::use_self)]
#![allow(dead_code, unreachable_code)]
#![allow(
@@ -608,3 +609,44 @@ mod issue8845 {
}
}
}
+
+mod issue6902 {
+ use serde::Serialize;
+
+ #[derive(Serialize)]
+ pub enum Foo {
+ Bar = 1,
+ }
+}
+
+fn msrv_1_36() {
+ #![clippy::msrv = "1.36"]
+
+ enum E {
+ A,
+ }
+
+ impl E {
+ fn foo(self) {
+ match self {
+ E::A => {},
+ }
+ }
+ }
+}
+
+fn msrv_1_37() {
+ #![clippy::msrv = "1.37"]
+
+ enum E {
+ A,
+ }
+
+ impl E {
+ fn foo(self) {
+ match self {
+ E::A => {},
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr
index f06bb959b..16fb06092 100644
--- a/src/tools/clippy/tests/ui/use_self.stderr
+++ b/src/tools/clippy/tests/ui/use_self.stderr
@@ -1,5 +1,5 @@
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:22:21
+ --> $DIR/use_self.rs:23:21
|
LL | fn new() -> Foo {
| ^^^ help: use the applicable keyword: `Self`
@@ -7,244 +7,250 @@ LL | fn new() -> Foo {
= note: `-D clippy::use-self` implied by `-D warnings`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:23:13
+ --> $DIR/use_self.rs:24:13
|
LL | Foo {}
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:25:22
+ --> $DIR/use_self.rs:26:22
|
LL | fn test() -> Foo {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:26:13
+ --> $DIR/use_self.rs:27:13
|
LL | Foo::new()
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:31:25
+ --> $DIR/use_self.rs:32:25
|
LL | fn default() -> Foo {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:32:13
+ --> $DIR/use_self.rs:33:13
|
LL | Foo::new()
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:97:24
+ --> $DIR/use_self.rs:98: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:97:55
+ --> $DIR/use_self.rs:98: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:112:13
+ --> $DIR/use_self.rs:113:13
|
LL | TS(0)
| ^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:147:29
+ --> $DIR/use_self.rs:148:29
|
LL | fn bar() -> Bar {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:148:21
+ --> $DIR/use_self.rs:149:21
|
LL | Bar { foo: Foo {} }
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:159:21
+ --> $DIR/use_self.rs:160:21
|
LL | fn baz() -> Foo {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:160:13
+ --> $DIR/use_self.rs:161:13
|
LL | Foo {}
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:177:21
+ --> $DIR/use_self.rs:178:21
|
LL | let _ = Enum::B(42);
| ^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:178:21
+ --> $DIR/use_self.rs:179:21
|
LL | let _ = Enum::C { field: true };
| ^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:179:21
+ --> $DIR/use_self.rs:180:21
|
LL | let _ = Enum::A;
| ^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:221:13
+ --> $DIR/use_self.rs:222:13
|
LL | nested::A::fun_1();
| ^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:222:13
+ --> $DIR/use_self.rs:223:13
|
LL | nested::A::A;
| ^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:224:13
+ --> $DIR/use_self.rs:225:13
|
LL | nested::A {};
| ^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:243:13
+ --> $DIR/use_self.rs:244:13
|
LL | TestStruct::from_something()
| ^^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:257:25
+ --> $DIR/use_self.rs:258:25
|
LL | async fn g() -> S {
| ^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:258:13
+ --> $DIR/use_self.rs:259:13
|
LL | S {}
| ^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:262:16
+ --> $DIR/use_self.rs:263:16
|
LL | &p[S::A..S::B]
| ^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:262:22
+ --> $DIR/use_self.rs:263:22
|
LL | &p[S::A..S::B]
| ^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:285:29
+ --> $DIR/use_self.rs:286:29
|
LL | fn foo(value: T) -> Foo<T> {
| ^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:286:13
+ --> $DIR/use_self.rs:287:13
|
LL | Foo::<T> { value }
| ^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:458:13
+ --> $DIR/use_self.rs:459: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
+ --> $DIR/use_self.rs:496:13
|
LL | S2::new()
| ^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:532:17
+ --> $DIR/use_self.rs:533:17
|
LL | Foo::Bar => unimplemented!(),
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:533:17
+ --> $DIR/use_self.rs:534:17
|
LL | Foo::Baz => unimplemented!(),
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:539:20
+ --> $DIR/use_self.rs:540:20
|
LL | if let Foo::Bar = self {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:563:17
+ --> $DIR/use_self.rs:564:17
|
LL | Something::Num(n) => *n,
| ^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:564:17
+ --> $DIR/use_self.rs:565:17
|
LL | Something::TupleNums(n, _m) => *n,
| ^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:565:17
+ --> $DIR/use_self.rs:566:17
|
LL | Something::StructNums { one, two: _ } => *one,
| ^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:571:17
+ --> $DIR/use_self.rs:572:17
|
LL | crate::issue8845::Something::Num(n) => *n,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:572:17
+ --> $DIR/use_self.rs:573:17
|
LL | crate::issue8845::Something::TupleNums(n, _m) => *n,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:573:17
+ --> $DIR/use_self.rs:574:17
|
LL | crate::issue8845::Something::StructNums { one, two: _ } => *one,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:589:17
+ --> $DIR/use_self.rs:590:17
|
LL | let Foo(x) = self;
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:594:17
+ --> $DIR/use_self.rs:595:17
|
LL | let crate::issue8845::Foo(x) = self;
| ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:601:17
+ --> $DIR/use_self.rs:602:17
|
LL | let Bar { x, .. } = self;
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:606:17
+ --> $DIR/use_self.rs:607:17
|
LL | let crate::issue8845::Bar { x, .. } = self;
| ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
-error: aborting due to 41 previous errors
+error: unnecessary structure name repetition
+ --> $DIR/use_self.rs:648:17
+ |
+LL | E::A => {},
+ | ^ help: use the applicable keyword: `Self`
+
+error: aborting due to 42 previous errors
diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.rs b/src/tools/clippy/tests/ui/used_underscore_binding.rs
index d20977d55..8c29e15b1 100644
--- a/src/tools/clippy/tests/ui/used_underscore_binding.rs
+++ b/src/tools/clippy/tests/ui/used_underscore_binding.rs
@@ -1,9 +1,8 @@
// aux-build:proc_macro_derive.rs
-
#![feature(rustc_private)]
#![warn(clippy::all)]
-#![allow(clippy::blacklisted_name, clippy::eq_op)]
#![warn(clippy::used_underscore_binding)]
+#![allow(clippy::disallowed_names, clippy::eq_op, clippy::uninlined_format_args)]
#[macro_use]
extern crate proc_macro_derive;
diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.stderr b/src/tools/clippy/tests/ui/used_underscore_binding.stderr
index 61a9161d2..875fafe43 100644
--- a/src/tools/clippy/tests/ui/used_underscore_binding.stderr
+++ b/src/tools/clippy/tests/ui/used_underscore_binding.stderr
@@ -1,5 +1,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:25:5
+ --> $DIR/used_underscore_binding.rs:24:5
|
LL | _foo + 1
| ^^^^
@@ -7,31 +7,31 @@ 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:30:20
+ --> $DIR/used_underscore_binding.rs:29: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:31:16
+ --> $DIR/used_underscore_binding.rs:30: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:31:22
+ --> $DIR/used_underscore_binding.rs:30: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:44:5
+ --> $DIR/used_underscore_binding.rs:43: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:105:16
+ --> $DIR/used_underscore_binding.rs:104:16
|
LL | uses_i(_i);
| ^^
diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed
index 90cb8945e..38e4b9201 100644
--- a/src/tools/clippy/tests/ui/useless_asref.fixed
+++ b/src/tools/clippy/tests/ui/useless_asref.fixed
@@ -1,7 +1,6 @@
// run-rustfix
-
#![deny(clippy::useless_asref)]
-#![allow(clippy::explicit_auto_deref)]
+#![allow(clippy::explicit_auto_deref, clippy::uninlined_format_args)]
use std::fmt::Debug;
diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs
index cb9f8ae59..f1e83f9d3 100644
--- a/src/tools/clippy/tests/ui/useless_asref.rs
+++ b/src/tools/clippy/tests/ui/useless_asref.rs
@@ -1,7 +1,6 @@
// run-rustfix
-
#![deny(clippy::useless_asref)]
-#![allow(clippy::explicit_auto_deref)]
+#![allow(clippy::explicit_auto_deref, clippy::uninlined_format_args)]
use std::fmt::Debug;
diff --git a/src/tools/clippy/tests/ui/useless_asref.stderr b/src/tools/clippy/tests/ui/useless_asref.stderr
index b21c67bb3..67ce8b64e 100644
--- a/src/tools/clippy/tests/ui/useless_asref.stderr
+++ b/src/tools/clippy/tests/ui/useless_asref.stderr
@@ -1,71 +1,71 @@
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:44:18
+ --> $DIR/useless_asref.rs:43:18
|
LL | foo_rstr(rstr.as_ref());
| ^^^^^^^^^^^^^ help: try this: `rstr`
|
note: the lint level is defined here
- --> $DIR/useless_asref.rs:3:9
+ --> $DIR/useless_asref.rs:2:9
|
LL | #![deny(clippy::useless_asref)]
| ^^^^^^^^^^^^^^^^^^^^^
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:46:20
+ --> $DIR/useless_asref.rs:45:20
|
LL | foo_rslice(rslice.as_ref());
| ^^^^^^^^^^^^^^^ help: try this: `rslice`
error: this call to `as_mut` does nothing
- --> $DIR/useless_asref.rs:50:21
+ --> $DIR/useless_asref.rs:49:21
|
LL | foo_mrslice(mrslice.as_mut());
| ^^^^^^^^^^^^^^^^ help: try this: `mrslice`
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:52:20
+ --> $DIR/useless_asref.rs:51:20
|
LL | foo_rslice(mrslice.as_ref());
| ^^^^^^^^^^^^^^^^ help: try this: `mrslice`
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:59:20
+ --> $DIR/useless_asref.rs:58:20
|
LL | foo_rslice(rrrrrslice.as_ref());
| ^^^^^^^^^^^^^^^^^^^ help: try this: `rrrrrslice`
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:61:18
+ --> $DIR/useless_asref.rs:60:18
|
LL | foo_rstr(rrrrrstr.as_ref());
| ^^^^^^^^^^^^^^^^^ help: try this: `rrrrrstr`
error: this call to `as_mut` does nothing
- --> $DIR/useless_asref.rs:66:21
+ --> $DIR/useless_asref.rs:65:21
|
LL | foo_mrslice(mrrrrrslice.as_mut());
| ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice`
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:68:20
+ --> $DIR/useless_asref.rs:67:20
|
LL | foo_rslice(mrrrrrslice.as_ref());
| ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice`
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:72:16
+ --> $DIR/useless_asref.rs:71:16
|
LL | foo_rrrrmr((&&&&MoreRef).as_ref());
| ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(&&&&MoreRef)`
error: this call to `as_mut` does nothing
- --> $DIR/useless_asref.rs:122:13
+ --> $DIR/useless_asref.rs:121:13
|
LL | foo_mrt(mrt.as_mut());
| ^^^^^^^^^^^^ help: try this: `mrt`
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:124:12
+ --> $DIR/useless_asref.rs:123:12
|
LL | foo_rt(mrt.as_ref());
| ^^^^^^^^^^^^ help: try this: `mrt`
diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr
index e6760f700..65ee3807f 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.stderr
+++ b/src/tools/clippy/tests/ui/useless_conversion.stderr
@@ -46,7 +46,7 @@ error: useless conversion to the same type: `std::string::String`
LL | let _ = String::from(format!("A: {:04}", 123));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
-error: useless conversion to the same type: `std::str::Lines`
+error: useless conversion to the same type: `std::str::Lines<'_>`
--> $DIR/useless_conversion.rs:65:13
|
LL | let _ = "".lines().into_iter();
diff --git a/src/tools/clippy/tests/ui/useless_conversion_try.rs b/src/tools/clippy/tests/ui/useless_conversion_try.rs
index 39f54c27b..4acf5b5fa 100644
--- a/src/tools/clippy/tests/ui/useless_conversion_try.rs
+++ b/src/tools/clippy/tests/ui/useless_conversion_try.rs
@@ -29,10 +29,10 @@ fn main() {
let _ = String::try_from("foo".to_string()).unwrap();
let _ = String::try_from(format!("A: {:04}", 123)).unwrap();
let _: String = format!("Hello {}", "world").try_into().unwrap();
- let _: String = "".to_owned().try_into().unwrap();
+ let _: String = String::new().try_into().unwrap();
let _: String = match String::from("_").try_into() {
Ok(a) => a,
- Err(_) => "".into(),
+ Err(_) => String::new(),
};
// FIXME this is a false negative
#[allow(clippy::cmp_owned)]
diff --git a/src/tools/clippy/tests/ui/useless_conversion_try.stderr b/src/tools/clippy/tests/ui/useless_conversion_try.stderr
index b691c13f7..9aef9dda6 100644
--- a/src/tools/clippy/tests/ui/useless_conversion_try.stderr
+++ b/src/tools/clippy/tests/ui/useless_conversion_try.stderr
@@ -4,12 +4,12 @@ error: useless conversion to the same type: `T`
LL | let _ = T::try_from(val).unwrap();
| ^^^^^^^^^^^^^^^^
|
+ = help: consider removing `T::try_from()`
note: the lint level is defined here
--> $DIR/useless_conversion_try.rs:1:9
|
LL | #![deny(clippy::useless_conversion)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: consider removing `T::try_from()`
error: useless conversion to the same type: `T`
--> $DIR/useless_conversion_try.rs:5:5
@@ -62,7 +62,7 @@ LL | let _: String = format!("Hello {}", "world").try_into().unwrap();
error: useless conversion to the same type: `std::string::String`
--> $DIR/useless_conversion_try.rs:32:21
|
-LL | let _: String = "".to_owned().try_into().unwrap();
+LL | let _: String = String::new().try_into().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider removing `.try_into()`
diff --git a/src/tools/clippy/tests/ui/vec.fixed b/src/tools/clippy/tests/ui/vec.fixed
index 318f9c2dc..2518d8049 100644
--- a/src/tools/clippy/tests/ui/vec.fixed
+++ b/src/tools/clippy/tests/ui/vec.fixed
@@ -1,6 +1,6 @@
// run-rustfix
-#![allow(clippy::nonstandard_macro_braces)]
#![warn(clippy::useless_vec)]
+#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args)]
#[derive(Debug)]
struct NonCopy;
diff --git a/src/tools/clippy/tests/ui/vec.rs b/src/tools/clippy/tests/ui/vec.rs
index d7673ce3e..e1492e2f3 100644
--- a/src/tools/clippy/tests/ui/vec.rs
+++ b/src/tools/clippy/tests/ui/vec.rs
@@ -1,6 +1,6 @@
// run-rustfix
-#![allow(clippy::nonstandard_macro_braces)]
#![warn(clippy::useless_vec)]
+#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args)]
#[derive(Debug)]
struct NonCopy;
diff --git a/src/tools/clippy/tests/ui/vec_resize_to_zero.rs b/src/tools/clippy/tests/ui/vec_resize_to_zero.rs
index 7ed27439e..a8307e741 100644
--- a/src/tools/clippy/tests/ui/vec_resize_to_zero.rs
+++ b/src/tools/clippy/tests/ui/vec_resize_to_zero.rs
@@ -1,15 +1,19 @@
#![warn(clippy::vec_resize_to_zero)]
fn main() {
+ let mut v = vec![1, 2, 3, 4, 5];
+
// applicable here
- vec![1, 2, 3, 4, 5].resize(0, 5);
+ v.resize(0, 5);
// not applicable
- vec![1, 2, 3, 4, 5].resize(2, 5);
+ v.resize(2, 5);
+
+ let mut v = vec!["foo", "bar", "baz"];
// applicable here, but only implemented for integer literals for now
- vec!["foo", "bar", "baz"].resize(0, "bar");
+ v.resize(0, "bar");
// not applicable
- vec!["foo", "bar", "baz"].resize(2, "bar")
+ v.resize(2, "bar")
}
diff --git a/src/tools/clippy/tests/ui/vec_resize_to_zero.stderr b/src/tools/clippy/tests/ui/vec_resize_to_zero.stderr
index feb846298..8851e9f38 100644
--- a/src/tools/clippy/tests/ui/vec_resize_to_zero.stderr
+++ b/src/tools/clippy/tests/ui/vec_resize_to_zero.stderr
@@ -1,13 +1,13 @@
error: emptying a vector with `resize`
- --> $DIR/vec_resize_to_zero.rs:5:5
+ --> $DIR/vec_resize_to_zero.rs:7:5
|
-LL | vec![1, 2, 3, 4, 5].resize(0, 5);
- | ^^^^^^^^^^^^^^^^^^^^------------
- | |
- | help: ...or you can empty the vector with: `clear()`
+LL | v.resize(0, 5);
+ | ^^------------
+ | |
+ | help: ...or you can empty the vector with: `clear()`
|
- = note: `-D clippy::vec-resize-to-zero` implied by `-D warnings`
= help: the arguments may be inverted...
+ = note: `-D clippy::vec-resize-to-zero` implied by `-D warnings`
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/verbose_file_reads.rs b/src/tools/clippy/tests/ui/verbose_file_reads.rs
index e0065e05a..df267e987 100644
--- a/src/tools/clippy/tests/ui/verbose_file_reads.rs
+++ b/src/tools/clippy/tests/ui/verbose_file_reads.rs
@@ -18,7 +18,7 @@ fn main() -> std::io::Result<()> {
s.read_to_end();
s.read_to_string();
// Should catch this
- let mut f = File::open(&path)?;
+ let mut f = File::open(path)?;
let mut buffer = Vec::new();
f.read_to_end(&mut buffer)?;
// ...and this
diff --git a/src/tools/clippy/tests/ui/verbose_file_reads.stderr b/src/tools/clippy/tests/ui/verbose_file_reads.stderr
index 550b6ab67..44266c7c0 100644
--- a/src/tools/clippy/tests/ui/verbose_file_reads.stderr
+++ b/src/tools/clippy/tests/ui/verbose_file_reads.stderr
@@ -4,8 +4,8 @@ error: use of `File::read_to_end`
LL | f.read_to_end(&mut buffer)?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::verbose-file-reads` implied by `-D warnings`
= help: consider using `fs::read` instead
+ = note: `-D clippy::verbose-file-reads` implied by `-D warnings`
error: use of `File::read_to_string`
--> $DIR/verbose_file_reads.rs:26:5
diff --git a/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr b/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr
index 2f1be61e5..14748f583 100644
--- a/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr
+++ b/src/tools/clippy/tests/ui/vtable_address_comparisons.stderr
@@ -4,8 +4,8 @@ error: comparing trait object pointers compares a non-unique vtable address
LL | let _ = a == b;
| ^^^^^^
|
- = note: `-D clippy::vtable-address-comparisons` implied by `-D warnings`
= help: consider extracting and comparing data pointers only
+ = note: `-D clippy::vtable-address-comparisons` implied by `-D warnings`
error: comparing trait object pointers compares a non-unique vtable address
--> $DIR/vtable_address_comparisons.rs:15:13
diff --git a/src/tools/clippy/tests/ui/while_let_loop.rs b/src/tools/clippy/tests/ui/while_let_loop.rs
index c42e2a79a..5b8075731 100644
--- a/src/tools/clippy/tests/ui/while_let_loop.rs
+++ b/src/tools/clippy/tests/ui/while_let_loop.rs
@@ -1,4 +1,5 @@
#![warn(clippy::while_let_loop)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
let y = Some(true);
diff --git a/src/tools/clippy/tests/ui/while_let_loop.stderr b/src/tools/clippy/tests/ui/while_let_loop.stderr
index 13dd0ee22..04808c0b3 100644
--- a/src/tools/clippy/tests/ui/while_let_loop.stderr
+++ b/src/tools/clippy/tests/ui/while_let_loop.stderr
@@ -1,5 +1,5 @@
error: this loop could be written as a `while let` loop
- --> $DIR/while_let_loop.rs:5:5
+ --> $DIR/while_let_loop.rs:6:5
|
LL | / loop {
LL | | if let Some(_x) = y {
@@ -13,7 +13,7 @@ LL | | }
= note: `-D clippy::while-let-loop` implied by `-D warnings`
error: this loop could be written as a `while let` loop
- --> $DIR/while_let_loop.rs:22:5
+ --> $DIR/while_let_loop.rs:23:5
|
LL | / loop {
LL | | match y {
@@ -24,7 +24,7 @@ LL | | }
| |_____^ help: try: `while let Some(_x) = y { .. }`
error: this loop could be written as a `while let` loop
- --> $DIR/while_let_loop.rs:29:5
+ --> $DIR/while_let_loop.rs:30:5
|
LL | / loop {
LL | | let x = match y {
@@ -36,7 +36,7 @@ LL | | }
| |_____^ help: try: `while let Some(x) = y { .. }`
error: this loop could be written as a `while let` loop
- --> $DIR/while_let_loop.rs:38:5
+ --> $DIR/while_let_loop.rs:39:5
|
LL | / loop {
LL | | let x = match y {
@@ -48,7 +48,7 @@ LL | | }
| |_____^ help: try: `while let Some(x) = y { .. }`
error: this loop could be written as a `while let` loop
- --> $DIR/while_let_loop.rs:68:5
+ --> $DIR/while_let_loop.rs:69:5
|
LL | / loop {
LL | | let (e, l) = match "".split_whitespace().next() {
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
index c57c46736..5afa0a89f 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
@@ -1,14 +1,12 @@
// run-rustfix
-
#![warn(clippy::while_let_on_iterator)]
+#![allow(dead_code, unreachable_code, unused_mut)]
#![allow(
- clippy::never_loop,
- unreachable_code,
- unused_mut,
- dead_code,
clippy::equatable_if_let,
clippy::manual_find,
- clippy::redundant_closure_call
+ clippy::never_loop,
+ clippy::redundant_closure_call,
+ clippy::uninlined_format_args
)]
fn base() {
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.rs b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
index 8b9a2dbcc..3de586c9d 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.rs
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
@@ -1,14 +1,12 @@
// run-rustfix
-
#![warn(clippy::while_let_on_iterator)]
+#![allow(dead_code, unreachable_code, unused_mut)]
#![allow(
- clippy::never_loop,
- unreachable_code,
- unused_mut,
- dead_code,
clippy::equatable_if_let,
clippy::manual_find,
- clippy::redundant_closure_call
+ clippy::never_loop,
+ clippy::redundant_closure_call,
+ clippy::uninlined_format_args
)]
fn base() {
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
index 3236765e1..4d9866619 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
@@ -1,5 +1,5 @@
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:16:5
+ --> $DIR/while_let_on_iterator.rs:14:5
|
LL | while let Option::Some(x) = iter.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter`
@@ -7,151 +7,151 @@ LL | while let Option::Some(x) = iter.next() {
= note: `-D clippy::while-let-on-iterator` implied by `-D warnings`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:21:5
+ --> $DIR/while_let_on_iterator.rs:19:5
|
LL | while let Some(x) = iter.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:26:5
+ --> $DIR/while_let_on_iterator.rs:24:5
|
LL | while let Some(_) = iter.next() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:102:9
+ --> $DIR/while_let_on_iterator.rs:100:9
|
LL | while let Some([..]) = it.next() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:109:9
+ --> $DIR/while_let_on_iterator.rs:107:9
|
LL | while let Some([_x]) = it.next() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:122:9
+ --> $DIR/while_let_on_iterator.rs:120:9
|
LL | while let Some(x @ [_]) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:142:9
+ --> $DIR/while_let_on_iterator.rs:140:9
|
LL | while let Some(_) = y.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:199:9
+ --> $DIR/while_let_on_iterator.rs:197:9
|
LL | while let Some(m) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:210:5
+ --> $DIR/while_let_on_iterator.rs:208:5
|
LL | while let Some(n) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:212:9
+ --> $DIR/while_let_on_iterator.rs:210:9
|
LL | while let Some(m) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:221:9
+ --> $DIR/while_let_on_iterator.rs:219:9
|
LL | while let Some(m) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:230:9
+ --> $DIR/while_let_on_iterator.rs:228:9
|
LL | while let Some(m) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:247:9
+ --> $DIR/while_let_on_iterator.rs:245:9
|
LL | while let Some(m) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:262:13
+ --> $DIR/while_let_on_iterator.rs:260:13
|
LL | while let Some(i) = self.0.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.by_ref()`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:294:13
+ --> $DIR/while_let_on_iterator.rs:292:13
|
LL | while let Some(i) = self.0.0.0.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.0.0.by_ref()`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:323:5
+ --> $DIR/while_let_on_iterator.rs:321:5
|
LL | while let Some(n) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it.by_ref()`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:335:9
+ --> $DIR/while_let_on_iterator.rs:333:9
|
LL | while let Some(x) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:349:5
+ --> $DIR/while_let_on_iterator.rs:347:5
|
LL | while let Some(x) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:360:5
+ --> $DIR/while_let_on_iterator.rs:358:5
|
LL | while let Some(x) = it.0.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.0.by_ref()`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:395:5
+ --> $DIR/while_let_on_iterator.rs:393:5
|
LL | while let Some(x) = s.x.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in s.x.by_ref()`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:402:5
+ --> $DIR/while_let_on_iterator.rs:400:5
|
LL | while let Some(x) = x[0].next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in x[0].by_ref()`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:410:9
+ --> $DIR/while_let_on_iterator.rs:408:9
|
LL | while let Some(x) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:420:9
+ --> $DIR/while_let_on_iterator.rs:418:9
|
LL | while let Some(x) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:430:9
+ --> $DIR/while_let_on_iterator.rs:428:9
|
LL | while let Some(x) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:440:9
+ --> $DIR/while_let_on_iterator.rs:438:9
|
LL | while let Some(x) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it`
error: this loop could be written as a `for` loop
- --> $DIR/while_let_on_iterator.rs:450:5
+ --> $DIR/while_let_on_iterator.rs:448:5
|
LL | while let Some(..) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`
diff --git a/src/tools/clippy/tests/ui/wild_in_or_pats.stderr b/src/tools/clippy/tests/ui/wild_in_or_pats.stderr
index 45b87aa0f..bd5860f45 100644
--- a/src/tools/clippy/tests/ui/wild_in_or_pats.stderr
+++ b/src/tools/clippy/tests/ui/wild_in_or_pats.stderr
@@ -4,8 +4,8 @@ error: wildcard pattern covers any other pattern as it will match anyway
LL | "bar" | _ => {
| ^^^^^^^^^
|
- = note: `-D clippy::wildcard-in-or-patterns` implied by `-D warnings`
= help: consider handling `_` separately
+ = note: `-D clippy::wildcard-in-or-patterns` implied by `-D warnings`
error: wildcard pattern covers any other pattern as it will match anyway
--> $DIR/wild_in_or_pats.rs:16:9
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
index 3ee4ab48a..236074978 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
@@ -1,15 +1,13 @@
// run-rustfix
// aux-build:non-exhaustive-enum.rs
-
#![deny(clippy::wildcard_enum_match_arm)]
+#![allow(dead_code, unreachable_code, unused_variables)]
#![allow(
- unreachable_code,
- unused_variables,
- dead_code,
+ clippy::diverging_sub_expression,
clippy::single_match,
- clippy::wildcard_in_or_patterns,
+ clippy::uninlined_format_args,
clippy::unnested_or_patterns,
- clippy::diverging_sub_expression
+ clippy::wildcard_in_or_patterns
)]
extern crate non_exhaustive_enum;
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
index 468865504..decd86165 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
@@ -1,15 +1,13 @@
// run-rustfix
// aux-build:non-exhaustive-enum.rs
-
#![deny(clippy::wildcard_enum_match_arm)]
+#![allow(dead_code, unreachable_code, unused_variables)]
#![allow(
- unreachable_code,
- unused_variables,
- dead_code,
+ clippy::diverging_sub_expression,
clippy::single_match,
- clippy::wildcard_in_or_patterns,
+ clippy::uninlined_format_args,
clippy::unnested_or_patterns,
- clippy::diverging_sub_expression
+ clippy::wildcard_in_or_patterns
)]
extern crate non_exhaustive_enum;
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
index d63f20903..efecc9576 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
@@ -1,41 +1,41 @@
error: wildcard match will also match any future added variants
- --> $DIR/wildcard_enum_match_arm.rs:42:9
+ --> $DIR/wildcard_enum_match_arm.rs:40:9
|
LL | _ => eprintln!("Not red"),
| ^ help: try this: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan`
|
note: the lint level is defined here
- --> $DIR/wildcard_enum_match_arm.rs:4:9
+ --> $DIR/wildcard_enum_match_arm.rs:3:9
|
LL | #![deny(clippy::wildcard_enum_match_arm)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: wildcard match will also match any future added variants
- --> $DIR/wildcard_enum_match_arm.rs:46:9
+ --> $DIR/wildcard_enum_match_arm.rs:44:9
|
LL | _not_red => eprintln!("Not red"),
| ^^^^^^^^ help: try this: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan`
error: wildcard match will also match any future added variants
- --> $DIR/wildcard_enum_match_arm.rs:50:9
+ --> $DIR/wildcard_enum_match_arm.rs:48:9
|
LL | not_red => format!("{:?}", not_red),
| ^^^^^^^ help: try this: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan`
error: wildcard match will also match any future added variants
- --> $DIR/wildcard_enum_match_arm.rs:66:9
+ --> $DIR/wildcard_enum_match_arm.rs:64:9
|
LL | _ => "No red",
| ^ help: try this: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan`
error: wildcard matches known variants and will also match future added variants
- --> $DIR/wildcard_enum_match_arm.rs:83:9
+ --> $DIR/wildcard_enum_match_arm.rs:81:9
|
LL | _ => {},
| ^ help: try this: `ErrorKind::PermissionDenied | _`
error: wildcard matches known variants and will also match future added variants
- --> $DIR/wildcard_enum_match_arm.rs:101:13
+ --> $DIR/wildcard_enum_match_arm.rs:99:13
|
LL | _ => (),
| ^ help: try this: `Enum::B | _`
diff --git a/src/tools/clippy/tests/ui/write_literal.rs b/src/tools/clippy/tests/ui/write_literal.rs
index 446691744..218385ea1 100644
--- a/src/tools/clippy/tests/ui/write_literal.rs
+++ b/src/tools/clippy/tests/ui/write_literal.rs
@@ -1,5 +1,5 @@
-#![allow(unused_must_use)]
#![warn(clippy::write_literal)]
+#![allow(clippy::uninlined_format_args, unused_must_use)]
use std::io::Write;
@@ -25,11 +25,13 @@ fn main() {
writeln!(v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
writeln!(v, "10 / 4 is {}", 2.5);
writeln!(v, "2 + 1 = {}", 3);
+ writeln!(v, "From expansion {}", stringify!(not a string literal));
// these should throw warnings
write!(v, "Hello {}", "world");
writeln!(v, "Hello {} {}", world, "world");
writeln!(v, "Hello {}", "world");
+ writeln!(v, "{} {:.4}", "a literal", 5);
// positional args don't change the fact
// that we're using a literal -- this should
diff --git a/src/tools/clippy/tests/ui/write_literal.stderr b/src/tools/clippy/tests/ui/write_literal.stderr
index 3c5ec91d3..1e306ae28 100644
--- a/src/tools/clippy/tests/ui/write_literal.stderr
+++ b/src/tools/clippy/tests/ui/write_literal.stderr
@@ -1,5 +1,5 @@
error: literal with an empty format string
- --> $DIR/write_literal.rs:30:27
+ --> $DIR/write_literal.rs:31:27
|
LL | write!(v, "Hello {}", "world");
| ^^^^^^^
@@ -12,7 +12,7 @@ LL + write!(v, "Hello world");
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:31:39
+ --> $DIR/write_literal.rs:32:39
|
LL | writeln!(v, "Hello {} {}", world, "world");
| ^^^^^^^
@@ -24,7 +24,7 @@ LL + writeln!(v, "Hello {} world", world);
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:32:29
+ --> $DIR/write_literal.rs:33:29
|
LL | writeln!(v, "Hello {}", "world");
| ^^^^^^^
@@ -36,7 +36,19 @@ LL + writeln!(v, "Hello world");
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:37:28
+ --> $DIR/write_literal.rs:34:29
+ |
+LL | writeln!(v, "{} {:.4}", "a literal", 5);
+ | ^^^^^^^^^^^
+ |
+help: try this
+ |
+LL - writeln!(v, "{} {:.4}", "a literal", 5);
+LL + writeln!(v, "a literal {:.4}", 5);
+ |
+
+error: literal with an empty format string
+ --> $DIR/write_literal.rs:39:28
|
LL | writeln!(v, "{0} {1}", "hello", "world");
| ^^^^^^^
@@ -48,7 +60,7 @@ LL + writeln!(v, "hello {1}", "world");
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:37:37
+ --> $DIR/write_literal.rs:39:37
|
LL | writeln!(v, "{0} {1}", "hello", "world");
| ^^^^^^^
@@ -60,34 +72,34 @@ LL + writeln!(v, "{0} world", "hello");
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:38:28
+ --> $DIR/write_literal.rs:40:37
|
LL | writeln!(v, "{1} {0}", "hello", "world");
- | ^^^^^^^
+ | ^^^^^^^
|
help: try this
|
LL - writeln!(v, "{1} {0}", "hello", "world");
-LL + writeln!(v, "{1} hello", "world");
+LL + writeln!(v, "world {0}", "hello");
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:38:37
+ --> $DIR/write_literal.rs:40:28
|
LL | writeln!(v, "{1} {0}", "hello", "world");
- | ^^^^^^^
+ | ^^^^^^^
|
help: try this
|
LL - writeln!(v, "{1} {0}", "hello", "world");
-LL + writeln!(v, "world {0}", "hello");
+LL + writeln!(v, "{1} hello", "world");
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:41:32
+ --> $DIR/write_literal.rs:43:38
|
LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
- | ^^^^^^^^^^^^^
+ | ^^^^^^^
|
help: try this
|
@@ -96,10 +108,10 @@ LL + writeln!(v, "hello {bar}", bar = "world");
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:41:47
+ --> $DIR/write_literal.rs:43:53
|
LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
- | ^^^^^^^^^^^^^
+ | ^^^^^^^
|
help: try this
|
@@ -108,28 +120,28 @@ LL + writeln!(v, "{foo} world", foo = "hello");
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:42:32
+ --> $DIR/write_literal.rs:44:53
|
LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
- | ^^^^^^^^^^^^^
+ | ^^^^^^^
|
help: try this
|
LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
-LL + writeln!(v, "{bar} hello", bar = "world");
+LL + writeln!(v, "world {foo}", foo = "hello");
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:42:47
+ --> $DIR/write_literal.rs:44:38
|
LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
- | ^^^^^^^^^^^^^
+ | ^^^^^^^
|
help: try this
|
LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
-LL + writeln!(v, "world {foo}", foo = "hello");
+LL + writeln!(v, "{bar} hello", bar = "world");
|
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/write_literal_2.rs b/src/tools/clippy/tests/ui/write_literal_2.rs
index ba0d7be5e..55a11daa1 100644
--- a/src/tools/clippy/tests/ui/write_literal_2.rs
+++ b/src/tools/clippy/tests/ui/write_literal_2.rs
@@ -10,7 +10,7 @@ fn main() {
writeln!(v, r"{}", r"{hello}");
writeln!(v, "{}", '\'');
writeln!(v, "{}", '"');
- writeln!(v, r"{}", '"'); // don't lint
+ writeln!(v, r"{}", '"');
writeln!(v, r"{}", '\'');
writeln!(
v,
@@ -24,4 +24,11 @@ fn main() {
{} \\ {}",
"1", "2", "3",
);
+ writeln!(v, "{}", "\\");
+ writeln!(v, r"{}", "\\");
+ writeln!(v, r#"{}"#, "\\");
+ writeln!(v, "{}", r"\");
+ writeln!(v, "{}", "\r");
+ writeln!(v, r#"{}{}"#, '#', '"'); // hard mode
+ writeln!(v, r"{}", "\r"); // should not lint
}
diff --git a/src/tools/clippy/tests/ui/write_literal_2.stderr b/src/tools/clippy/tests/ui/write_literal_2.stderr
index 9ff297069..d5956db9f 100644
--- a/src/tools/clippy/tests/ui/write_literal_2.stderr
+++ b/src/tools/clippy/tests/ui/write_literal_2.stderr
@@ -48,6 +48,12 @@ LL + writeln!(v, "/"");
|
error: literal with an empty format string
+ --> $DIR/write_literal_2.rs:13:24
+ |
+LL | writeln!(v, r"{}", '"');
+ | ^^^
+
+error: literal with an empty format string
--> $DIR/write_literal_2.rs:14:24
|
LL | writeln!(v, r"{}", '/'');
@@ -108,5 +114,77 @@ LL ~ {} / 3",
LL ~ "1", "2",
|
-error: aborting due to 9 previous errors
+error: literal with an empty format string
+ --> $DIR/write_literal_2.rs:27:23
+ |
+LL | writeln!(v, "{}", "/");
+ | ^^^^
+ |
+help: try this
+ |
+LL - writeln!(v, "{}", "/");
+LL + writeln!(v, "/");
+ |
+
+error: literal with an empty format string
+ --> $DIR/write_literal_2.rs:28:24
+ |
+LL | writeln!(v, r"{}", "/");
+ | ^^^^
+ |
+help: try this
+ |
+LL - writeln!(v, r"{}", "/");
+LL + writeln!(v, r"/");
+ |
+
+error: literal with an empty format string
+ --> $DIR/write_literal_2.rs:29:26
+ |
+LL | writeln!(v, r#"{}"#, "/");
+ | ^^^^
+ |
+help: try this
+ |
+LL - writeln!(v, r#"{}"#, "/");
+LL + writeln!(v, r#"/"#);
+ |
+
+error: literal with an empty format string
+ --> $DIR/write_literal_2.rs:30:23
+ |
+LL | writeln!(v, "{}", r"/");
+ | ^^^^
+ |
+help: try this
+ |
+LL - writeln!(v, "{}", r"/");
+LL + writeln!(v, "/");
+ |
+
+error: literal with an empty format string
+ --> $DIR/write_literal_2.rs:31:23
+ |
+LL | writeln!(v, "{}", "/r");
+ | ^^^^
+ |
+help: try this
+ |
+LL - writeln!(v, "{}", "/r");
+LL + writeln!(v, "/r");
+ |
+
+error: literal with an empty format string
+ --> $DIR/write_literal_2.rs:32:28
+ |
+LL | writeln!(v, r#"{}{}"#, '#', '"'); // hard mode
+ | ^^^
+
+error: literal with an empty format string
+ --> $DIR/write_literal_2.rs:32:33
+ |
+LL | writeln!(v, r#"{}{}"#, '#', '"'); // hard mode
+ | ^^^
+
+error: aborting due to 17 previous errors
diff --git a/src/tools/clippy/tests/ui/write_with_newline.rs b/src/tools/clippy/tests/ui/write_with_newline.rs
index 446d6914d..b79364c87 100644
--- a/src/tools/clippy/tests/ui/write_with_newline.rs
+++ b/src/tools/clippy/tests/ui/write_with_newline.rs
@@ -56,4 +56,12 @@ fn main() {
write!(v, "foo\r\n");
write!(v, "\\r\n"); //~ ERROR
write!(v, "foo\rbar\n");
+
+ // Ignore expanded format strings
+ macro_rules! newline {
+ () => {
+ "\n"
+ };
+ }
+ write!(v, newline!());
}
diff --git a/src/tools/clippy/tests/ui/write_with_newline.stderr b/src/tools/clippy/tests/ui/write_with_newline.stderr
index 5f55431be..2baaea166 100644
--- a/src/tools/clippy/tests/ui/write_with_newline.stderr
+++ b/src/tools/clippy/tests/ui/write_with_newline.stderr
@@ -5,7 +5,7 @@ LL | write!(v, "Hello/n");
| ^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::write-with-newline` implied by `-D warnings`
-help: use `writeln!()` instead
+help: use `writeln!` instead
|
LL - write!(v, "Hello/n");
LL + writeln!(v, "Hello");
@@ -17,7 +17,7 @@ error: using `write!()` with a format string that ends in a single newline
LL | write!(v, "Hello {}/n", "world");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: use `writeln!()` instead
+help: use `writeln!` instead
|
LL - write!(v, "Hello {}/n", "world");
LL + writeln!(v, "Hello {}", "world");
@@ -29,7 +29,7 @@ error: using `write!()` with a format string that ends in a single newline
LL | write!(v, "Hello {} {}/n", "world", "#2");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: use `writeln!()` instead
+help: use `writeln!` instead
|
LL - write!(v, "Hello {} {}/n", "world", "#2");
LL + writeln!(v, "Hello {} {}", "world", "#2");
@@ -41,7 +41,7 @@ error: using `write!()` with a format string that ends in a single newline
LL | write!(v, "{}/n", 1265);
| ^^^^^^^^^^^^^^^^^^^^^^^
|
-help: use `writeln!()` instead
+help: use `writeln!` instead
|
LL - write!(v, "{}/n", 1265);
LL + writeln!(v, "{}", 1265);
@@ -53,7 +53,7 @@ error: using `write!()` with a format string that ends in a single newline
LL | write!(v, "/n");
| ^^^^^^^^^^^^^^^
|
-help: use `writeln!()` instead
+help: use `writeln!` instead
|
LL - write!(v, "/n");
LL + writeln!(v);
@@ -65,7 +65,7 @@ error: using `write!()` with a format string that ends in a single newline
LL | write!(v, "//n"); // should fail
| ^^^^^^^^^^^^^^^^^
|
-help: use `writeln!()` instead
+help: use `writeln!` instead
|
LL - write!(v, "//n"); // should fail
LL + writeln!(v, "/"); // should fail
@@ -81,11 +81,10 @@ LL | | "
LL | | );
| |_____^
|
-help: use `writeln!()` instead
+help: use `writeln!` instead
|
LL ~ writeln!(
-LL | v,
-LL ~ ""
+LL ~ v
|
error: using `write!()` with a format string that ends in a single newline
@@ -98,11 +97,10 @@ LL | | "
LL | | );
| |_____^
|
-help: use `writeln!()` instead
+help: use `writeln!` instead
|
LL ~ writeln!(
-LL | v,
-LL ~ r""
+LL ~ v
|
error: using `write!()` with a format string that ends in a single newline
@@ -111,23 +109,11 @@ error: using `write!()` with a format string that ends in a single newline
LL | write!(v, "/r/n"); //~ ERROR
| ^^^^^^^^^^^^^^^^^^
|
-help: use `writeln!()` instead
+help: use `writeln!` instead
|
LL - write!(v, "/r/n"); //~ ERROR
LL + writeln!(v, "/r"); //~ ERROR
|
-error: using `write!()` with a format string that ends in a single newline
- --> $DIR/write_with_newline.rs:58:5
- |
-LL | write!(v, "foo/rbar/n");
- | ^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: use `writeln!()` instead
- |
-LL - write!(v, "foo/rbar/n");
-LL + writeln!(v, "foo/rbar");
- |
-
-error: aborting due to 10 previous errors
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.stderr b/src/tools/clippy/tests/ui/writeln_empty_string.stderr
index ac65aadfc..25e69ec48 100644
--- a/src/tools/clippy/tests/ui/writeln_empty_string.stderr
+++ b/src/tools/clippy/tests/ui/writeln_empty_string.stderr
@@ -1,16 +1,20 @@
-error: using `writeln!(v, "")`
+error: empty string literal in `writeln!`
--> $DIR/writeln_empty_string.rs:11:5
|
LL | writeln!(v, "");
- | ^^^^^^^^^^^^^^^ help: replace it with: `writeln!(v)`
+ | ^^^^^^^^^^----^
+ | |
+ | help: remove the empty string
|
= note: `-D clippy::writeln-empty-string` implied by `-D warnings`
-error: using `writeln!(suggestion, "")`
+error: empty string literal in `writeln!`
--> $DIR/writeln_empty_string.rs:14:5
|
LL | writeln!(suggestion, "");
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(suggestion)`
+ | ^^^^^^^^^^^^^^^^^^^----^
+ | |
+ | help: remove the empty string
error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.stderr b/src/tools/clippy/tests/ui/wrong_self_convention.stderr
index 2e7ee51d7..d002e55c5 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention.stderr
+++ b/src/tools/clippy/tests/ui/wrong_self_convention.stderr
@@ -4,8 +4,8 @@ error: methods called `from_*` usually take no `self`
LL | fn from_i32(self) {}
| ^^^^
|
- = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
= help: consider choosing a less ambiguous name
+ = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
error: methods called `from_*` usually take no `self`
--> $DIR/wrong_self_convention.rs:22:21
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr
index 5bdc47f91..8de10e7be 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr
+++ b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr
@@ -4,8 +4,8 @@ error: methods called `from_*` usually take no `self`
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
+ = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
error: methods called `from_*` usually take no `self`
--> $DIR/wrong_self_convention2.rs:63:25
diff --git a/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr
index 8665d8dc9..3d009083c 100644
--- a/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr
+++ b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr
@@ -4,8 +4,8 @@ error: methods with the following characteristics: (`to_*` and `self` type is no
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
+ = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
error: methods with the following characteristics: (`to_*` and `*_mut`) usually take `self` by mutable reference
--> $DIR/wrong_self_conventions_mut.rs:22:28
diff --git a/src/tools/clippy/tests/ui/zero_div_zero.stderr b/src/tools/clippy/tests/ui/zero_div_zero.stderr
index 86563542e..2793d1606 100644
--- a/src/tools/clippy/tests/ui/zero_div_zero.stderr
+++ b/src/tools/clippy/tests/ui/zero_div_zero.stderr
@@ -4,8 +4,8 @@ error: constant division of `0.0` with `0.0` will always result in NaN
LL | let nan = 0.0 / 0.0;
| ^^^^^^^^^
|
- = note: `-D clippy::zero-divided-by-zero` implied by `-D warnings`
= help: consider using `f64::NAN` if you would like a constant representing NaN
+ = note: `-D clippy::zero-divided-by-zero` implied by `-D warnings`
error: constant division of `0.0` with `0.0` will always result in NaN
--> $DIR/zero_div_zero.rs:5:19
diff --git a/src/tools/clippy/tests/ui/zero_sized_btreemap_values.stderr b/src/tools/clippy/tests/ui/zero_sized_btreemap_values.stderr
index d924f3379..c6ba6fa76 100644
--- a/src/tools/clippy/tests/ui/zero_sized_btreemap_values.stderr
+++ b/src/tools/clippy/tests/ui/zero_sized_btreemap_values.stderr
@@ -4,8 +4,8 @@ error: map with zero-sized value type
LL | const CONST_NOT_OK: Option<BTreeMap<String, ()>> = None;
| ^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::zero-sized-map-values` implied by `-D warnings`
= help: consider using a set instead
+ = note: `-D clippy::zero-sized-map-values` implied by `-D warnings`
error: map with zero-sized value type
--> $DIR/zero_sized_btreemap_values.rs:8:30
diff --git a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr
index 79770bf90..75bdeb42e 100644
--- a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr
+++ b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr
@@ -4,8 +4,8 @@ error: map with zero-sized value type
LL | const CONST_NOT_OK: Option<HashMap<String, ()>> = None;
| ^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::zero-sized-map-values` implied by `-D warnings`
= help: consider using a set instead
+ = note: `-D clippy::zero-sized-map-values` implied by `-D warnings`
error: map with zero-sized value type
--> $DIR/zero_sized_hashmap_values.rs:8:30
diff --git a/src/tools/clippy/tests/versioncheck.rs b/src/tools/clippy/tests/versioncheck.rs
index 38498ebdc..a6d8d0307 100644
--- a/src/tools/clippy/tests/versioncheck.rs
+++ b/src/tools/clippy/tests/versioncheck.rs
@@ -8,12 +8,12 @@ use std::fs;
#[test]
fn check_that_clippy_lints_and_clippy_utils_have_the_same_version_as_clippy() {
fn read_version(path: &str) -> String {
- let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("error reading `{}`: {:?}", path, e));
+ let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("error reading `{path}`: {e:?}"));
contents
.lines()
.filter_map(|l| l.split_once('='))
.find_map(|(k, v)| (k.trim() == "version").then(|| v.trim()))
- .unwrap_or_else(|| panic!("error finding version in `{}`", path))
+ .unwrap_or_else(|| panic!("error finding version in `{path}`"))
.to_string()
}
@@ -48,7 +48,7 @@ fn check_that_clippy_has_the_same_major_version_as_rustc() {
// `RUSTC_REAL` if Clippy is build in the Rust repo with `./x.py`.
let rustc = std::env::var("RUSTC_REAL").unwrap_or_else(|_| "rustc".to_string());
let rustc_version = String::from_utf8(
- std::process::Command::new(&rustc)
+ std::process::Command::new(rustc)
.arg("--version")
.output()
.expect("failed to run `rustc --version`")
@@ -83,7 +83,7 @@ fn check_that_clippy_has_the_same_major_version_as_rustc() {
// we don't want our tests failing suddenly
},
_ => {
- panic!("Failed to parse rustc version: {:?}", vsplit);
+ panic!("Failed to parse rustc version: {vsplit:?}");
},
};
}
diff --git a/src/tools/clippy/tests/workspace.rs b/src/tools/clippy/tests/workspace.rs
index e13efb3e0..95325e060 100644
--- a/src/tools/clippy/tests/workspace.rs
+++ b/src/tools/clippy/tests/workspace.rs
@@ -20,8 +20,8 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
.current_dir(&cwd)
.env("CARGO_TARGET_DIR", &target_dir)
.arg("clean")
- .args(&["-p", "subcrate"])
- .args(&["-p", "path_dep"])
+ .args(["-p", "subcrate"])
+ .args(["-p", "path_dep"])
.output()
.unwrap();
@@ -32,11 +32,11 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
.env("CARGO_INCREMENTAL", "0")
.env("CARGO_TARGET_DIR", &target_dir)
.arg("clippy")
- .args(&["-p", "subcrate"])
+ .args(["-p", "subcrate"])
.arg("--no-deps")
.arg("--")
.arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
- .args(&["--cfg", r#"feature="primary_package_test""#])
+ .args(["--cfg", r#"feature="primary_package_test""#])
.output()
.unwrap();
println!("status: {}", output.status);
@@ -52,10 +52,10 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
.env("CARGO_INCREMENTAL", "0")
.env("CARGO_TARGET_DIR", &target_dir)
.arg("clippy")
- .args(&["-p", "subcrate"])
+ .args(["-p", "subcrate"])
.arg("--")
.arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
- .args(&["--cfg", r#"feature="primary_package_test""#])
+ .args(["--cfg", r#"feature="primary_package_test""#])
.output()
.unwrap();
println!("status: {}", output.status);
@@ -79,7 +79,7 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
.env("CARGO_INCREMENTAL", "0")
.env("CARGO_TARGET_DIR", &target_dir)
.arg("clippy")
- .args(&["-p", "subcrate"])
+ .args(["-p", "subcrate"])
.arg("--")
.arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
.output()