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"
mkdir 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
if [[ -n $TAG_NAME ]]; then

View File

@ -8,9 +8,9 @@ document.
[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)
@ -111,7 +111,7 @@ Current beta, released 2022-05-19
## 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)
@ -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
[`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
[`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
[`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
@ -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
[`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_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
[`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
[`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
[`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
[`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
[`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
[`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def
[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
[`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
[`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
[`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
@ -3350,8 +3355,11 @@ Released 2018-09-13
[`derivable_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls
[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
[`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_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
[`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
@ -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_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
[`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
[`drop_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_bounds
[`drop_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy
[`drop_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_non_drop
[`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
[`duplicate_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
[`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
@ -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_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_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
[`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
@ -3425,9 +3437,11 @@ Released 2018-09-13
[`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
[`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
[`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
[`identity_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
[`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex
[`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
[`if_let_some_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_some_result
[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
[`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
[`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering
[`invalid_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_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
@ -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_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
[`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum
[`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget
[`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none
[`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default
@ -3549,6 +3567,7 @@ Released 2018-09-13
[`missing_spin_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_spin_loop
[`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes
[`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals
[`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
[`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
@ -3592,6 +3611,7 @@ Released 2018-09-13
[`never_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#never_loop
[`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self
[`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
[`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_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
@ -3605,19 +3625,25 @@ Released 2018-09-13
[`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect
[`only_used_in_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion
[`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
[`option_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_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_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
[`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none
[`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn
[`option_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_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_then_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_then_unwrap
[`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
[`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
[`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic
[`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
[`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
@ -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_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_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
[`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
@ -3658,14 +3685,18 @@ Released 2018-09-13
[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
[`result_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_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_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
[`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
@ -3684,10 +3715,12 @@ Released 2018-09-13
[`short_circuit_statement`]: https://rust-lang.github.io/rust-clippy/master/index.html#short_circuit_statement
[`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq
[`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
[`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
[`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
[`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names
[`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
[`single_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_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
@ -3707,6 +3740,7 @@ Released 2018-09-13
[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
[`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
[`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
[`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
@ -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
[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
[`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
[`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args
[`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
[`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
@ -3753,6 +3789,7 @@ Released 2018-09-13
[`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
[`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash
[`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
[`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints
[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
[`unnecessary_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_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
[`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
[`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
[`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
[`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
[`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
@ -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_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_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
<!-- 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.
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].
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`]
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
[`ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty
[nodes in the AST docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/
[deep-nesting]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/mem_forget.rs#L29-L43
[if_chain]: https://docs.rs/if_chain/*/if_chain
[nest-less]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/bit_mask.rs#L124-L150
[deep-nesting]: https://github.com/rust-lang/rust-clippy/blob/5e4f0922911536f80d9591180fa604229ac13939/clippy_lints/src/mem_forget.rs#L31-L45
[let chains]: https://github.com/rust-lang/rust/pull/94927
[nest-less]: https://github.com/rust-lang/rust-clippy/blob/5e4f0922911536f80d9591180fa604229ac13939/clippy_lints/src/bit_mask.rs#L133-L159
## Writing code

View File

@ -1,6 +1,6 @@
[package]
name = "clippy"
version = "0.1.62"
version = "0.1.63"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@ -25,6 +25,7 @@ clippy_lints = { path = "clippy_lints" }
semver = "1.0"
rustc_tools_util = { path = "rustc_tools_util" }
tempfile = { version = "3.2", optional = true }
termize = "0.1"
[dev-dependencies]
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) {
Ok(metadata) => metadata.is_file(),
Err(e) => {
@ -30,6 +30,7 @@ pub fn run(path: &str) {
.args(["-Z", "no-codegen"])
.args(["--edition", "2021"])
.arg(path)
.args(args)
.status(),
);
} else {
@ -42,6 +43,8 @@ pub fn run(path: &str) {
.expect("failed to create tempdir");
let status = Command::new(cargo_clippy_path())
.arg("clippy")
.args(args)
.current_dir(path)
.env("CARGO_TARGET_DIR", target.as_ref())
.status();

View File

@ -76,7 +76,8 @@ fn main() {
},
("lint", Some(matches)) => {
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)) => {
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 changelog contains markdown link references at the bottom\n \
* all lint groups include the correct lints\n \
* lint modules in `clippy_lints/*` are visible in `src/lifb.rs` via `pub mod`\n \
* lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
* all lints are registered in the lint store",
)
.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:
cargo dev lint tests/ui-cargo/wildcard_dependencies/fail
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::with_name("path")
.required(true)
.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(

View File

@ -133,7 +133,7 @@ fn to_camel_case(name: &str) -> String {
.collect()
}
fn get_stabilisation_version() -> String {
fn get_stabilization_version() -> String {
fn parse_manifest(contents: &str) -> Option<String> {
let version = contents
.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 category = lint.category;
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";
#[derive(Clone, Copy, PartialEq)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum UpdateMode {
Check,
Change,
@ -66,8 +66,13 @@ fn generate_lint_files(
|res| {
for lint in usable_lints
.iter()
.map(|l| &l.name)
.chain(deprecated_lints.iter().map(|l| &l.name))
.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()
{
writeln!(res, "[`{}`]: {}#{}", lint, DOCS_LINK, lint).unwrap();
@ -372,7 +377,7 @@ fn exit_with_failure() {
}
/// Lint data parsed from the Clippy source code.
#[derive(Clone, PartialEq, Debug)]
#[derive(Clone, PartialEq, Eq, Debug)]
struct Lint {
name: String,
group: String,
@ -414,7 +419,7 @@ impl Lint {
}
}
#[derive(Clone, PartialEq, Debug)]
#[derive(Clone, PartialEq, Eq, Debug)]
struct DeprecatedLint {
name: String,
reason: String,

View File

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

View File

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

View File

@ -50,7 +50,7 @@ declare_clippy_lint! {
/// ### Known problems
/// Clippy cannot know for sure if `a op= a op b` should have
/// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both.
/// If `a op= a op b` is really the correct 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.
///
/// ### 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::{extract_msrv_attr, meets_msrv};
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_hir::{
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) {
for attr in &item.attrs {
let attr_item = if let AttrKind::Normal(ref attr, _) = attr.kind {
attr
} else {
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;
}
if matches!(attr.kind, AttrKind::Normal(..))
&& attr.style == AttrStyle::Outer
&& is_present_in_source(cx, attr.span)
{
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());
@ -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>) {
if_chain! {
if meets_msrv(msrv.as_ref(), &msrvs::TOOL_ATTRIBUTES);
if meets_msrv(msrv, msrvs::TOOL_ATTRIBUTES);
// check cfg_attr
if attr.has_name(sym::cfg_attr);
if let Some(items) = attr.meta_item_list();

View File

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

View File

@ -137,7 +137,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
}
for (n, expr) in self.terminals.iter().enumerate() {
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));
}
@ -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_rhs, expr_rhs);
then {
#[allow(clippy::cast_possible_truncation)]
#[expect(clippy::cast_possible_truncation)]
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();
self.terminals.push(e);
if n < 32 {
#[allow(clippy::cast_possible_truncation)]
#[expect(clippy::cast_possible_truncation)]
Ok(Bool::Term(n as u8))
} else {
Err("too many literals".to_owned())

View File

@ -57,7 +57,7 @@ impl BorrowAsPtr {
impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr {
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;
}

View File

@ -16,10 +16,10 @@ pub(super) fn check(
cast_expr: &Expr<'_>,
cast_from: Ty<'_>,
cast_to: Ty<'_>,
msrv: &Option<RustcVersion>,
msrv: Option<RustcVersion>,
) {
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_to.is_integral();
if cast_from.is_signed();

View File

@ -16,7 +16,7 @@ pub(super) fn check(
cast_op: &Expr<'_>,
cast_from: Ty<'_>,
cast_to: Ty<'_>,
msrv: &Option<RustcVersion>,
msrv: Option<RustcVersion>,
) {
if !should_lint(cx, expr, cast_from, cast_to, msrv) {
return;
@ -68,7 +68,7 @@ fn should_lint(
expr: &Expr<'_>,
cast_from: Ty<'_>,
cast_to: Ty<'_>,
msrv: &Option<RustcVersion>,
msrv: Option<RustcVersion>,
) -> bool {
// Do not suggest using From in consts/statics until it is valid to do so (see #2267).
if in_constant(cx, expr.hir_id) {
@ -93,9 +93,9 @@ fn should_lint(
} else {
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))
},

View File

@ -8,9 +8,9 @@ use rustc_semver::RustcVersion;
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
if !meets_msrv(msrv.as_ref(), &msrvs::PTR_SLICE_RAW_PARTS) {
if !meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS) {
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)?;
// 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
if let Some(prev_info) = expr_cast_chain_tys(cx, cast_expr) {
Some(CastChainInfo {

View File

@ -306,7 +306,7 @@ declare_clippy_lint! {
/// Checks for casts of `&T` to `&mut T` anywhere in the code.
///
/// ### 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
/// mutable.
///
@ -413,6 +413,7 @@ declare_clippy_lint! {
}
declare_clippy_lint! {
/// ### What it does
/// Checks for `as` casts between raw pointers to slices with differently sized elements.
///
/// ### Why is this bad?
@ -531,7 +532,7 @@ impl_lint_pass!(Casts => [
impl<'tcx> LateLintPass<'tcx> for Casts {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !in_external_macro(cx.sess(), expr.span) {
ptr_as_ptr::check(cx, expr, &self.msrv);
ptr_as_ptr::check(cx, expr, self.msrv);
}
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_precision_loss::check(cx, expr, cast_from, cast_to);
cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
cast_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);
}
}
@ -571,8 +572,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
cast_ref_to_mut::check(cx, expr);
cast_ptr_alignment::check(cx, expr);
char_lit_as_u8::check(cx, expr);
ptr_as_ptr::check(cx, expr, &self.msrv);
cast_slice_different_sizes::check(cx, expr, &self.msrv);
ptr_as_ptr::check(cx, expr, self.msrv);
cast_slice_different_sizes::check(cx, expr, self.msrv);
}
extract_msrv_attr!(LateContext);

View File

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

View File

@ -30,7 +30,6 @@ declare_clippy_lint! {
/// Could be written:
///
/// ```rust
/// # use std::convert::TryFrom;
/// # let foo = 1;
/// # let _ =
/// i32::try_from(foo).is_ok()
@ -57,7 +56,7 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);
impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
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;
}
@ -123,7 +122,7 @@ struct Conversion<'a> {
}
/// The kind of conversion that is checked
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum ConversionType {
SignedToUnsigned,
SignedToSigned,

View File

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

View File

@ -109,7 +109,10 @@ fn check_arm<'tcx>(
(Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b),
};
// 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
if match inner {
IfLetOrMatch::IfLet(_, _, body, els) => {

View File

@ -1,7 +1,7 @@
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::source::snippet_with_applicability;
use clippy_utils::{is_in_cfg_test, is_in_test_function};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
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 };
if cx.tcx.is_diagnostic_item(sym::dbg_macro, macro_call.def_id) {
// 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;
}
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>) {
// start from the `let mut _ = _::default();` and look at all the following
// 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> {
#[allow(clippy::too_many_lines)]
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
match &expr.kind {
ExprKind::Call(func, args) => {

View File

@ -25,7 +25,7 @@ declare_clippy_lint! {
///
/// fn main() {
/// 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() {
/// 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
/// The `avoid_breaking_exported_api` config option was added, which
/// enables the `enum_variant_names` lint for public items.
/// ```
#[clippy::version = "1.54.0"]
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"

View File

@ -168,7 +168,7 @@ struct RefPat {
}
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<'_>) {
// Skip path expressions from deref calls. e.g. `Deref::deref(e)`
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) {
match state {
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::ty::{implements_trait, is_copy};
use clippy_utils::{is_lint_allowed, match_def_path};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
use rustc_hir::{
BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, TraitRef, UnsafeSource, Unsafety,
@ -101,8 +102,8 @@ declare_clippy_lint! {
/// types.
///
/// ### Why is this bad?
/// To avoid surprising behaviour, these traits should
/// agree and the behaviour of `Copy` cannot be overridden. In almost all
/// To avoid surprising behavior, these traits should
/// agree and the behavior of `Copy` cannot be overridden. In almost all
/// situations a `Copy` type should have a `Clone` implementation that does
/// nothing more than copy the object, which is what `#[derive(Copy, Clone)]`
/// gets you.
@ -156,11 +157,44 @@ declare_clippy_lint! {
"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 => [
EXPL_IMPL_CLONE_ON_COPY,
DERIVE_HASH_XOR_EQ,
DERIVE_ORD_XOR_PARTIAL_ORD,
UNSAFE_DERIVE_DESERIALIZE
UNSAFE_DERIVE_DESERIALIZE,
DERIVE_PARTIAL_EQ_WITHOUT_EQ
]);
impl<'tcx> LateLintPass<'tcx> for Derive {
@ -171,14 +205,14 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
}) = item.kind
{
let ty = cx.tcx.type_of(item.def_id);
let is_automatically_derived =
cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
let is_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_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
if is_automatically_derived {
check_unsafe_derive_deserialize(cx, item, trait_ref, ty);
check_partial_eq_without_eq(cx, item.span, trait_ref, ty);
} else {
check_copy_clone(cx, item, trait_ref, ty);
}
@ -419,3 +453,36 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
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::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_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<'_>) {
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,
None => return,
};

View File

@ -198,7 +198,7 @@ declare_clippy_lint! {
"presence of `fn main() {` in code examples"
}
#[allow(clippy::module_name_repetitions)]
#[expect(clippy::module_name_repetitions)]
#[derive(Clone)]
pub struct DocMarkdown {
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
/// need to keep track of
/// the spans but this function is inspired from the later.
#[allow(clippy::cast_possible_truncation)]
#[expect(clippy::cast_possible_truncation)]
#[must_use]
pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: Span) -> (String, Vec<(usize, Span)>) {
// one-line comments lose their prefix
@ -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
/// actually care about rendering them, just pretend that all broken links are
/// point to a fake address.
#[allow(clippy::unnecessary_wraps)] // we're following a type signature
#[expect(clippy::unnecessary_wraps)] // we're following a type signature
fn fake_broken_link_callback<'a>(_: BrokenLink<'_>) -> Option<(CowStr<'a>, CowStr<'a>)> {
Some(("fake".into(), "fake".into()))
}

View File

@ -40,7 +40,7 @@ declare_clippy_lint! {
declare_lint_pass!(DoubleComparisons => [DOUBLE_COMPARISONS]);
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) {
let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (&lhs.kind, &rhs.kind) {
(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]);
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<'_>) {
let (cond_expr, then_expr, else_expr) = match higher::If::hir(expr) {
Some(higher::If { cond, then, r#else }) => (cond, then, r#else),
@ -319,7 +319,7 @@ struct Insertion<'tcx> {
/// `or_insert_with`.
/// * Determine if there's any sub-expression that can't be placed in a closure.
/// * Determine if there's only a single insert statement. `or_insert` can be used in this case.
#[allow(clippy::struct_excessive_bools)]
#[expect(clippy::struct_excessive_bools)]
struct InsertSearcher<'cx, 'tcx> {
cx: &'cx LateContext<'tcx>,
/// 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::{self, IntTy, UintTy};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use std::convert::TryFrom;
declare_clippy_lint! {
/// ### What it does
@ -37,7 +36,7 @@ declare_clippy_lint! {
declare_lint_pass!(UnportableVariant => [ENUM_CLIKE_UNPORTABLE_VARIANT]);
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<'_>) {
if cx.tcx.data_layout.pointer_size.bits() != 64 {
return;

View File

@ -240,7 +240,7 @@ impl LateLintPass<'_> for EnumVariantNames {
assert!(last.is_some());
}
#[allow(clippy::similar_names)]
#[expect(clippy::similar_names)]
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
let item_name = item.ident.name.as_str();
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]);
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<'_>) {
if_chain! {
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 {
#[allow(clippy::match_same_arms)]
match (&left.kind, &right.kind) {
// do not suggest to dereference literals
(&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_span::{sym, Span};
use std::convert::TryInto;
declare_clippy_lint! {
/// ### What it does
/// Checks for excessive

View File

@ -32,7 +32,6 @@ declare_clippy_lint! {
/// // Good
/// struct Foo(i32);
///
/// use std::convert::TryFrom;
/// impl TryFrom<String> for Foo {
/// type 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
// ranges [-16777215, 16777216) for type f32 as whole number floats outside
// 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> {
match value {
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 {
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;
}

View File

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

View File

@ -62,7 +62,7 @@ declare_clippy_lint! {
declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]);
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<'_>) {
use rustc_span::BytePos;

View File

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

View File

@ -14,7 +14,6 @@ use rustc_middle::ty;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{symbol::Ident, Span};
use std::convert::TryInto;
declare_clippy_lint! {
/// ### 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 let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr);
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);
if !found_slices.is_empty();

View File

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

View File

@ -46,6 +46,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(derivable_impls::DERIVABLE_IMPLS),
LintId::of(derive::DERIVE_HASH_XOR_EQ),
LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
LintId::of(disallowed_methods::DISALLOWED_METHODS),
LintId::of(disallowed_types::DISALLOWED_TYPES),
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_REF),
LintId::of(drop_forget_ref::UNDROPPED_MANUALLY_DROPS),
LintId::of(duplicate_mod::DUPLICATE_MOD),
LintId::of(duration_subsec::DURATION_SUBSEC),
LintId::of(entry::MAP_ENTRY),
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(escape::BOXED_LOCAL),
LintId::of(eta_reduction::REDUNDANT_CLOSURE),
LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION),
LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE),
LintId::of(explicit_write::EXPLICIT_WRITE),
LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
LintId::of(float_literal::EXCESSIVE_PRECISION),
@ -228,6 +228,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(misc_early::REDUNDANT_PATTERN),
LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
LintId::of(mut_key::MUTABLE_KEY_TYPE),
LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
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::RANGE_ZIP_WITH_LEN),
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_closure_call::REDUNDANT_CLOSURE_CALL),
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_named_constructors::SELF_NAMED_CONSTRUCTORS),
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(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
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_parens::DOUBLE_PARENS),
LintId::of(duration_subsec::DURATION_SUBSEC),
LintId::of(eval_order_dependence::DIVERGING_SUB_EXPRESSION),
LintId::of(explicit_write::EXPLICIT_WRITE),
LintId::of(format::USELESS_FORMAT),
LintId::of(functions::TOO_MANY_ARGUMENTS),
@ -59,6 +58,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
LintId::of(needless_bool::BOOL_COMPARISON),
LintId::of(needless_bool::NEEDLESS_BOOL),

View File

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

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_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
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::SELF_NAMED_MODULE_FILES),
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(default::FIELD_REASSIGN_WITH_DEFAULT),
LintId::of(dereference::NEEDLESS_BORROW),
LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
LintId::of(disallowed_methods::DISALLOWED_METHODS),
LintId::of(disallowed_types::DISALLOWED_TYPES),
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(drop_forget_ref::DROP_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(format_impl::PRINT_IN_FORMAT_IMPL),
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(mut_key::MUTABLE_KEY_TYPE),
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_OP_ASSIGN_IMPL),
])

View File

@ -8,6 +8,7 @@
#![feature(iter_intersperse)]
#![feature(let_chains)]
#![feature(let_else)]
#![feature(lint_reasons)]
#![feature(once_cell)]
#![feature(rustc_private)]
#![feature(stmt_expr_attributes)]
@ -210,6 +211,7 @@ mod doc;
mod double_comparison;
mod double_parens;
mod drop_forget_ref;
mod duplicate_mod;
mod duration_subsec;
mod else_if_without_else;
mod empty_drop;
@ -223,7 +225,6 @@ mod equatable_if_let;
mod erasing_op;
mod escape;
mod eta_reduction;
mod eval_order_dependence;
mod excessive_bools;
mod exhaustive_items;
mod exit;
@ -299,6 +300,7 @@ mod missing_const_for_fn;
mod missing_doc;
mod missing_enforced_import_rename;
mod missing_inline;
mod mixed_read_write_in_expression;
mod module_style;
mod modulo_arithmetic;
mod mut_key;
@ -345,6 +347,7 @@ mod ptr_offset_with_cast;
mod pub_use;
mod question_mark;
mod ranges;
mod rc_clone_in_vec_init;
mod redundant_clone;
mod redundant_closure_call;
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`
pub use crate::utils::conf::Conf;
use crate::utils::conf::TryConf;
use crate::utils::conf::{format_error, TryConf};
/// Register all pre expansion lints
///
@ -462,7 +465,7 @@ pub fn read_conf(sess: &Session) -> Conf {
sess.struct_err(&format!(
"error reading Clippy's configuration file `{}`: {}",
file_name.display(),
error
format_error(error)
))
.emit();
}
@ -473,7 +476,7 @@ pub fn read_conf(sess: &Session) -> Conf {
/// Register all lints and lint groups with the rustc plugin registry
///
/// 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) {
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 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(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_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::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(assign_ops::AssignOps));
store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq));
store.register_late_pass(|| Box::new(eval_order_dependence::EvalOrderDependence));
store.register_late_pass(|| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
store.register_late_pass(|| Box::new(missing_doc::MissingDoc::new()));
store.register_late_pass(|| Box::new(missing_inline::MissingInline));
store.register_late_pass(move || Box::new(exhaustive_items::ExhaustiveItems));
@ -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;
store.register_late_pass(move || Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace));
store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default()));
// 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)]
pub struct LiteralDigitGrouping {
lint_fraction_readability: bool,
@ -432,7 +431,7 @@ impl LiteralDigitGrouping {
}
}
#[allow(clippy::module_name_repetitions)]
#[expect(clippy::module_name_repetitions)]
#[derive(Copy, Clone)]
pub struct DecimalLiteralRepresentation {
threshold: u64,

View File

@ -620,7 +620,6 @@ declare_lint_pass!(Loops => [
]);
impl<'tcx> LateLintPass<'tcx> for Loops {
#[allow(clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let for_loop = higher::ForLoop::hir(expr);
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.
/// The iteratee must be a range literal.
#[allow(clippy::too_many_lines)]
#[expect(clippy::too_many_lines)]
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
pat: &'tcx Pat<'_>,

View File

@ -13,7 +13,7 @@ use rustc_span::symbol::{sym, Symbol};
use rustc_typeck::hir_ty_to_ty;
use std::iter::Iterator;
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Eq)]
enum IncrementVisitorVarState {
Initial, // Not examined yet
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
}
#[allow(clippy::too_many_lines)]
#[expect(clippy::too_many_lines)]
fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &Expr<'_>) -> bool {
struct AfterLoopVisitor<'a, 'b, 'tcx> {
cx: &'a LateContext<'tcx>,

View File

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

View File

@ -12,7 +12,7 @@ declare_clippy_lint! {
///
/// ### Why is this bad?
/// 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
/// ```no_run

View File

@ -48,7 +48,7 @@ impl_lint_pass!(ManualBits => [MANUAL_BITS]);
impl<'tcx> LateLintPass<'tcx> for ManualBits {
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;
}

View File

@ -46,7 +46,7 @@ declare_clippy_lint! {
declare_lint_pass!(ManualMap => [MANUAL_MAP]);
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<'_>) {
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),

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
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_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@ -61,7 +61,7 @@ declare_clippy_lint! {
"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 {
msrv: Option<RustcVersion>,
}
@ -75,7 +75,7 @@ impl ManualNonExhaustiveStruct {
impl_lint_pass!(ManualNonExhaustiveStruct => [MANUAL_NON_EXHAUSTIVE]);
#[allow(clippy::module_name_repetitions)]
#[expect(clippy::module_name_repetitions)]
pub struct ManualNonExhaustiveEnum {
msrv: Option<RustcVersion>,
constructed_enum_variants: FxHashSet<(DefId, DefId)>,
@ -97,7 +97,7 @@ impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]);
impl EarlyLintPass for ManualNonExhaustiveStruct {
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;
}
@ -149,7 +149,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
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;
}
@ -160,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
let id = cx.tcx.hir().local_def_id(v.id);
(matches!(v.data, hir::VariantData::Unit(_))
&& 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))
});
if let Some((id, span)) = iter.next()

View File

@ -68,7 +68,7 @@ enum StripKind {
impl<'tcx> LateLintPass<'tcx> for ManualStrip {
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;
}

View File

@ -144,7 +144,7 @@ impl MapClone {
fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) {
let mut applicability = Applicability::MachineApplicable;
let (message, sugg_method) = if is_copy && meets_msrv(self.msrv.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")
} else {
("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;
#[allow(clippy::too_many_lines)]
#[expect(clippy::too_many_lines)]
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 {
let mut h = SpanlessHash::new(cx);
@ -225,9 +225,9 @@ fn iter_matching_struct_fields<'a>(
Iter(left.iter(), right.iter())
}
#[allow(clippy::similar_names)]
#[expect(clippy::similar_names)]
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 {
match pat.kind {
PatKind::Wild | PatKind::Binding(.., None) => Self::Wild,

View File

@ -1,15 +1,22 @@
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::{get_parent_expr, is_refutable, peel_blocks};
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_span::Span;
use super::MATCH_SINGLE_BINDING;
#[allow(clippy::too_many_lines)]
pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
enum AssignmentExpr {
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) {
return;
}
@ -42,61 +49,59 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
let mut applicability = Applicability::MaybeIncorrect;
match arms[0].pat.kind {
PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => {
// If this match is in a local (`let`) stmt
let (target_span, sugg) = if let Some(parent_let_node) = opt_parent_let(cx, ex) {
(
parent_let_node.span,
let (target_span, sugg) = match opt_parent_assign_span(cx, ex) {
Some(AssignmentExpr::Assign { span, match_span }) => {
let sugg = sugg_with_curlies(
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!(
"let {} = {};\n{}let {} = {};",
snippet_with_applicability(cx, bind_names, "..", &mut applicability),
snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
" ".repeat(indent_of(cx, expr.span).unwrap_or(0)),
snippet_with_applicability(cx, parent_let_node.pat.span, "..", &mut applicability),
snippet_with_applicability(cx, pat_span, "..", &mut applicability),
snippet_body
),
)
} else {
// If we are in closure, we need curly braces around suggestion
let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
let (mut cbrace_start, mut cbrace_end) = ("".to_string(), "".to_string());
if let Some(parent_expr) = get_parent_expr(cx, expr) {
if let ExprKind::Closure(..) = parent_expr.kind {
cbrace_end = format!("\n{}}}", indent);
// Fix body indent due to the closure
indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
cbrace_start = format!("{{\n{}", indent);
}
}
// If the parent is already an arm, and the body is another match statement,
// we need curly braces around suggestion
let parent_node_id = cx.tcx.hir().get_parent_node(expr.hir_id);
if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) {
if let ExprKind::Match(..) = arm.body.kind {
cbrace_end = format!("\n{}}}", indent);
// Fix body indent due to the match
indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
cbrace_start = format!("{{\n{}", indent);
}
}
(
expr.span,
format!(
"{}let {} = {};\n{}{}{}",
cbrace_start,
snippet_with_applicability(cx, bind_names, "..", &mut applicability),
snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
indent,
snippet_body,
cbrace_end
),
)
),
None => {
let sugg = sugg_with_curlies(
cx,
(ex, expr),
(bind_names, matched_vars),
&*snippet_body,
&mut applicability,
None,
);
(expr.span, sugg)
},
};
span_lint_and_sugg(
cx,
MATCH_SINGLE_BINDING,
target_span,
"this match could be written as a `let` statement",
"consider using `let` statement",
"consider using a `let` statement",
sugg,
applicability,
);
@ -110,6 +115,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
indent,
snippet_body
);
span_lint_and_sugg(
cx,
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
fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'a>> {
/// Returns true if the `ex` match expression is in a local (`let`) or assign expression
fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<AssignmentExpr> {
let map = &cx.tcx.hir();
if_chain! {
if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id));
if let Some(Node::Local(parent_let_expr)) = map.find(map.get_parent_node(parent_arm_expr.hir_id));
then {
return Some(parent_let_expr);
}
if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id)) {
return match map.find(map.get_parent_node(parent_arm_expr.hir_id)) {
Some(Node::Local(parent_let_expr)) => Some(AssignmentExpr::Local {
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
}
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};
#[allow(clippy::too_many_lines)]
#[expect(clippy::too_many_lines)]
pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
let ty = cx.typeck_results().expr_ty(ex).peel_refs();
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| {
let path = match &peel_hir_pat_refs(pat).0.kind {
PatKind::Path(path) => {
#[allow(clippy::match_same_arms)]
let id = match cx.qpath_res(path, pat.hir_id) {
Res::Def(
DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,

View File

@ -658,7 +658,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
}
if !contains_cfg_arm(cx, expr, ex, arms) {
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_same_arms::check(cx, arms);
@ -685,7 +685,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
match_wild_err_arm::check(cx, ex, arms);
wild_in_or_pats::check(cx, arms);
} else {
if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) {
if meets_msrv(self.msrv, msrvs::MATCHES_MACRO) {
match_like_matches::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>(
cx: &LateContext<'_>,
arms: &[Arm<'_>],

View File

@ -254,7 +254,7 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace {
then {
check_replace_option_with_none(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);
}
}

View File

@ -10,16 +10,16 @@ use rustc_span::{sym, Span};
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 inner_ty = match recv_ty.kind() {
// `Option<T>` -> `T`
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)
},
_ 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) {
// <T as Iterator>::Item
Some(ty) => ty,

View File

@ -13,7 +13,7 @@ pub(super) fn check(
cx: &LateContext<'_>,
_expr: &rustc_hir::Expr<'_>,
recv: &rustc_hir::Expr<'_>,
msrv: Option<&RustcVersion>,
msrv: Option<RustcVersion>,
expect_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);
// Test the version to make sure the lint can be showed (expect_err has been
// introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982)
if meets_msrv(msrv, &msrvs::EXPECT_ERR);
if meets_msrv(msrv, msrvs::EXPECT_ERR);
// Grabs the `Result<T, E>` type
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::is_in_test_function;
use clippy_utils::ty::is_type_diagnostic_item;
use rustc_hir as hir;
use rustc_lint::LateContext;
@ -7,7 +8,7 @@ use rustc_span::sym;
use super::EXPECT_USED;
/// lint use of `expect()` for `Option`s and `Result`s
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
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 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
};
if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
return;
}
if let Some((lint, kind, none_value)) = mess {
span_lint_and_help(
cx,

View File

@ -14,10 +14,10 @@ pub(super) fn check<'tcx>(
expr: &'tcx hir::Expr<'_>,
recv: &'tcx hir::Expr<'_>,
arg: &'tcx hir::Expr<'_>,
msrv: Option<&RustcVersion>,
msrv: Option<RustcVersion>,
) {
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;
}

View File

@ -15,9 +15,9 @@ pub(super) fn check<'tcx>(
expr: &'tcx Expr<'_>,
self_arg: &'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;
}

View File

@ -19,13 +19,13 @@ pub(super) fn check<'tcx>(
recv: &'tcx hir::Expr<'_>,
map_arg: &'tcx hir::Expr<'_>,
unwrap_arg: &'tcx hir::Expr<'_>,
msrv: Option<&RustcVersion>,
msrv: Option<RustcVersion>,
) -> bool {
// 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_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;
}

View File

@ -1563,7 +1563,7 @@ declare_clippy_lint! {
#[clippy::version = "1.39.0"]
pub MANUAL_SATURATING_ARITHMETIC,
style,
"`.chcked_add/sub(x).unwrap_or(MAX/MIN)`"
"`.checked_add/sub(x).unwrap_or(MAX/MIN)`"
}
declare_clippy_lint! {
@ -1776,8 +1776,6 @@ declare_clippy_lint! {
///
/// ### Example
/// ```rust
/// use std::iter::FromIterator;
///
/// let five_fives = std::iter::repeat(5).take(5);
///
/// let v = Vec::from_iter(five_fives);
@ -2200,14 +2198,23 @@ declare_clippy_lint! {
pub struct Methods {
avoid_breaking_exported_api: bool,
msrv: Option<RustcVersion>,
allow_expect_in_tests: bool,
allow_unwrap_in_tests: bool,
}
impl Methods {
#[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 {
avoid_breaking_exported_api,
msrv,
allow_expect_in_tests,
allow_unwrap_in_tests,
}
}
}
@ -2306,7 +2313,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
return;
}
check_methods(cx, expr, self.msrv.as_ref());
self.check_methods(cx, expr);
match expr.kind {
hir::ExprKind::Call(func, args) => {
@ -2322,7 +2329,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
single_char_add_str::check(cx, expr, args);
into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args);
single_char_pattern::check(cx, expr, method_call.ident.name, args);
unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv.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 => {
let mut info = BinaryExprInfo {
@ -2505,196 +2512,201 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
extract_msrv_attr!(LateContext);
}
#[allow(clippy::too_many_lines)]
fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) {
if let Some((name, [recv, args @ ..], span)) = method_call(expr) {
match (name, args) {
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
zst_offset::check(cx, expr, recv);
},
("and_then", [arg]) => {
let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
if !biom_option_linted && !biom_result_linted {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
}
},
("as_deref" | "as_deref_mut", []) => {
needless_option_as_deref::check(cx, expr, recv, name);
},
("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv),
("collect", []) => match method_call(recv) {
Some((name @ ("cloned" | "copied"), [recv2], _)) => {
iter_cloned_collect::check(cx, name, expr, recv2);
impl Methods {
#[allow(clippy::too_many_lines)]
fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let Some((name, [recv, args @ ..], span)) = method_call(expr) {
match (name, args) {
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
zst_offset::check(cx, expr, recv);
},
Some(("map", [m_recv, m_arg], _)) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
},
Some(("take", [take_self_arg, take_arg], _)) => {
if meets_msrv(msrv, &msrvs::STR_REPEAT) {
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
("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");
}
},
_ => {},
},
(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);
("as_deref" | "as_deref_mut", []) => {
needless_option_as_deref::check(cx, expr, recv, name);
},
Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
_ => {},
},
("drain", [arg]) => {
iter_with_drain::check(cx, expr, recv, span, arg);
},
("expect", [_]) => match method_call(recv) {
Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, msrv, span, err_span),
_ => expect_used::check(cx, expr, recv),
},
("extend", [arg]) => {
string_extend_chars::check(cx, expr, recv, arg);
extend_with_drain::check(cx, expr, recv, arg);
},
("filter_map", [arg]) => {
unnecessary_filter_map::check(cx, expr, arg, name);
filter_map_identity::check(cx, expr, arg, span);
},
("find_map", [arg]) => {
unnecessary_filter_map::check(cx, expr, arg, name);
},
("flat_map", [arg]) => {
flat_map_identity::check(cx, expr, arg, span);
flat_map_option::check(cx, expr, arg, span);
},
(name @ "flatten", args @ []) => match method_call(recv) {
Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
_ => {},
},
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
("for_each", [_]) => {
if let Some(("inspect", [_, _], span2)) = method_call(recv) {
inspect_for_each::check(cx, expr, span2);
}
},
("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
("is_file", []) => filetype_is_file::check(cx, expr, recv),
("is_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);
("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, self.msrv),
("collect", []) => match method_call(recv) {
Some((name @ ("cloned" | "copied"), [recv2], _)) => {
iter_cloned_collect::check(cx, name, expr, recv2);
},
Some(("get_mut", [recv, get_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, true);
Some(("map", [m_recv, m_arg], _)) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
},
Some(("or", [recv, or_arg], or_span)) => {
or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
Some(("take", [take_self_arg, take_arg], _)) => {
if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
}
},
_ => {},
}
unwrap_used::check(cx, expr, recv);
},
("unwrap_or", [u_arg]) => match method_call(recv) {
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
},
Some(("map", [m_recv, m_arg], span)) => {
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
(name @ "count", args @ []) => match method_call(recv) {
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
iter_count::check(cx, expr, recv2, name2);
},
Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
_ => {},
},
("drain", [arg]) => {
iter_with_drain::check(cx, expr, recv, span, arg);
},
("expect", [_]) => match method_call(recv) {
Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, 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),
];
#[derive(Clone, Copy, PartialEq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum SelfKind {
Value,
Ref,

View File

@ -19,9 +19,9 @@ pub(super) fn check<'tcx>(
as_ref_recv: &hir::Expr<'_>,
map_arg: &hir::Expr<'_>,
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;
}

View File

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

View File

@ -26,7 +26,7 @@ pub fn check<'tcx>(
expr: &'tcx Expr<'tcx>,
method_name: Symbol,
args: &'tcx [Expr<'tcx>],
msrv: Option<&RustcVersion>,
msrv: Option<RustcVersion>,
) {
if_chain! {
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 ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = parent.kind;
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`
[
Adjustment {
kind: Adjust::Deref(None),
..
target: referent_ty,
},
Adjustment {
kind: Adjust::Borrow(_),
@ -82,7 +81,7 @@ fn check_addr_of_expr(
| [
Adjustment {
kind: Adjust::Deref(None),
..
target: referent_ty,
},
Adjustment {
kind: Adjust::Borrow(_),
@ -97,7 +96,7 @@ fn check_addr_of_expr(
| [
Adjustment {
kind: Adjust::Deref(None),
..
target: referent_ty,
},
Adjustment {
kind: Adjust::Deref(Some(OverloadedDeref { .. })),
@ -107,17 +106,24 @@ fn check_addr_of_expr(
kind: Adjust::Borrow(_),
target: target_ty,
},
] => Some(target_ty),
_ => None,
};
] = adjustments[..];
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
// restriction is to ensure there is not overlap between `redundant_clone` and this lint.
if is_copy(cx, receiver_ty) || is_cow_into_owned(cx, method_name, method_def_id);
let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty);
let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty);
// 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);
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 {
span_lint_and_sugg(
cx,
@ -192,7 +198,7 @@ fn check_into_iter_call_arg(
expr: &Expr<'_>,
method_name: Symbol,
receiver: &Expr<'_>,
msrv: Option<&RustcVersion>,
msrv: Option<RustcVersion>,
) -> bool {
if_chain! {
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) {
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
// 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.

View File

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

View File

@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
span: Span,
hir_id: HirId,
) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::CONST_IF_MATCH) {
if !meets_msrv(self.msrv, msrvs::CONST_IF_MATCH) {
return;
}
@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
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()) {
cx.tcx.sess.span_err(span, err.as_ref());
}

View File

@ -40,8 +40,8 @@ declare_clippy_lint! {
/// let a = tmp + x;
/// ```
#[clippy::version = "pre 1.29.0"]
pub EVAL_ORDER_DEPENDENCE,
suspicious,
pub MIXED_READ_WRITE_IN_EXPRESSION,
restriction,
"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"
}
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 {
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) {
span_lint_and_note(
self.cx,
EVAL_ORDER_DEPENDENCE,
MIXED_READ_WRITE_IN_EXPRESSION,
expr.span,
&format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)),
Some(self.write_expr.span),

View File

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

View File

@ -53,7 +53,7 @@ fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
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 (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) {
let op_snippet = match op.node {
@ -75,7 +75,7 @@ impl LateLintPass<'_> for NeedlessBitwiseBool {
expr.span,
"use of bitwise operator instead of lazy operator between booleans",
|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);
}
},

View File

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

View File

@ -34,7 +34,6 @@ declare_clippy_lint! {
declare_lint_pass!(NegMultiply => [NEG_MULTIPLY]);
#[allow(clippy::match_same_arms)]
impl<'tcx> LateLintPass<'tcx> for NegMultiply {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
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<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
#[allow(clippy::too_many_lines)]
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
if let hir::ItemKind::Impl(hir::Impl {
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) {
let interned_name = ident.name.as_str();
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
/// [this issue](https://github.com/rust-lang/rust-clippy/issues/5953)
/// that explains a real case in which this false positive
/// led to an **undefined behaviour** introduced with unsafe code.
/// led to an **undefined behavior** introduced with unsafe code.
///
/// ### Example
///
@ -124,7 +124,7 @@ impl<'tcx> PassByRefOrValue {
// Cap the calculated bit width at 32-bits to reduce
// portability problems between 32 and 64-bit targets
let bit_width = cmp::min(bit_width, 32);
#[allow(clippy::integer_division)]
#[expect(clippy::integer_division)]
let byte_width = bit_width / 8;
// Use a limit of 2 times the register byte width
byte_width * 2

View File

@ -163,7 +163,6 @@ enum Level {
Lower,
}
#[allow(rustc::usage_of_ty_tykind)]
fn find_first_mismatch<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>) -> Option<(Span, Mutability, Level)> {
let mut result = None;
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> {
struct V<'cx, '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);
},
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);
}
},
@ -207,7 +207,13 @@ impl<'tcx> LateLintPass<'tcx> for Ranges {
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) {
return;
}
@ -219,21 +225,19 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
_ => return,
};
// value, name, order (higher/lower), inclusiveness
if let (Some((lval, lid, name_span, lval_span, lord, linc)), Some((rval, rid, _, rval_span, rord, rinc))) =
(check_range_bounds(cx, l), check_range_bounds(cx, r))
{
if let (Some(l), Some(r)) = (check_range_bounds(cx, left), check_range_bounds(cx, right)) {
// we only lint comparisons on the same name and with different
// direction
if lid != rid || lord == rord {
if l.id != r.id || l.ord == r.ord {
return;
}
let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(l), &lval, &rval);
if combine_and && ord == Some(rord) {
let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(l.expr), &l.val, &r.val);
if combine_and && ord == Some(r.ord) {
// order lower bound and upper bound
let (l_span, u_span, l_inc, u_inc) = if rord == Ordering::Less {
(lval_span, rval_span, linc, rinc)
let (l_span, u_span, l_inc, u_inc) = if r.ord == Ordering::Less {
(l.val_span, r.val_span, l.inc, r.inc)
} else {
(rval_span, lval_span, rinc, linc)
(r.val_span, l.val_span, r.inc, l.inc)
};
// we only lint inclusive lower bounds
if !l_inc {
@ -245,7 +249,7 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
("Range", "..")
};
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 hi = snippet_with_applicability(cx, u_span, "_", &mut applicability);
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),
applicability,
);
} else if !combine_and && ord == Some(lord) {
} else if !combine_and && ord == Some(l.ord) {
// `!_.contains(_)`
// order lower bound and upper bound
let (l_span, u_span, l_inc, u_inc) = if lord == Ordering::Less {
(lval_span, rval_span, linc, rinc)
let (l_span, u_span, l_inc, u_inc) = if l.ord == Ordering::Less {
(l.val_span, r.val_span, l.inc, r.inc)
} else {
(rval_span, lval_span, rinc, linc)
(r.val_span, l.val_span, r.inc, l.inc)
};
if l_inc {
return;
@ -275,7 +279,7 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
("RangeInclusive", "..=")
};
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 hi = snippet_with_applicability(cx, u_span, "_", &mut applicability);
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 {
let (inclusive, ordering) = match op.node {
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((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) {
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_span::source_map::{BytePos, Span};
use rustc_span::sym;
use std::convert::TryFrom;
use std::ops::ControlFlow;
macro_rules! unwrap_or_continue {
@ -71,7 +70,7 @@ declare_clippy_lint! {
declare_lint_pass!(RedundantClone => [REDUNDANT_CLONE]);
impl<'tcx> LateLintPass<'tcx> for RedundantClone {
#[allow(clippy::too_many_lines)]
#[expect(clippy::too_many_lines)]
fn check_fn(
&mut self,
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.
/// For exampel, `_1 = &mut _2` generate _1: {_2,...}
/// For example, `_1 = &mut _2` generate _1: {_2,...}
/// Known Problems: not sure all borrowed are tracked
struct PossibleOriginVisitor<'a, 'tcx> {
possible_origin: TransitiveRelation,

View File

@ -51,7 +51,7 @@ impl_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]);
impl EarlyLintPass for RedundantFieldNames {
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;
}

View File

@ -99,7 +99,7 @@ impl RedundantStaticLifetimes {
impl EarlyLintPass for RedundantStaticLifetimes {
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;
}

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