mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-10 07:04:18 +00:00
Merge 'rust-clippy/master' into clippyup
This commit is contained in:
parent
8d04a32ab4
commit
4587b6628d
239 changed files with 4446 additions and 1708 deletions
1
.github/deploy.sh
vendored
1
.github/deploy.sh
vendored
|
@ -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
|
||||
|
|
45
CHANGELOG.md
45
CHANGELOG.md
|
@ -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 -->
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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))
|
||||
},
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -306,7 +306,7 @@ declare_clippy_lint! {
|
|||
/// Checks for casts of `&T` to `&mut T` anywhere in the code.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// It’s basically guaranteed to be undefined behaviour.
|
||||
/// It’s 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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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
|
||||
/// };
|
||||
/// }
|
||||
/// ```
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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()))
|
||||
}
|
||||
|
|
|
@ -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)) => {
|
||||
|
|
102
clippy_lints/src/duplicate_mod.rs
Normal file
102
clippy_lints/src/duplicate_mod.rs
Normal 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",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(..)) => {},
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
])
|
||||
|
|
|
@ -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, it’s 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`
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<'_>,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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![];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<'_>],
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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),
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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| {
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
141
clippy_lints/src/rc_clone_in_vec_init.rs
Normal file
141
clippy_lints/src/rc_clone_in_vec_init.rs
Normal 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
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue