Merge 'rust-clippy/master' into clippyup

This commit is contained in:
xFrednet 2022-05-21 13:24:00 +02:00
parent 8d04a32ab4
commit 4587b6628d
239 changed files with 4446 additions and 1708 deletions

1
.github/deploy.sh vendored
View File

@ -8,6 +8,7 @@ rm -rf out/master/ || exit 0
echo "Making the docs for master" echo "Making the docs for master"
mkdir out/master/ mkdir out/master/
cp util/gh-pages/index.html out/master cp util/gh-pages/index.html out/master
cp util/gh-pages/script.js out/master
cp util/gh-pages/lints.json out/master cp util/gh-pages/lints.json out/master
if [[ -n $TAG_NAME ]]; then if [[ -n $TAG_NAME ]]; then

View File

@ -8,9 +8,9 @@ document.
[d0cf3481...master](https://github.com/rust-lang/rust-clippy/compare/d0cf3481...master) [d0cf3481...master](https://github.com/rust-lang/rust-clippy/compare/d0cf3481...master)
## Rust 1.61 (beta) ## Rust 1.61
Current beta, released 2022-05-19 Current stable, released 2022-05-19
[57b3c4b...d0cf3481](https://github.com/rust-lang/rust-clippy/compare/57b3c4b...d0cf3481) [57b3c4b...d0cf3481](https://github.com/rust-lang/rust-clippy/compare/57b3c4b...d0cf3481)
@ -111,7 +111,7 @@ Current beta, released 2022-05-19
## Rust 1.60 ## Rust 1.60
Current stable, released 2022-04-07 Released 2022-04-07
[0eff589...57b3c4b](https://github.com/rust-lang/rust-clippy/compare/0eff589...57b3c4b) [0eff589...57b3c4b](https://github.com/rust-lang/rust-clippy/compare/0eff589...57b3c4b)
@ -3290,6 +3290,8 @@ Released 2018-09-13
[`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map [`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map
[`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name [`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name
[`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints [`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints
[`block_in_if_condition_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_expr
[`block_in_if_condition_stmt`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_stmt
[`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions [`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_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_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
@ -3297,6 +3299,7 @@ Released 2018-09-13
[`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const [`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 [`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_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection
[`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 [`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 [`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow [`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
@ -3332,10 +3335,12 @@ Released 2018-09-13
[`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match [`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match
[`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain [`comparison_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 [`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
[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
[`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def [`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def
[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir [`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
[`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute [`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
[`cyclomatic_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cyclomatic_complexity
[`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro [`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro
[`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
[`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation [`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
@ -3350,8 +3355,11 @@ Released 2018-09-13
[`derivable_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls [`derivable_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls
[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq [`derive_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_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_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_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
[`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents [`disallowed_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 [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
@ -3359,9 +3367,11 @@ Released 2018-09-13
[`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
[`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg [`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
[`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens [`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
[`drop_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_bounds
[`drop_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy [`drop_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy
[`drop_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_non_drop [`drop_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_non_drop
[`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref [`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
[`duplicate_mod`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_mod
[`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument [`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
[`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec [`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
[`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
@ -3413,6 +3423,8 @@ Released 2018-09-13
[`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any [`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any
[`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation [`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
[`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map [`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map
[`for_loop_over_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loop_over_option
[`for_loop_over_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loop_over_result
[`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles [`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
[`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy [`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
[`forget_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_non_drop [`forget_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_non_drop
@ -3425,9 +3437,11 @@ Released 2018-09-13
[`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send [`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
[`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len [`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
[`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap [`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
[`identity_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion
[`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op [`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op
[`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex [`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex
[`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching [`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
[`if_let_some_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_some_result
[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else [`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
@ -3456,8 +3470,11 @@ Released 2018-09-13
[`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one [`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
[`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic [`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division [`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref [`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering
[`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage [`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage
[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
[`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex [`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
[`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons [`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
[`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters [`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters
@ -3531,6 +3548,7 @@ Released 2018-09-13
[`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm [`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
[`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants [`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
[`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter [`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum
[`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget [`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget
[`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none [`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none
[`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default [`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default
@ -3549,6 +3567,7 @@ Released 2018-09-13
[`missing_spin_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_spin_loop [`missing_spin_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_spin_loop
[`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes [`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_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
[`mod_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#mod_module_files [`mod_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#mod_module_files
[`module_inception`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_inception [`module_inception`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_inception
[`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions [`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions
@ -3592,6 +3611,7 @@ Released 2018-09-13
[`never_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#never_loop [`never_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#never_loop
[`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self [`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self
[`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default [`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
[`new_without_default_derive`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default_derive
[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect [`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
[`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding [`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
@ -3605,19 +3625,25 @@ Released 2018-09-13
[`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect [`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect
[`only_used_in_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion [`only_used_in_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion
[`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
[`option_and_then_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_and_then_some
[`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref [`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref
[`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap [`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap
[`option_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_expect_used
[`option_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_filter_map [`option_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_filter_map
[`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else [`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
[`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none [`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none
[`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn [`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn
[`option_map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or
[`option_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or_else
[`option_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option [`option_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option
[`option_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_unwrap_used
[`or_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call [`or_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call
[`or_then_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_then_unwrap [`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 [`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 [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
[`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic [`panic`]: 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_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 [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
@ -3642,6 +3668,7 @@ Released 2018-09-13
[`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero [`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
[`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len [`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len
[`rc_buffer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer [`rc_buffer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer
[`rc_clone_in_vec_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_clone_in_vec_init
[`rc_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex [`rc_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex
[`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl [`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl
[`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation [`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
@ -3658,14 +3685,18 @@ Released 2018-09-13
[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing [`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference [`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts [`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 [`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_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option [`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_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
[`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err [`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err
[`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used
[`return_self_not_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use [`return_self_not_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use
[`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges [`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
[`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
@ -3684,10 +3715,12 @@ Released 2018-09-13
[`short_circuit_statement`]: https://rust-lang.github.io/rust-clippy/master/index.html#short_circuit_statement [`short_circuit_statement`]: https://rust-lang.github.io/rust-clippy/master/index.html#short_circuit_statement
[`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq [`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq
[`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait [`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
[`significant_drop_in_scrutinee`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_in_scrutinee
[`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names [`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
[`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str [`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
[`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names [`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names
[`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern [`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
[`single_char_push_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_push_str
[`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports [`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports
[`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop [`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop
[`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
@ -3707,6 +3740,7 @@ Released 2018-09-13
[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
[`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings [`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools [`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
[`stutter`]: https://rust-lang.github.io/rust-clippy/master/index.html#stutter
[`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops [`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops
[`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl [`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
[`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting [`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting
@ -3718,7 +3752,9 @@ Released 2018-09-13
[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
[`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
[`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args [`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args
[`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo [`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
[`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
@ -3753,6 +3789,7 @@ Released 2018-09-13
[`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp [`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
[`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash [`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash
[`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord [`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
[`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints
[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
[`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map [`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map
@ -3782,6 +3819,7 @@ Released 2018-09-13
[`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async [`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_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
[`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
[`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
[`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self [`unused_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 [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
[`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings [`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
@ -3822,5 +3860,6 @@ Released 2018-09-13
[`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal [`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
[`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr [`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr
[`zero_sized_map_values`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_sized_map_values [`zero_sized_map_values`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_sized_map_values
[`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space
[`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
<!-- end autogenerated links to lint list --> <!-- end autogenerated links to lint list -->

View File

@ -67,9 +67,9 @@ and resolved paths.
[`T-AST`] issues will generally need you to match against a predefined syntax structure. [`T-AST`] issues will generally need you to match against a predefined syntax structure.
To figure out how this syntax structure is encoded in the AST, it is recommended to run To figure out how this syntax structure is encoded in the AST, it is recommended to run
`rustc -Z ast-json` on an example of the structure and compare with the [nodes in the AST docs]. `rustc -Z unpretty=ast-tree` on an example of the structure and compare with the [nodes in the AST docs].
Usually the lint will end up to be a nested series of matches and ifs, [like so][deep-nesting]. Usually the lint will end up to be a nested series of matches and ifs, [like so][deep-nesting].
But we can make it nest-less by using [if_chain] macro, [like this][nest-less]. But we can make it nest-less by using [let chains], [like this][nest-less].
[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good-first-issue`] [`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good-first-issue`]
first. Sometimes they are only somewhat involved code wise, but not difficult per-se. first. Sometimes they are only somewhat involved code wise, but not difficult per-se.
@ -87,9 +87,9 @@ an AST expression). `match_def_path()` in Clippy's `utils` module can also be us
[`E-medium`]: https://github.com/rust-lang/rust-clippy/labels/E-medium [`E-medium`]: https://github.com/rust-lang/rust-clippy/labels/E-medium
[`ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty [`ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty
[nodes in the AST docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/ [nodes in the AST docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/
[deep-nesting]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/mem_forget.rs#L29-L43 [deep-nesting]: https://github.com/rust-lang/rust-clippy/blob/5e4f0922911536f80d9591180fa604229ac13939/clippy_lints/src/mem_forget.rs#L31-L45
[if_chain]: https://docs.rs/if_chain/*/if_chain [let chains]: https://github.com/rust-lang/rust/pull/94927
[nest-less]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/bit_mask.rs#L124-L150 [nest-less]: https://github.com/rust-lang/rust-clippy/blob/5e4f0922911536f80d9591180fa604229ac13939/clippy_lints/src/bit_mask.rs#L133-L159
## Writing code ## Writing code

View File

@ -1,6 +1,6 @@
[package] [package]
name = "clippy" name = "clippy"
version = "0.1.62" version = "0.1.63"
description = "A bunch of helpful lints to avoid common pitfalls in Rust" description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy" repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md" readme = "README.md"
@ -25,6 +25,7 @@ clippy_lints = { path = "clippy_lints" }
semver = "1.0" semver = "1.0"
rustc_tools_util = { path = "rustc_tools_util" } rustc_tools_util = { path = "rustc_tools_util" }
tempfile = { version = "3.2", optional = true } tempfile = { version = "3.2", optional = true }
termize = "0.1"
[dev-dependencies] [dev-dependencies]
compiletest_rs = { version = "0.7.1", features = ["tmp"] } compiletest_rs = { version = "0.7.1", features = ["tmp"] }

View File

@ -13,7 +13,7 @@ fn exit_if_err(status: io::Result<ExitStatus>) {
} }
} }
pub fn run(path: &str) { pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a str>) {
let is_file = match fs::metadata(path) { let is_file = match fs::metadata(path) {
Ok(metadata) => metadata.is_file(), Ok(metadata) => metadata.is_file(),
Err(e) => { Err(e) => {
@ -30,6 +30,7 @@ pub fn run(path: &str) {
.args(["-Z", "no-codegen"]) .args(["-Z", "no-codegen"])
.args(["--edition", "2021"]) .args(["--edition", "2021"])
.arg(path) .arg(path)
.args(args)
.status(), .status(),
); );
} else { } else {
@ -42,6 +43,8 @@ pub fn run(path: &str) {
.expect("failed to create tempdir"); .expect("failed to create tempdir");
let status = Command::new(cargo_clippy_path()) let status = Command::new(cargo_clippy_path())
.arg("clippy")
.args(args)
.current_dir(path) .current_dir(path)
.env("CARGO_TARGET_DIR", target.as_ref()) .env("CARGO_TARGET_DIR", target.as_ref())
.status(); .status();

View File

@ -76,7 +76,8 @@ fn main() {
}, },
("lint", Some(matches)) => { ("lint", Some(matches)) => {
let path = matches.value_of("path").unwrap(); let path = matches.value_of("path").unwrap();
lint::run(path); let args = matches.values_of("args").into_iter().flatten();
lint::run(path, args);
}, },
("rename_lint", Some(matches)) => { ("rename_lint", Some(matches)) => {
let old_name = matches.value_of("old_name").unwrap(); let old_name = matches.value_of("old_name").unwrap();
@ -123,7 +124,7 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
* the lint count in README.md is correct\n \ * the lint count in README.md is correct\n \
* the changelog contains markdown link references at the bottom\n \ * the changelog contains markdown link references at the bottom\n \
* all lint groups include the correct lints\n \ * all lint groups include the correct lints\n \
* lint modules in `clippy_lints/*` are visible in `src/lifb.rs` via `pub mod`\n \ * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
* all lints are registered in the lint store", * all lints are registered in the lint store",
) )
.arg(Arg::with_name("print-only").long("print-only").help( .arg(Arg::with_name("print-only").long("print-only").help(
@ -278,11 +279,23 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
Lint a package directory: Lint a package directory:
cargo dev lint tests/ui-cargo/wildcard_dependencies/fail cargo dev lint tests/ui-cargo/wildcard_dependencies/fail
cargo dev lint ~/my-project cargo dev lint ~/my-project
Run rustfix:
cargo dev lint ~/my-project -- --fix
Set lint levels:
cargo dev lint file.rs -- -W clippy::pedantic
cargo dev lint ~/my-project -- -- -W clippy::pedantic
"}) "})
.arg( .arg(
Arg::with_name("path") Arg::with_name("path")
.required(true) .required(true)
.help("The path to a file or package directory to lint"), .help("The path to a file or package directory to lint"),
)
.arg(
Arg::with_name("args")
.multiple(true)
.help("Pass extra arguments to cargo/clippy-driver"),
), ),
) )
.subcommand( .subcommand(

View File

@ -133,7 +133,7 @@ fn to_camel_case(name: &str) -> String {
.collect() .collect()
} }
fn get_stabilisation_version() -> String { fn get_stabilization_version() -> String {
fn parse_manifest(contents: &str) -> Option<String> { fn parse_manifest(contents: &str) -> Option<String> {
let version = contents let version = contents
.lines() .lines()
@ -199,7 +199,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
}, },
}; };
let version = get_stabilisation_version(); let version = get_stabilization_version();
let lint_name = lint.name; let lint_name = lint.name;
let category = lint.category; let category = lint.category;
let name_camel = to_camel_case(lint.name); let name_camel = to_camel_case(lint.name);

View File

@ -17,7 +17,7 @@ const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev u
const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html"; const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html";
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq, Eq)]
pub enum UpdateMode { pub enum UpdateMode {
Check, Check,
Change, Change,
@ -66,8 +66,13 @@ fn generate_lint_files(
|res| { |res| {
for lint in usable_lints for lint in usable_lints
.iter() .iter()
.map(|l| &l.name) .map(|l| &*l.name)
.chain(deprecated_lints.iter().map(|l| &l.name)) .chain(deprecated_lints.iter().map(|l| &*l.name))
.chain(
renamed_lints
.iter()
.map(|l| l.old_name.strip_prefix("clippy::").unwrap_or(&l.old_name)),
)
.sorted() .sorted()
{ {
writeln!(res, "[`{}`]: {}#{}", lint, DOCS_LINK, lint).unwrap(); writeln!(res, "[`{}`]: {}#{}", lint, DOCS_LINK, lint).unwrap();
@ -372,7 +377,7 @@ fn exit_with_failure() {
} }
/// Lint data parsed from the Clippy source code. /// Lint data parsed from the Clippy source code.
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
struct Lint { struct Lint {
name: String, name: String,
group: String, group: String,
@ -414,7 +419,7 @@ impl Lint {
} }
} }
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
struct DeprecatedLint { struct DeprecatedLint {
name: String, name: String,
reason: String, reason: String,

View File

@ -1,6 +1,6 @@
[package] [package]
name = "clippy_lints" name = "clippy_lints"
version = "0.1.62" version = "0.1.63"
description = "A bunch of helpful lints to avoid common pitfalls in Rust" description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy" repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md" readme = "README.md"

View File

@ -87,9 +87,7 @@ impl ApproxConstant {
let s = s.as_str(); let s = s.as_str();
if s.parse::<f64>().is_ok() { if s.parse::<f64>().is_ok() {
for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS { for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
if is_approx_const(constant, s, min_digits) if is_approx_const(constant, s, min_digits) && msrv.map_or(true, |msrv| meets_msrv(self.msrv, msrv)) {
&& msrv.as_ref().map_or(true, |msrv| meets_msrv(self.msrv.as_ref(), msrv))
{
span_lint_and_help( span_lint_and_help(
cx, cx,
APPROX_CONSTANT, APPROX_CONSTANT,

View File

@ -50,7 +50,7 @@ declare_clippy_lint! {
/// ### Known problems /// ### Known problems
/// Clippy cannot know for sure if `a op= a op b` should have /// 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. /// 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 behaviour it should be /// 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. /// written as `a = a op a op b` as it's less confusing.
/// ///
/// ### Example /// ### Example

View File

@ -6,7 +6,7 @@ use clippy_utils::msrvs;
use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
use clippy_utils::{extract_msrv_attr, meets_msrv}; use clippy_utils::{extract_msrv_attr, meets_msrv};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MacArgs, MacArgsEq, MetaItemKind, NestedMetaItem}; use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{ use rustc_hir::{
Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind, Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
@ -586,21 +586,10 @@ impl EarlyLintPass for EarlyAttributes {
fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
for attr in &item.attrs { for attr in &item.attrs {
let attr_item = if let AttrKind::Normal(ref attr, _) = attr.kind { if matches!(attr.kind, AttrKind::Normal(..))
attr && attr.style == AttrStyle::Outer
} else { && is_present_in_source(cx, attr.span)
return; {
};
if attr.style == AttrStyle::Outer {
if let MacArgs::Eq(_, MacArgsEq::Ast(expr)) = &attr_item.args
&& !matches!(expr.kind, rustc_ast::ExprKind::Lit(..)) {
return;
}
if attr_item.args.inner_tokens().is_empty() || !is_present_in_source(cx, attr.span) {
return;
}
let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent()); let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent());
let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt(), item.span.parent()); let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt(), item.span.parent());
@ -624,7 +613,7 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It
fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Option<RustcVersion>) { fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Option<RustcVersion>) {
if_chain! { if_chain! {
if meets_msrv(msrv.as_ref(), &msrvs::TOOL_ATTRIBUTES); if meets_msrv(msrv, msrvs::TOOL_ATTRIBUTES);
// check cfg_attr // check cfg_attr
if attr.has_name(sym::cfg_attr); if attr.has_name(sym::cfg_attr);
if let Some(items) = attr.meta_item_list(); if let Some(items) = attr.meta_item_list();

View File

@ -1,7 +1,6 @@
use clippy_utils::consts::{constant, Constant}; use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use if_chain::if_chain;
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_hir::{BinOpKind, Expr, ExprKind};
@ -130,23 +129,24 @@ impl<'tcx> LateLintPass<'tcx> for BitMask {
} }
} }
} }
if_chain! {
if let ExprKind::Binary(op, left, right) = &e.kind; if let ExprKind::Binary(op, left, right) = &e.kind
if BinOpKind::Eq == op.node; && BinOpKind::Eq == op.node
if let ExprKind::Binary(op1, left1, right1) = &left.kind; && let ExprKind::Binary(op1, left1, right1) = &left.kind
if BinOpKind::BitAnd == op1.node; && BinOpKind::BitAnd == op1.node
if let ExprKind::Lit(lit) = &right1.kind; && let ExprKind::Lit(lit) = &right1.kind
if let LitKind::Int(n, _) = lit.node; && let LitKind::Int(n, _) = lit.node
if let ExprKind::Lit(lit1) = &right.kind; && let ExprKind::Lit(lit1) = &right.kind
if let LitKind::Int(0, _) = lit1.node; && let LitKind::Int(0, _) = lit1.node
if n.leading_zeros() == n.count_zeros(); && n.leading_zeros() == n.count_zeros()
if n > u128::from(self.verbose_bit_mask_threshold); && n > u128::from(self.verbose_bit_mask_threshold)
then { {
span_lint_and_then(cx, span_lint_and_then(
VERBOSE_BIT_MASK, cx,
e.span, VERBOSE_BIT_MASK,
"bit mask could be simplified with a call to `trailing_zeros`", e.span,
|diag| { "bit mask could be simplified with a call to `trailing_zeros`",
|diag| {
let sugg = Sugg::hir(cx, left1, "...").maybe_par(); let sugg = Sugg::hir(cx, left1, "...").maybe_par();
diag.span_suggestion( diag.span_suggestion(
e.span, e.span,
@ -154,8 +154,8 @@ impl<'tcx> LateLintPass<'tcx> for BitMask {
format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()), format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
}); },
} );
} }
} }
} }

View File

@ -137,7 +137,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
} }
for (n, expr) in self.terminals.iter().enumerate() { for (n, expr) in self.terminals.iter().enumerate() {
if eq_expr_value(self.cx, e, expr) { if eq_expr_value(self.cx, e, expr) {
#[allow(clippy::cast_possible_truncation)] #[expect(clippy::cast_possible_truncation)]
return Ok(Bool::Term(n as u8)); return Ok(Bool::Term(n as u8));
} }
@ -149,7 +149,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
if eq_expr_value(self.cx, e_lhs, expr_lhs); if eq_expr_value(self.cx, e_lhs, expr_lhs);
if eq_expr_value(self.cx, e_rhs, expr_rhs); if eq_expr_value(self.cx, e_rhs, expr_rhs);
then { then {
#[allow(clippy::cast_possible_truncation)] #[expect(clippy::cast_possible_truncation)]
return Ok(Bool::Not(Box::new(Bool::Term(n as u8)))); return Ok(Bool::Not(Box::new(Bool::Term(n as u8))));
} }
} }
@ -157,7 +157,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
let n = self.terminals.len(); let n = self.terminals.len();
self.terminals.push(e); self.terminals.push(e);
if n < 32 { if n < 32 {
#[allow(clippy::cast_possible_truncation)] #[expect(clippy::cast_possible_truncation)]
Ok(Bool::Term(n as u8)) Ok(Bool::Term(n as u8))
} else { } else {
Err("too many literals".to_owned()) Err("too many literals".to_owned())

View File

@ -57,7 +57,7 @@ impl BorrowAsPtr {
impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr { impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::BORROW_AS_PTR) { if !meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) {
return; return;
} }

View File

@ -16,10 +16,10 @@ pub(super) fn check(
cast_expr: &Expr<'_>, cast_expr: &Expr<'_>,
cast_from: Ty<'_>, cast_from: Ty<'_>,
cast_to: Ty<'_>, cast_to: Ty<'_>,
msrv: &Option<RustcVersion>, msrv: Option<RustcVersion>,
) { ) {
if_chain! { if_chain! {
if meets_msrv(msrv.as_ref(), &msrvs::UNSIGNED_ABS); if meets_msrv(msrv, msrvs::UNSIGNED_ABS);
if cast_from.is_integral(); if cast_from.is_integral();
if cast_to.is_integral(); if cast_to.is_integral();
if cast_from.is_signed(); if cast_from.is_signed();

View File

@ -16,7 +16,7 @@ pub(super) fn check(
cast_op: &Expr<'_>, cast_op: &Expr<'_>,
cast_from: Ty<'_>, cast_from: Ty<'_>,
cast_to: Ty<'_>, cast_to: Ty<'_>,
msrv: &Option<RustcVersion>, msrv: Option<RustcVersion>,
) { ) {
if !should_lint(cx, expr, cast_from, cast_to, msrv) { if !should_lint(cx, expr, cast_from, cast_to, msrv) {
return; return;
@ -68,7 +68,7 @@ fn should_lint(
expr: &Expr<'_>, expr: &Expr<'_>,
cast_from: Ty<'_>, cast_from: Ty<'_>,
cast_to: Ty<'_>, cast_to: Ty<'_>,
msrv: &Option<RustcVersion>, msrv: Option<RustcVersion>,
) -> bool { ) -> bool {
// Do not suggest using From in consts/statics until it is valid to do so (see #2267). // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
if in_constant(cx, expr.hir_id) { if in_constant(cx, expr.hir_id) {
@ -93,9 +93,9 @@ fn should_lint(
} else { } else {
64 64
}; };
from_nbits < to_nbits !is_isize_or_usize(cast_from) && from_nbits < to_nbits
}, },
(false, true) if matches!(cast_from.kind(), ty::Bool) && meets_msrv(msrv.as_ref(), &msrvs::FROM_BOOL) => true, (false, true) if matches!(cast_from.kind(), ty::Bool) && meets_msrv(msrv, msrvs::FROM_BOOL) => true,
(_, _) => { (_, _) => {
matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)) matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64))
}, },

View File

@ -8,9 +8,9 @@ use rustc_semver::RustcVersion;
use super::CAST_SLICE_DIFFERENT_SIZES; use super::CAST_SLICE_DIFFERENT_SIZES;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Option<RustcVersion>) { pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Option<RustcVersion>) {
// suggestion is invalid if `ptr::slice_from_raw_parts` does not exist // suggestion is invalid if `ptr::slice_from_raw_parts` does not exist
if !meets_msrv(msrv.as_ref(), &msrvs::PTR_SLICE_RAW_PARTS) { if !meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS) {
return; return;
} }
@ -121,7 +121,7 @@ fn expr_cast_chain_tys<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Optio
let to_slice_ty = get_raw_slice_ty_mut(cast_to)?; let to_slice_ty = get_raw_slice_ty_mut(cast_to)?;
// If the expression that makes up the source of this cast is itself a cast, recursively // If the expression that makes up the source of this cast is itself a cast, recursively
// call `expr_cast_chain_tys` and update the end type with the final tartet type. // call `expr_cast_chain_tys` and update the end type with the final target type.
// Otherwise, this cast is not immediately nested, just construct the info for this cast // Otherwise, this cast is not immediately nested, just construct the info for this cast
if let Some(prev_info) = expr_cast_chain_tys(cx, cast_expr) { if let Some(prev_info) = expr_cast_chain_tys(cx, cast_expr) {
Some(CastChainInfo { Some(CastChainInfo {

View File

@ -306,7 +306,7 @@ declare_clippy_lint! {
/// Checks for casts of `&T` to `&mut T` anywhere in the code. /// Checks for casts of `&T` to `&mut T` anywhere in the code.
/// ///
/// ### Why is this bad? /// ### Why is this bad?
/// Its basically guaranteed to be undefined behaviour. /// Its basically guaranteed to be undefined behavior.
/// `UnsafeCell` is the only way to obtain aliasable data that is considered /// `UnsafeCell` is the only way to obtain aliasable data that is considered
/// mutable. /// mutable.
/// ///
@ -413,6 +413,7 @@ declare_clippy_lint! {
} }
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does
/// Checks for `as` casts between raw pointers to slices with differently sized elements. /// Checks for `as` casts between raw pointers to slices with differently sized elements.
/// ///
/// ### Why is this bad? /// ### Why is this bad?
@ -531,7 +532,7 @@ impl_lint_pass!(Casts => [
impl<'tcx> LateLintPass<'tcx> for Casts { impl<'tcx> LateLintPass<'tcx> for Casts {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !in_external_macro(cx.sess(), expr.span) { if !in_external_macro(cx.sess(), expr.span) {
ptr_as_ptr::check(cx, expr, &self.msrv); ptr_as_ptr::check(cx, expr, self.msrv);
} }
if expr.span.from_expansion() { if expr.span.from_expansion() {
@ -561,9 +562,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_possible_wrap::check(cx, expr, cast_from, cast_to);
cast_precision_loss::check(cx, expr, cast_from, cast_to); cast_precision_loss::check(cx, expr, cast_from, cast_to);
cast_sign_loss::check(cx, expr, cast_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_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
} }
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
cast_enum_constructor::check(cx, expr, cast_expr, cast_from); cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
} }
} }
@ -571,8 +572,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
cast_ref_to_mut::check(cx, expr); cast_ref_to_mut::check(cx, expr);
cast_ptr_alignment::check(cx, expr); cast_ptr_alignment::check(cx, expr);
char_lit_as_u8::check(cx, expr); char_lit_as_u8::check(cx, expr);
ptr_as_ptr::check(cx, expr, &self.msrv); ptr_as_ptr::check(cx, expr, self.msrv);
cast_slice_different_sizes::check(cx, expr, &self.msrv); cast_slice_different_sizes::check(cx, expr, self.msrv);
} }
extract_msrv_attr!(LateContext); extract_msrv_attr!(LateContext);

View File

@ -12,8 +12,8 @@ use rustc_semver::RustcVersion;
use super::PTR_AS_PTR; use super::PTR_AS_PTR;
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVersion>) { pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option<RustcVersion>) {
if !meets_msrv(msrv.as_ref(), &msrvs::POINTER_CAST) { if !meets_msrv(msrv, msrvs::POINTER_CAST) {
return; return;
} }

View File

@ -30,7 +30,6 @@ declare_clippy_lint! {
/// Could be written: /// Could be written:
/// ///
/// ```rust /// ```rust
/// # use std::convert::TryFrom;
/// # let foo = 1; /// # let foo = 1;
/// # let _ = /// # let _ =
/// i32::try_from(foo).is_ok() /// i32::try_from(foo).is_ok()
@ -57,7 +56,7 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);
impl<'tcx> LateLintPass<'tcx> for CheckedConversions { impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::TRY_FROM) { if !meets_msrv(self.msrv, msrvs::TRY_FROM) {
return; return;
} }
@ -123,7 +122,7 @@ struct Conversion<'a> {
} }
/// The kind of conversion that is checked /// The kind of conversion that is checked
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum ConversionType { enum ConversionType {
SignedToUnsigned, SignedToUnsigned,
SignedToSigned, SignedToSigned,

View File

@ -48,7 +48,7 @@ impl CognitiveComplexity {
impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]); impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]);
impl CognitiveComplexity { impl CognitiveComplexity {
#[allow(clippy::cast_possible_truncation)] #[expect(clippy::cast_possible_truncation)]
fn check<'tcx>( fn check<'tcx>(
&mut self, &mut self,
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
@ -70,7 +70,7 @@ impl CognitiveComplexity {
let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::Result) { let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::Result) {
returns returns
} else { } else {
#[allow(clippy::integer_division)] #[expect(clippy::integer_division)]
(returns / 2) (returns / 2)
}; };

View File

@ -109,7 +109,10 @@ fn check_arm<'tcx>(
(Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b), (Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b),
}; };
// the binding must not be used in the if guard // the binding must not be used in the if guard
if outer_guard.map_or(true, |(Guard::If(e) | Guard::IfLet(Let { init: e, .. }))| !is_local_used(cx, *e, binding_id)); if outer_guard.map_or(
true,
|(Guard::If(e) | Guard::IfLet(Let { init: e, .. }))| !is_local_used(cx, *e, binding_id)
);
// ...or anywhere in the inner expression // ...or anywhere in the inner expression
if match inner { if match inner {
IfLetOrMatch::IfLet(_, _, body, els) => { IfLetOrMatch::IfLet(_, _, body, els) => {

View File

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_in_test_function;
use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{is_in_cfg_test, is_in_test_function};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
@ -37,7 +37,7 @@ impl LateLintPass<'_> for DbgMacro {
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return }; let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
if cx.tcx.is_diagnostic_item(sym::dbg_macro, macro_call.def_id) { if cx.tcx.is_diagnostic_item(sym::dbg_macro, macro_call.def_id) {
// we make an exception for test code // we make an exception for test code
if is_in_test_function(cx.tcx, expr.hir_id) { if is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id) {
return; return;
} }
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;

View File

@ -110,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
} }
} }
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
// start from the `let mut _ = _::default();` and look at all the following // start from the `let mut _ = _::default();` and look at all the following
// statements, see if they re-assign the fields of the binding // statements, see if they re-assign the fields of the binding

View File

@ -116,7 +116,6 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
} }
impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
#[allow(clippy::too_many_lines)]
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
match &expr.kind { match &expr.kind {
ExprKind::Call(func, args) => { ExprKind::Call(func, args) => {

View File

@ -25,7 +25,7 @@ declare_clippy_lint! {
/// ///
/// fn main() { /// fn main() {
/// let _x: u32 = unsafe { /// let _x: u32 = unsafe {
/// Foo { a: 0_i32 }.b // Undefined behaviour: `b` is allowed to be padding /// Foo { a: 0_i32 }.b // Undefined behavior: `b` is allowed to be padding
/// }; /// };
/// } /// }
/// ``` /// ```
@ -39,7 +39,7 @@ declare_clippy_lint! {
/// ///
/// fn main() { /// fn main() {
/// let _x: u32 = unsafe { /// let _x: u32 = unsafe {
/// Foo { a: 0_i32 }.b // Now defined behaviour, this is just an i32 -> u32 transmute /// Foo { a: 0_i32 }.b // Now defined behavior, this is just an i32 -> u32 transmute
/// }; /// };
/// } /// }
/// ``` /// ```

View File

@ -194,7 +194,6 @@ declare_deprecated_lint! {
/// ### Deprecation reason /// ### Deprecation reason
/// The `avoid_breaking_exported_api` config option was added, which /// The `avoid_breaking_exported_api` config option was added, which
/// enables the `enum_variant_names` lint for public items. /// enables the `enum_variant_names` lint for public items.
/// ```
#[clippy::version = "1.54.0"] #[clippy::version = "1.54.0"]
pub PUB_ENUM_VARIANT_NAMES, pub PUB_ENUM_VARIANT_NAMES,
"set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items" "set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items"

View File

@ -168,7 +168,7 @@ struct RefPat {
} }
impl<'tcx> LateLintPass<'tcx> for Dereferencing { impl<'tcx> LateLintPass<'tcx> for Dereferencing {
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// Skip path expressions from deref calls. e.g. `Deref::deref(e)` // Skip path expressions from deref calls. e.g. `Deref::deref(e)`
if Some(expr.hir_id) == self.skip_expr.take() { if Some(expr.hir_id) == self.skip_expr.take() {
@ -580,7 +580,7 @@ fn find_adjustments<'tcx>(
} }
} }
#[allow(clippy::needless_pass_by_value)] #[expect(clippy::needless_pass_by_value)]
fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData) { fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData) {
match state { match state {
State::DerefMethod { State::DerefMethod {

View File

@ -1,8 +1,9 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::paths; use clippy_utils::paths;
use clippy_utils::ty::{implements_trait, is_copy}; use clippy_utils::ty::{implements_trait, is_copy};
use clippy_utils::{is_lint_allowed, match_def_path}; use clippy_utils::{is_lint_allowed, match_def_path};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
use rustc_hir::{ use rustc_hir::{
BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, TraitRef, UnsafeSource, Unsafety, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, TraitRef, UnsafeSource, Unsafety,
@ -101,8 +102,8 @@ declare_clippy_lint! {
/// types. /// types.
/// ///
/// ### Why is this bad? /// ### Why is this bad?
/// To avoid surprising behaviour, these traits should /// To avoid surprising behavior, these traits should
/// agree and the behaviour of `Copy` cannot be overridden. In almost all /// agree and the behavior of `Copy` cannot be overridden. In almost all
/// situations a `Copy` type should have a `Clone` implementation that does /// situations a `Copy` type should have a `Clone` implementation that does
/// nothing more than copy the object, which is what `#[derive(Copy, Clone)]` /// nothing more than copy the object, which is what `#[derive(Copy, Clone)]`
/// gets you. /// gets you.
@ -156,11 +157,44 @@ declare_clippy_lint! {
"deriving `serde::Deserialize` on a type that has methods using `unsafe`" "deriving `serde::Deserialize` on a type that has methods using `unsafe`"
} }
declare_clippy_lint! {
/// ### 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
/// ```rust
/// #[derive(PartialEq)]
/// struct Foo {
/// i_am_eq: i32,
/// i_am_eq_too: Vec<String>,
/// }
/// ```
/// Use instead:
/// ```rust
/// #[derive(PartialEq, Eq)]
/// struct Foo {
/// i_am_eq: i32,
/// i_am_eq_too: Vec<String>,
/// }
/// ```
#[clippy::version = "1.62.0"]
pub DERIVE_PARTIAL_EQ_WITHOUT_EQ,
style,
"deriving `PartialEq` on a type that can implement `Eq`, without implementing `Eq`"
}
declare_lint_pass!(Derive => [ declare_lint_pass!(Derive => [
EXPL_IMPL_CLONE_ON_COPY, EXPL_IMPL_CLONE_ON_COPY,
DERIVE_HASH_XOR_EQ, DERIVE_HASH_XOR_EQ,
DERIVE_ORD_XOR_PARTIAL_ORD, DERIVE_ORD_XOR_PARTIAL_ORD,
UNSAFE_DERIVE_DESERIALIZE UNSAFE_DERIVE_DESERIALIZE,
DERIVE_PARTIAL_EQ_WITHOUT_EQ
]); ]);
impl<'tcx> LateLintPass<'tcx> for Derive { impl<'tcx> LateLintPass<'tcx> for Derive {
@ -171,14 +205,14 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
}) = item.kind }) = item.kind
{ {
let ty = cx.tcx.type_of(item.def_id); let ty = cx.tcx.type_of(item.def_id);
let is_automatically_derived = let is_automatically_derived = cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
check_hash_peq(cx, item.span, trait_ref, ty, is_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); check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
if is_automatically_derived { if is_automatically_derived {
check_unsafe_derive_deserialize(cx, item, trait_ref, ty); check_unsafe_derive_deserialize(cx, item, trait_ref, ty);
check_partial_eq_without_eq(cx, item.span, trait_ref, ty);
} else { } else {
check_copy_clone(cx, item, trait_ref, ty); check_copy_clone(cx, item, trait_ref, ty);
} }
@ -419,3 +453,36 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
self.cx.tcx.hir() self.cx.tcx.hir()
} }
} }
/// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint.
fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &TraitRef<'_>, ty: Ty<'tcx>) {
if_chain! {
if let ty::Adt(adt, substs) = ty.kind();
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);
if !implements_trait(cx, ty, eq_trait_def_id, substs);
then {
// If all of our fields implement `Eq`, we can implement `Eq` too
for variant in adt.variants() {
for field in &variant.fields {
let ty = field.ty(cx.tcx, substs);
if !implements_trait(cx, ty, eq_trait_def_id, substs) {
return;
}
}
}
span_lint_and_sugg(
cx,
DERIVE_PARTIAL_EQ_WITHOUT_EQ,
span.ctxt().outer_expn_data().call_site,
"you are deriving `PartialEq` and can implement `Eq`",
"consider deriving `Eq` as well",
"PartialEq, Eq".to_string(),
Applicability::MachineApplicable,
)
}
}
}

View File

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::fn_def_id; use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
use rustc_hir::{def::Res, def_id::DefIdMap, Expr}; use rustc_hir::{def::Res, def_id::DefIdMap, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
@ -84,7 +84,15 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
} }
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let def_id = match fn_def_id(cx, expr) { let uncalled_path = if let Some(parent) = get_parent_expr(cx, expr)
&& let ExprKind::Call(receiver, _) = parent.kind
&& receiver.hir_id == expr.hir_id
{
None
} else {
path_def_id(cx, expr)
};
let def_id = match uncalled_path.or_else(|| fn_def_id(cx, expr)) {
Some(def_id) => def_id, Some(def_id) => def_id,
None => return, None => return,
}; };

View File

@ -198,7 +198,7 @@ declare_clippy_lint! {
"presence of `fn main() {` in code examples" "presence of `fn main() {` in code examples"
} }
#[allow(clippy::module_name_repetitions)] #[expect(clippy::module_name_repetitions)]
#[derive(Clone)] #[derive(Clone)]
pub struct DocMarkdown { pub struct DocMarkdown {
valid_idents: FxHashSet<String>, valid_idents: FxHashSet<String>,
@ -373,7 +373,7 @@ fn lint_for_missing_headers<'tcx>(
/// `rustc_ast::parse::lexer::comments::strip_doc_comment_decoration` because we /// `rustc_ast::parse::lexer::comments::strip_doc_comment_decoration` because we
/// need to keep track of /// need to keep track of
/// the spans but this function is inspired from the later. /// the spans but this function is inspired from the later.
#[allow(clippy::cast_possible_truncation)] #[expect(clippy::cast_possible_truncation)]
#[must_use] #[must_use]
pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: Span) -> (String, Vec<(usize, Span)>) { pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: Span) -> (String, Vec<(usize, Span)>) {
// one-line comments lose their prefix // one-line comments lose their prefix
@ -428,7 +428,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
/// We don't want the parser to choke on intra doc links. Since we don't /// We don't want the parser to choke on intra doc links. Since we don't
/// actually care about rendering them, just pretend that all broken links are /// actually care about rendering them, just pretend that all broken links are
/// point to a fake address. /// point to a fake address.
#[allow(clippy::unnecessary_wraps)] // we're following a type signature #[expect(clippy::unnecessary_wraps)] // we're following a type signature
fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowStr<'a>)> { fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowStr<'a>)> {
Some(("fake".into(), "fake".into())) Some(("fake".into(), "fake".into()))
} }

View File

@ -40,7 +40,7 @@ declare_clippy_lint! {
declare_lint_pass!(DoubleComparisons => [DOUBLE_COMPARISONS]); declare_lint_pass!(DoubleComparisons => [DOUBLE_COMPARISONS]);
impl<'tcx> DoubleComparisons { impl<'tcx> DoubleComparisons {
#[allow(clippy::similar_names)] #[expect(clippy::similar_names)]
fn check_binop(cx: &LateContext<'tcx>, op: BinOpKind, lhs: &'tcx Expr<'_>, rhs: &'tcx Expr<'_>, span: Span) { fn check_binop(cx: &LateContext<'tcx>, op: BinOpKind, lhs: &'tcx Expr<'_>, rhs: &'tcx Expr<'_>, span: Span) {
let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (&lhs.kind, &rhs.kind) { let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (&lhs.kind, &rhs.kind) {
(ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => { (ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => {

View File

@ -0,0 +1,102 @@
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{Crate, Inline, Item, ItemKind, ModKind};
use rustc_errors::MultiSpan;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{FileName, Span};
use std::collections::BTreeMap;
use std::path::PathBuf;
declare_clippy_lint! {
/// ### 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
/// ```rust,ignore
/// // lib.rs
/// mod a;
/// mod b;
/// ```
/// ```rust,ignore
/// // a.rs
/// #[path = "./b.rs"]
/// mod b;
/// ```
///
/// Use instead:
///
/// ```rust,ignore
/// // lib.rs
/// mod a;
/// mod b;
/// ```
/// ```rust,ignore
/// // a.rs
/// use crate::b;
/// ```
#[clippy::version = "1.62.0"]
pub DUPLICATE_MOD,
suspicious,
"file loaded as module multiple times"
}
#[derive(PartialOrd, Ord, PartialEq, Eq)]
struct Modules {
local_path: PathBuf,
spans: Vec<Span>,
}
#[derive(Default)]
pub struct DuplicateMod {
/// map from the canonicalized path to `Modules`, `BTreeMap` to make the
/// order deterministic for tests
modules: BTreeMap<PathBuf, Modules>,
}
impl_lint_pass!(DuplicateMod => [DUPLICATE_MOD]);
impl EarlyLintPass for DuplicateMod {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, mod_spans)) = &item.kind
&& let FileName::Real(real) = cx.sess().source_map().span_to_filename(mod_spans.inner_span)
&& let Some(local_path) = real.into_local_path()
&& let Ok(absolute_path) = local_path.canonicalize()
{
let modules = self.modules.entry(absolute_path).or_insert(Modules {
local_path,
spans: Vec::new(),
});
modules.spans.push(item.span_with_attributes());
}
}
fn check_crate_post(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
for Modules { local_path, spans } in self.modules.values() {
if spans.len() < 2 {
continue;
}
let mut multi_span = MultiSpan::from_spans(spans.clone());
let (&first, duplicates) = spans.split_first().unwrap();
multi_span.push_span_label(first, "first loaded here");
for &duplicate in duplicates {
multi_span.push_span_label(duplicate, "loaded again here");
}
span_lint_and_help(
cx,
DUPLICATE_MOD,
multi_span,
&format!("file is loaded as a module multiple times: `{}`", local_path.display()),
None,
"replace all but one `mod` item with `use` items",
);
}
}
}

View File

@ -63,7 +63,7 @@ declare_clippy_lint! {
declare_lint_pass!(HashMapPass => [MAP_ENTRY]); declare_lint_pass!(HashMapPass => [MAP_ENTRY]);
impl<'tcx> LateLintPass<'tcx> for HashMapPass { impl<'tcx> LateLintPass<'tcx> for HashMapPass {
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let (cond_expr, then_expr, else_expr) = match higher::If::hir(expr) { let (cond_expr, then_expr, else_expr) = match higher::If::hir(expr) {
Some(higher::If { cond, then, r#else }) => (cond, then, r#else), Some(higher::If { cond, then, r#else }) => (cond, then, r#else),
@ -319,7 +319,7 @@ struct Insertion<'tcx> {
/// `or_insert_with`. /// `or_insert_with`.
/// * Determine if there's any sub-expression that can't be placed in a closure. /// * Determine if there's any sub-expression that can't be placed in a closure.
/// * Determine if there's only a single insert statement. `or_insert` can be used in this case. /// * Determine if there's only a single insert statement. `or_insert` can be used in this case.
#[allow(clippy::struct_excessive_bools)] #[expect(clippy::struct_excessive_bools)]
struct InsertSearcher<'cx, 'tcx> { struct InsertSearcher<'cx, 'tcx> {
cx: &'cx LateContext<'tcx>, cx: &'cx LateContext<'tcx>,
/// The map expression used in the contains call. /// The map expression used in the contains call.

View File

@ -8,7 +8,6 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, IntTy, UintTy}; use rustc_middle::ty::{self, IntTy, UintTy};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use std::convert::TryFrom;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@ -37,7 +36,7 @@ declare_clippy_lint! {
declare_lint_pass!(UnportableVariant => [ENUM_CLIKE_UNPORTABLE_VARIANT]); declare_lint_pass!(UnportableVariant => [ENUM_CLIKE_UNPORTABLE_VARIANT]);
impl<'tcx> LateLintPass<'tcx> for UnportableVariant { impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_sign_loss)] #[expect(clippy::cast_possible_wrap)]
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if cx.tcx.data_layout.pointer_size.bits() != 64 { if cx.tcx.data_layout.pointer_size.bits() != 64 {
return; return;

View File

@ -240,7 +240,7 @@ impl LateLintPass<'_> for EnumVariantNames {
assert!(last.is_some()); assert!(last.is_some());
} }
#[allow(clippy::similar_names)] #[expect(clippy::similar_names)]
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
let item_name = item.ident.name.as_str(); let item_name = item.ident.name.as_str();
let item_camel = to_camel_case(item_name); let item_camel = to_camel_case(item_name);

View File

@ -72,7 +72,7 @@ declare_clippy_lint! {
declare_lint_pass!(EqOp => [EQ_OP, OP_REF]); declare_lint_pass!(EqOp => [EQ_OP, OP_REF]);
impl<'tcx> LateLintPass<'tcx> for EqOp { impl<'tcx> LateLintPass<'tcx> for EqOp {
#[allow(clippy::similar_names, clippy::too_many_lines)] #[expect(clippy::similar_names, clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if_chain! { if_chain! {
if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| { if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| {
@ -138,7 +138,6 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
}, },
}; };
if let Some(trait_id) = trait_id { if let Some(trait_id) = trait_id {
#[allow(clippy::match_same_arms)]
match (&left.kind, &right.kind) { match (&left.kind, &right.kind) {
// do not suggest to dereference literals // do not suggest to dereference literals
(&ExprKind::Lit(..), _) | (_, &ExprKind::Lit(..)) => {}, (&ExprKind::Lit(..), _) | (_, &ExprKind::Lit(..)) => {},

View File

@ -4,8 +4,6 @@ use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
use std::convert::TryInto;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
/// Checks for excessive /// Checks for excessive

View File

@ -32,7 +32,6 @@ declare_clippy_lint! {
/// // Good /// // Good
/// struct Foo(i32); /// struct Foo(i32);
/// ///
/// use std::convert::TryFrom;
/// impl TryFrom<String> for Foo { /// impl TryFrom<String> for Foo {
/// type Error = (); /// type Error = ();
/// fn try_from(s: String) -> Result<Self, Self::Error> { /// fn try_from(s: String) -> Result<Self, Self::Error> {

View File

@ -215,7 +215,7 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
// converted to an integer without loss of precision. For now we only check // converted to an integer without loss of precision. For now we only check
// ranges [-16777215, 16777216) for type f32 as whole number floats outside // ranges [-16777215, 16777216) for type f32 as whole number floats outside
// this range are lossy and ambiguous. // this range are lossy and ambiguous.
#[allow(clippy::cast_possible_truncation)] #[expect(clippy::cast_possible_truncation)]
fn get_integer_from_float_constant(value: &Constant) -> Option<i32> { fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
match value { match value {
F32(num) if num.fract() == 0.0 => { F32(num) if num.fract() == 0.0 => {

View File

@ -55,7 +55,7 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
impl<'tcx> LateLintPass<'tcx> for FromOverInto { impl<'tcx> LateLintPass<'tcx> for FromOverInto {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::RE_REBALANCING_COHERENCE) { if !meets_msrv(self.msrv, msrvs::RE_REBALANCING_COHERENCE) {
return; return;
} }

View File

@ -57,7 +57,7 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::BOOL_THEN) { if !meets_msrv(self.msrv, msrvs::BOOL_THEN) {
return; return;
} }

View File

@ -62,7 +62,7 @@ declare_clippy_lint! {
declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]); declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]);
impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
#[allow(clippy::cast_possible_truncation, clippy::too_many_lines)] #[expect(clippy::cast_possible_truncation, clippy::too_many_lines)]
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
use rustc_span::BytePos; use rustc_span::BytePos;

View File

@ -164,7 +164,7 @@ fn lint_implicit_returns(
}) })
.visit_block(block); .visit_block(block);
if add_return { if add_return {
#[allow(clippy::option_if_let_else)] #[expect(clippy::option_if_let_else)]
if let Some(span) = call_site_span { if let Some(span) = call_site_span {
lint_return(cx, span); lint_return(cx, span);
LintLocation::Parent LintLocation::Parent
@ -196,7 +196,7 @@ fn lint_implicit_returns(
_ => _ =>
{ {
#[allow(clippy::option_if_let_else)] #[expect(clippy::option_if_let_else)]
if let Some(span) = call_site_span { if let Some(span) = call_site_span {
lint_return(cx, span); lint_return(cx, span);
LintLocation::Parent LintLocation::Parent

View File

@ -14,7 +14,6 @@ use rustc_middle::ty;
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{symbol::Ident, Span}; use rustc_span::{symbol::Ident, Span};
use std::convert::TryInto;
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@ -75,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some(); if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some();
if let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr); if let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr);
if !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id); if !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id);
if meets_msrv(self.msrv.as_ref(), &msrvs::SLICE_PATTERNS); if meets_msrv(self.msrv, msrvs::SLICE_PATTERNS);
let found_slices = find_slice_values(cx, let_pat); let found_slices = find_slice_values(cx, let_pat);
if !found_slices.is_empty(); if !found_slices.is_empty();

View File

@ -52,7 +52,7 @@ enum Side {
} }
impl IntPlusOne { impl IntPlusOne {
#[allow(clippy::cast_sign_loss)] #[expect(clippy::cast_sign_loss)]
fn check_lit(lit: &Lit, target_value: i128) -> bool { fn check_lit(lit: &Lit, target_value: i128) -> bool {
if let LitKind::Int(value, ..) = lit.kind { if let LitKind::Int(value, ..) = lit.kind {
return value == (target_value as u128); return value == (target_value as u128);

View File

@ -46,6 +46,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(derivable_impls::DERIVABLE_IMPLS), LintId::of(derivable_impls::DERIVABLE_IMPLS),
LintId::of(derive::DERIVE_HASH_XOR_EQ), LintId::of(derive::DERIVE_HASH_XOR_EQ),
LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
LintId::of(disallowed_methods::DISALLOWED_METHODS), LintId::of(disallowed_methods::DISALLOWED_METHODS),
LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(disallowed_types::DISALLOWED_TYPES),
LintId::of(doc::MISSING_SAFETY_DOC), LintId::of(doc::MISSING_SAFETY_DOC),
@ -59,6 +60,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(drop_forget_ref::FORGET_NON_DROP), LintId::of(drop_forget_ref::FORGET_NON_DROP),
LintId::of(drop_forget_ref::FORGET_REF), LintId::of(drop_forget_ref::FORGET_REF),
LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS), LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS),
LintId::of(duplicate_mod::DUPLICATE_MOD),
LintId::of(duration_subsec::DURATION_SUBSEC), LintId::of(duration_subsec::DURATION_SUBSEC),
LintId::of(entry::MAP_ENTRY), LintId::of(entry::MAP_ENTRY),
LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT), LintId::of(enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT),
@ -69,8 +71,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(erasing_op::ERASING_OP), LintId::of(erasing_op::ERASING_OP),
LintId::of(escape::BOXED_LOCAL), LintId::of(escape::BOXED_LOCAL),
LintId::of(eta_reduction::REDUNDANT_CLOSURE), LintId::of(eta_reduction::REDUNDANT_CLOSURE),
LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION),
LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
LintId::of(explicit_write::EXPLICIT_WRITE), LintId::of(explicit_write::EXPLICIT_WRITE),
LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
LintId::of(float_literal::EXCESSIVE_PRECISION), LintId::of(float_literal::EXCESSIVE_PRECISION),
@ -228,6 +228,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(misc_early::REDUNDANT_PATTERN), LintId::of(misc_early::REDUNDANT_PATTERN),
LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
LintId::of(misc_early::ZERO_PREFIXED_LITERAL), LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
LintId::of(mut_key::MUTABLE_KEY_TYPE), LintId::of(mut_key::MUTABLE_KEY_TYPE),
LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
@ -263,6 +264,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(ranges::MANUAL_RANGE_CONTAINS), LintId::of(ranges::MANUAL_RANGE_CONTAINS),
LintId::of(ranges::RANGE_ZIP_WITH_LEN), LintId::of(ranges::RANGE_ZIP_WITH_LEN),
LintId::of(ranges::REVERSED_EMPTY_RANGES), LintId::of(ranges::REVERSED_EMPTY_RANGES),
LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
LintId::of(redundant_clone::REDUNDANT_CLONE), LintId::of(redundant_clone::REDUNDANT_CLONE),
LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES), LintId::of(redundant_field_names::REDUNDANT_FIELD_NAMES),
@ -276,6 +278,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(self_assignment::SELF_ASSIGNMENT), LintId::of(self_assignment::SELF_ASSIGNMENT),
LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
LintId::of(serde_api::SERDE_API_MISUSE), LintId::of(serde_api::SERDE_API_MISUSE),
LintId::of(significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE),
LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),

View File

@ -12,7 +12,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
LintId::of(double_comparison::DOUBLE_COMPARISONS), LintId::of(double_comparison::DOUBLE_COMPARISONS),
LintId::of(double_parens::DOUBLE_PARENS), LintId::of(double_parens::DOUBLE_PARENS),
LintId::of(duration_subsec::DURATION_SUBSEC), LintId::of(duration_subsec::DURATION_SUBSEC),
LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION),
LintId::of(explicit_write::EXPLICIT_WRITE), LintId::of(explicit_write::EXPLICIT_WRITE),
LintId::of(format::USELESS_FORMAT), LintId::of(format::USELESS_FORMAT),
LintId::of(functions::TOO_MANY_ARGUMENTS), LintId::of(functions::TOO_MANY_ARGUMENTS),
@ -59,6 +58,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
LintId::of(misc::SHORT_CIRCUIT_STATEMENT), LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
LintId::of(misc_early::ZERO_PREFIXED_LITERAL), LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
LintId::of(needless_bool::BOOL_COMPARISON), LintId::of(needless_bool::BOOL_COMPARISON),
LintId::of(needless_bool::NEEDLESS_BOOL), LintId::of(needless_bool::NEEDLESS_BOOL),

View File

@ -113,6 +113,7 @@ store.register_lints(&[
derivable_impls::DERIVABLE_IMPLS, derivable_impls::DERIVABLE_IMPLS,
derive::DERIVE_HASH_XOR_EQ, derive::DERIVE_HASH_XOR_EQ,
derive::DERIVE_ORD_XOR_PARTIAL_ORD, derive::DERIVE_ORD_XOR_PARTIAL_ORD,
derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ,
derive::EXPL_IMPL_CLONE_ON_COPY, derive::EXPL_IMPL_CLONE_ON_COPY,
derive::UNSAFE_DERIVE_DESERIALIZE, derive::UNSAFE_DERIVE_DESERIALIZE,
disallowed_methods::DISALLOWED_METHODS, disallowed_methods::DISALLOWED_METHODS,
@ -132,6 +133,7 @@ store.register_lints(&[
drop_forget_ref::FORGET_NON_DROP, drop_forget_ref::FORGET_NON_DROP,
drop_forget_ref::FORGET_REF, drop_forget_ref::FORGET_REF,
drop_forget_ref::UNDROPPED_MANUALLY_DROPS, drop_forget_ref::UNDROPPED_MANUALLY_DROPS,
duplicate_mod::DUPLICATE_MOD,
duration_subsec::DURATION_SUBSEC, duration_subsec::DURATION_SUBSEC,
else_if_without_else::ELSE_IF_WITHOUT_ELSE, else_if_without_else::ELSE_IF_WITHOUT_ELSE,
empty_drop::EMPTY_DROP, empty_drop::EMPTY_DROP,
@ -149,8 +151,6 @@ store.register_lints(&[
escape::BOXED_LOCAL, escape::BOXED_LOCAL,
eta_reduction::REDUNDANT_CLOSURE, eta_reduction::REDUNDANT_CLOSURE,
eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS, eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
eval_order_dependence::DIVERGING_SUB_EXPRESSION,
eval_order_dependence::EVAL_ORDER_DEPENDENCE,
excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS, excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
excessive_bools::STRUCT_EXCESSIVE_BOOLS, excessive_bools::STRUCT_EXCESSIVE_BOOLS,
exhaustive_items::EXHAUSTIVE_ENUMS, exhaustive_items::EXHAUSTIVE_ENUMS,
@ -381,6 +381,8 @@ store.register_lints(&[
missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS, missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES, missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES,
missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS, missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
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::MOD_MODULE_FILES,
module_style::SELF_NAMED_MODULE_FILES, module_style::SELF_NAMED_MODULE_FILES,
modulo_arithmetic::MODULO_ARITHMETIC, modulo_arithmetic::MODULO_ARITHMETIC,
@ -446,6 +448,7 @@ store.register_lints(&[
ranges::RANGE_PLUS_ONE, ranges::RANGE_PLUS_ONE,
ranges::RANGE_ZIP_WITH_LEN, ranges::RANGE_ZIP_WITH_LEN,
ranges::REVERSED_EMPTY_RANGES, ranges::REVERSED_EMPTY_RANGES,
rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT,
redundant_clone::REDUNDANT_CLONE, redundant_clone::REDUNDANT_CLONE,
redundant_closure_call::REDUNDANT_CLOSURE_CALL, redundant_closure_call::REDUNDANT_CLOSURE_CALL,
redundant_else::REDUNDANT_ELSE, redundant_else::REDUNDANT_ELSE,
@ -470,6 +473,7 @@ store.register_lints(&[
shadow::SHADOW_REUSE, shadow::SHADOW_REUSE,
shadow::SHADOW_SAME, shadow::SHADOW_SAME,
shadow::SHADOW_UNRELATED, shadow::SHADOW_UNRELATED,
significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE,
single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES, single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES,
single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,

View File

@ -46,6 +46,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES), LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS), LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION),
LintId::of(module_style::MOD_MODULE_FILES), LintId::of(module_style::MOD_MODULE_FILES),
LintId::of(module_style::SELF_NAMED_MODULE_FILES), LintId::of(module_style::SELF_NAMED_MODULE_FILES),
LintId::of(modulo_arithmetic::MODULO_ARITHMETIC), LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),

View File

@ -16,6 +16,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(comparison_chain::COMPARISON_CHAIN), LintId::of(comparison_chain::COMPARISON_CHAIN),
LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT), LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
LintId::of(dereference::NEEDLESS_BORROW), LintId::of(dereference::NEEDLESS_BORROW),
LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
LintId::of(disallowed_methods::DISALLOWED_METHODS), LintId::of(disallowed_methods::DISALLOWED_METHODS),
LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(disallowed_types::DISALLOWED_TYPES),
LintId::of(doc::MISSING_SAFETY_DOC), LintId::of(doc::MISSING_SAFETY_DOC),

View File

@ -14,7 +14,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF), LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
LintId::of(drop_forget_ref::DROP_NON_DROP), LintId::of(drop_forget_ref::DROP_NON_DROP),
LintId::of(drop_forget_ref::FORGET_NON_DROP), LintId::of(drop_forget_ref::FORGET_NON_DROP),
LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), LintId::of(duplicate_mod::DUPLICATE_MOD),
LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
LintId::of(format_impl::PRINT_IN_FORMAT_IMPL), LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
@ -26,6 +26,8 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
LintId::of(methods::SUSPICIOUS_MAP), LintId::of(methods::SUSPICIOUS_MAP),
LintId::of(mut_key::MUTABLE_KEY_TYPE), LintId::of(mut_key::MUTABLE_KEY_TYPE),
LintId::of(octal_escapes::OCTAL_ESCAPES), LintId::of(octal_escapes::OCTAL_ESCAPES),
LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
LintId::of(significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE),
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
]) ])

View File

@ -8,6 +8,7 @@
#![feature(iter_intersperse)] #![feature(iter_intersperse)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(let_else)] #![feature(let_else)]
#![feature(lint_reasons)]
#![feature(once_cell)] #![feature(once_cell)]
#![feature(rustc_private)] #![feature(rustc_private)]
#![feature(stmt_expr_attributes)] #![feature(stmt_expr_attributes)]
@ -210,6 +211,7 @@ mod doc;
mod double_comparison; mod double_comparison;
mod double_parens; mod double_parens;
mod drop_forget_ref; mod drop_forget_ref;
mod duplicate_mod;
mod duration_subsec; mod duration_subsec;
mod else_if_without_else; mod else_if_without_else;
mod empty_drop; mod empty_drop;
@ -223,7 +225,6 @@ mod equatable_if_let;
mod erasing_op; mod erasing_op;
mod escape; mod escape;
mod eta_reduction; mod eta_reduction;
mod eval_order_dependence;
mod excessive_bools; mod excessive_bools;
mod exhaustive_items; mod exhaustive_items;
mod exit; mod exit;
@ -299,6 +300,7 @@ mod missing_const_for_fn;
mod missing_doc; mod missing_doc;
mod missing_enforced_import_rename; mod missing_enforced_import_rename;
mod missing_inline; mod missing_inline;
mod mixed_read_write_in_expression;
mod module_style; mod module_style;
mod modulo_arithmetic; mod modulo_arithmetic;
mod mut_key; mod mut_key;
@ -345,6 +347,7 @@ mod ptr_offset_with_cast;
mod pub_use; mod pub_use;
mod question_mark; mod question_mark;
mod ranges; mod ranges;
mod rc_clone_in_vec_init;
mod redundant_clone; mod redundant_clone;
mod redundant_closure_call; mod redundant_closure_call;
mod redundant_else; mod redundant_else;
@ -417,7 +420,7 @@ mod zero_sized_map_values;
// end lints modules, do not remove this comment, its used in `update_lints` // end lints modules, do not remove this comment, its used in `update_lints`
pub use crate::utils::conf::Conf; pub use crate::utils::conf::Conf;
use crate::utils::conf::TryConf; use crate::utils::conf::{format_error, TryConf};
/// Register all pre expansion lints /// Register all pre expansion lints
/// ///
@ -462,7 +465,7 @@ pub fn read_conf(sess: &Session) -> Conf {
sess.struct_err(&format!( sess.struct_err(&format!(
"error reading Clippy's configuration file `{}`: {}", "error reading Clippy's configuration file `{}`: {}",
file_name.display(), file_name.display(),
error format_error(error)
)) ))
.emit(); .emit();
} }
@ -473,7 +476,7 @@ pub fn read_conf(sess: &Session) -> Conf {
/// Register all lints and lint groups with the rustc plugin registry /// Register all lints and lint groups with the rustc plugin registry
/// ///
/// Used in `./src/driver.rs`. /// Used in `./src/driver.rs`.
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) { pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
register_removed_non_tool_lints(store); register_removed_non_tool_lints(store);
@ -583,8 +586,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
}); });
let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; 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 || Box::new(approx_const::ApproxConstant::new(msrv)));
store.register_late_pass(move || Box::new(methods::Methods::new(avoid_breaking_exported_api, msrv))); store.register_late_pass(move || {
Box::new(methods::Methods::new(
avoid_breaking_exported_api,
msrv,
allow_expect_in_tests,
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_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_non_exhaustive::ManualNonExhaustiveEnum::new(msrv)));
@ -669,7 +681,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| Box::new(arithmetic::Arithmetic::default())); store.register_late_pass(|| Box::new(arithmetic::Arithmetic::default()));
store.register_late_pass(|| Box::new(assign_ops::AssignOps)); store.register_late_pass(|| Box::new(assign_ops::AssignOps));
store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq)); store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq));
store.register_late_pass(|| Box::new(eval_order_dependence::EvalOrderDependence)); 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_doc::MissingDoc::new()));
store.register_late_pass(|| Box::new(missing_inline::MissingInline)); store.register_late_pass(|| Box::new(missing_inline::MissingInline));
store.register_late_pass(move || Box::new(exhaustive_items::ExhaustiveItems)); store.register_late_pass(move || Box::new(exhaustive_items::ExhaustiveItems));
@ -892,6 +904,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
let max_include_file_size = conf.max_include_file_size; 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(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(strings::TrimSplitWhitespace));
store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default()));
// add lints here, do not remove this comment, it's used in `new_lint` // add lints here, do not remove this comment, it's used in `new_lint`
} }

View File

@ -204,7 +204,6 @@ impl WarningType {
} }
} }
#[allow(clippy::module_name_repetitions)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct LiteralDigitGrouping { pub struct LiteralDigitGrouping {
lint_fraction_readability: bool, lint_fraction_readability: bool,
@ -432,7 +431,7 @@ impl LiteralDigitGrouping {
} }
} }
#[allow(clippy::module_name_repetitions)] #[expect(clippy::module_name_repetitions)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct DecimalLiteralRepresentation { pub struct DecimalLiteralRepresentation {
threshold: u64, threshold: u64,

View File

@ -620,7 +620,6 @@ declare_lint_pass!(Loops => [
]); ]);
impl<'tcx> LateLintPass<'tcx> for Loops { impl<'tcx> LateLintPass<'tcx> for Loops {
#[allow(clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let for_loop = higher::ForLoop::hir(expr); let for_loop = higher::ForLoop::hir(expr);
if let Some(higher::ForLoop { if let Some(higher::ForLoop {

View File

@ -19,7 +19,7 @@ use std::mem;
/// Checks for looping over a range and then indexing a sequence with it. /// Checks for looping over a range and then indexing a sequence with it.
/// The iteratee must be a range literal. /// The iteratee must be a range literal.
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
pub(super) fn check<'tcx>( pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
pat: &'tcx Pat<'_>, pat: &'tcx Pat<'_>,

View File

@ -13,7 +13,7 @@ use rustc_span::symbol::{sym, Symbol};
use rustc_typeck::hir_ty_to_ty; use rustc_typeck::hir_ty_to_ty;
use std::iter::Iterator; use std::iter::Iterator;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Eq)]
enum IncrementVisitorVarState { enum IncrementVisitorVarState {
Initial, // Not examined yet Initial, // Not examined yet
IncrOnce, // Incremented exactly once, may be a loop counter IncrOnce, // Incremented exactly once, may be a loop counter

View File

@ -239,7 +239,7 @@ fn uses_iter<'tcx>(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tc
v.uses_iter v.uses_iter
} }
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &Expr<'_>) -> bool { fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &Expr<'_>) -> bool {
struct AfterLoopVisitor<'a, 'b, 'tcx> { struct AfterLoopVisitor<'a, 'b, 'tcx> {
cx: &'a LateContext<'tcx>, cx: &'a LateContext<'tcx>,

View File

@ -48,7 +48,7 @@ impl MacroRefData {
} }
#[derive(Default)] #[derive(Default)]
#[allow(clippy::module_name_repetitions)] #[expect(clippy::module_name_repetitions)]
pub struct MacroUseImports { pub struct MacroUseImports {
/// the actual import path used and the span of the attribute above it. /// the actual import path used and the span of the attribute above it.
imports: Vec<(String, Span)>, imports: Vec<(String, Span)>,
@ -134,7 +134,6 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
self.push_unique_macro_pat_ty(cx, ty.span); self.push_unique_macro_pat_ty(cx, ty.span);
} }
} }
#[allow(clippy::too_many_lines)]
fn check_crate_post(&mut self, cx: &LateContext<'_>) { fn check_crate_post(&mut self, cx: &LateContext<'_>) {
let mut used = FxHashMap::default(); let mut used = FxHashMap::default();
let mut check_dup = vec![]; let mut check_dup = vec![];

View File

@ -12,7 +12,7 @@ declare_clippy_lint! {
/// ///
/// ### Why is this bad? /// ### Why is this bad?
/// Apart from special setups (which we could detect following attributes like #![no_std]), /// Apart from special setups (which we could detect following attributes like #![no_std]),
/// recursing into main() seems like an unintuitive antipattern we should be able to detect. /// recursing into main() seems like an unintuitive anti-pattern we should be able to detect.
/// ///
/// ### Example /// ### Example
/// ```no_run /// ```no_run

View File

@ -48,7 +48,7 @@ impl_lint_pass!(ManualBits => [MANUAL_BITS]);
impl<'tcx> LateLintPass<'tcx> for ManualBits { impl<'tcx> LateLintPass<'tcx> for ManualBits {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::MANUAL_BITS) { if !meets_msrv(self.msrv, msrvs::MANUAL_BITS) {
return; return;
} }

View File

@ -46,7 +46,7 @@ declare_clippy_lint! {
declare_lint_pass!(ManualMap => [MANUAL_MAP]); declare_lint_pass!(ManualMap => [MANUAL_MAP]);
impl<'tcx> LateLintPass<'tcx> for ManualMap { impl<'tcx> LateLintPass<'tcx> for ManualMap {
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let (scrutinee, then_pat, then_body, else_pat, else_body) = match IfLetOrMatch::parse(cx, expr) { let (scrutinee, then_pat, then_body, else_pat, else_body) = match IfLetOrMatch::parse(cx, expr) {
Some(IfLetOrMatch::IfLet(scrutinee, pat, body, Some(r#else))) => (scrutinee, pat, body, None, r#else), Some(IfLetOrMatch::IfLet(scrutinee, pat, body, Some(r#else))) => (scrutinee, pat, body, None, r#else),

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use clippy_utils::{is_lint_allowed, meets_msrv, msrvs}; use clippy_utils::{is_doc_hidden, is_lint_allowed, meets_msrv, msrvs};
use rustc_ast::ast::{self, VisibilityKind}; use rustc_ast::ast::{self, VisibilityKind};
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -61,7 +61,7 @@ declare_clippy_lint! {
"manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]" "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]"
} }
#[allow(clippy::module_name_repetitions)] #[expect(clippy::module_name_repetitions)]
pub struct ManualNonExhaustiveStruct { pub struct ManualNonExhaustiveStruct {
msrv: Option<RustcVersion>, msrv: Option<RustcVersion>,
} }
@ -75,7 +75,7 @@ impl ManualNonExhaustiveStruct {
impl_lint_pass!(ManualNonExhaustiveStruct => [MANUAL_NON_EXHAUSTIVE]); impl_lint_pass!(ManualNonExhaustiveStruct => [MANUAL_NON_EXHAUSTIVE]);
#[allow(clippy::module_name_repetitions)] #[expect(clippy::module_name_repetitions)]
pub struct ManualNonExhaustiveEnum { pub struct ManualNonExhaustiveEnum {
msrv: Option<RustcVersion>, msrv: Option<RustcVersion>,
constructed_enum_variants: FxHashSet<(DefId, DefId)>, constructed_enum_variants: FxHashSet<(DefId, DefId)>,
@ -97,7 +97,7 @@ impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]);
impl EarlyLintPass for ManualNonExhaustiveStruct { impl EarlyLintPass for ManualNonExhaustiveStruct {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::NON_EXHAUSTIVE) { if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) {
return; return;
} }
@ -149,7 +149,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::NON_EXHAUSTIVE) { if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) {
return; return;
} }
@ -160,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
let id = cx.tcx.hir().local_def_id(v.id); let id = cx.tcx.hir().local_def_id(v.id);
(matches!(v.data, hir::VariantData::Unit(_)) (matches!(v.data, hir::VariantData::Unit(_))
&& v.ident.as_str().starts_with('_') && v.ident.as_str().starts_with('_')
&& cx.tcx.is_doc_hidden(id.to_def_id())) && is_doc_hidden(cx.tcx.hir().attrs(v.id)))
.then(|| (id, v.span)) .then(|| (id, v.span))
}); });
if let Some((id, span)) = iter.next() if let Some((id, span)) = iter.next()

View File

@ -68,7 +68,7 @@ enum StripKind {
impl<'tcx> LateLintPass<'tcx> for ManualStrip { impl<'tcx> LateLintPass<'tcx> for ManualStrip {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::STR_STRIP_PREFIX) { if !meets_msrv(self.msrv, msrvs::STR_STRIP_PREFIX) {
return; return;
} }

View File

@ -144,7 +144,7 @@ impl MapClone {
fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) { fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) {
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
let (message, sugg_method) = if is_copy && meets_msrv(self.msrv.as_ref(), &msrvs::ITERATOR_COPIED) { let (message, sugg_method) = if is_copy && meets_msrv(self.msrv, msrvs::ITERATOR_COPIED) {
("you are using an explicit closure for copying elements", "copied") ("you are using an explicit closure for copying elements", "copied")
} else { } else {
("you are using an explicit closure for cloning elements", "cloned") ("you are using an explicit closure for cloning elements", "cloned")

View File

@ -16,7 +16,7 @@ use std::collections::hash_map::Entry;
use super::MATCH_SAME_ARMS; use super::MATCH_SAME_ARMS;
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 { let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 {
let mut h = SpanlessHash::new(cx); let mut h = SpanlessHash::new(cx);
@ -225,9 +225,9 @@ fn iter_matching_struct_fields<'a>(
Iter(left.iter(), right.iter()) Iter(left.iter(), right.iter())
} }
#[allow(clippy::similar_names)] #[expect(clippy::similar_names)]
impl<'a> NormalizedPat<'a> { impl<'a> NormalizedPat<'a> {
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self { fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self {
match pat.kind { match pat.kind {
PatKind::Wild | PatKind::Binding(.., None) => Self::Wild, PatKind::Wild | PatKind::Binding(.., None) => Self::Wild,

View File

@ -1,15 +1,22 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{indent_of, snippet_block, snippet_with_applicability}; use clippy_utils::macros::HirNode;
use clippy_utils::source::{indent_of, snippet, snippet_block, snippet_with_applicability};
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::{get_parent_expr, is_refutable, peel_blocks}; use clippy_utils::{get_parent_expr, is_refutable, peel_blocks};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Arm, Expr, ExprKind, Local, Node, PatKind}; use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::Span;
use super::MATCH_SINGLE_BINDING; use super::MATCH_SINGLE_BINDING;
#[allow(clippy::too_many_lines)] enum AssignmentExpr {
pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) { Assign { span: Span, match_span: Span },
Local { span: Span, pat_span: Span },
}
#[expect(clippy::too_many_lines)]
pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'a>) {
if expr.span.from_expansion() || arms.len() != 1 || is_refutable(cx, arms[0].pat) { if expr.span.from_expansion() || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
return; return;
} }
@ -42,61 +49,59 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
let mut applicability = Applicability::MaybeIncorrect; let mut applicability = Applicability::MaybeIncorrect;
match arms[0].pat.kind { match arms[0].pat.kind {
PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => { PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => {
// If this match is in a local (`let`) stmt let (target_span, sugg) = match opt_parent_assign_span(cx, ex) {
let (target_span, sugg) = if let Some(parent_let_node) = opt_parent_let(cx, ex) { Some(AssignmentExpr::Assign { span, match_span }) => {
( let sugg = sugg_with_curlies(
parent_let_node.span, cx,
(ex, expr),
(bind_names, matched_vars),
&*snippet_body,
&mut applicability,
Some(span),
);
span_lint_and_sugg(
cx,
MATCH_SINGLE_BINDING,
span.to(match_span),
"this assignment could be simplified",
"consider removing the `match` expression",
sugg,
applicability,
);
return;
},
Some(AssignmentExpr::Local { span, pat_span }) => (
span,
format!( format!(
"let {} = {};\n{}let {} = {};", "let {} = {};\n{}let {} = {};",
snippet_with_applicability(cx, bind_names, "..", &mut applicability), snippet_with_applicability(cx, bind_names, "..", &mut applicability),
snippet_with_applicability(cx, matched_vars, "..", &mut applicability), snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
" ".repeat(indent_of(cx, expr.span).unwrap_or(0)), " ".repeat(indent_of(cx, expr.span).unwrap_or(0)),
snippet_with_applicability(cx, parent_let_node.pat.span, "..", &mut applicability), snippet_with_applicability(cx, pat_span, "..", &mut applicability),
snippet_body snippet_body
), ),
) ),
} else { None => {
// If we are in closure, we need curly braces around suggestion let sugg = sugg_with_curlies(
let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0)); cx,
let (mut cbrace_start, mut cbrace_end) = ("".to_string(), "".to_string()); (ex, expr),
if let Some(parent_expr) = get_parent_expr(cx, expr) { (bind_names, matched_vars),
if let ExprKind::Closure(..) = parent_expr.kind { &*snippet_body,
cbrace_end = format!("\n{}}}", indent); &mut applicability,
// Fix body indent due to the closure None,
indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0)); );
cbrace_start = format!("{{\n{}", indent); (expr.span, sugg)
} },
}
// If the parent is already an arm, and the body is another match statement,
// we need curly braces around suggestion
let parent_node_id = cx.tcx.hir().get_parent_node(expr.hir_id);
if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) {
if let ExprKind::Match(..) = arm.body.kind {
cbrace_end = format!("\n{}}}", indent);
// Fix body indent due to the match
indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
cbrace_start = format!("{{\n{}", indent);
}
}
(
expr.span,
format!(
"{}let {} = {};\n{}{}{}",
cbrace_start,
snippet_with_applicability(cx, bind_names, "..", &mut applicability),
snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
indent,
snippet_body,
cbrace_end
),
)
}; };
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
MATCH_SINGLE_BINDING, MATCH_SINGLE_BINDING,
target_span, target_span,
"this match could be written as a `let` statement", "this match could be written as a `let` statement",
"consider using `let` statement", "consider using a `let` statement",
sugg, sugg,
applicability, applicability,
); );
@ -110,6 +115,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
indent, indent,
snippet_body snippet_body
); );
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
MATCH_SINGLE_BINDING, MATCH_SINGLE_BINDING,
@ -135,15 +141,76 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
} }
} }
/// Returns true if the `ex` match expression is in a local (`let`) statement /// Returns true if the `ex` match expression is in a local (`let`) or assign expression
fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'a>> { fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<AssignmentExpr> {
let map = &cx.tcx.hir(); let map = &cx.tcx.hir();
if_chain! {
if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id)); if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id)) {
if let Some(Node::Local(parent_let_expr)) = map.find(map.get_parent_node(parent_arm_expr.hir_id)); return match map.find(map.get_parent_node(parent_arm_expr.hir_id)) {
then { Some(Node::Local(parent_let_expr)) => Some(AssignmentExpr::Local {
return Some(parent_let_expr); span: parent_let_expr.span,
} pat_span: parent_let_expr.pat.span(),
}),
Some(Node::Expr(Expr {
kind: ExprKind::Assign(parent_assign_expr, match_expr, _),
..
})) => Some(AssignmentExpr::Assign {
span: parent_assign_expr.span,
match_span: match_expr.span,
}),
_ => None,
};
} }
None None
} }
fn sugg_with_curlies<'a>(
cx: &LateContext<'a>,
(ex, match_expr): (&Expr<'a>, &Expr<'a>),
(bind_names, matched_vars): (Span, Span),
snippet_body: &str,
applicability: &mut Applicability,
assignment: Option<Span>,
) -> 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);
// Fix body indent due to the closure
indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
cbrace_start = format!("{{\n{}", indent);
}
}
// If the parent is already an arm, and the body is another match statement,
// we need curly braces around suggestion
let parent_node_id = cx.tcx.hir().get_parent_node(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);
// Fix body indent due to the match
indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
cbrace_start = format!("{{\n{}", indent);
}
}
let assignment_str = assignment.map_or_else(String::new, |span| {
let mut s = snippet(cx, span, "..").to_string();
s.push_str(" = ");
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
)
}

View File

@ -10,7 +10,7 @@ use rustc_span::sym;
use super::{MATCH_WILDCARD_FOR_SINGLE_VARIANTS, WILDCARD_ENUM_MATCH_ARM}; use super::{MATCH_WILDCARD_FOR_SINGLE_VARIANTS, WILDCARD_ENUM_MATCH_ARM};
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
let ty = cx.typeck_results().expr_ty(ex).peel_refs(); let ty = cx.typeck_results().expr_ty(ex).peel_refs();
let adt_def = match ty.kind() { let adt_def = match ty.kind() {
@ -56,7 +56,6 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
recurse_or_patterns(arm.pat, |pat| { recurse_or_patterns(arm.pat, |pat| {
let path = match &peel_hir_pat_refs(pat).0.kind { let path = match &peel_hir_pat_refs(pat).0.kind {
PatKind::Path(path) => { PatKind::Path(path) => {
#[allow(clippy::match_same_arms)]
let id = match cx.qpath_res(path, pat.hir_id) { let id = match cx.qpath_res(path, pat.hir_id) {
Res::Def( Res::Def(
DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst, DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,

View File

@ -658,7 +658,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
} }
if !contains_cfg_arm(cx, expr, ex, arms) { if !contains_cfg_arm(cx, expr, ex, arms) {
if source == MatchSource::Normal { if source == MatchSource::Normal {
if !(meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) if !(meets_msrv(self.msrv, msrvs::MATCHES_MACRO)
&& match_like_matches::check_match(cx, expr, ex, arms)) && match_like_matches::check_match(cx, expr, ex, arms))
{ {
match_same_arms::check(cx, arms); match_same_arms::check(cx, arms);
@ -685,7 +685,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
match_wild_err_arm::check(cx, ex, arms); match_wild_err_arm::check(cx, ex, arms);
wild_in_or_pats::check(cx, arms); wild_in_or_pats::check(cx, arms);
} else { } else {
if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) { if meets_msrv(self.msrv, msrvs::MATCHES_MACRO) {
match_like_matches::check(cx, expr); match_like_matches::check(cx, expr);
} }
redundant_pattern_match::check(cx, expr); redundant_pattern_match::check(cx, expr);

View File

@ -340,7 +340,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
} }
} }
#[allow(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
fn find_good_method_for_match<'a>( fn find_good_method_for_match<'a>(
cx: &LateContext<'_>, cx: &LateContext<'_>,
arms: &[Arm<'_>], arms: &[Arm<'_>],

View File

@ -254,7 +254,7 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace {
then { then {
check_replace_option_with_none(cx, src, dest, expr.span); check_replace_option_with_none(cx, src, dest, expr.span);
check_replace_with_uninit(cx, src, dest, expr.span); check_replace_with_uninit(cx, src, dest, expr.span);
if meets_msrv(self.msrv.as_ref(), &msrvs::MEM_TAKE) { if meets_msrv(self.msrv, msrvs::MEM_TAKE) {
check_replace_with_default(cx, src, dest, expr.span); check_replace_with_default(cx, src, dest, expr.span);
} }
} }

View File

@ -10,16 +10,16 @@ use rustc_span::{sym, Span};
use super::CLONED_INSTEAD_OF_COPIED; use super::CLONED_INSTEAD_OF_COPIED;
pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<&RustcVersion>) { pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<RustcVersion>) {
let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); let recv_ty = cx.typeck_results().expr_ty_adjusted(recv);
let inner_ty = match recv_ty.kind() { let inner_ty = match recv_ty.kind() {
// `Option<T>` -> `T` // `Option<T>` -> `T`
ty::Adt(adt, subst) ty::Adt(adt, subst)
if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && meets_msrv(msrv, &msrvs::OPTION_COPIED) => if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && meets_msrv(msrv, msrvs::OPTION_COPIED) =>
{ {
subst.type_at(0) subst.type_at(0)
}, },
_ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) => { _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) => {
match get_iterator_item_ty(cx, recv_ty) { match get_iterator_item_ty(cx, recv_ty) {
// <T as Iterator>::Item // <T as Iterator>::Item
Some(ty) => ty, Some(ty) => ty,

View File

@ -13,7 +13,7 @@ pub(super) fn check(
cx: &LateContext<'_>, cx: &LateContext<'_>,
_expr: &rustc_hir::Expr<'_>, _expr: &rustc_hir::Expr<'_>,
recv: &rustc_hir::Expr<'_>, recv: &rustc_hir::Expr<'_>,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
expect_span: Span, expect_span: Span,
err_span: Span, err_span: Span,
) { ) {
@ -21,7 +21,7 @@ pub(super) fn check(
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
// Test the version to make sure the lint can be showed (expect_err has been // Test the version to make sure the lint can be showed (expect_err has been
// introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982) // introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982)
if meets_msrv(msrv, &msrvs::EXPECT_ERR); if meets_msrv(msrv, msrvs::EXPECT_ERR);
// Grabs the `Result<T, E>` type // Grabs the `Result<T, E>` type
let result_type = cx.typeck_results().expr_ty(recv); let result_type = cx.typeck_results().expr_ty(recv);

View File

@ -1,4 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help; 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::ty::is_type_diagnostic_item;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::LateContext; use rustc_lint::LateContext;
@ -7,7 +8,7 @@ use rustc_span::sym;
use super::EXPECT_USED; use super::EXPECT_USED;
/// lint use of `expect()` for `Option`s and `Result`s /// lint use of `expect()` for `Option`s and `Result`s
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_expect_in_tests: bool) {
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
@ -18,6 +19,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
None None
}; };
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)) = mess {
span_lint_and_help( span_lint_and_help(
cx, cx,

View File

@ -14,10 +14,10 @@ pub(super) fn check<'tcx>(
expr: &'tcx hir::Expr<'_>, expr: &'tcx hir::Expr<'_>,
recv: &'tcx hir::Expr<'_>, recv: &'tcx hir::Expr<'_>,
arg: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) { ) {
if is_trait_method(cx, expr, sym::Iterator) { if is_trait_method(cx, expr, sym::Iterator) {
if !meets_msrv(msrv, &msrvs::ITERATOR_FIND_MAP) { if !meets_msrv(msrv, msrvs::ITERATOR_FIND_MAP) {
return; return;
} }

View File

@ -15,9 +15,9 @@ pub(super) fn check<'tcx>(
expr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>,
self_arg: &'tcx Expr<'_>, self_arg: &'tcx Expr<'_>,
radix: &'tcx Expr<'_>, radix: &'tcx Expr<'_>,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) { ) {
if !meets_msrv(msrv, &msrvs::IS_ASCII_DIGIT) { if !meets_msrv(msrv, msrvs::IS_ASCII_DIGIT) {
return; return;
} }

View File

@ -19,13 +19,13 @@ pub(super) fn check<'tcx>(
recv: &'tcx hir::Expr<'_>, recv: &'tcx hir::Expr<'_>,
map_arg: &'tcx hir::Expr<'_>, map_arg: &'tcx hir::Expr<'_>,
unwrap_arg: &'tcx hir::Expr<'_>, unwrap_arg: &'tcx hir::Expr<'_>,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) -> bool { ) -> bool {
// lint if the caller of `map()` is an `Option` // lint if the caller of `map()` is an `Option`
let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); 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_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
if is_result && !meets_msrv(msrv, &msrvs::RESULT_MAP_OR_ELSE) { if is_result && !meets_msrv(msrv, msrvs::RESULT_MAP_OR_ELSE) {
return false; return false;
} }

View File

@ -1563,7 +1563,7 @@ declare_clippy_lint! {
#[clippy::version = "1.39.0"] #[clippy::version = "1.39.0"]
pub MANUAL_SATURATING_ARITHMETIC, pub MANUAL_SATURATING_ARITHMETIC,
style, style,
"`.chcked_add/sub(x).unwrap_or(MAX/MIN)`" "`.checked_add/sub(x).unwrap_or(MAX/MIN)`"
} }
declare_clippy_lint! { declare_clippy_lint! {
@ -1776,8 +1776,6 @@ declare_clippy_lint! {
/// ///
/// ### Example /// ### Example
/// ```rust /// ```rust
/// use std::iter::FromIterator;
///
/// let five_fives = std::iter::repeat(5).take(5); /// let five_fives = std::iter::repeat(5).take(5);
/// ///
/// let v = Vec::from_iter(five_fives); /// let v = Vec::from_iter(five_fives);
@ -2200,14 +2198,23 @@ declare_clippy_lint! {
pub struct Methods { pub struct Methods {
avoid_breaking_exported_api: bool, avoid_breaking_exported_api: bool,
msrv: Option<RustcVersion>, msrv: Option<RustcVersion>,
allow_expect_in_tests: bool,
allow_unwrap_in_tests: bool,
} }
impl Methods { impl Methods {
#[must_use] #[must_use]
pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Self { pub fn new(
avoid_breaking_exported_api: bool,
msrv: Option<RustcVersion>,
allow_expect_in_tests: bool,
allow_unwrap_in_tests: bool,
) -> Self {
Self { Self {
avoid_breaking_exported_api, avoid_breaking_exported_api,
msrv, msrv,
allow_expect_in_tests,
allow_unwrap_in_tests,
} }
} }
} }
@ -2306,7 +2313,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
return; return;
} }
check_methods(cx, expr, self.msrv.as_ref()); self.check_methods(cx, expr);
match expr.kind { match expr.kind {
hir::ExprKind::Call(func, args) => { hir::ExprKind::Call(func, args) => {
@ -2322,7 +2329,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
single_char_add_str::check(cx, expr, args); single_char_add_str::check(cx, expr, args);
into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, 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); single_char_pattern::check(cx, expr, method_call.ident.name, args);
unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv.as_ref()); unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv);
}, },
hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
let mut info = BinaryExprInfo { let mut info = BinaryExprInfo {
@ -2505,196 +2512,201 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
extract_msrv_attr!(LateContext); extract_msrv_attr!(LateContext);
} }
#[allow(clippy::too_many_lines)] impl Methods {
fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) { #[allow(clippy::too_many_lines)]
if let Some((name, [recv, args @ ..], span)) = method_call(expr) { fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
match (name, args) { if let Some((name, [recv, args @ ..], span)) = method_call(expr) {
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { match (name, args) {
zst_offset::check(cx, expr, recv); ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
}, zst_offset::check(cx, expr, recv);
("and_then", [arg]) => {
let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
if !biom_option_linted && !biom_result_linted {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
}
},
("as_deref" | "as_deref_mut", []) => {
needless_option_as_deref::check(cx, expr, recv, name);
},
("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv),
("collect", []) => match method_call(recv) {
Some((name @ ("cloned" | "copied"), [recv2], _)) => {
iter_cloned_collect::check(cx, name, expr, recv2);
}, },
Some(("map", [m_recv, m_arg], _)) => { ("and_then", [arg]) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv); let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
}, let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
Some(("take", [take_self_arg, take_arg], _)) => { if !biom_option_linted && !biom_result_linted {
if meets_msrv(msrv, &msrvs::STR_REPEAT) { unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
} }
}, },
_ => {}, ("as_deref" | "as_deref_mut", []) => {
}, needless_option_as_deref::check(cx, expr, recv, name);
(name @ "count", args @ []) => match method_call(recv) {
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
iter_count::check(cx, expr, recv2, name2);
}, },
Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg), ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
_ => {}, ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
}, ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
("drain", [arg]) => { ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
iter_with_drain::check(cx, expr, recv, span, arg); ("collect", []) => match method_call(recv) {
}, Some((name @ ("cloned" | "copied"), [recv2], _)) => {
("expect", [_]) => match method_call(recv) { iter_cloned_collect::check(cx, name, expr, recv2);
Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, msrv, span, err_span),
_ => expect_used::check(cx, expr, recv),
},
("extend", [arg]) => {
string_extend_chars::check(cx, expr, recv, arg);
extend_with_drain::check(cx, expr, recv, arg);
},
("filter_map", [arg]) => {
unnecessary_filter_map::check(cx, expr, arg, name);
filter_map_identity::check(cx, expr, arg, span);
},
("find_map", [arg]) => {
unnecessary_filter_map::check(cx, expr, arg, name);
},
("flat_map", [arg]) => {
flat_map_identity::check(cx, expr, arg, span);
flat_map_option::check(cx, expr, arg, span);
},
(name @ "flatten", args @ []) => match method_call(recv) {
Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
_ => {},
},
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
("for_each", [_]) => {
if let Some(("inspect", [_, _], span2)) = method_call(recv) {
inspect_for_each::check(cx, expr, span2);
}
},
("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
("is_file", []) => filetype_is_file::check(cx, expr, recv),
("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, msrv),
("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
("join", [join_arg]) => {
if let Some(("collect", _, span)) = method_call(recv) {
unnecessary_join::check(cx, expr, recv, join_arg, span);
}
},
("last", args @ []) | ("skip", args @ [_]) => {
if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv2, name, args);
}
}
},
(name @ ("map" | "map_err"), [m_arg]) => {
if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
match (name, args) {
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
("filter", [f_arg]) => {
filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
},
("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true),
_ => {},
}
}
map_identity::check(cx, expr, recv, m_arg, name, span);
},
("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
(name @ "next", args @ []) => {
if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
match (name2, args2) {
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, msrv),
("iter", []) => iter_next_slice::check(cx, expr, recv2),
("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
("skip_while", [_]) => skip_while_next::check(cx, expr),
_ => {},
}
}
},
("nth", args @ [n_arg]) => match method_call(recv) {
Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
},
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
("or_else", [arg]) => {
if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
}
},
("splitn" | "rsplitn", [count_arg, pat_arg]) => {
if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count);
str_splitn::check(cx, name, expr, recv, pat_arg, count, msrv);
}
},
("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count);
}
},
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
("take", args @ [_arg]) => {
if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv2, name, args);
}
}
},
("take", []) => needless_option_take::check(cx, expr, recv),
("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
implicit_clone::check(cx, name, expr, recv);
},
("unwrap", []) => {
match method_call(recv) {
Some(("get", [recv, get_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, false);
}, },
Some(("get_mut", [recv, get_arg], _)) => { Some(("map", [m_recv, m_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, true); map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
}, },
Some(("or", [recv, or_arg], or_span)) => { Some(("take", [take_self_arg, take_arg], _)) => {
or_then_unwrap::check(cx, expr, recv, or_arg, or_span); if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
}
}, },
_ => {}, _ => {},
}
unwrap_used::check(cx, expr, recv);
},
("unwrap_or", [u_arg]) => match method_call(recv) {
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
}, },
Some(("map", [m_recv, m_arg], span)) => { (name @ "count", args @ []) => match method_call(recv) {
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span); Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
iter_count::check(cx, expr, recv2, name2);
},
Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
_ => {},
},
("drain", [arg]) => {
iter_with_drain::check(cx, expr, recv, span, arg);
},
("expect", [_]) => match method_call(recv) {
Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
_ => expect_used::check(cx, expr, recv, self.allow_expect_in_tests),
},
("extend", [arg]) => {
string_extend_chars::check(cx, expr, recv, arg);
extend_with_drain::check(cx, expr, recv, arg);
},
("filter_map", [arg]) => {
unnecessary_filter_map::check(cx, expr, arg, name);
filter_map_identity::check(cx, expr, arg, span);
},
("find_map", [arg]) => {
unnecessary_filter_map::check(cx, expr, arg, name);
},
("flat_map", [arg]) => {
flat_map_identity::check(cx, expr, arg, span);
flat_map_option::check(cx, expr, arg, span);
},
(name @ "flatten", args @ []) => match method_call(recv) {
Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
_ => {},
},
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
("for_each", [_]) => {
if let Some(("inspect", [_, _], span2)) = method_call(recv) {
inspect_for_each::check(cx, expr, span2);
}
},
("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
("is_file", []) => filetype_is_file::check(cx, expr, recv),
("is_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),
("join", [join_arg]) => {
if let Some(("collect", _, span)) = method_call(recv) {
unnecessary_join::check(cx, expr, recv, join_arg, span);
}
},
("last", args @ []) | ("skip", args @ [_]) => {
if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv2, name, args);
}
}
},
(name @ ("map" | "map_err"), [m_arg]) => {
if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
match (name, args) {
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
("filter", [f_arg]) => {
filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
},
("find", [f_arg]) => {
filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true);
},
_ => {},
}
}
map_identity::check(cx, expr, recv, m_arg, name, span);
},
("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
(name @ "next", args @ []) => {
if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
match (name2, args2) {
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv),
("iter", []) => iter_next_slice::check(cx, expr, recv2),
("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
("skip_while", [_]) => skip_while_next::check(cx, expr),
_ => {},
}
}
},
("nth", args @ [n_arg]) => match method_call(recv) {
Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
},
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
("or_else", [arg]) => {
if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
}
},
("splitn" | "rsplitn", [count_arg, pat_arg]) => {
if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count);
str_splitn::check(cx, name, expr, recv, pat_arg, count, self.msrv);
}
},
("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count);
}
},
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
("take", args @ [_arg]) => {
if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv2, name, args);
}
}
},
("take", []) => needless_option_take::check(cx, expr, recv),
("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
implicit_clone::check(cx, name, expr, recv);
},
("unwrap", []) => {
match method_call(recv) {
Some(("get", [recv, get_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, false);
},
Some(("get_mut", [recv, get_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, true);
},
Some(("or", [recv, or_arg], or_span)) => {
or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
},
_ => {},
}
unwrap_used::check(cx, expr, recv, self.allow_unwrap_in_tests);
},
("unwrap_or", [u_arg]) => match method_call(recv) {
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
},
Some(("map", [m_recv, m_arg], span)) => {
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
},
_ => {},
},
("unwrap_or_else", [u_arg]) => match method_call(recv) {
Some(("map", [recv, map_arg], _))
if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
_ => {
unwrap_or_else_default::check(cx, expr, recv, u_arg);
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
},
}, },
_ => {}, _ => {},
}, }
("unwrap_or_else", [u_arg]) => match method_call(recv) {
Some(("map", [recv, map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, msrv) => {},
_ => {
unwrap_or_else_default::check(cx, expr, recv, u_arg);
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
},
},
_ => {},
} }
} }
} }
@ -2821,7 +2833,7 @@ const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
ShouldImplTraitCase::new("std::ops::Sub", "sub", 2, FN_HEADER, SelfKind::Value, OutType::Any, true), ShouldImplTraitCase::new("std::ops::Sub", "sub", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
]; ];
#[derive(Clone, Copy, PartialEq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum SelfKind { enum SelfKind {
Value, Value,
Ref, Ref,

View File

@ -19,9 +19,9 @@ pub(super) fn check<'tcx>(
as_ref_recv: &hir::Expr<'_>, as_ref_recv: &hir::Expr<'_>,
map_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>,
is_mut: bool, is_mut: bool,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) { ) {
if !meets_msrv(msrv, &msrvs::OPTION_AS_DEREF) { if !meets_msrv(msrv, msrvs::OPTION_AS_DEREF) {
return; return;
} }

View File

@ -24,7 +24,7 @@ pub(super) fn check(
self_arg: &Expr<'_>, self_arg: &Expr<'_>,
pat_arg: &Expr<'_>, pat_arg: &Expr<'_>,
count: u128, count: u128,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) { ) {
if count < 2 || !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() { if count < 2 || !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() {
return; return;
@ -34,7 +34,7 @@ pub(super) fn check(
IterUsageKind::Nth(n) => count > n + 1, IterUsageKind::Nth(n) => count > n + 1,
IterUsageKind::NextTuple => count > 2, IterUsageKind::NextTuple => count > 2,
}; };
let manual = count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE); let manual = count == 2 && meets_msrv(msrv, msrvs::STR_SPLIT_ONCE);
match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir().parent_iter(expr.hir_id)) { match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir().parent_iter(expr.hir_id)) {
Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg), Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg),
@ -271,7 +271,7 @@ enum IterUsageKind {
NextTuple, NextTuple,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Eq)]
enum UnwrapKind { enum UnwrapKind {
Unwrap, Unwrap,
QuestionMark, QuestionMark,

View File

@ -26,7 +26,7 @@ pub fn check<'tcx>(
expr: &'tcx Expr<'tcx>, expr: &'tcx Expr<'tcx>,
method_name: Symbol, method_name: Symbol,
args: &'tcx [Expr<'tcx>], args: &'tcx [Expr<'tcx>],
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) { ) {
if_chain! { if_chain! {
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
@ -65,13 +65,12 @@ fn check_addr_of_expr(
if let Some(parent) = get_parent_expr(cx, expr); if let Some(parent) = get_parent_expr(cx, expr);
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = parent.kind; if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = parent.kind;
let adjustments = cx.typeck_results().expr_adjustments(parent).iter().collect::<Vec<_>>(); let adjustments = cx.typeck_results().expr_adjustments(parent).iter().collect::<Vec<_>>();
if let Some(target_ty) = match adjustments[..] if let
{
// For matching uses of `Cow::from` // For matching uses of `Cow::from`
[ [
Adjustment { Adjustment {
kind: Adjust::Deref(None), kind: Adjust::Deref(None),
.. target: referent_ty,
}, },
Adjustment { Adjustment {
kind: Adjust::Borrow(_), kind: Adjust::Borrow(_),
@ -82,7 +81,7 @@ fn check_addr_of_expr(
| [ | [
Adjustment { Adjustment {
kind: Adjust::Deref(None), kind: Adjust::Deref(None),
.. target: referent_ty,
}, },
Adjustment { Adjustment {
kind: Adjust::Borrow(_), kind: Adjust::Borrow(_),
@ -97,7 +96,7 @@ fn check_addr_of_expr(
| [ | [
Adjustment { Adjustment {
kind: Adjust::Deref(None), kind: Adjust::Deref(None),
.. target: referent_ty,
}, },
Adjustment { Adjustment {
kind: Adjust::Deref(Some(OverloadedDeref { .. })), kind: Adjust::Deref(Some(OverloadedDeref { .. })),
@ -107,17 +106,24 @@ fn check_addr_of_expr(
kind: Adjust::Borrow(_), kind: Adjust::Borrow(_),
target: target_ty, target: target_ty,
}, },
] => Some(target_ty), ] = adjustments[..];
_ => None,
};
let receiver_ty = cx.typeck_results().expr_ty(receiver); let receiver_ty = cx.typeck_results().expr_ty(receiver);
// Only flag cases where the receiver is copyable or the method is `Cow::into_owned`. This let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty);
// restriction is to ensure there is not overlap between `redundant_clone` and this lint. let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty);
if is_copy(cx, receiver_ty) || is_cow_into_owned(cx, method_name, method_def_id); // Only flag cases satisfying at least one of the following three conditions:
// * the referent and receiver types are distinct
// * the referent/receiver type is a copyable array
// * the method is `Cow::into_owned`
// This restriction is to ensure there is no overlap between `redundant_clone` and this
// lint. It also avoids the following false positive:
// https://github.com/rust-lang/rust-clippy/issues/8759
// Arrays are a bit of a corner case. Non-copyable arrays are handled by
// `redundant_clone`, but copyable arrays are not.
if *referent_ty != receiver_ty
|| (matches!(referent_ty.kind(), ty::Array(..)) && is_copy(cx, *referent_ty))
|| is_cow_into_owned(cx, method_name, method_def_id);
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
then { then {
let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty);
let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty);
if receiver_ty == target_ty && n_target_refs >= n_receiver_refs { if receiver_ty == target_ty && n_target_refs >= n_receiver_refs {
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
@ -192,7 +198,7 @@ fn check_into_iter_call_arg(
expr: &Expr<'_>, expr: &Expr<'_>,
method_name: Symbol, method_name: Symbol,
receiver: &Expr<'_>, receiver: &Expr<'_>,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) -> bool { ) -> bool {
if_chain! { if_chain! {
if let Some(parent) = get_parent_expr(cx, expr); if let Some(parent) = get_parent_expr(cx, expr);
@ -207,7 +213,11 @@ fn check_into_iter_call_arg(
if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) { if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) {
return true; return true;
} }
let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) { "copied" } else { "cloned" }; let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) {
"copied"
} else {
"cloned"
};
// The next suggestion may be incorrect because the removal of the `to_owned`-like // The next suggestion may be incorrect because the removal of the `to_owned`-like
// function could cause the iterator to hold a reference to a resource that is used // function could cause the iterator to hold a reference to a resource that is used
// mutably. See https://github.com/rust-lang/rust-clippy/issues/8148. // mutably. See https://github.com/rust-lang/rust-clippy/issues/8148.

View File

@ -1,4 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help; 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::ty::is_type_diagnostic_item;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::LateContext; use rustc_lint::LateContext;
@ -7,7 +8,7 @@ use rustc_span::sym;
use super::UNWRAP_USED; use super::UNWRAP_USED;
/// lint use of `unwrap()` for `Option`s and `Result`s /// lint use of `unwrap()` for `Option`s and `Result`s
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) {
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
@ -18,6 +19,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
None None
}; };
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)) = mess {
span_lint_and_help( span_lint_and_help(
cx, cx,

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::source::{snippet, snippet_opt};
use clippy_utils::ty::implements_trait; use clippy_utils::ty::{implements_trait, is_copy};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -20,8 +20,8 @@ use rustc_span::symbol::sym;
use clippy_utils::consts::{constant, Constant}; use clippy_utils::consts::{constant, Constant};
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::{ use clippy_utils::{
get_item_name, get_parent_expr, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats, get_item_name, get_parent_expr, in_constant, is_integer_const, iter_input_pats, last_path_segment,
last_path_segment, match_any_def_paths, path_def_id, paths, unsext, SpanlessEq, match_any_def_paths, path_def_id, paths, unsext, SpanlessEq,
}; };
declare_clippy_lint! { declare_clippy_lint! {
@ -548,7 +548,7 @@ fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _)) matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _))
} }
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) { fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
#[derive(Default)] #[derive(Default)]
struct EqImpl { struct EqImpl {
@ -569,33 +569,34 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left:
}) })
} }
let (arg_ty, snip) = match expr.kind { let typeck = cx.typeck_results();
ExprKind::MethodCall(.., args, _) if args.len() == 1 => { let (arg, arg_span) = match expr.kind {
if_chain!( ExprKind::MethodCall(.., [arg], _)
if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if typeck
if is_diag_trait_item(cx, expr_def_id, sym::ToString) .type_dependent_def_id(expr.hir_id)
|| is_diag_trait_item(cx, expr_def_id, sym::ToOwned); .and_then(|id| cx.tcx.trait_of_item(id))
then { .map_or(false, |id| {
(cx.typeck_results().expr_ty(&args[0]), snippet(cx, args[0].span, "..")) matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ToString | sym::ToOwned))
} else { }) =>
return; {
} (arg, arg.span)
)
}, },
ExprKind::Call(path, [arg]) => { ExprKind::Call(path, [arg])
if path_def_id(cx, path) if path_def_id(cx, path)
.and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM])) .and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM]))
.is_some() .map_or(false, |idx| match idx {
{ 0 => true,
(cx.typeck_results().expr_ty(arg), snippet(cx, arg.span, "..")) 1 => !is_copy(cx, typeck.expr_ty(expr)),
} else { _ => false,
return; }) =>
} {
(arg, arg.span)
}, },
_ => return, _ => return,
}; };
let other_ty = cx.typeck_results().expr_ty(other); let arg_ty = typeck.expr_ty(arg);
let other_ty = typeck.expr_ty(other);
let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default(); let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default();
let with_deref = arg_ty let with_deref = arg_ty
@ -627,13 +628,14 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left:
return; return;
} }
let arg_snip = snippet(cx, arg_span, "..");
let expr_snip; let expr_snip;
let eq_impl; let eq_impl;
if with_deref.is_implemented() { if with_deref.is_implemented() {
expr_snip = format!("*{}", snip); expr_snip = format!("*{}", arg_snip);
eq_impl = with_deref; eq_impl = with_deref;
} else { } else {
expr_snip = snip.to_string(); expr_snip = arg_snip.to_string();
eq_impl = without_deref; eq_impl = without_deref;
}; };

View File

@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
span: Span, span: Span,
hir_id: HirId, hir_id: HirId,
) { ) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::CONST_IF_MATCH) { if !meets_msrv(self.msrv, msrvs::CONST_IF_MATCH) {
return; return;
} }
@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
let mir = cx.tcx.optimized_mir(def_id); let mir = cx.tcx.optimized_mir(def_id);
if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv.as_ref()) { if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) {
if cx.tcx.is_const_fn_raw(def_id.to_def_id()) { if cx.tcx.is_const_fn_raw(def_id.to_def_id()) {
cx.tcx.sess.span_err(span, err.as_ref()); cx.tcx.sess.span_err(span, err.as_ref());
} }

View File

@ -40,8 +40,8 @@ declare_clippy_lint! {
/// let a = tmp + x; /// let a = tmp + x;
/// ``` /// ```
#[clippy::version = "pre 1.29.0"] #[clippy::version = "pre 1.29.0"]
pub EVAL_ORDER_DEPENDENCE, pub MIXED_READ_WRITE_IN_EXPRESSION,
suspicious, restriction,
"whether a variable read occurs before a write depends on sub-expression evaluation order" "whether a variable read occurs before a write depends on sub-expression evaluation order"
} }
@ -73,7 +73,7 @@ declare_clippy_lint! {
"whether an expression contains a diverging sub expression" "whether an expression contains a diverging sub expression"
} }
declare_lint_pass!(EvalOrderDependence => [EVAL_ORDER_DEPENDENCE, DIVERGING_SUB_EXPRESSION]); declare_lint_pass!(EvalOrderDependence => [MIXED_READ_WRITE_IN_EXPRESSION, DIVERGING_SUB_EXPRESSION]);
impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence { impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
@ -303,7 +303,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
if !is_in_assignment_position(self.cx, expr) { if !is_in_assignment_position(self.cx, expr) {
span_lint_and_note( span_lint_and_note(
self.cx, self.cx,
EVAL_ORDER_DEPENDENCE, MIXED_READ_WRITE_IN_EXPRESSION,
expr.span, expr.span,
&format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)), &format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)),
Some(self.write_expr.span), Some(self.write_expr.span),

View File

@ -16,7 +16,7 @@ declare_clippy_lint! {
/// ### Why is this bad? /// ### Why is this bad?
/// In release builds `debug_assert!` macros are optimized out by the /// In release builds `debug_assert!` macros are optimized out by the
/// compiler. /// compiler.
/// Therefore mutating something in a `debug_assert!` macro results in different behaviour /// Therefore mutating something in a `debug_assert!` macro results in different behavior
/// between a release and debug build. /// between a release and debug build.
/// ///
/// ### Example /// ### Example

View File

@ -53,7 +53,7 @@ fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
false false
} }
fn suggesstion_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> { fn suggestion_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
if let ExprKind::Binary(ref op, left, right) = expr.kind { if let ExprKind::Binary(ref op, left, right) = expr.kind {
if let (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) { if let (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) {
let op_snippet = match op.node { let op_snippet = match op.node {
@ -75,7 +75,7 @@ impl LateLintPass<'_> for NeedlessBitwiseBool {
expr.span, expr.span,
"use of bitwise operator instead of lazy operator between booleans", "use of bitwise operator instead of lazy operator between booleans",
|diag| { |diag| {
if let Some(sugg) = suggesstion_snippet(cx, expr) { if let Some(sugg) = suggestion_snippet(cx, expr) {
diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable); diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable);
} }
}, },

View File

@ -70,7 +70,7 @@ macro_rules! need {
} }
impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn check_fn( fn check_fn(
&mut self, &mut self,
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,

View File

@ -34,7 +34,6 @@ declare_clippy_lint! {
declare_lint_pass!(NegMultiply => [NEG_MULTIPLY]); declare_lint_pass!(NegMultiply => [NEG_MULTIPLY]);
#[allow(clippy::match_same_arms)]
impl<'tcx> LateLintPass<'tcx> for NegMultiply { impl<'tcx> LateLintPass<'tcx> for NegMultiply {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if let ExprKind::Binary(ref op, left, right) = e.kind { if let ExprKind::Binary(ref op, left, right) = e.kind {

View File

@ -58,7 +58,6 @@ pub struct NewWithoutDefault {
impl_lint_pass!(NewWithoutDefault => [NEW_WITHOUT_DEFAULT]); impl_lint_pass!(NewWithoutDefault => [NEW_WITHOUT_DEFAULT]);
impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
#[allow(clippy::too_many_lines)]
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
if let hir::ItemKind::Impl(hir::Impl { if let hir::ItemKind::Impl(hir::Impl {
of_trait: None, of_trait: None,

View File

@ -191,7 +191,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
} }
} }
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn check_ident(&mut self, ident: Ident) { fn check_ident(&mut self, ident: Ident) {
let interned_name = ident.name.as_str(); let interned_name = ident.name.as_str();
if interned_name.chars().any(char::is_uppercase) { if interned_name.chars().any(char::is_uppercase) {

View File

@ -52,7 +52,7 @@ declare_clippy_lint! {
/// to a function that needs the memory address. For further details, refer to /// to a function that needs the memory address. For further details, refer to
/// [this issue](https://github.com/rust-lang/rust-clippy/issues/5953) /// [this issue](https://github.com/rust-lang/rust-clippy/issues/5953)
/// that explains a real case in which this false positive /// that explains a real case in which this false positive
/// led to an **undefined behaviour** introduced with unsafe code. /// led to an **undefined behavior** introduced with unsafe code.
/// ///
/// ### Example /// ### Example
/// ///
@ -124,7 +124,7 @@ impl<'tcx> PassByRefOrValue {
// Cap the calculated bit width at 32-bits to reduce // Cap the calculated bit width at 32-bits to reduce
// portability problems between 32 and 64-bit targets // portability problems between 32 and 64-bit targets
let bit_width = cmp::min(bit_width, 32); let bit_width = cmp::min(bit_width, 32);
#[allow(clippy::integer_division)] #[expect(clippy::integer_division)]
let byte_width = bit_width / 8; let byte_width = bit_width / 8;
// Use a limit of 2 times the register byte width // Use a limit of 2 times the register byte width
byte_width * 2 byte_width * 2

View File

@ -163,7 +163,6 @@ enum Level {
Lower, Lower,
} }
#[allow(rustc::usage_of_ty_tykind)]
fn find_first_mismatch<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>) -> Option<(Span, Mutability, Level)> { fn find_first_mismatch<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>) -> Option<(Span, Mutability, Level)> {
let mut result = None; let mut result = None;
pat.walk(|p| { pat.walk(|p| {

View File

@ -514,7 +514,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
} }
} }
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: &[PtrArg<'tcx>]) -> Vec<PtrArgResult> { fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: &[PtrArg<'tcx>]) -> Vec<PtrArgResult> {
struct V<'cx, 'tcx> { struct V<'cx, 'tcx> {
cx: &'cx LateContext<'tcx>, cx: &'cx LateContext<'tcx>,

View File

@ -193,7 +193,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges {
check_range_zip_with_len(cx, path, args, expr.span); check_range_zip_with_len(cx, path, args, expr.span);
}, },
ExprKind::Binary(ref op, l, r) => { ExprKind::Binary(ref op, l, r) => {
if meets_msrv(self.msrv.as_ref(), &msrvs::RANGE_CONTAINS) { if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) {
check_possible_range_contains(cx, op.node, l, r, expr); check_possible_range_contains(cx, op.node, l, r, expr);
} }
}, },
@ -207,7 +207,13 @@ impl<'tcx> LateLintPass<'tcx> for Ranges {
extract_msrv_attr!(LateContext); extract_msrv_attr!(LateContext);
} }
fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'_>, r: &Expr<'_>, expr: &Expr<'_>) { fn check_possible_range_contains(
cx: &LateContext<'_>,
op: BinOpKind,
left: &Expr<'_>,
right: &Expr<'_>,
expr: &Expr<'_>,
) {
if in_constant(cx, expr.hir_id) { if in_constant(cx, expr.hir_id) {
return; return;
} }
@ -219,21 +225,19 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
_ => return, _ => return,
}; };
// value, name, order (higher/lower), inclusiveness // value, name, order (higher/lower), inclusiveness
if let (Some((lval, lid, name_span, lval_span, lord, linc)), Some((rval, rid, _, rval_span, rord, rinc))) = if let (Some(l), Some(r)) = (check_range_bounds(cx, left), check_range_bounds(cx, right)) {
(check_range_bounds(cx, l), check_range_bounds(cx, r))
{
// we only lint comparisons on the same name and with different // we only lint comparisons on the same name and with different
// direction // direction
if lid != rid || lord == rord { if l.id != r.id || l.ord == r.ord {
return; return;
} }
let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(l), &lval, &rval); let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(l.expr), &l.val, &r.val);
if combine_and && ord == Some(rord) { if combine_and && ord == Some(r.ord) {
// order lower bound and upper bound // order lower bound and upper bound
let (l_span, u_span, l_inc, u_inc) = if rord == Ordering::Less { let (l_span, u_span, l_inc, u_inc) = if r.ord == Ordering::Less {
(lval_span, rval_span, linc, rinc) (l.val_span, r.val_span, l.inc, r.inc)
} else { } else {
(rval_span, lval_span, rinc, linc) (r.val_span, l.val_span, r.inc, l.inc)
}; };
// we only lint inclusive lower bounds // we only lint inclusive lower bounds
if !l_inc { if !l_inc {
@ -245,7 +249,7 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
("Range", "..") ("Range", "..")
}; };
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
let name = snippet_with_applicability(cx, name_span, "_", &mut applicability); let name = snippet_with_applicability(cx, l.name_span, "_", &mut applicability);
let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability); let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability);
let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability); let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability);
let space = if lo.ends_with('.') { " " } else { "" }; let space = if lo.ends_with('.') { " " } else { "" };
@ -258,13 +262,13 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
format!("({}{}{}{}).contains(&{})", lo, space, range_op, hi, name), format!("({}{}{}{}).contains(&{})", lo, space, range_op, hi, name),
applicability, applicability,
); );
} else if !combine_and && ord == Some(lord) { } else if !combine_and && ord == Some(l.ord) {
// `!_.contains(_)` // `!_.contains(_)`
// order lower bound and upper bound // order lower bound and upper bound
let (l_span, u_span, l_inc, u_inc) = if lord == Ordering::Less { let (l_span, u_span, l_inc, u_inc) = if l.ord == Ordering::Less {
(lval_span, rval_span, linc, rinc) (l.val_span, r.val_span, l.inc, r.inc)
} else { } else {
(rval_span, lval_span, rinc, linc) (r.val_span, l.val_span, r.inc, l.inc)
}; };
if l_inc { if l_inc {
return; return;
@ -275,7 +279,7 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
("RangeInclusive", "..=") ("RangeInclusive", "..=")
}; };
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
let name = snippet_with_applicability(cx, name_span, "_", &mut applicability); let name = snippet_with_applicability(cx, l.name_span, "_", &mut applicability);
let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability); let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability);
let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability); let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability);
let space = if lo.ends_with('.') { " " } else { "" }; let space = if lo.ends_with('.') { " " } else { "" };
@ -292,7 +296,20 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
} }
} }
fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, HirId, Span, Span, Ordering, bool)> { struct RangeBounds<'a> {
val: Constant,
expr: &'a Expr<'a>,
id: HirId,
name_span: Span,
val_span: Span,
ord: Ordering,
inc: bool,
}
// Takes a binary expression such as x <= 2 as input
// Breaks apart into various pieces, such as the value of the number,
// hir id of the variable, and direction/inclusiveness of the operator
fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<RangeBounds<'a>> {
if let ExprKind::Binary(ref op, l, r) = ex.kind { if let ExprKind::Binary(ref op, l, r) = ex.kind {
let (inclusive, ordering) = match op.node { let (inclusive, ordering) = match op.node {
BinOpKind::Gt => (false, Ordering::Greater), BinOpKind::Gt => (false, Ordering::Greater),
@ -303,11 +320,27 @@ fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant,
}; };
if let Some(id) = path_to_local(l) { if let Some(id) = path_to_local(l) {
if let Some((c, _)) = constant(cx, cx.typeck_results(), r) { if let Some((c, _)) = constant(cx, cx.typeck_results(), r) {
return Some((c, id, l.span, r.span, ordering, inclusive)); return Some(RangeBounds {
val: c,
expr: r,
id,
name_span: l.span,
val_span: r.span,
ord: ordering,
inc: inclusive,
});
} }
} else if let Some(id) = path_to_local(r) { } else if let Some(id) = path_to_local(r) {
if let Some((c, _)) = constant(cx, cx.typeck_results(), l) { if let Some((c, _)) = constant(cx, cx.typeck_results(), l) {
return Some((c, id, r.span, l.span, ordering.reverse(), inclusive)); return Some(RangeBounds {
val: c,
expr: l,
id,
name_span: r.span,
val_span: l.span,
ord: ordering.reverse(),
inc: inclusive,
});
} }
} }
} }

View File

@ -0,0 +1,141 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::VecArgs;
use clippy_utils::last_path_segment;
use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::source::{indent_of, snippet};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span, Symbol};
declare_clippy_lint! {
/// ### What it does
/// Checks for `Arc::new` or `Rc::new` in `vec![elem; len]`
///
/// ### Why is this bad?
/// This will create `elem` once and clone it `len` times - doing so with `Arc` or `Rc`
/// is a bit misleading, as it will create references to the same pointer, rather
/// than different instances.
///
/// ### Example
/// ```rust
/// 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:
/// ```rust
///
/// // 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];
/// ```
#[clippy::version = "1.62.0"]
pub RC_CLONE_IN_VEC_INIT,
suspicious,
"initializing `Arc` or `Rc` in `vec![elem; len]`"
}
declare_lint_pass!(RcCloneInVecInit => [RC_CLONE_IN_VEC_INIT]);
impl LateLintPass<'_> for RcCloneInVecInit {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return; };
let Some(VecArgs::Repeat(elem, len)) = VecArgs::hir(cx, expr) else { return; };
let Some(symbol) = new_reference_call(cx, elem) else { return; };
emit_lint(cx, symbol, macro_call.span, elem, len);
}
}
fn elem_snippet(cx: &LateContext<'_>, elem: &Expr<'_>, symbol_name: &str) -> String {
let elem_snippet = snippet(cx, elem.span, "..").to_string();
if elem_snippet.contains('\n') {
// This string must be found in `elem_snippet`, otherwise we won't be constructing
// the snippet in the first place.
let reference_creation = format!("{symbol_name}::new");
let (code_until_reference_creation, _right) = elem_snippet.split_once(&reference_creation).unwrap();
return format!("{code_until_reference_creation}{reference_creation}(..)");
}
elem_snippet
}
fn loop_init_suggestion(elem: &str, len: &str, indent: &str) -> String {
format!(
r#"{{
{indent} let mut v = Vec::with_capacity({len});
{indent} (0..{len}).for_each(|_| v.push({elem}));
{indent} v
{indent}}}"#
)
}
fn extract_suggestion(elem: &str, len: &str, indent: &str) -> String {
format!(
"{{
{indent} let data = {elem};
{indent} vec![data; {len}]
{indent}}}"
)
}
fn emit_lint(cx: &LateContext<'_>, symbol: Symbol, lint_span: Span, elem: &Expr<'_>, len: &Expr<'_>) {
let symbol_name = symbol.as_str();
span_lint_and_then(
cx,
RC_CLONE_IN_VEC_INIT,
lint_span,
&format!("calling `{symbol_name}::new` in `vec![elem; len]`"),
|diag| {
let len_snippet = snippet(cx, len.span, "..");
let elem_snippet = elem_snippet(cx, elem, symbol_name);
let indentation = " ".repeat(indent_of(cx, lint_span).unwrap_or(0));
let loop_init_suggestion = loop_init_suggestion(&elem_snippet, len_snippet.as_ref(), &indentation);
let extract_suggestion = extract_suggestion(&elem_snippet, len_snippet.as_ref(), &indentation);
diag.note(format!("each element will point to the same `{symbol_name}` instance"));
diag.span_suggestion(
lint_span,
format!("consider initializing each `{symbol_name}` element individually"),
loop_init_suggestion,
Applicability::Unspecified,
);
diag.span_suggestion(
lint_span,
format!(
"or if this is intentional, consider extracting the `{symbol_name}` initialization to a variable"
),
extract_suggestion,
Applicability::Unspecified,
);
},
);
}
/// Checks whether the given `expr` is a call to `Arc::new` or `Rc::new`
fn new_reference_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
if_chain! {
if let ExprKind::Call(func, _args) = expr.kind;
if let ExprKind::Path(ref func_path @ QPath::TypeRelative(ty, _)) = func.kind;
if let TyKind::Path(ref ty_path) = ty.kind;
if let Some(def_id) = cx.qpath_res(ty_path, ty.hir_id).opt_def_id();
if last_path_segment(func_path).ident.name == sym::new;
then {
return cx.tcx.get_diagnostic_name(def_id).filter(|symbol| symbol == &sym::Arc || symbol == &sym::Rc);
}
}
None
}

View File

@ -19,7 +19,6 @@ use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces, GenKill, Ge
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::{BytePos, Span}; use rustc_span::source_map::{BytePos, Span};
use rustc_span::sym; use rustc_span::sym;
use std::convert::TryFrom;
use std::ops::ControlFlow; use std::ops::ControlFlow;
macro_rules! unwrap_or_continue { macro_rules! unwrap_or_continue {
@ -71,7 +70,7 @@ declare_clippy_lint! {
declare_lint_pass!(RedundantClone => [REDUNDANT_CLONE]); declare_lint_pass!(RedundantClone => [REDUNDANT_CLONE]);
impl<'tcx> LateLintPass<'tcx> for RedundantClone { impl<'tcx> LateLintPass<'tcx> for RedundantClone {
#[allow(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn check_fn( fn check_fn(
&mut self, &mut self,
cx: &LateContext<'tcx>, cx: &LateContext<'tcx>,
@ -633,7 +632,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> {
} }
/// Collect possible borrowed for every `&mut` local. /// Collect possible borrowed for every `&mut` local.
/// For exampel, `_1 = &mut _2` generate _1: {_2,...} /// For example, `_1 = &mut _2` generate _1: {_2,...}
/// Known Problems: not sure all borrowed are tracked /// Known Problems: not sure all borrowed are tracked
struct PossibleOriginVisitor<'a, 'tcx> { struct PossibleOriginVisitor<'a, 'tcx> {
possible_origin: TransitiveRelation, possible_origin: TransitiveRelation,

View File

@ -51,7 +51,7 @@ impl_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]);
impl EarlyLintPass for RedundantFieldNames { impl EarlyLintPass for RedundantFieldNames {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::FIELD_INIT_SHORTHAND) { if !meets_msrv(self.msrv, msrvs::FIELD_INIT_SHORTHAND) {
return; return;
} }

View File

@ -99,7 +99,7 @@ impl RedundantStaticLifetimes {
impl EarlyLintPass for RedundantStaticLifetimes { impl EarlyLintPass for RedundantStaticLifetimes {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::STATIC_IN_CONST) { if !meets_msrv(self.msrv, msrvs::STATIC_IN_CONST) {
return; return;
} }

Some files were not shown because too many files have changed in this diff Show More