summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_lints
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /src/tools/clippy/clippy_lints
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz
rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/clippy/clippy_lints')
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml7
-rw-r--r--src/tools/clippy/clippy_lints/src/absolute_paths.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/allow_attributes.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/almost_complete_range.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/approx_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/as_conversions.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/asm_syntax.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_constants.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/async_yields_async.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs.rs166
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs137
-rw-r--r--src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs142
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs57
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs55
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs98
-rw-r--r--src/tools/clippy/clippy_lints/src/checked_conversions.rs113
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/collapsible_if.rs87
-rw-r--r--src/tools/clippy/clippy_lints/src/collection_is_never_read.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/comparison_chain.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/copy_iterator.rs40
-rw-r--r--src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs78
-rw-r--r--src/tools/clippy/clippy_lints/src/create_dir.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/dbg_macro.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs177
-rw-r--r--src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs124
-rw-r--r--src/tools/clippy/clippy_lints/src/default_union_representation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs287
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs124
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs231
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_macros.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_methods.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_names.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_types.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/link_with_quotes.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/markdown.rs119
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/missing_headers.rs86
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs (renamed from src/tools/clippy/clippy_lints/src/doc.rs)469
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs135
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs48
-rw-r--r--src/tools/clippy/clippy_lints/src/double_parens.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_forget_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/duplicate_mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/else_if_without_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_drop.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_enum.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/endian_bytes.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/error_impl_error.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_bools.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_nesting.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/exhaustive_items.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/exit.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/explicit_write.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs110
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs460
-rw-r--r--src/tools/clippy/clippy_lints/src/format.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs83
-rw-r--r--src/tools/clippy/clippy_lints/src/format_impl.rs117
-rw-r--r--src/tools/clippy/clippy_lints/src/format_push_string.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/formatting.rs215
-rw-r--r--src/tools/clippy/clippy_lints/src/four_forward_slashes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/from_str_radix_10.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs82
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/result.rs101
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/if_let_mutex.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/if_not_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs106
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs72
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_return.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs87
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs144
-rw-r--r--src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs86
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ineffective_open_options.rs95
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_impl.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/init_numbered_fields.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/instant_subtraction.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/int_plus_one.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/item_name_repetitions.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_statements.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_test_module.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs78
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs68
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_futures.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_include_file.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/large_stack_arrays.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_stack_frames.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs73
-rw-r--r--src/tools/clippy/clippy_lints/src/let_if_seq.rs161
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs40
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs206
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs113
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs99
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs125
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_find.rs177
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs94
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs124
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs172
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs118
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs89
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/main_recursion.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_assert.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs194
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_bits.rs84
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_clamp.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_float_methods.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_hash_one.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs118
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_range_patterns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_string_new.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs171
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/match_result_ok.rs55
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs94
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_filter.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs103
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_utils.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs135
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs102
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs90
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/try_err.rs162
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_replace.rs104
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs91
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytecount.rs76
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs90
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/err_expect.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs164
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_next.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs112
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_first.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs55
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs103
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs72
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_clone.rs89
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_flatten.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_identity.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs160
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/ok_expect.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_or_err_ok.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs90
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/search_is_some.rs103
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs56
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs85
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs121
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs112
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs312
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/useless_asref.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/utils.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/zst_offset.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/min_ident_chars.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs124
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs102
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_assert_message.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_trait_methods.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/module_style.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/multi_assignments.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_mut.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mutex_atomic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs93
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_continue.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs96
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_if.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_late_init.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs205
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_update.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_multiply.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs125
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs169
-rw-r--r--src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_canonical_impls.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs130
-rw-r--r--src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs117
-rw-r--r--src/tools/clippy/clippy_lints/src/octal_escapes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs68
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs143
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/eq_op.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_cmp.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/op_ref.rs57
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/option_env_unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs166
-rw-r--r--src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs63
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_unimplemented.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/partial_pub_fields.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_to_none.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/precedence.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/pub_use.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs153
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark_used.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs214
-rw-r--r--src/tools/clippy/clippy_lints/src/raw_strings.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_async_block.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs116
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs90
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_else.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_field_names.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs144
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ref_option_ref.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/ref_patterns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/reference.rs97
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs114
-rw-r--r--src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs56
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs106
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/self_named_constructors.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_block.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs48
-rw-r--r--src/tools/clippy/clippy_lints/src/serde_api.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/single_call_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/single_component_path_imports.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs77
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs112
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs278
-rw-r--r--src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs80
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs95
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs107
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs72
-rw-r--r--src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/temporary_assignment.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/to_digit_is_some.rs99
-rw-r--r--src/tools/clippy/clippy_lints/src/trailing_empty_array.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs329
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs81
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs110
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/borrowed_box.rs145
-rw-r--r--src/tools/clippy/clippy_lints/src/types/box_collection.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/types/option_option.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/types/rc_mutex.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/types/utils.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/types/vec_box.rs84
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unicode.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/uninhabited_references.rs84
-rw-r--r--src/tools/clippy/clippy_lints/src/uninit_vec.rs74
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs95
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/unnamed_address.rs100
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs77
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_peekable.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_rounding.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_self.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_unit.rs78
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs194
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap_in_result.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs206
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs115
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs79
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs166
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs93
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs132
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs199
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs148
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/visibility.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs108
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_div_zero.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs38
450 files changed, 10969 insertions, 10788 deletions
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 4bc27fd48..ad8b7ded4 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy_lints"
-version = "0.1.75"
+version = "0.1.76"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@@ -14,10 +14,9 @@ cargo_metadata = "0.15.3"
clippy_config = { path = "../clippy_config" }
clippy_utils = { path = "../clippy_utils" }
declare_clippy_lint = { path = "../declare_clippy_lint" }
-if_chain = "1.0"
-itertools = "0.10.1"
+itertools = "0.11"
quine-mc_cluskey = "0.2"
-regex-syntax = "0.7"
+regex-syntax = "0.8"
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", optional = true }
tempfile = { version = "3.3.0", optional = true }
diff --git a/src/tools/clippy/clippy_lints/src/absolute_paths.rs b/src/tools/clippy/clippy_lints/src/absolute_paths.rs
index 582423603..3822b83b4 100644
--- a/src/tools/clippy/clippy_lints/src/absolute_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/absolute_paths.rs
@@ -5,7 +5,7 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
use rustc_hir::{HirId, ItemKind, Node, Path};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::kw;
declare_clippy_lint! {
@@ -62,7 +62,7 @@ impl LateLintPass<'_> for AbsolutePaths {
} = self;
if !path.span.from_expansion()
- && let Some(node) = cx.tcx.hir().find(hir_id)
+ && let Some(node) = cx.tcx.opt_hir_node(hir_id)
&& !matches!(node, Node::Item(item) if matches!(item.kind, ItemKind::Use(_, _)))
&& let [first, rest @ ..] = path.segments
// Handle `::std`
diff --git a/src/tools/clippy/clippy_lints/src/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
index e3f4cf79d..39fc49dee 100644
--- a/src/tools/clippy/clippy_lints/src/allow_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
@@ -5,7 +5,7 @@ use rustc_ast as ast;
use rustc_errors::Applicability;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -52,24 +52,22 @@ declare_lint_pass!(AllowAttribute => [ALLOW_ATTRIBUTES]);
impl LateLintPass<'_> for AllowAttribute {
// Separate each crate's features.
fn check_attribute<'cx>(&mut self, cx: &LateContext<'cx>, attr: &'cx Attribute) {
- if_chain! {
- if !in_external_macro(cx.sess(), attr.span);
- if cx.tcx.features().lint_reasons;
- if let AttrStyle::Outer = attr.style;
- if let Some(ident) = attr.ident();
- if ident.name == rustc_span::symbol::sym::allow;
- if !is_from_proc_macro(cx, &attr);
- then {
- span_lint_and_sugg(
- cx,
- ALLOW_ATTRIBUTES,
- ident.span,
- "#[allow] attribute found",
- "replace it with",
- "expect".into(),
- Applicability::MachineApplicable,
- );
- }
+ if !in_external_macro(cx.sess(), attr.span)
+ && cx.tcx.features().lint_reasons
+ && let AttrStyle::Outer = attr.style
+ && let Some(ident) = attr.ident()
+ && ident.name == rustc_span::symbol::sym::allow
+ && !is_from_proc_macro(cx, &attr)
+ {
+ span_lint_and_sugg(
+ cx,
+ ALLOW_ATTRIBUTES,
+ ident.span,
+ "#[allow] attribute found",
+ "replace it with",
+ "expect".into(),
+ Applicability::MachineApplicable,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
index e85878eb5..57a5cd8fb 100644
--- a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
+++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
@@ -5,7 +5,7 @@ use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimit
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index b4f778f12..409ae0c85 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -4,7 +4,7 @@ use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_semver::RustcVersion;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol;
use std::f64::consts as f64;
diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
index 192bc7d9d..657d52d0e 100644
--- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
+++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
@@ -6,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::GenericArgKind;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
declare_clippy_lint! {
@@ -14,7 +14,9 @@ declare_clippy_lint! {
/// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`.
///
/// ### Why is this bad?
- /// `Arc<T>` is only `Send`/`Sync` when `T` is [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-Send-for-Arc%3CT%3E),
+ /// `Arc<T>` is an Atomic `RC<T>` and guarantees that updates to the reference counter are
+ /// Atomic. This is useful in multiprocessing scenarios. To send an `Arc<T>` across processes
+ /// and make use of the atomic ref counter, `T` must be [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-Send-for-Arc%3CT%3E),
/// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc`
///
/// ### Example
@@ -34,7 +36,7 @@ declare_clippy_lint! {
#[clippy::version = "1.72.0"]
pub ARC_WITH_NON_SEND_SYNC,
suspicious,
- "using `Arc` with a type that does not implement `Send` or `Sync`"
+ "using `Arc` with a type that does not implement `Send` and `Sync`"
}
declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]);
@@ -61,19 +63,25 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync {
cx,
ARC_WITH_NON_SEND_SYNC,
expr.span,
- "usage of an `Arc` that is not `Send` or `Sync`",
+ "usage of an `Arc` that is not `Send` and `Sync`",
|diag| {
with_forced_trimmed_paths!({
+ diag.note(format!("`Arc<{arg_ty}>` is not `Send` and `Sync` as:"));
+
if !is_send {
- diag.note(format!("the trait `Send` is not implemented for `{arg_ty}`"));
+ diag.note(format!("- the trait `Send` is not implemented for `{arg_ty}`"));
}
if !is_sync {
- diag.note(format!("the trait `Sync` is not implemented for `{arg_ty}`"));
+ diag.note(format!("- the trait `Sync` is not implemented for `{arg_ty}`"));
}
- diag.note(format!("required for `{ty}` to implement `Send` and `Sync`"));
+ diag.help("consider using an `Rc` instead. `Arc` does not provide benefits for non `Send` and `Sync` types");
+
+ diag.note("if you intend to use `Arc` with `Send` and `Sync` traits");
- diag.help("consider using an `Rc` instead or wrapping the inner type with a `Mutex`");
+ diag.note(format!(
+ "wrap the inner type with a `Mutex` or implement `Send` and `Sync` for `{arg_ty}`"
+ ));
});
},
);
diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs
index 2de205d80..e3daf75c3 100644
--- a/src/tools/clippy/clippy_lints/src/as_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs
@@ -3,7 +3,7 @@ use clippy_utils::is_from_proc_macro;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/asm_syntax.rs b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
index 9717aa9e9..feb6437ee 100644
--- a/src/tools/clippy/clippy_lints/src/asm_syntax.rs
+++ b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
@@ -3,7 +3,7 @@ use std::fmt;
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions};
use rustc_lint::{EarlyContext, EarlyLintPass, Lint};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
#[derive(Clone, Copy, PartialEq, Eq)]
enum AsmStyle {
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
index b90914e93..a15ec199a 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
use rustc_hir::Expr;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
index 71ec87a88..aec22965b 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
@@ -9,7 +9,7 @@ use rustc_hir::def::Res;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
index ec2447dae..3e5a01c45 100644
--- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs
+++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
@@ -4,7 +4,7 @@ use clippy_utils::ty::implements_trait;
use rustc_errors::Applicability;
use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index 38364af27..da3842287 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -5,7 +5,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sug
use clippy_utils::is_from_proc_macro;
use clippy_utils::macros::{is_panic, macro_backtrace};
use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
-use if_chain::if_chain;
use rustc_ast::token::{Token, TokenKind};
use rustc_ast::tokenstream::TokenTree;
use rustc_ast::{
@@ -18,9 +17,9 @@ use rustc_hir::{
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
+use rustc_session::{declare_lint_pass, impl_lint_pass};
use rustc_span::symbol::Symbol;
-use rustc_span::{sym, DUMMY_SP, Span};
+use rustc_span::{sym, Span, DUMMY_SP};
use semver::Version;
static UNIX_SYSTEMS: &[&str] = &[
@@ -121,7 +120,8 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
/// Checks for `#[deprecated]` annotations with a `since`
- /// field that is not a valid semantic version.
+ /// field that is not a valid semantic version. Also allows "TBD" to signal
+ /// future deprecation.
///
/// ### Why is this bad?
/// For checking the version of the deprecation, it must be
@@ -371,7 +371,7 @@ declare_clippy_lint! {
/// let _ = 1 / random();
/// }
/// ```
- #[clippy::version = "1.73.0"]
+ #[clippy::version = "1.74.0"]
pub SHOULD_PANIC_WITHOUT_EXPECT,
pedantic,
"ensures that all `should_panic` attributes specify its expected panic message"
@@ -406,20 +406,26 @@ declare_clippy_lint! {
/// Checks for `#[cfg(features = "...")]` and suggests to replace it with
/// `#[cfg(feature = "...")]`.
///
+ /// It also checks if `cfg(test)` was misspelled.
+ ///
/// ### Why is this bad?
- /// Misspelling `feature` as `features` can be sometimes hard to spot. It
+ /// Misspelling `feature` as `features` or `test` as `tests` can be sometimes hard to spot. It
/// may cause conditional compilation not work quietly.
///
/// ### Example
/// ```no_run
/// #[cfg(features = "some-feature")]
/// fn conditional() { }
+ /// #[cfg(tests)]
+ /// mod tests { }
/// ```
///
/// Use instead:
/// ```no_run
/// #[cfg(feature = "some-feature")]
/// fn conditional() { }
+ /// #[cfg(test)]
+ /// mod tests { }
/// ```
#[clippy::version = "1.69.0"]
pub MAYBE_MISUSED_CFG,
@@ -470,13 +476,11 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
return;
}
for item in items {
- if_chain! {
- if let NestedMetaItem::MetaItem(mi) = &item;
- if let MetaItemKind::NameValue(lit) = &mi.kind;
- if mi.has_name(sym::since);
- then {
- check_semver(cx, item.span(), lit);
- }
+ if let NestedMetaItem::MetaItem(mi) = &item
+ && let MetaItemKind::NameValue(lit) = &mi.kind
+ && mi.has_name(sym::since)
+ {
+ check_deprecated_since(cx, item.span(), lit);
}
}
}
@@ -579,15 +583,13 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
/// Returns the lint name if it is clippy lint.
fn extract_clippy_lint(lint: &NestedMetaItem) -> Option<Symbol> {
- if_chain! {
- if let Some(meta_item) = lint.meta_item();
- if meta_item.path.segments.len() > 1;
- if let tool_name = meta_item.path.segments[0].ident;
- if tool_name.name == sym::clippy;
- then {
- let lint_name = meta_item.path.segments.last().unwrap().ident.name;
- return Some(lint_name);
- }
+ if let Some(meta_item) = lint.meta_item()
+ && meta_item.path.segments.len() > 1
+ && let tool_name = meta_item.path.segments[0].ident
+ && tool_name.name == sym::clippy
+ {
+ let lint_name = meta_item.path.segments.last().unwrap().ident.name;
+ return Some(lint_name);
}
None
}
@@ -759,9 +761,9 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribut
}
}
-fn check_semver(cx: &LateContext<'_>, span: Span, lit: &MetaItemLit) {
+fn check_deprecated_since(cx: &LateContext<'_>, span: Span, lit: &MetaItemLit) {
if let LitKind::Str(is, _) = lit.kind {
- if Version::parse(is.as_str()).is_ok() {
+ if is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok() {
return;
}
}
@@ -856,18 +858,17 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It
}
fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msrv) {
- if_chain! {
- if msrv.meets(msrvs::TOOL_ATTRIBUTES);
+ if msrv.meets(msrvs::TOOL_ATTRIBUTES)
// check cfg_attr
- if attr.has_name(sym::cfg_attr);
- if let Some(items) = attr.meta_item_list();
- if items.len() == 2;
+ && attr.has_name(sym::cfg_attr)
+ && let Some(items) = attr.meta_item_list()
+ && items.len() == 2
// check for `rustfmt`
- if let Some(feature_item) = items[0].meta_item();
- if feature_item.has_name(sym::rustfmt);
+ && let Some(feature_item) = items[0].meta_item()
+ && feature_item.has_name(sym::rustfmt)
// check for `rustfmt_skip` and `rustfmt::skip`
- if let Some(skip_item) = &items[1].meta_item();
- if skip_item.has_name(sym!(rustfmt_skip))
+ && let Some(skip_item) = &items[1].meta_item()
+ && (skip_item.has_name(sym!(rustfmt_skip))
|| skip_item
.path
.segments
@@ -875,21 +876,20 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msr
.expect("empty path in attribute")
.ident
.name
- == sym::skip;
+ == sym::skip)
// Only lint outer attributes, because custom inner attributes are unstable
// Tracking issue: https://github.com/rust-lang/rust/issues/54726
- if attr.style == AttrStyle::Outer;
- then {
- span_lint_and_sugg(
- cx,
- DEPRECATED_CFG_ATTR,
- attr.span,
- "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes",
- "use",
- "#[rustfmt::skip]".to_string(),
- Applicability::MachineApplicable,
- );
- }
+ && attr.style == AttrStyle::Outer
+ {
+ span_lint_and_sugg(
+ cx,
+ DEPRECATED_CFG_ATTR,
+ attr.span,
+ "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes",
+ "use",
+ "#[rustfmt::skip]".to_string(),
+ Applicability::MachineApplicable,
+ );
}
}
@@ -930,21 +930,35 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
for item in items {
if let NestedMetaItem::MetaItem(meta) = item {
- if meta.has_name(sym!(features))
+ if let Some(ident) = meta.ident()
+ && ident.name.as_str() == "features"
&& let Some(val) = meta.value_str()
{
span_lint_and_sugg(
cx,
MAYBE_MISUSED_CFG,
meta.span,
- "feature may misspelled as features",
- "use",
+ "'feature' may be misspelled as 'features'",
+ "did you mean",
format!("feature = \"{val}\""),
Applicability::MaybeIncorrect,
);
}
if let MetaItemKind::List(list) = &meta.kind {
check_nested_misused_cfg(cx, list);
+ // If this is not a list, then we check for `cfg(test)`.
+ } else if let Some(ident) = meta.ident()
+ && matches!(ident.name.as_str(), "tests" | "Test")
+ {
+ span_lint_and_sugg(
+ cx,
+ MAYBE_MISUSED_CFG,
+ meta.span,
+ &format!("'test' may be misspelled as '{}'", ident.name.as_str()),
+ "did you mean",
+ "test".to_string(),
+ Applicability::MaybeIncorrect,
+ );
}
}
}
@@ -989,12 +1003,10 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
mismatched.extend(find_mismatched_target_os(list));
},
MetaItemKind::Word => {
- if_chain! {
- if let Some(ident) = meta.ident();
- if let Some(os) = find_os(ident.name.as_str());
- then {
- mismatched.push((os, ident.span));
- }
+ if let Some(ident) = meta.ident()
+ && let Some(os) = find_os(ident.name.as_str())
+ {
+ mismatched.push((os, ident.span));
}
},
MetaItemKind::NameValue(..) => {},
@@ -1005,30 +1017,28 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
mismatched
}
- if_chain! {
- if attr.has_name(sym::cfg);
- if let Some(list) = attr.meta_item_list();
- let mismatched = find_mismatched_target_os(&list);
- if !mismatched.is_empty();
- then {
- let mess = "operating system used in target family position";
-
- span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, mess, |diag| {
- // Avoid showing the unix suggestion multiple times in case
- // we have more than one mismatch for unix-like systems
- let mut unix_suggested = false;
-
- for (os, span) in mismatched {
- let sugg = format!("target_os = \"{os}\"");
- diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect);
-
- if !unix_suggested && is_unix(os) {
- diag.help("did you mean `unix`?");
- unix_suggested = true;
- }
+ if attr.has_name(sym::cfg)
+ && let Some(list) = attr.meta_item_list()
+ && let mismatched = find_mismatched_target_os(&list)
+ && !mismatched.is_empty()
+ {
+ let mess = "operating system used in target family position";
+
+ span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, mess, |diag| {
+ // Avoid showing the unix suggestion multiple times in case
+ // we have more than one mismatch for unix-like systems
+ let mut unix_suggested = false;
+
+ for (os, span) in mismatched {
+ let sugg = format!("target_os = \"{os}\"");
+ diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect);
+
+ if !unix_suggested && is_unix(os) {
+ diag.help("did you mean `unix`?");
+ unix_suggested = true;
}
- });
- }
+ }
+ });
}
}
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index 06b74b972..9894a1639 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::{Body, CoroutineKind, CoroutineSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::CoroutineLayout;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{sym, Span};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs
new file mode 100644
index 000000000..1417e230a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs
@@ -0,0 +1,137 @@
+use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::source::snippet_block_with_applicability;
+use clippy_utils::ty::implements_trait;
+use clippy_utils::visitors::{for_each_expr, Descend};
+use clippy_utils::{get_parent_expr, higher};
+use core::ops::ControlFlow;
+use rustc_errors::Applicability;
+use rustc_hir::{BlockCheckMode, Expr, ExprKind, MatchSource};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::declare_lint_pass;
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for `if` conditions that use blocks containing an
+ /// expression, statements or conditions that use closures with blocks.
+ ///
+ /// ### Why is this bad?
+ /// Style, using blocks in the condition makes it hard to read.
+ ///
+ /// ### Examples
+ /// ```no_run
+ /// # fn somefunc() -> bool { true };
+ /// if { true } { /* ... */ }
+ ///
+ /// if { let x = somefunc(); x } { /* ... */ }
+ /// ```
+ ///
+ /// Use instead:
+ /// ```no_run
+ /// # fn somefunc() -> bool { true };
+ /// if true { /* ... */ }
+ ///
+ /// let res = { let x = somefunc(); x };
+ /// if res { /* ... */ }
+ /// ```
+ #[clippy::version = "1.45.0"]
+ pub BLOCKS_IN_CONDITIONS,
+ style,
+ "useless or complex blocks that can be eliminated in conditions"
+}
+
+declare_lint_pass!(BlocksInConditions => [BLOCKS_IN_CONDITIONS]);
+
+const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition";
+
+impl<'tcx> LateLintPass<'tcx> for BlocksInConditions {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ if in_external_macro(cx.sess(), expr.span) {
+ return;
+ }
+
+ let Some((cond, keyword, desc)) = higher::If::hir(expr)
+ .map(|hif| (hif.cond, "if", "an `if` condition"))
+ .or(if let ExprKind::Match(match_ex, _, MatchSource::Normal) = expr.kind {
+ Some((match_ex, "match", "a `match` scrutinee"))
+ } else {
+ None
+ })
+ else {
+ return;
+ };
+ let complex_block_message = &format!(
+ "in {desc}, avoid complex blocks or closures with blocks; \
+ instead, move the block or closure higher and bind it with a `let`",
+ );
+
+ if let ExprKind::Block(block, _) = &cond.kind {
+ if block.rules == BlockCheckMode::DefaultBlock {
+ if block.stmts.is_empty() {
+ if let Some(ex) = &block.expr {
+ // don't dig into the expression here, just suggest that they remove
+ // the block
+ if expr.span.from_expansion() || ex.span.from_expansion() {
+ return;
+ }
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ BLOCKS_IN_CONDITIONS,
+ cond.span,
+ BRACED_EXPR_MESSAGE,
+ "try",
+ snippet_block_with_applicability(cx, ex.span, "..", Some(expr.span), &mut applicability)
+ .to_string(),
+ applicability,
+ );
+ }
+ } else {
+ let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
+ if span.from_expansion() || expr.span.from_expansion() {
+ return;
+ }
+ // move block higher
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ BLOCKS_IN_CONDITIONS,
+ expr.span.with_hi(cond.span.hi()),
+ complex_block_message,
+ "try",
+ format!(
+ "let res = {}; {keyword} res",
+ snippet_block_with_applicability(cx, block.span, "..", Some(expr.span), &mut applicability),
+ ),
+ applicability,
+ );
+ }
+ }
+ } else {
+ let _: Option<!> = for_each_expr(cond, |e| {
+ if let ExprKind::Closure(closure) = e.kind {
+ // do not lint if the closure is called using an iterator (see #1141)
+ if let Some(parent) = get_parent_expr(cx, e)
+ && let ExprKind::MethodCall(_, self_arg, _, _) = &parent.kind
+ && let caller = cx.typeck_results().expr_ty(self_arg)
+ && let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
+ && implements_trait(cx, caller, iter_id, &[])
+ {
+ return ControlFlow::Continue(Descend::No);
+ }
+
+ let body = cx.tcx.hir().body(closure.body);
+ let ex = &body.value;
+ if let ExprKind::Block(block, _) = ex.kind {
+ if !body.value.span.from_expansion() && !block.stmts.is_empty() {
+ span_lint(cx, BLOCKS_IN_CONDITIONS, ex.span, complex_block_message);
+ return ControlFlow::Continue(Descend::No);
+ }
+ }
+ }
+ ControlFlow::Continue(Descend::Yes)
+ });
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
deleted file mode 100644
index 04bf541a5..000000000
--- a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::source::snippet_block_with_applicability;
-use clippy_utils::ty::implements_trait;
-use clippy_utils::visitors::{for_each_expr, Descend};
-use clippy_utils::{get_parent_expr, higher};
-use core::ops::ControlFlow;
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{BlockCheckMode, Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for `if` conditions that use blocks containing an
- /// expression, statements or conditions that use closures with blocks.
- ///
- /// ### Why is this bad?
- /// Style, using blocks in the condition makes it hard to read.
- ///
- /// ### Examples
- /// ```no_run
- /// # fn somefunc() -> bool { true };
- /// if { true } { /* ... */ }
- ///
- /// if { let x = somefunc(); x } { /* ... */ }
- /// ```
- ///
- /// Use instead:
- /// ```no_run
- /// # fn somefunc() -> bool { true };
- /// if true { /* ... */ }
- ///
- /// let res = { let x = somefunc(); x };
- /// if res { /* ... */ }
- /// ```
- #[clippy::version = "1.45.0"]
- pub BLOCKS_IN_IF_CONDITIONS,
- style,
- "useless or complex blocks that can be eliminated in conditions"
-}
-
-declare_lint_pass!(BlocksInIfConditions => [BLOCKS_IN_IF_CONDITIONS]);
-
-const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition";
-const COMPLEX_BLOCK_MESSAGE: &str = "in an `if` condition, avoid complex blocks or closures with blocks; \
- instead, move the block or closure higher and bind it with a `let`";
-
-impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if in_external_macro(cx.sess(), expr.span) {
- return;
- }
- if let Some(higher::If { cond, .. }) = higher::If::hir(expr) {
- if let ExprKind::Block(block, _) = &cond.kind {
- if block.rules == BlockCheckMode::DefaultBlock {
- if block.stmts.is_empty() {
- if let Some(ex) = &block.expr {
- // don't dig into the expression here, just suggest that they remove
- // the block
- if expr.span.from_expansion() || ex.span.from_expansion() {
- return;
- }
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- BLOCKS_IN_IF_CONDITIONS,
- cond.span,
- BRACED_EXPR_MESSAGE,
- "try",
- format!(
- "{}",
- snippet_block_with_applicability(
- cx,
- ex.span,
- "..",
- Some(expr.span),
- &mut applicability
- )
- ),
- applicability,
- );
- }
- } else {
- let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
- if span.from_expansion() || expr.span.from_expansion() {
- return;
- }
- // move block higher
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- BLOCKS_IN_IF_CONDITIONS,
- expr.span.with_hi(cond.span.hi()),
- COMPLEX_BLOCK_MESSAGE,
- "try",
- format!(
- "let res = {}; if res",
- snippet_block_with_applicability(
- cx,
- block.span,
- "..",
- Some(expr.span),
- &mut applicability
- ),
- ),
- applicability,
- );
- }
- }
- } else {
- let _: Option<!> = for_each_expr(cond, |e| {
- if let ExprKind::Closure(closure) = e.kind {
- // do not lint if the closure is called using an iterator (see #1141)
- if_chain! {
- if let Some(parent) = get_parent_expr(cx, e);
- if let ExprKind::MethodCall(_, self_arg, _, _) = &parent.kind;
- let caller = cx.typeck_results().expr_ty(self_arg);
- if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
- if implements_trait(cx, caller, iter_id, &[]);
- then {
- return ControlFlow::Continue(Descend::No);
- }
- }
-
- let body = cx.tcx.hir().body(closure.body);
- let ex = &body.value;
- if let ExprKind::Block(block, _) = ex.kind {
- if !body.value.span.from_expansion() && !block.stmts.is_empty() {
- span_lint(cx, BLOCKS_IN_IF_CONDITIONS, ex.span, COMPLEX_BLOCK_MESSAGE);
- return ControlFlow::Continue(Descend::No);
- }
- }
- }
- ControlFlow::Continue(Descend::Yes)
- });
- }
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index 665dbd6f7..74201e9cc 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -7,7 +7,7 @@ use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Lit};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::Ident;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
index 156cb34df..cfb76cab6 100644
--- a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
@@ -2,7 +2,7 @@ use clippy_utils::higher::If;
use rustc_ast::LitKind;
use rustc_hir::{Block, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg::Sugg;
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 0e0d229e8..e11f83f22 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -2,13 +2,12 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::eq_expr_value;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp};
use rustc_lint::{LateContext, LateLintPass, Level};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span};
@@ -151,17 +150,15 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
return Ok(Bool::Term(n as u8));
}
- if_chain! {
- if let ExprKind::Binary(e_binop, e_lhs, e_rhs) = &e.kind;
- if implements_ord(self.cx, e_lhs);
- if let ExprKind::Binary(expr_binop, expr_lhs, expr_rhs) = &expr.kind;
- if negate(e_binop.node) == Some(expr_binop.node);
- if eq_expr_value(self.cx, e_lhs, expr_lhs);
- if eq_expr_value(self.cx, e_rhs, expr_rhs);
- then {
- #[expect(clippy::cast_possible_truncation)]
- return Ok(Bool::Not(Box::new(Bool::Term(n as u8))));
- }
+ if let ExprKind::Binary(e_binop, e_lhs, e_rhs) = &e.kind
+ && implements_ord(self.cx, e_lhs)
+ && let ExprKind::Binary(expr_binop, expr_lhs, expr_rhs) = &expr.kind
+ && negate(e_binop.node) == Some(expr_binop.node)
+ && eq_expr_value(self.cx, e_lhs, expr_lhs)
+ && eq_expr_value(self.cx, e_rhs, expr_rhs)
+ {
+ #[expect(clippy::cast_possible_truncation)]
+ return Ok(Bool::Not(Box::new(Bool::Term(n as u8))));
}
}
let n = self.terminals.len();
@@ -427,8 +424,9 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
improvements.push(suggestion);
}
}
- let nonminimal_bool_lint = |suggestions: Vec<_>| {
+ let nonminimal_bool_lint = |mut suggestions: Vec<_>| {
if self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, e.hir_id).0 != Level::Allow {
+ suggestions.sort();
span_lint_hir_and_then(
self.cx,
NONMINIMAL_BOOL,
diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
index a38269083..0ca4a0e06 100644
--- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
@@ -8,7 +8,7 @@ use rustc_hir::{ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::Mutability;
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 9c78c6e53..ef12fe344 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::IsSuggestable;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -45,7 +45,7 @@ impl LateLintPass<'_> for BoxDefault {
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_new.kind
&& let ExprKind::Call(arg_path, ..) = arg.kind
&& !in_external_macro(cx.sess(), expr.span)
- && (expr.span.eq_ctxt(arg.span) || is_vec_expn(cx, arg))
+ && (expr.span.eq_ctxt(arg.span) || is_local_vec_expn(cx, arg, expr))
&& seg.ident.name == sym::new
&& path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box())
&& is_default_equivalent(cx, arg)
@@ -81,10 +81,10 @@ fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool {
}
}
-fn is_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- macro_backtrace(expr.span)
- .next()
- .map_or(false, |call| cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id))
+fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) -> bool {
+ macro_backtrace(expr.span).next().map_or(false, |call| {
+ cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id) && call.span.eq_ctxt(ref_expr.span)
+ })
}
#[derive(Default)]
diff --git a/src/tools/clippy/clippy_lints/src/cargo/mod.rs b/src/tools/clippy/clippy_lints/src/cargo/mod.rs
index 3a872e54c..fea6924d8 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/mod.rs
@@ -8,7 +8,7 @@ use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_lint_allowed;
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_lint::{LateContext, LateLintPass, Lint};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::DUMMY_SP;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs
index f7a5b1857..ec681adb7 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs
@@ -2,7 +2,6 @@
use cargo_metadata::{DependencyKind, Metadata, Node, Package, PackageId};
use clippy_utils::diagnostics::span_lint;
-use if_chain::if_chain;
use itertools::Itertools;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_lint::LateContext;
@@ -15,31 +14,33 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) {
let mut packages = metadata.packages.clone();
packages.sort_by(|a, b| a.name.cmp(&b.name));
- if_chain! {
- if let Some(resolve) = &metadata.resolve;
- if let Some(local_id) = packages
- .iter()
- .find_map(|p| if p.name == local_name.as_str() { Some(&p.id) } else { None });
- then {
- for (name, group) in &packages.iter().group_by(|p| p.name.clone()) {
- let group: Vec<&Package> = group.collect();
-
- if group.len() <= 1 {
- continue;
- }
-
- if group.iter().all(|p| is_normal_dep(&resolve.nodes, local_id, &p.id)) {
- let mut versions: Vec<_> = group.into_iter().map(|p| &p.version).collect();
- versions.sort();
- let versions = versions.iter().join(", ");
-
- span_lint(
- cx,
- MULTIPLE_CRATE_VERSIONS,
- DUMMY_SP,
- &format!("multiple versions for dependency `{name}`: {versions}"),
- );
- }
+ if let Some(resolve) = &metadata.resolve
+ && let Some(local_id) = packages.iter().find_map(|p| {
+ if p.name == local_name.as_str() {
+ Some(&p.id)
+ } else {
+ None
+ }
+ })
+ {
+ for (name, group) in &packages.iter().group_by(|p| p.name.clone()) {
+ let group: Vec<&Package> = group.collect();
+
+ if group.len() <= 1 {
+ continue;
+ }
+
+ if group.iter().all(|p| is_normal_dep(&resolve.nodes, local_id, &p.id)) {
+ let mut versions: Vec<_> = group.into_iter().map(|p| &p.version).collect();
+ versions.sort();
+ let versions = versions.iter().join(", ");
+
+ span_lint(
+ cx,
+ MULTIPLE_CRATE_VERSIONS,
+ DUMMY_SP,
+ &format!("multiple versions for dependency `{name}`: {versions}"),
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs b/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs
index 4dcc9cbe3..244e98eb6 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs
@@ -1,6 +1,5 @@
use cargo_metadata::Metadata;
use clippy_utils::diagnostics::span_lint;
-use if_chain::if_chain;
use rustc_lint::LateContext;
use rustc_span::DUMMY_SP;
@@ -9,19 +8,17 @@ use super::WILDCARD_DEPENDENCIES;
pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) {
for dep in &metadata.packages[0].dependencies {
// VersionReq::any() does not work
- if_chain! {
- if let Ok(wildcard_ver) = semver::VersionReq::parse("*");
- if let Some(ref source) = dep.source;
- if !source.starts_with("git");
- if dep.req == wildcard_ver;
- then {
- span_lint(
- cx,
- WILDCARD_DEPENDENCIES,
- DUMMY_SP,
- &format!("wildcard dependency for `{}`", dep.name),
- );
- }
+ if let Ok(wildcard_ver) = semver::VersionReq::parse("*")
+ && let Some(ref source) = dep.source
+ && !source.starts_with("git")
+ && dep.req == wildcard_ver
+ {
+ span_lint(
+ cx,
+ WILDCARD_DEPENDENCIES,
+ DUMMY_SP,
+ &format!("wildcard dependency for `{}`", dep.name),
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
index 55294f5f3..8bfb7383f 100644
--- a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
@@ -9,11 +9,10 @@ use rustc_middle::ty::{self, Ty, TypeAndMut};
use super::AS_PTR_CAST_MUT;
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>) {
- if let ty::RawPtr(
- ptrty @ TypeAndMut {
- mutbl: Mutability::Mut, ..
- },
- ) = cast_to.kind()
+ if let ty::RawPtr(TypeAndMut {
+ mutbl: Mutability::Mut,
+ ty: ptrty,
+ }) = cast_to.kind()
&& let ty::RawPtr(TypeAndMut {
mutbl: Mutability::Not, ..
}) = cx.typeck_results().node_type(cast_expr.hir_id).kind()
@@ -34,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
cx,
AS_PTR_CAST_MUT,
expr.span,
- &format!("casting the result of `as_ptr` to *{ptrty}"),
+ &format!("casting the result of `as_ptr` to *mut {ptrty}"),
"replace with",
format!("{recv}.as_mut_ptr()"),
applicability,
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
index ffa571abb..2ddb0f00e 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
@@ -1,5 +1,6 @@
+use clippy_utils::diagnostics::span_lint_and_then;
use rustc_hir::Expr;
-use rustc_lint::{LateContext, LintContext};
+use rustc_lint::LateContext;
use rustc_middle::ty::Ty;
use super::{utils, CAST_POSSIBLE_WRAP};
@@ -78,13 +79,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
),
};
- cx.struct_span_lint(CAST_POSSIBLE_WRAP, expr.span, message, |diag| {
+ span_lint_and_then(cx, CAST_POSSIBLE_WRAP, expr.span, &message, |diag| {
if let EmitState::LintOnPtrSize(16) = should_lint {
diag
- .note("`usize` and `isize` may be as small as 16 bits on some platforms")
- .note("for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types")
- } else {
- diag
- }
+ .note("`usize` and `isize` may be as small as 16 bits on some platforms")
+ .note("for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types");
+ };
});
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index a83dfd94d..bd12ee406 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -1,7 +1,6 @@
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{method_chain_args, sext};
-use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
@@ -28,13 +27,11 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast
// Don't lint for positive constants.
let const_val = constant(cx, cx.typeck_results(), cast_op);
- if_chain! {
- if let Some(Constant::Int(n)) = const_val;
- if let ty::Int(ity) = *cast_from.kind();
- if sext(cx.tcx, n, ity) >= 0;
- then {
- return false;
- }
+ if let Some(Constant::Int(n)) = const_val
+ && let ty::Int(ity) = *cast_from.kind()
+ && sext(cx.tcx, n, ity) >= 0
+ {
+ return false;
}
// Don't lint for the result of methods that always return non-negative values.
@@ -42,13 +39,11 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast
let mut method_name = path.ident.name.as_str();
let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
- if_chain! {
- if method_name == "unwrap";
- if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]);
- if let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind;
- then {
- method_name = inner_path.ident.name.as_str();
- }
+ if method_name == "unwrap"
+ && let Some(arglist) = method_chain_args(cast_op, &["unwrap"])
+ && let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind
+ {
+ method_name = inner_path.ident.name.as_str();
}
if allowed_methods.iter().any(|&name| method_name == name) {
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
index d14104029..91bad8256 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
@@ -1,7 +1,6 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source;
-use if_chain::if_chain;
use rustc_ast::Mutability;
use rustc_hir::{Expr, ExprKind, Node};
use rustc_lint::LateContext;
@@ -69,26 +68,24 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv
fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let map = cx.tcx.hir();
- if_chain! {
- if let Some(parent_id) = map.opt_parent_id(expr.hir_id);
- if let Some(parent) = map.find(parent_id);
- then {
- let expr = match parent {
- Node::Block(block) => {
- if let Some(parent_expr) = block.expr {
- parent_expr
- } else {
- return false;
- }
- },
- Node::Expr(expr) => expr,
- _ => return false,
- };
+ if let Some(parent_id) = map.opt_parent_id(expr.hir_id)
+ && let Some(parent) = cx.tcx.opt_hir_node(parent_id)
+ {
+ let expr = match parent {
+ Node::Block(block) => {
+ if let Some(parent_expr) = block.expr {
+ parent_expr
+ } else {
+ return false;
+ }
+ },
+ Node::Expr(expr) => expr,
+ _ => return false,
+ };
- matches!(expr.kind, ExprKind::Cast(..))
- } else {
- false
- }
+ matches!(expr.kind, ExprKind::Cast(..))
+ } else {
+ false
}
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
index badadf2c9..3db1e3e6d 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
@@ -1,7 +1,6 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind};
@@ -25,34 +24,32 @@ fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option<RawPartsKind> {
}
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>, msrv: &Msrv) {
- if_chain! {
- if msrv.meets(msrvs::PTR_SLICE_RAW_PARTS);
- if let ty::RawPtr(ptrty) = cast_to.kind();
- if let ty::Slice(_) = ptrty.ty.kind();
- if let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind;
- if let ExprKind::Path(ref qpath) = fun.kind;
- if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
- if let Some(rpk) = raw_parts_kind(cx, fun_def_id);
- let ctxt = expr.span.ctxt();
- if cast_expr.span.ctxt() == ctxt;
- then {
- let func = match rpk {
- RawPartsKind::Immutable => "from_raw_parts",
- RawPartsKind::Mutable => "from_raw_parts_mut"
- };
- let span = expr.span;
- let mut applicability = Applicability::MachineApplicable;
- let ptr = snippet_with_context(cx, ptr_arg.span, ctxt, "ptr", &mut applicability).0;
- let len = snippet_with_context(cx, len_arg.span, ctxt, "len", &mut applicability).0;
- span_lint_and_sugg(
- cx,
- CAST_SLICE_FROM_RAW_PARTS,
- span,
- &format!("casting the result of `{func}` to {cast_to}"),
- "replace with",
- format!("core::ptr::slice_{func}({ptr}, {len})"),
- applicability
- );
- }
+ if msrv.meets(msrvs::PTR_SLICE_RAW_PARTS)
+ && let ty::RawPtr(ptrty) = cast_to.kind()
+ && let ty::Slice(_) = ptrty.ty.kind()
+ && let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind
+ && let ExprKind::Path(ref qpath) = fun.kind
+ && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
+ && let Some(rpk) = raw_parts_kind(cx, fun_def_id)
+ && let ctxt = expr.span.ctxt()
+ && cast_expr.span.ctxt() == ctxt
+ {
+ let func = match rpk {
+ RawPartsKind::Immutable => "from_raw_parts",
+ RawPartsKind::Mutable => "from_raw_parts_mut",
+ };
+ let span = expr.span;
+ let mut applicability = Applicability::MachineApplicable;
+ let ptr = snippet_with_context(cx, ptr_arg.span, ctxt, "ptr", &mut applicability).0;
+ let len = snippet_with_context(cx, len_arg.span, ctxt, "len", &mut applicability).0;
+ span_lint_and_sugg(
+ cx,
+ CAST_SLICE_FROM_RAW_PARTS,
+ span,
+ &format!("casting the result of `{func}` to {cast_to}"),
+ "replace with",
+ format!("core::ptr::slice_{func}({ptr}, {len})"),
+ applicability,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs b/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs
index 82e07c98a..a7d3868f7 100644
--- a/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_with_applicability;
-use if_chain::if_chain;
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
@@ -10,32 +9,31 @@ use rustc_middle::ty::{self, UintTy};
use super::CHAR_LIT_AS_U8;
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
- if_chain! {
- if let ExprKind::Cast(e, _) = &expr.kind;
- if let ExprKind::Lit(l) = &e.kind;
- if let LitKind::Char(c) = l.node;
- if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(expr).kind();
- then {
- let mut applicability = Applicability::MachineApplicable;
- let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability);
+ if let ExprKind::Cast(e, _) = &expr.kind
+ && let ExprKind::Lit(l) = &e.kind
+ && let LitKind::Char(c) = l.node
+ && ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(expr).kind()
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability);
- span_lint_and_then(
- cx,
- CHAR_LIT_AS_U8,
- expr.span,
- "casting a character literal to `u8` truncates",
- |diag| {
- diag.note("`char` is four bytes wide, but `u8` is a single byte");
+ span_lint_and_then(
+ cx,
+ CHAR_LIT_AS_U8,
+ expr.span,
+ "casting a character literal to `u8` truncates",
+ |diag| {
+ diag.note("`char` is four bytes wide, but `u8` is a single byte");
- if c.is_ascii() {
- diag.span_suggestion(
- expr.span,
- "use a byte literal instead",
- format!("b{snippet}"),
- applicability,
- );
- }
- });
- }
+ if c.is_ascii() {
+ diag.span_suggestion(
+ expr.span,
+ "use a byte literal instead",
+ format!("b{snippet}"),
+ applicability,
+ );
+ }
+ },
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index 49a90a2f3..e05b8f66d 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -27,7 +27,7 @@ use clippy_utils::is_hir_ty_cfg_dependant;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index 0c555c1ac..35e36e9ef 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -3,12 +3,29 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, Mutability, TyKind};
+use rustc_hir::{Expr, ExprKind, Mutability, QPath, TyKind};
+use rustc_hir_pretty::qpath_to_string;
use rustc_lint::LateContext;
use rustc_middle::ty::{self, TypeAndMut};
+use rustc_span::sym;
use super::PTR_AS_PTR;
+enum OmitFollowedCastReason<'a> {
+ None,
+ Null(&'a QPath<'a>),
+ NullMut(&'a QPath<'a>),
+}
+
+impl OmitFollowedCastReason<'_> {
+ fn corresponding_item(&self) -> Option<&QPath<'_>> {
+ match self {
+ OmitFollowedCastReason::None => None,
+ OmitFollowedCastReason::Null(x) | OmitFollowedCastReason::NullMut(x) => Some(*x),
+ }
+ }
+}
+
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
if !msrv.meets(msrvs::POINTER_CAST) {
return;
@@ -25,7 +42,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
&& to_pointee_ty.is_sized(cx.tcx, cx.param_env)
{
let mut app = Applicability::MachineApplicable;
- let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app);
let turbofish = match &cast_to_hir_ty.kind {
TyKind::Infer => String::new(),
TyKind::Ptr(mut_ty) => {
@@ -41,13 +57,44 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
_ => return,
};
+ // following `cast` does not compile because it fails to infer what type is expected
+ // as type argument to `std::ptr::ptr_null` or `std::ptr::ptr_null_mut`, so
+ // we omit following `cast`:
+ let omit_cast = if let ExprKind::Call(func, []) = cast_expr.kind
+ && let ExprKind::Path(ref qpath @ QPath::Resolved(None, path)) = func.kind
+ {
+ let method_defid = path.res.def_id();
+ if cx.tcx.is_diagnostic_item(sym::ptr_null, method_defid) {
+ OmitFollowedCastReason::Null(qpath)
+ } else if cx.tcx.is_diagnostic_item(sym::ptr_null_mut, method_defid) {
+ OmitFollowedCastReason::NullMut(qpath)
+ } else {
+ OmitFollowedCastReason::None
+ }
+ } else {
+ OmitFollowedCastReason::None
+ };
+
+ let (help, final_suggestion) = if let Some(method) = omit_cast.corresponding_item() {
+ // don't force absolute path
+ let method = qpath_to_string(method);
+ ("try call directly", format!("{method}{turbofish}()"))
+ } else {
+ let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app);
+
+ (
+ "try `pointer::cast`, a safer alternative",
+ format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()),
+ )
+ };
+
span_lint_and_sugg(
cx,
PTR_AS_PTR,
expr.span,
"`as` casting between raw pointers without changing its mutability",
- "try `pointer::cast`, a safer alternative",
- format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()),
+ help,
+ final_suggestion,
app,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
index 0172e9336..ff069860a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
@@ -1,7 +1,6 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, Mutability};
use rustc_lint::LateContext;
@@ -17,29 +16,35 @@ pub(super) fn check<'tcx>(
cast_to: Ty<'tcx>,
msrv: &Msrv,
) {
- if_chain! {
- if msrv.meets(msrvs::POINTER_CAST_CONSTNESS);
- if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, ty: from_ty }) = cast_from.kind();
- if let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, ty: to_ty }) = cast_to.kind();
- if matches!((from_mutbl, to_mutbl),
- (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not));
- if from_ty == to_ty;
- then {
- let sugg = Sugg::hir(cx, cast_expr, "_");
- let constness = match *to_mutbl {
- Mutability::Not => "const",
- Mutability::Mut => "mut",
- };
+ if msrv.meets(msrvs::POINTER_CAST_CONSTNESS)
+ && let ty::RawPtr(TypeAndMut {
+ mutbl: from_mutbl,
+ ty: from_ty,
+ }) = cast_from.kind()
+ && let ty::RawPtr(TypeAndMut {
+ mutbl: to_mutbl,
+ ty: to_ty,
+ }) = cast_to.kind()
+ && matches!(
+ (from_mutbl, to_mutbl),
+ (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not)
+ )
+ && from_ty == to_ty
+ {
+ let sugg = Sugg::hir(cx, cast_expr, "_");
+ let constness = match *to_mutbl {
+ Mutability::Not => "const",
+ Mutability::Mut => "mut",
+ };
- span_lint_and_sugg(
- cx,
- PTR_CAST_CONSTNESS,
- expr.span,
- "`as` casting between raw pointers while changing only its constness",
- &format!("try `pointer::cast_{constness}`, a safer alternative"),
- format!("{}.cast_{constness}()", sugg.maybe_par()),
- Applicability::MachineApplicable,
- );
- }
+ span_lint_and_sugg(
+ cx,
+ PTR_CAST_CONSTNESS,
+ expr.span,
+ "`as` casting between raw pointers while changing only its constness",
+ &format!("try `pointer::cast_{constness}`, a safer alternative"),
+ format!("{}.cast_{constness}()", sugg.maybe_par()),
+ Applicability::MachineApplicable,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index 61bfce07e..849920bb7 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -3,7 +3,6 @@ use clippy_utils::numeric_literal::NumericLiteral;
use clippy_utils::source::snippet_opt;
use clippy_utils::visitors::{for_each_expr, Visitable};
use clippy_utils::{get_parent_expr, get_parent_node, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local};
-use if_chain::if_chain;
use rustc_ast::{LitFloatType, LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
@@ -25,40 +24,40 @@ pub(super) fn check<'tcx>(
) -> bool {
let cast_str = snippet_opt(cx, cast_expr.span).unwrap_or_default();
- if_chain! {
- if let ty::RawPtr(..) = cast_from.kind();
+ if let ty::RawPtr(..) = cast_from.kind()
// check both mutability and type are the same
- if cast_from.kind() == cast_to.kind();
- if let ExprKind::Cast(_, cast_to_hir) = expr.kind;
+ && cast_from.kind() == cast_to.kind()
+ && let ExprKind::Cast(_, cast_to_hir) = expr.kind
// Ignore casts to e.g. type aliases and infer types
// - p as pointer_alias
// - p as _
- if let TyKind::Ptr(to_pointee) = cast_to_hir.kind;
- then {
- match to_pointee.ty.kind {
- // Ignore casts to pointers that are aliases or cfg dependant, e.g.
- // - p as *const std::ffi::c_char (alias)
- // - p as *const std::os::raw::c_char (cfg dependant)
- TyKind::Path(qpath) => {
- if is_ty_alias(&qpath) || is_hir_ty_cfg_dependant(cx, to_pointee.ty) {
- return false;
- }
- },
- // Ignore `p as *const _`
- TyKind::Infer => return false,
- _ => {},
- }
-
- span_lint_and_sugg(
- cx,
- UNNECESSARY_CAST,
- expr.span,
- &format!("casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"),
- "try",
- cast_str.clone(),
- Applicability::MaybeIncorrect,
- );
+ && let TyKind::Ptr(to_pointee) = cast_to_hir.kind
+ {
+ match to_pointee.ty.kind {
+ // Ignore casts to pointers that are aliases or cfg dependant, e.g.
+ // - p as *const std::ffi::c_char (alias)
+ // - p as *const std::os::raw::c_char (cfg dependant)
+ TyKind::Path(qpath) => {
+ if is_ty_alias(&qpath) || is_hir_ty_cfg_dependant(cx, to_pointee.ty) {
+ return false;
+ }
+ },
+ // Ignore `p as *const _`
+ TyKind::Infer => return false,
+ _ => {},
}
+
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_CAST,
+ expr.span,
+ &format!(
+ "casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"
+ ),
+ "try",
+ cast_str.clone(),
+ Applicability::MaybeIncorrect,
+ );
}
// skip cast of local that is a type alias
@@ -86,14 +85,12 @@ pub(super) fn check<'tcx>(
}
// skip cast to non-primitive type
- if_chain! {
- if let ExprKind::Cast(_, cast_to) = expr.kind;
- if let TyKind::Path(QPath::Resolved(_, path)) = &cast_to.kind;
- if let Res::PrimTy(_) = path.res;
- then {}
- else {
- return false;
- }
+ if let ExprKind::Cast(_, cast_to) = expr.kind
+ && let TyKind::Path(QPath::Resolved(_, path)) = &cast_to.kind
+ && let Res::PrimTy(_) = path.res
+ {
+ } else {
+ return false;
}
// skip cast of fn call that returns type alias
@@ -106,18 +103,19 @@ pub(super) fn check<'tcx>(
if let Some(lit) = get_numeric_literal(cast_expr) {
let literal_str = &cast_str;
- if_chain! {
- if let LitKind::Int(n, _) = lit.node;
- if let Some(src) = snippet_opt(cx, cast_expr.span);
- if cast_to.is_floating_point();
- if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node);
- let from_nbits = 128 - n.leading_zeros();
- let to_nbits = fp_ty_mantissa_nbits(cast_to);
- if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal();
- then {
- lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
- return true
- }
+ if let LitKind::Int(n, _) = lit.node
+ && let Some(src) = snippet_opt(cx, cast_expr.span)
+ && cast_to.is_floating_point()
+ && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node)
+ && let from_nbits = 128 - n.leading_zeros()
+ && let to_nbits = fp_ty_mantissa_nbits(cast_to)
+ && from_nbits != 0
+ && to_nbits != 0
+ && from_nbits <= to_nbits
+ && num_lit.is_decimal()
+ {
+ lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
+ return true;
}
match lit.node {
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index d31c2268a..92810ea2a 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -4,12 +4,11 @@ use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{in_constant, is_integer_literal, SpanlessEq};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -55,20 +54,17 @@ impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
return;
}
- let result = if_chain! {
- if !in_constant(cx, item.hir_id);
- if !in_external_macro(cx.sess(), item.span);
- if let ExprKind::Binary(op, left, right) = &item.kind;
-
- then {
- match op.node {
- BinOpKind::Ge | BinOpKind::Le => single_check(item),
- BinOpKind::And => double_check(cx, left, right),
- _ => None,
- }
- } else {
- None
+ let result = if !in_constant(cx, item.hir_id)
+ && !in_external_macro(cx.sess(), item.span)
+ && let ExprKind::Binary(op, left, right) = &item.kind
+ {
+ match op.node {
+ BinOpKind::Ge | BinOpKind::Le => single_check(item),
+ BinOpKind::And => double_check(cx, left, right),
+ _ => None,
}
+ } else {
+ None
};
if let Some(cv) = result {
@@ -193,16 +189,13 @@ impl ConversionType {
/// Check for `expr <= (to_type::MAX as from_type)`
fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
- if_chain! {
- if let ExprKind::Binary(ref op, left, right) = &expr.kind;
- if let Some((candidate, check)) = normalize_le_ge(op, left, right);
- if let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX");
-
- then {
- Conversion::try_new(candidate, from, to)
- } else {
- None
- }
+ if let ExprKind::Binary(ref op, left, right) = &expr.kind
+ && let Some((candidate, check)) = normalize_le_ge(op, left, right)
+ && let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX")
+ {
+ Conversion::try_new(candidate, from, to)
+ } else {
+ None
}
}
@@ -243,33 +236,27 @@ fn get_types_from_cast<'a>(
) -> Option<(&'a str, &'a str)> {
// `to_type::max_value() as from_type`
// or `to_type::MAX as from_type`
- let call_from_cast: Option<(&Expr<'_>, &str)> = if_chain! {
+ let call_from_cast: Option<(&Expr<'_>, &str)> = if let ExprKind::Cast(limit, from_type) = &expr.kind
// to_type::max_value(), from_type
- if let ExprKind::Cast(limit, from_type) = &expr.kind;
- if let TyKind::Path(ref from_type_path) = &from_type.kind;
- if let Some(from_sym) = int_ty_to_sym(from_type_path);
-
- then {
- Some((limit, from_sym))
- } else {
- None
- }
+ && let TyKind::Path(ref from_type_path) = &from_type.kind
+ && let Some(from_sym) = int_ty_to_sym(from_type_path)
+ {
+ Some((limit, from_sym))
+ } else {
+ None
};
// `from_type::from(to_type::max_value())`
let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| {
- if_chain! {
+ if let ExprKind::Call(from_func, [limit]) = &expr.kind
// `from_type::from, to_type::max_value()`
- if let ExprKind::Call(from_func, [limit]) = &expr.kind;
// `from_type::from`
- if let ExprKind::Path(ref path) = &from_func.kind;
- if let Some(from_sym) = get_implementing_type(path, INTS, "from");
-
- then {
- Some((limit, from_sym))
- } else {
- None
- }
+ && let ExprKind::Path(ref path) = &from_func.kind
+ && let Some(from_sym) = get_implementing_type(path, INTS, "from")
+ {
+ Some((limit, from_sym))
+ } else {
+ None
}
});
@@ -298,31 +285,27 @@ fn get_types_from_cast<'a>(
/// Gets the type which implements the called function
fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: &str) -> Option<&'a str> {
- if_chain! {
- if let QPath::TypeRelative(ty, path) = &path;
- if path.ident.name.as_str() == function;
- if let TyKind::Path(QPath::Resolved(None, tp)) = &ty.kind;
- if let [int] = tp.segments;
- then {
- let name = int.ident.name.as_str();
- candidates.iter().find(|c| &name == *c).copied()
- } else {
- None
- }
+ if let QPath::TypeRelative(ty, path) = &path
+ && path.ident.name.as_str() == function
+ && let TyKind::Path(QPath::Resolved(None, tp)) = &ty.kind
+ && let [int] = tp.segments
+ {
+ let name = int.ident.name.as_str();
+ candidates.iter().find(|c| &name == *c).copied()
+ } else {
+ None
}
}
/// Gets the type as a string, if it is a supported integer
fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> {
- if_chain! {
- if let QPath::Resolved(_, path) = *path;
- if let [ty] = path.segments;
- then {
- let name = ty.ident.name.as_str();
- INTS.iter().find(|c| &name == *c).copied()
- } else {
- None
- }
+ if let QPath::Resolved(_, path) = *path
+ && let [ty] = path.segments
+ {
+ let name = ty.ident.name.as_str();
+ INTS.iter().find(|c| &name == *c).copied()
+ } else {
+ None
}
}
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 74ecaa60c..60f436dc5 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -10,7 +10,7 @@ use rustc_ast::ast::Attribute;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, Expr, ExprKind, FnDecl};
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, BytePos, Span};
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index d21ef195d..07b02c98d 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -15,11 +15,10 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_block, snippet_block_with_applicability};
use clippy_utils::sugg::Sugg;
-use if_chain::if_chain;
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
@@ -121,49 +120,55 @@ fn block_starts_with_comment(cx: &EarlyContext<'_>, expr: &ast::Block) -> bool {
}
fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, then_span: Span, else_: &ast::Expr) {
- if_chain! {
- if let ast::ExprKind::Block(ref block, _) = else_.kind;
- if !block_starts_with_comment(cx, block);
- if let Some(else_) = expr_block(block);
- if else_.attrs.is_empty();
- if !else_.span.from_expansion();
- if let ast::ExprKind::If(..) = else_.kind;
- then {
- // Prevent "elseif"
- // Check that the "else" is followed by whitespace
- let up_to_else = then_span.between(block.span);
- let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { !c.is_whitespace() } else { false };
+ if let ast::ExprKind::Block(ref block, _) = else_.kind
+ && !block_starts_with_comment(cx, block)
+ && let Some(else_) = expr_block(block)
+ && else_.attrs.is_empty()
+ && !else_.span.from_expansion()
+ && let ast::ExprKind::If(..) = else_.kind
+ {
+ // Prevent "elseif"
+ // Check that the "else" is followed by whitespace
+ let up_to_else = then_span.between(block.span);
+ let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() {
+ !c.is_whitespace()
+ } else {
+ false
+ };
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- COLLAPSIBLE_ELSE_IF,
- block.span,
- "this `else { if .. }` block can be collapsed",
- "collapse nested if block",
- format!(
- "{}{}",
- if requires_space { " " } else { "" },
- snippet_block_with_applicability(cx, else_.span, "..", Some(block.span), &mut applicability)
- ),
- applicability,
- );
- }
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ COLLAPSIBLE_ELSE_IF,
+ block.span,
+ "this `else { if .. }` block can be collapsed",
+ "collapse nested if block",
+ format!(
+ "{}{}",
+ if requires_space { " " } else { "" },
+ snippet_block_with_applicability(cx, else_.span, "..", Some(block.span), &mut applicability)
+ ),
+ applicability,
+ );
}
}
fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &ast::Expr, then: &ast::Block) {
- if_chain! {
- if !block_starts_with_comment(cx, then);
- if let Some(inner) = expr_block(then);
- if inner.attrs.is_empty();
- if let ast::ExprKind::If(ref check_inner, ref content, None) = inner.kind;
+ if !block_starts_with_comment(cx, then)
+ && let Some(inner) = expr_block(then)
+ && inner.attrs.is_empty()
+ && let ast::ExprKind::If(ref check_inner, ref content, None) = inner.kind
// Prevent triggering on `if c { if let a = b { .. } }`.
- if !matches!(check_inner.kind, ast::ExprKind::Let(..));
- let ctxt = expr.span.ctxt();
- if inner.span.ctxt() == ctxt;
- then {
- span_lint_and_then(cx, COLLAPSIBLE_IF, expr.span, "this `if` statement can be collapsed", |diag| {
+ && !matches!(check_inner.kind, ast::ExprKind::Let(..))
+ && let ctxt = expr.span.ctxt()
+ && inner.span.ctxt() == ctxt
+ {
+ span_lint_and_then(
+ cx,
+ COLLAPSIBLE_IF,
+ expr.span,
+ "this `if` statement can be collapsed",
+ |diag| {
let mut app = Applicability::MachineApplicable;
let lhs = Sugg::ast(cx, check, "..", ctxt, &mut app);
let rhs = Sugg::ast(cx, check_inner, "..", ctxt, &mut app);
@@ -177,8 +182,8 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &
),
app, // snippet
);
- });
- }
+ },
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
index 1dfc2e251..d0c989cff 100644
--- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
+++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
@@ -5,7 +5,7 @@ use clippy_utils::{get_enclosing_block, get_parent_node, path_to_local_id};
use core::ops::ControlFlow;
use rustc_hir::{Block, ExprKind, HirId, LangItem, Local, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
use rustc_span::Symbol;
diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
index 0fe973b49..2c23c0b4f 100644
--- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs
+++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::implements_trait;
use clippy_utils::{if_sequence, in_constant, is_else_clause, SpanlessEq};
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index e3a09636e..d91af76f5 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -13,7 +13,7 @@ use rustc_hir::def_id::DefIdSet;
use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::query::Key;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::hygiene::walk_chain;
use rustc_span::source_map::SourceMap;
use rustc_span::{BytePos, Span, Symbol};
@@ -117,7 +117,7 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "pre 1.29.0"]
pub IF_SAME_THEN_ELSE,
- correctness,
+ style,
"`if` with the same `then` and `else` blocks"
}
diff --git a/src/tools/clippy/clippy_lints/src/copy_iterator.rs b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
index 5d04ad011..50fd76a3a 100644
--- a/src/tools/clippy/clippy_lints/src/copy_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
@@ -2,11 +2,9 @@ use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::ty::is_copy;
use rustc_hir::{Impl, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
-use if_chain::if_chain;
-
declare_clippy_lint! {
/// ### What it does
/// Checks for types that implement `Copy` as well as
@@ -38,25 +36,23 @@ declare_lint_pass!(CopyIterator => [COPY_ITERATOR]);
impl<'tcx> LateLintPass<'tcx> for CopyIterator {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
- if_chain! {
- if let ItemKind::Impl(Impl {
- of_trait: Some(ref trait_ref),
- ..
- }) = item.kind;
- let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
- if is_copy(cx, ty);
- if let Some(trait_id) = trait_ref.trait_def_id();
- if cx.tcx.is_diagnostic_item(sym::Iterator, trait_id);
- then {
- span_lint_and_note(
- cx,
- COPY_ITERATOR,
- item.span,
- "you are implementing `Iterator` on a `Copy` type",
- None,
- "consider implementing `IntoIterator` instead",
- );
- }
+ if let ItemKind::Impl(Impl {
+ of_trait: Some(ref trait_ref),
+ ..
+ }) = item.kind
+ && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+ && is_copy(cx, ty)
+ && let Some(trait_id) = trait_ref.trait_def_id()
+ && cx.tcx.is_diagnostic_item(sym::Iterator, trait_id)
+ {
+ span_lint_and_note(
+ cx,
+ COPY_ITERATOR,
+ item.span,
+ "you are implementing `Iterator` on a `Copy` type",
+ None,
+ "consider implementing `IntoIterator` instead",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
index a2005638d..b1aa472aa 100644
--- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
+++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
@@ -4,7 +4,7 @@ use rustc_ast::token::{Token, TokenKind};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
use rustc_span::Span;
@@ -53,35 +53,31 @@ declare_lint_pass!(CrateInMacroDef => [CRATE_IN_MACRO_DEF]);
impl EarlyLintPass for CrateInMacroDef {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
- if_chain! {
- if item.attrs.iter().any(is_macro_export);
- if let ItemKind::MacroDef(macro_def) = &item.kind;
- let tts = macro_def.body.tokens.clone();
- if let Some(span) = contains_unhygienic_crate_reference(&tts);
- then {
- span_lint_and_sugg(
- cx,
- CRATE_IN_MACRO_DEF,
- span,
- "`crate` references the macro call's crate",
- "to reference the macro definition's crate, use",
- String::from("$crate"),
- Applicability::MachineApplicable,
- );
- }
+ if item.attrs.iter().any(is_macro_export)
+ && let ItemKind::MacroDef(macro_def) = &item.kind
+ && let tts = macro_def.body.tokens.clone()
+ && let Some(span) = contains_unhygienic_crate_reference(&tts)
+ {
+ span_lint_and_sugg(
+ cx,
+ CRATE_IN_MACRO_DEF,
+ span,
+ "`crate` references the macro call's crate",
+ "to reference the macro definition's crate, use",
+ String::from("$crate"),
+ Applicability::MachineApplicable,
+ );
}
}
}
fn is_macro_export(attr: &Attribute) -> bool {
- if_chain! {
- if let AttrKind::Normal(normal) = &attr.kind;
- if let [segment] = normal.item.path.segments.as_slice();
- then {
- segment.ident.name == sym::macro_export
- } else {
- false
- }
+ if let AttrKind::Normal(normal) = &attr.kind
+ && let [segment] = normal.item.path.segments.as_slice()
+ {
+ segment.ident.name == sym::macro_export
+ } else {
+ false
}
}
@@ -89,16 +85,14 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option<Span> {
let mut prev_is_dollar = false;
let mut cursor = tts.trees();
while let Some(curr) = cursor.next() {
- if_chain! {
- if !prev_is_dollar;
- if let Some(span) = is_crate_keyword(curr);
- if let Some(next) = cursor.look_ahead(0);
- if is_token(next, &TokenKind::ModSep);
- then {
- return Some(span);
- }
+ if !prev_is_dollar
+ && let Some(span) = is_crate_keyword(curr)
+ && let Some(next) = cursor.look_ahead(0)
+ && is_token(next, &TokenKind::ModSep)
+ {
+ return Some(span);
}
- if let TokenTree::Delimited(_, _, tts) = &curr {
+ if let TokenTree::Delimited(.., tts) = &curr {
let span = contains_unhygienic_crate_reference(tts);
if span.is_some() {
return span;
@@ -110,10 +104,18 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option<Span> {
}
fn is_crate_keyword(tt: &TokenTree) -> Option<Span> {
- if_chain! {
- if let TokenTree::Token(Token { kind: TokenKind::Ident(symbol, _), span }, _) = tt;
- if symbol.as_str() == "crate";
- then { Some(*span) } else { None }
+ if let TokenTree::Token(
+ Token {
+ kind: TokenKind::Ident(symbol, _),
+ span,
+ },
+ _,
+ ) = tt
+ && symbol.as_str() == "crate"
+ {
+ Some(*span)
+ } else {
+ None
}
}
diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs
index 2bca695c4..7a3d5a070 100644
--- a/src/tools/clippy/clippy_lints/src/create_dir.rs
+++ b/src/tools/clippy/clippy_lints/src/create_dir.rs
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -33,22 +32,20 @@ declare_lint_pass!(CreateDir => [CREATE_DIR]);
impl LateLintPass<'_> for CreateDir {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- if_chain! {
- if let ExprKind::Call(func, [arg, ..]) = expr.kind;
- if let ExprKind::Path(ref path) = func.kind;
- if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
- if cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id);
- then {
- span_lint_and_sugg(
- cx,
- CREATE_DIR,
- expr.span,
- "calling `std::fs::create_dir` where there may be a better way",
- "consider calling `std::fs::create_dir_all` instead",
- format!("create_dir_all({})", snippet(cx, arg.span, "..")),
- Applicability::MaybeIncorrect,
- )
- }
+ if let ExprKind::Call(func, [arg, ..]) = expr.kind
+ && let ExprKind::Path(ref path) = func.kind
+ && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
+ && cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id)
+ {
+ span_lint_and_sugg(
+ cx,
+ CREATE_DIR,
+ expr.span,
+ "calling `std::fs::create_dir` where there may be a better way",
+ "consider calling `std::fs::create_dir_all` instead",
+ format!("create_dir_all({})", snippet(cx, arg.span, "..")),
+ Applicability::MaybeIncorrect,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
index 49452136d..9424a9103 100644
--- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs
+++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
@@ -5,8 +5,8 @@ use clippy_utils::{is_in_cfg_test, is_in_test_function};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Node};
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{sym, BytePos, Pos, Span};
+use rustc_session::impl_lint_pass;
+use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -31,31 +31,6 @@ declare_clippy_lint! {
"`dbg!` macro is intended as a debugging tool"
}
-/// Gets the span of the statement up to the next semicolon, if and only if the next
-/// non-whitespace character actually is a semicolon.
-/// E.g.
-/// ```rust,ignore
-///
-/// dbg!();
-/// ^^^^^^^ this span is returned
-///
-/// foo!(dbg!());
-/// no span is returned
-/// ```
-fn span_including_semi(cx: &LateContext<'_>, span: Span) -> Option<Span> {
- let sm = cx.sess().source_map();
- let sf = sm.lookup_source_file(span.hi());
- let src = sf.src.as_ref()?.get(span.hi().to_usize()..)?;
- let first_non_whitespace = src.find(|c: char| !c.is_whitespace())?;
-
- if src.as_bytes()[first_non_whitespace] == b';' {
- let hi = span.hi() + BytePos::from_usize(first_non_whitespace + 1);
- Some(span.with_hi(hi))
- } else {
- None
- }
-}
-
#[derive(Copy, Clone)]
pub struct DbgMacro {
allow_dbg_in_tests: bool,
@@ -88,10 +63,10 @@ impl LateLintPass<'_> for DbgMacro {
ExprKind::Block(..) => {
// If the `dbg!` macro is a "free" statement and not contained within other expressions,
// remove the whole statement.
- if let Some(Node::Stmt(stmt)) = cx.tcx.hir().find_parent(expr.hir_id)
- && let Some(span) = span_including_semi(cx, stmt.span.source_callsite())
+ if let Some(Node::Stmt(_)) = cx.tcx.hir().find_parent(expr.hir_id)
+ && let Some(semi_span) = cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
{
- (span, String::new())
+ (macro_call.span.to(semi_span), String::new())
} else {
(macro_call.span, String::from("()"))
}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 1a646ba38..1220eb890 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -10,8 +10,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
#[cfg(feature = "internal")]
crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO,
#[cfg(feature = "internal")]
- crate::utils::internal_lints::if_chain_style::IF_CHAIN_STYLE_INFO,
- #[cfg(feature = "internal")]
crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO,
@@ -65,7 +63,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO,
crate::await_holding_invalid::AWAIT_HOLDING_LOCK_INFO,
crate::await_holding_invalid::AWAIT_HOLDING_REFCELL_REF_INFO,
- crate::blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS_INFO,
+ crate::blocks_in_conditions::BLOCKS_IN_CONDITIONS_INFO,
crate::bool_assert_comparison::BOOL_ASSERT_COMPARISON_INFO,
crate::bool_to_int_with_if::BOOL_TO_INT_WITH_IF_INFO,
crate::booleans::NONMINIMAL_BOOL_INFO,
@@ -141,6 +139,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::doc::MISSING_PANICS_DOC_INFO,
crate::doc::MISSING_SAFETY_DOC_INFO,
crate::doc::NEEDLESS_DOCTEST_MAIN_INFO,
+ crate::doc::SUSPICIOUS_DOC_COMMENTS_INFO,
+ crate::doc::TEST_ATTR_IN_DOCTEST_INFO,
crate::doc::UNNECESSARY_SAFETY_DOC_INFO,
crate::double_parens::DOUBLE_PARENS_INFO,
crate::drop_forget_ref::DROP_NON_DROP_INFO,
@@ -205,6 +205,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::if_not_else::IF_NOT_ELSE_INFO,
crate::if_then_some_else_none::IF_THEN_SOME_ELSE_NONE_INFO,
crate::ignored_unit_patterns::IGNORED_UNIT_PATTERNS_INFO,
+ crate::impl_hash_with_borrow_str_and_bytes::IMPL_HASH_BORROW_WITH_STR_AND_BYTES_INFO,
crate::implicit_hasher::IMPLICIT_HASHER_INFO,
crate::implicit_return::IMPLICIT_RETURN_INFO,
crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO,
@@ -214,6 +215,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO,
crate::indexing_slicing::INDEXING_SLICING_INFO,
crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO,
+ crate::ineffective_open_options::INEFFECTIVE_OPEN_OPTIONS_INFO,
crate::infinite_iter::INFINITE_ITER_INFO,
crate::infinite_iter::MAYBE_INFINITE_ITER_INFO,
crate::inherent_impl::MULTIPLE_INHERENT_IMPL_INFO,
@@ -232,6 +234,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO,
crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO,
crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO,
+ crate::iter_over_hash_type::ITER_OVER_HASH_TYPE_INFO,
crate::iter_without_into_iter::INTO_ITER_WITHOUT_ITER_INFO,
crate::iter_without_into_iter::ITER_WITHOUT_INTO_ITER_INFO,
crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO,
@@ -263,6 +266,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::loops::EXPLICIT_INTO_ITER_LOOP_INFO,
crate::loops::EXPLICIT_ITER_LOOP_INFO,
crate::loops::FOR_KV_MAP_INFO,
+ crate::loops::INFINITE_LOOP_INFO,
crate::loops::ITER_NEXT_LOOP_INFO,
crate::loops::MANUAL_FIND_INFO,
crate::loops::MANUAL_FLATTEN_INFO,
@@ -376,6 +380,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::methods::ITER_SKIP_NEXT_INFO,
crate::methods::ITER_SKIP_ZERO_INFO,
crate::methods::ITER_WITH_DRAIN_INFO,
+ crate::methods::JOIN_ABSOLUTE_PATHS_INFO,
crate::methods::MANUAL_FILTER_MAP_INFO,
crate::methods::MANUAL_FIND_MAP_INFO,
crate::methods::MANUAL_NEXT_BACK_INFO,
@@ -403,6 +408,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::methods::OK_EXPECT_INFO,
crate::methods::OPTION_AS_REF_DEREF_INFO,
crate::methods::OPTION_FILTER_MAP_INFO,
+ crate::methods::OPTION_MAP_OR_ERR_OK_INFO,
crate::methods::OPTION_MAP_OR_NONE_INFO,
crate::methods::OR_FUN_CALL_INFO,
crate::methods::OR_THEN_UNWRAP_INFO,
@@ -594,6 +600,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::reference::DEREF_ADDROF_INFO,
crate::regex::INVALID_REGEX_INFO,
crate::regex::TRIVIAL_REGEX_INFO,
+ crate::repeat_vec_with_capacity::REPEAT_VEC_WITH_CAPACITY_INFO,
crate::reserve_after_initialization::RESERVE_AFTER_INITIALIZATION_INFO,
crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
crate::returns::LET_AND_RETURN_INFO,
@@ -628,7 +635,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::strings::STR_TO_STRING_INFO,
crate::strings::TRIM_SPLIT_WHITESPACE_INFO,
crate::strlen_on_c_strings::STRLEN_ON_C_STRINGS_INFO,
- crate::suspicious_doc_comments::SUSPICIOUS_DOC_COMMENTS_INFO,
crate::suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS_INFO,
crate::suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL_INFO,
crate::suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL_INFO,
@@ -675,13 +681,13 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::unicode::INVISIBLE_CHARACTERS_INFO,
crate::unicode::NON_ASCII_LITERAL_INFO,
crate::unicode::UNICODE_NOT_NFC_INFO,
+ crate::uninhabited_references::UNINHABITED_REFERENCES_INFO,
crate::uninit_vec::UNINIT_VEC_INFO,
crate::unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD_INFO,
crate::unit_types::LET_UNIT_VALUE_INFO,
crate::unit_types::UNIT_ARG_INFO,
crate::unit_types::UNIT_CMP_INFO,
crate::unnamed_address::FN_ADDRESS_COMPARISONS_INFO,
- crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO,
crate::unnecessary_box_returns::UNNECESSARY_BOX_RETURNS_INFO,
crate::unnecessary_map_on_constructor::UNNECESSARY_MAP_ON_CONSTRUCTOR_INFO,
crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index c74b2b883..d8a070b78 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::{has_drop, is_copy};
use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro};
-use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
@@ -10,7 +9,7 @@ use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::print::with_forced_trimmed_paths;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{sym, Span};
@@ -81,33 +80,31 @@ impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]);
impl<'tcx> LateLintPass<'tcx> for Default {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if_chain! {
- if !expr.span.from_expansion();
+ if !expr.span.from_expansion()
// Avoid cases already linted by `field_reassign_with_default`
- if !self.reassigned_linted.contains(&expr.span);
- if let ExprKind::Call(path, ..) = expr.kind;
- if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
- if let ExprKind::Path(ref qpath) = path.kind;
- if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
- if cx.tcx.is_diagnostic_item(sym::default_fn, def_id);
- if !is_update_syntax_base(cx, expr);
+ && !self.reassigned_linted.contains(&expr.span)
+ && let ExprKind::Call(path, ..) = expr.kind
+ && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id)
+ && let ExprKind::Path(ref qpath) = path.kind
+ && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+ && cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
+ && !is_update_syntax_base(cx, expr)
// Detect and ignore <Foo as Default>::default() because these calls do explicitly name the type.
- if let QPath::Resolved(None, _path) = qpath;
- let expr_ty = cx.typeck_results().expr_ty(expr);
- if let ty::Adt(def, ..) = expr_ty.kind();
- if !is_from_proc_macro(cx, expr);
- then {
- let replacement = with_forced_trimmed_paths!(format!("{}::default()", cx.tcx.def_path_str(def.did())));
- span_lint_and_sugg(
- cx,
- DEFAULT_TRAIT_ACCESS,
- expr.span,
- &format!("calling `{replacement}` is more clear than this expression"),
- "try",
- replacement,
- Applicability::Unspecified, // First resolve the TODO above
- );
- }
+ && let QPath::Resolved(None, _path) = qpath
+ && let expr_ty = cx.typeck_results().expr_ty(expr)
+ && let ty::Adt(def, ..) = expr_ty.kind()
+ && !is_from_proc_macro(cx, expr)
+ {
+ let replacement = with_forced_trimmed_paths!(format!("{}::default()", cx.tcx.def_path_str(def.did())));
+ span_lint_and_sugg(
+ cx,
+ DEFAULT_TRAIT_ACCESS,
+ expr.span,
+ &format!("calling `{replacement}` is more clear than this expression"),
+ "try",
+ replacement,
+ Applicability::Unspecified, // First resolve the TODO above
+ );
}
}
@@ -124,38 +121,36 @@ impl<'tcx> LateLintPass<'tcx> for Default {
// find all binding statements like `let mut _ = T::default()` where `T::default()` is the
// `default` method of the `Default` trait, and store statement index in current block being
// checked and the name of the bound variable
- let (local, variant, binding_name, binding_type, span) = if_chain! {
+ let (local, variant, binding_name, binding_type, span) = if let StmtKind::Local(local) = stmt.kind
// only take `let ...` statements
- if let StmtKind::Local(local) = stmt.kind;
- if let Some(expr) = local.init;
- if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
- if !expr.span.from_expansion();
+ && let Some(expr) = local.init
+ && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id)
+ && !expr.span.from_expansion()
// only take bindings to identifiers
- if let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind;
+ && let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind
// only when assigning `... = Default::default()`
- if is_expr_default(expr, cx);
- let binding_type = cx.typeck_results().node_type(binding_id);
- if let Some(adt) = binding_type.ty_adt_def();
- if adt.is_struct();
- let variant = adt.non_enum_variant();
- if adt.did().is_local() || !variant.is_field_list_non_exhaustive();
- let module_did = cx.tcx.parent_module(stmt.hir_id);
- if variant
+ && is_expr_default(expr, cx)
+ && let binding_type = cx.typeck_results().node_type(binding_id)
+ && let Some(adt) = binding_type.ty_adt_def()
+ && adt.is_struct()
+ && let variant = adt.non_enum_variant()
+ && (adt.did().is_local() || !variant.is_field_list_non_exhaustive())
+ && let module_did = cx.tcx.parent_module(stmt.hir_id)
+ && variant
.fields
.iter()
- .all(|field| field.vis.is_accessible_from(module_did, cx.tcx));
- let all_fields_are_copy = variant
+ .all(|field| field.vis.is_accessible_from(module_did, cx.tcx))
+ && let all_fields_are_copy = variant
.fields
.iter()
.all(|field| {
is_copy(cx, cx.tcx.type_of(field.did).instantiate_identity())
- });
- if !has_drop(cx, binding_type) || all_fields_are_copy;
- then {
- (local, variant, ident.name, binding_type, expr.span)
- } else {
- continue;
- }
+ })
+ && (!has_drop(cx, binding_type) || all_fields_are_copy)
+ {
+ (local, variant, ident.name, binding_type, expr.span)
+ } else {
+ continue;
};
let init_ctxt = local.span.ctxt();
@@ -216,21 +211,19 @@ impl<'tcx> LateLintPass<'tcx> for Default {
.join(", ");
// give correct suggestion if generics are involved (see #6944)
- let binding_type = if_chain! {
- if let ty::Adt(adt_def, args) = binding_type.kind();
- if !args.is_empty();
- then {
- let adt_def_ty_name = cx.tcx.item_name(adt_def.did());
- let generic_args = args.iter().collect::<Vec<_>>();
- let tys_str = generic_args
- .iter()
- .map(ToString::to_string)
- .collect::<Vec<_>>()
- .join(", ");
- format!("{adt_def_ty_name}::<{}>", &tys_str)
- } else {
- binding_type.to_string()
- }
+ let binding_type = if let ty::Adt(adt_def, args) = binding_type.kind()
+ && !args.is_empty()
+ {
+ let adt_def_ty_name = cx.tcx.item_name(adt_def.did());
+ let generic_args = args.iter().collect::<Vec<_>>();
+ let tys_str = generic_args
+ .iter()
+ .map(ToString::to_string)
+ .collect::<Vec<_>>()
+ .join(", ");
+ format!("{adt_def_ty_name}::<{}>", &tys_str)
+ } else {
+ binding_type.to_string()
};
let sugg = if ext_with_default {
@@ -260,48 +253,42 @@ impl<'tcx> LateLintPass<'tcx> for Default {
/// Checks if the given expression is the `default` method belonging to the `Default` trait.
fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool {
- if_chain! {
- if let ExprKind::Call(fn_expr, _) = &expr.kind;
- if let ExprKind::Path(qpath) = &fn_expr.kind;
- if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
- then {
- // right hand side of assignment is `Default::default`
- cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
- } else {
- false
- }
+ if let ExprKind::Call(fn_expr, _) = &expr.kind
+ && let ExprKind::Path(qpath) = &fn_expr.kind
+ && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id)
+ {
+ // right hand side of assignment is `Default::default`
+ cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
+ } else {
+ false
}
}
/// Returns the reassigned field and the assigning expression (right-hand side of assign).
fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Option<(Ident, &'tcx Expr<'tcx>)> {
- if_chain! {
+ if let StmtKind::Semi(later_expr) = this.kind
// only take assignments
- if let StmtKind::Semi(later_expr) = this.kind;
- if let ExprKind::Assign(assign_lhs, assign_rhs, _) = later_expr.kind;
+ && let ExprKind::Assign(assign_lhs, assign_rhs, _) = later_expr.kind
// only take assignments to fields where the left-hand side field is a field of
// the same binding as the previous statement
- if let ExprKind::Field(binding, field_ident) = assign_lhs.kind;
- if let ExprKind::Path(QPath::Resolved(_, path)) = binding.kind;
- if let Some(second_binding_name) = path.segments.last();
- if second_binding_name.ident.name == binding_name;
- then {
- Some((field_ident, assign_rhs))
- } else {
- None
- }
+ && let ExprKind::Field(binding, field_ident) = assign_lhs.kind
+ && let ExprKind::Path(QPath::Resolved(_, path)) = binding.kind
+ && let Some(second_binding_name) = path.segments.last()
+ && second_binding_name.ident.name == binding_name
+ {
+ Some((field_ident, assign_rhs))
+ } else {
+ None
}
}
/// Returns whether `expr` is the update syntax base: `Foo { a: 1, .. base }`
fn is_update_syntax_base<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
- if_chain! {
- if let Some(parent) = get_parent_expr(cx, expr);
- if let ExprKind::Struct(_, _, Some(base)) = parent.kind;
- then {
- base.hir_id == expr.hir_id
- } else {
- false
- }
+ if let Some(parent) = get_parent_expr(cx, expr)
+ && let ExprKind::Struct(_, _, Some(base)) = parent.kind
+ {
+ base.hir_id == expr.hir_id
+ } else {
+ false
}
}
diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
index bf070432e..9ce5acfbc 100644
--- a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
+++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
@@ -6,7 +6,7 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -56,32 +56,30 @@ fn is_alias(ty: hir::Ty<'_>) -> bool {
impl LateLintPass<'_> for DefaultConstructedUnitStructs {
fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
- if_chain!(
+ if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind
// make sure we have a call to `Default::default`
- if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind;
- if let ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(base, _)) = fn_expr.kind;
+ && let ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(base, _)) = fn_expr.kind
// make sure this isn't a type alias:
// `<Foo as Bar>::Assoc` cannot be used as a constructor
- if !is_alias(*base);
- if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
- if cx.tcx.is_diagnostic_item(sym::default_fn, def_id);
+ && !is_alias(*base)
+ && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id)
+ && cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
// make sure we have a struct with no fields (unit struct)
- if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind();
- if def.is_struct();
- if let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant();
- if !var.is_field_list_non_exhaustive();
- if !expr.span.from_expansion() && !qpath.span().from_expansion();
- then {
- span_lint_and_sugg(
- cx,
- DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
- expr.span.with_lo(qpath.qself_span().hi()),
- "use of `default` to create a unit struct",
- "remove this call to `default`",
- String::new(),
- Applicability::MachineApplicable,
- )
- }
- );
+ && let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind()
+ && def.is_struct()
+ && let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant()
+ && !var.is_field_list_non_exhaustive()
+ && !expr.span.from_expansion() && !qpath.span().from_expansion()
+ {
+ span_lint_and_sugg(
+ cx,
+ DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
+ expr.span.with_lo(qpath.qself_span().hi()),
+ "use of `default` to create a unit struct",
+ "remove this call to `default`",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ };
}
}
diff --git a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
index 553b670fd..2472e2ee7 100644
--- a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
+++ b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context;
use rustc_errors::Applicability;
use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, SyntaxContext};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index b296ea20f..64a924a77 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::source::snippet_opt;
use clippy_utils::{get_parent_node, numeric_literal};
-use if_chain::if_chain;
use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, walk_stmt, Visitor};
@@ -9,7 +8,7 @@ use rustc_hir::{Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use std::iter;
declare_clippy_lint! {
@@ -82,40 +81,40 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
/// Check whether a passed literal has potential to cause fallback or not.
fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) {
- if_chain! {
- if !in_external_macro(self.cx.sess(), lit.span);
- if matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false)));
- if matches!(lit.node,
- LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed));
- then {
- let (suffix, is_float) = match lit_ty.kind() {
- ty::Int(IntTy::I32) => ("i32", false),
- ty::Float(FloatTy::F64) => ("f64", true),
- // Default numeric fallback never results in other types.
- _ => return,
- };
-
- let src = if let Some(src) = snippet_opt(self.cx, lit.span) {
- src
- } else {
- match lit.node {
- LitKind::Int(src, _) => format!("{src}"),
- LitKind::Float(src, _) => format!("{src}"),
- _ => return,
- }
- };
- let sugg = numeric_literal::format(&src, Some(suffix), is_float);
- span_lint_hir_and_then(
- self.cx,
- DEFAULT_NUMERIC_FALLBACK,
- emit_hir_id,
- lit.span,
- "default numeric fallback might occur",
- |diag| {
- diag.span_suggestion(lit.span, "consider adding suffix", sugg, Applicability::MaybeIncorrect);
- }
- );
+ if !in_external_macro(self.cx.sess(), lit.span)
+ && matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false)))
+ && matches!(
+ lit.node,
+ LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed)
+ )
+ {
+ let (suffix, is_float) = match lit_ty.kind() {
+ ty::Int(IntTy::I32) => ("i32", false),
+ ty::Float(FloatTy::F64) => ("f64", true),
+ // Default numeric fallback never results in other types.
+ _ => return,
+ };
+
+ let src = if let Some(src) = snippet_opt(self.cx, lit.span) {
+ src
+ } else {
+ match lit.node {
+ LitKind::Int(src, _) => format!("{src}"),
+ LitKind::Float(src, _) => format!("{src}"),
+ _ => return,
}
+ };
+ let sugg = numeric_literal::format(&src, Some(suffix), is_float);
+ span_lint_hir_and_then(
+ self.cx,
+ DEFAULT_NUMERIC_FALLBACK,
+ emit_hir_id,
+ lit.span,
+ "default numeric fallback might occur",
+ |diag| {
+ diag.span_suggestion(lit.span, "consider adding suffix", sugg, Applicability::MaybeIncorrect);
+ },
+ );
}
}
}
@@ -149,36 +148,33 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
ExprKind::Struct(_, fields, base) => {
let ty = self.cx.typeck_results().expr_ty(expr);
- if_chain! {
- if let Some(adt_def) = ty.ty_adt_def();
- if adt_def.is_struct();
- if let Some(variant) = adt_def.variants().iter().next();
- then {
- let fields_def = &variant.fields;
-
- // Push field type then visit each field expr.
- for field in *fields {
- let bound =
- fields_def
- .iter()
- .find_map(|f_def| {
- if f_def.ident(self.cx.tcx) == field.ident
- { Some(self.cx.tcx.type_of(f_def.did).instantiate_identity()) }
- else { None }
- });
- self.ty_bounds.push(bound.into());
- self.visit_expr(field.expr);
- self.ty_bounds.pop();
- }
-
- // Visit base with no bound.
- if let Some(base) = base {
- self.ty_bounds.push(ExplicitTyBound(false));
- self.visit_expr(base);
- self.ty_bounds.pop();
- }
- return;
+ if let Some(adt_def) = ty.ty_adt_def()
+ && adt_def.is_struct()
+ && let Some(variant) = adt_def.variants().iter().next()
+ {
+ let fields_def = &variant.fields;
+
+ // Push field type then visit each field expr.
+ for field in *fields {
+ let bound = fields_def.iter().find_map(|f_def| {
+ if f_def.ident(self.cx.tcx) == field.ident {
+ Some(self.cx.tcx.type_of(f_def.did).instantiate_identity())
+ } else {
+ None
+ }
+ });
+ self.ty_bounds.push(bound.into());
+ self.visit_expr(field.expr);
+ self.ty_bounds.pop();
+ }
+
+ // Visit base with no bound.
+ if let Some(base) = base {
+ self.ty_bounds.push(ExplicitTyBound(false));
+ self.visit_expr(base);
+ self.ty_bounds.pop();
}
+ return;
}
},
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
index 8c6749a95..db01ff2cd 100644
--- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
@@ -3,7 +3,7 @@ use rustc_hir::{HirId, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, FieldDef, GenericArg, List};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 6c109a51f..aaef163ad 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1,10 +1,11 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{implements_trait, peel_mid_ty_refs};
+use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs};
use clippy_utils::{
expr_use_ctxt, get_parent_expr, get_parent_node, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
};
+use core::mem;
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::Applicability;
@@ -16,7 +17,7 @@ use rustc_hir::{
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt, TypeckResults};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};
@@ -170,9 +171,7 @@ pub struct Dereferencing<'tcx> {
#[derive(Debug)]
struct StateData<'tcx> {
- /// Span of the top level expression
- span: Span,
- hir_id: HirId,
+ first_expr: &'tcx Expr<'tcx>,
adjusted_ty: Ty<'tcx>,
}
@@ -198,6 +197,7 @@ enum State {
},
ExplicitDerefField {
name: Symbol,
+ derefs_manually_drop: bool,
},
Reborrow {
mutability: Mutability,
@@ -242,7 +242,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
// Stop processing sub expressions when a macro call is seen
if expr.span.from_expansion() {
if let Some((state, data)) = self.state.take() {
- report(cx, expr, state, data);
+ report(cx, expr, state, data, cx.typeck_results());
}
return;
}
@@ -251,7 +251,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
let Some((kind, sub_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else {
// The whole chain of reference operations has been seen
if let Some((state, data)) = self.state.take() {
- report(cx, expr, state, data);
+ report(cx, expr, state, data, typeck);
}
return;
};
@@ -272,14 +272,16 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
(Some(use_cx), RefOp::Deref) => {
let sub_ty = typeck.expr_ty(sub_expr);
if let ExprUseNode::FieldAccess(name) = use_cx.node
- && adjusted_ty.ty_adt_def().map_or(true, |adt| !adt.is_union())
+ && !use_cx.moved_before_use
&& !ty_contains_field(sub_ty, name.name)
{
self.state = Some((
- State::ExplicitDerefField { name: name.name },
+ State::ExplicitDerefField {
+ name: name.name,
+ derefs_manually_drop: is_manually_drop(sub_ty),
+ },
StateData {
- span: expr.span,
- hir_id: expr.hir_id,
+ first_expr: expr,
adjusted_ty,
},
));
@@ -293,8 +295,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
self.state = Some((
State::ExplicitDeref { mutability: None },
StateData {
- span: expr.span,
- hir_id: expr.hir_id,
+ first_expr: expr,
adjusted_ty,
},
));
@@ -313,8 +314,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
mutbl,
},
StateData {
- span: expr.span,
- hir_id: expr.hir_id,
+ first_expr: expr,
adjusted_ty,
},
));
@@ -342,8 +342,18 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return())
});
let can_auto_borrow = match use_cx.node {
- ExprUseNode::Callee => true,
- ExprUseNode::FieldAccess(_) => adjusted_ty.ty_adt_def().map_or(true, |adt| !adt.is_union()),
+ ExprUseNode::FieldAccess(_)
+ if !use_cx.moved_before_use && matches!(sub_expr.kind, ExprKind::Field(..)) =>
+ {
+ // `DerefMut` will not be automatically applied to `ManuallyDrop<_>`
+ // field expressions when the base type is a union and the parent
+ // expression is also a field access.
+ //
+ // e.g. `&mut x.y.z` where `x` is a union, and accessing `z` requires a
+ // deref through `ManuallyDrop<_>` will not compile.
+ !adjust_derefs_manually_drop(use_cx.adjustments, expr_ty)
+ },
+ ExprUseNode::Callee | ExprUseNode::FieldAccess(_) => true,
ExprUseNode::MethodArg(hir_id, _, 0) if !use_cx.moved_before_use => {
// Check for calls to trait methods where the trait is implemented
// on a reference.
@@ -357,11 +367,8 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
.tcx
.erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target))
&& let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
- && let args = cx
- .typeck_results()
- .node_args_opt(hir_id)
- .map(|args| &args[1..])
- .unwrap_or_default()
+ && let args =
+ typeck.node_args_opt(hir_id).map(|args| &args[1..]).unwrap_or_default()
&& let impl_ty =
if cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder().inputs()[0]
.is_ref()
@@ -436,14 +443,16 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
count: deref_count - required_refs,
msg,
stability,
- for_field_access: match use_cx.node {
- ExprUseNode::FieldAccess(name) => Some(name.name),
- _ => None,
+ for_field_access: if let ExprUseNode::FieldAccess(name) = use_cx.node
+ && !use_cx.moved_before_use
+ {
+ Some(name.name)
+ } else {
+ None
},
}),
StateData {
- span: expr.span,
- hir_id: expr.hir_id,
+ first_expr: expr,
adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
},
));
@@ -455,8 +464,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
self.state = Some((
State::Borrow { mutability },
StateData {
- span: expr.span,
- hir_id: expr.hir_id,
+ first_expr: expr,
adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
},
));
@@ -501,13 +509,12 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
(Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => {
let adjusted_ty = data.adjusted_ty;
let stability = state.stability;
- report(cx, expr, State::DerefedBorrow(state), data);
+ report(cx, expr, State::DerefedBorrow(state), data, typeck);
if stability.is_deref_stable() {
self.state = Some((
State::Borrow { mutability },
StateData {
- span: expr.span,
- hir_id: expr.hir_id,
+ first_expr: expr,
adjusted_ty,
},
));
@@ -517,15 +524,18 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
let adjusted_ty = data.adjusted_ty;
let stability = state.stability;
let for_field_access = state.for_field_access;
- report(cx, expr, State::DerefedBorrow(state), data);
+ report(cx, expr, State::DerefedBorrow(state), data, typeck);
if let Some(name) = for_field_access
- && !ty_contains_field(typeck.expr_ty(sub_expr), name)
+ && let sub_expr_ty = typeck.expr_ty(sub_expr)
+ && !ty_contains_field(sub_expr_ty, name)
{
self.state = Some((
- State::ExplicitDerefField { name },
+ State::ExplicitDerefField {
+ name,
+ derefs_manually_drop: is_manually_drop(sub_expr_ty),
+ },
StateData {
- span: expr.span,
- hir_id: expr.hir_id,
+ first_expr: expr,
adjusted_ty,
},
));
@@ -535,8 +545,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
self.state = Some((
State::ExplicitDeref { mutability: None },
StateData {
- span: parent.span,
- hir_id: parent.hir_id,
+ first_expr: parent,
adjusted_ty,
},
));
@@ -566,13 +575,28 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
(state @ Some((State::ExplicitDeref { .. }, _)), RefOp::Deref) => {
self.state = state;
},
- (Some((State::ExplicitDerefField { name }, data)), RefOp::Deref)
- if !ty_contains_field(typeck.expr_ty(sub_expr), name) =>
+ (
+ Some((
+ State::ExplicitDerefField {
+ name,
+ derefs_manually_drop,
+ },
+ data,
+ )),
+ RefOp::Deref,
+ ) if let sub_expr_ty = typeck.expr_ty(sub_expr)
+ && !ty_contains_field(sub_expr_ty, name) =>
{
- self.state = Some((State::ExplicitDerefField { name }, data));
+ self.state = Some((
+ State::ExplicitDerefField {
+ name,
+ derefs_manually_drop: derefs_manually_drop || is_manually_drop(sub_expr_ty),
+ },
+ data,
+ ));
},
- (Some((state, data)), _) => report(cx, expr, state, data),
+ (Some((state, data)), _) => report(cx, expr, state, data, typeck),
}
}
@@ -597,26 +621,24 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
return;
}
- if_chain! {
- if !pat.span.from_expansion();
- if let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind();
+ if !pat.span.from_expansion()
+ && let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind()
// only lint immutable refs, because borrowed `&mut T` cannot be moved out
- if let ty::Ref(_, _, Mutability::Not) = *tam.kind();
- then {
- let mut app = Applicability::MachineApplicable;
- let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0;
- self.current_body = self.current_body.or(cx.enclosing_body);
- self.ref_locals.insert(
- id,
- Some(RefPat {
- always_deref: true,
- spans: vec![pat.span],
- app,
- replacements: vec![(pat.span, snip.into())],
- hir_id: pat.hir_id,
- }),
- );
- }
+ && let ty::Ref(_, _, Mutability::Not) = *tam.kind()
+ {
+ let mut app = Applicability::MachineApplicable;
+ let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0;
+ self.current_body = self.current_body.or(cx.enclosing_body);
+ self.ref_locals.insert(
+ id,
+ Some(RefPat {
+ always_deref: true,
+ spans: vec![pat.span],
+ app,
+ replacements: vec![(pat.span, snip.into())],
+ hir_id: pat.hir_id,
+ }),
+ );
}
}
}
@@ -689,6 +711,14 @@ fn try_parse_ref_op<'tcx>(
}
}
+// Checks if the adjustments contains a deref of `ManuallyDrop<_>`
+fn adjust_derefs_manually_drop<'tcx>(adjustments: &'tcx [Adjustment<'tcx>], mut ty: Ty<'tcx>) -> bool {
+ adjustments.iter().any(|a| {
+ let ty = mem::replace(&mut ty, a.target);
+ matches!(a.kind, Adjust::Deref(Some(ref op)) if op.mutbl == Mutability::Mut) && is_manually_drop(ty)
+ })
+}
+
// Checks whether the type for a deref call actually changed the type, not just the mutability of
// the reference.
fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
@@ -741,7 +771,7 @@ impl TyCoercionStability {
DefinedTy::Mir(ty) => Self::for_mir_ty(
cx.tcx,
ty.param_env,
- cx.tcx.erase_late_bound_regions(ty.value),
+ cx.tcx.instantiate_bound_regions_with_erased(ty.value),
for_return,
),
}
@@ -898,7 +928,13 @@ fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool {
}
#[expect(clippy::needless_pass_by_value, clippy::too_many_lines)]
-fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData<'tcx>) {
+fn report<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ state: State,
+ data: StateData<'tcx>,
+ typeck: &'tcx TypeckResults<'tcx>,
+) {
match state {
State::DerefMethod {
ty_changed_count,
@@ -906,8 +942,9 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
mutbl,
} => {
let mut app = Applicability::MachineApplicable;
- let (expr_str, _expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
- let ty = cx.typeck_results().expr_ty(expr);
+ let (expr_str, _expr_is_macro_call) =
+ snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
+ let ty = typeck.expr_ty(expr);
let (_, ref_count) = peel_mid_ty_refs(ty);
let deref_str = if ty_changed_count >= ref_count && ref_count != 0 {
// a deref call changing &T -> &U requires two deref operators the first time
@@ -947,7 +984,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
span_lint_and_sugg(
cx,
EXPLICIT_DEREF_METHODS,
- data.span,
+ data.first_expr.span,
match mutbl {
Mutability::Not => "explicit `deref` method call",
Mutability::Mut => "explicit `deref_mut` method call",
@@ -959,26 +996,34 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
},
State::DerefedBorrow(state) => {
let mut app = Applicability::MachineApplicable;
- let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
- span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, state.msg, |diag| {
- let (precedence, calls_field) = match get_parent_node(cx.tcx, data.hir_id) {
- Some(Node::Expr(e)) => match e.kind {
- ExprKind::Call(callee, _) if callee.hir_id != data.hir_id => (0, false),
- ExprKind::Call(..) => (PREC_POSTFIX, matches!(expr.kind, ExprKind::Field(..))),
- _ => (e.precedence().order(), false),
- },
- _ => (0, false),
- };
- let sugg = if !snip_is_macro
- && (calls_field || expr.precedence().order() < precedence)
- && !has_enclosing_paren(&snip)
- {
- format!("({snip})")
- } else {
- snip.into()
- };
- diag.span_suggestion(data.span, "change this to", sugg, app);
- });
+ let (snip, snip_is_macro) =
+ snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
+ span_lint_hir_and_then(
+ cx,
+ NEEDLESS_BORROW,
+ data.first_expr.hir_id,
+ data.first_expr.span,
+ state.msg,
+ |diag| {
+ let (precedence, calls_field) = match get_parent_node(cx.tcx, data.first_expr.hir_id) {
+ Some(Node::Expr(e)) => match e.kind {
+ ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => (0, false),
+ ExprKind::Call(..) => (PREC_POSTFIX, matches!(expr.kind, ExprKind::Field(..))),
+ _ => (e.precedence().order(), false),
+ },
+ _ => (0, false),
+ };
+ let sugg = if !snip_is_macro
+ && (calls_field || expr.precedence().order() < precedence)
+ && !has_enclosing_paren(&snip)
+ {
+ format!("({snip})")
+ } else {
+ snip.into()
+ };
+ diag.span_suggestion(data.first_expr.span, "change this to", sugg, app);
+ },
+ );
},
State::ExplicitDeref { mutability } => {
if matches!(
@@ -996,7 +1041,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
}
let (prefix, precedence) = if let Some(mutability) = mutability
- && !cx.typeck_results().expr_ty(expr).is_ref()
+ && !typeck.expr_ty(expr).is_ref()
{
let prefix = match mutability {
Mutability::Not => "&",
@@ -1009,53 +1054,61 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
span_lint_hir_and_then(
cx,
EXPLICIT_AUTO_DEREF,
- data.hir_id,
- data.span,
+ data.first_expr.hir_id,
+ data.first_expr.span,
"deref which would be done by auto-deref",
|diag| {
let mut app = Applicability::MachineApplicable;
- let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
+ let (snip, snip_is_macro) =
+ snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
let sugg =
if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) {
format!("{prefix}({snip})")
} else {
format!("{prefix}{snip}")
};
- diag.span_suggestion(data.span, "try", sugg, app);
+ diag.span_suggestion(data.first_expr.span, "try", sugg, app);
},
);
},
- State::ExplicitDerefField { .. } => {
- if matches!(
- expr.kind,
- ExprKind::Block(..)
- | ExprKind::ConstBlock(_)
- | ExprKind::If(..)
- | ExprKind::Loop(..)
- | ExprKind::Match(..)
- ) && data.adjusted_ty.is_sized(cx.tcx, cx.param_env)
- {
- // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
- return;
- }
-
- if let ExprKind::Field(parent_expr, _) = expr.kind
- && let ty::Adt(adt, _) = cx.typeck_results().expr_ty(parent_expr).kind()
- && adt.is_union()
- {
- // Auto deref does not apply on union field
- return;
- }
+ State::ExplicitDerefField {
+ derefs_manually_drop, ..
+ } => {
+ let (snip_span, needs_parens) = if matches!(expr.kind, ExprKind::Field(..))
+ && (derefs_manually_drop
+ || adjust_derefs_manually_drop(
+ typeck.expr_adjustments(data.first_expr),
+ typeck.expr_ty(data.first_expr),
+ )) {
+ // `DerefMut` will not be automatically applied to `ManuallyDrop<_>`
+ // field expressions when the base type is a union and the parent
+ // expression is also a field access.
+ //
+ // e.g. `&mut x.y.z` where `x` is a union, and accessing `z` requires a
+ // deref through `ManuallyDrop<_>` will not compile.
+ let parent_id = cx.tcx.hir().parent_id(expr.hir_id);
+ if parent_id == data.first_expr.hir_id {
+ return;
+ }
+ (cx.tcx.hir_node(parent_id).expect_expr().span, true)
+ } else {
+ (expr.span, false)
+ };
span_lint_hir_and_then(
cx,
EXPLICIT_AUTO_DEREF,
- data.hir_id,
- data.span,
+ data.first_expr.hir_id,
+ data.first_expr.span,
"deref which would be done by auto-deref",
|diag| {
let mut app = Applicability::MachineApplicable;
- let snip = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app).0;
- diag.span_suggestion(data.span, "try", snip.into_owned(), app);
+ let snip = snippet_with_context(cx, snip_span, data.first_expr.span.ctxt(), "..", &mut app).0;
+ let sugg = if needs_parens {
+ format!("({snip})")
+ } else {
+ snip.into_owned()
+ };
+ diag.span_suggestion(data.first_expr.span, "try", sugg, app);
},
);
},
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index a450becc6..6b0423200 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -10,7 +10,7 @@ use rustc_hir::{
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::adjustment::{Adjust, PointerCoercion};
use rustc_middle::ty::{self, Adt, AdtDef, GenericArgsRef, Ty, TypeckResults};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -148,83 +148,65 @@ fn check_struct<'tcx>(
}
fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Expr<'_>, adt_def: AdtDef<'_>) {
- if_chain! {
- if let ExprKind::Path(QPath::Resolved(None, p)) = &peel_blocks(func_expr).kind;
- if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res;
- if let variant_id = cx.tcx.parent(id);
- if let Some(variant_def) = adt_def.variants().iter().find(|v| v.def_id == variant_id);
- if variant_def.fields.is_empty();
- if !variant_def.is_field_list_non_exhaustive();
-
- then {
- let enum_span = cx.tcx.def_span(adt_def.did());
- let indent_enum = indent_of(cx, enum_span).unwrap_or(0);
- let variant_span = cx.tcx.def_span(variant_def.def_id);
- let indent_variant = indent_of(cx, variant_span).unwrap_or(0);
- span_lint_and_then(
- cx,
- DERIVABLE_IMPLS,
+ if let ExprKind::Path(QPath::Resolved(None, p)) = &peel_blocks(func_expr).kind
+ && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res
+ && let variant_id = cx.tcx.parent(id)
+ && let Some(variant_def) = adt_def.variants().iter().find(|v| v.def_id == variant_id)
+ && variant_def.fields.is_empty()
+ && !variant_def.is_field_list_non_exhaustive()
+ {
+ let enum_span = cx.tcx.def_span(adt_def.did());
+ let indent_enum = indent_of(cx, enum_span).unwrap_or(0);
+ let variant_span = cx.tcx.def_span(variant_def.def_id);
+ let indent_variant = indent_of(cx, variant_span).unwrap_or(0);
+ span_lint_and_then(cx, DERIVABLE_IMPLS, item.span, "this `impl` can be derived", |diag| {
+ diag.span_suggestion_hidden(
item.span,
- "this `impl` can be derived",
- |diag| {
- diag.span_suggestion_hidden(
- item.span,
- "remove the manual implementation...",
- String::new(),
- Applicability::MachineApplicable
- );
- diag.span_suggestion(
- enum_span.shrink_to_lo(),
- "...and instead derive it...",
- format!(
- "#[derive(Default)]\n{indent}",
- indent = " ".repeat(indent_enum),
- ),
- Applicability::MachineApplicable
- );
- diag.span_suggestion(
- variant_span.shrink_to_lo(),
- "...and mark the default variant",
- format!(
- "#[default]\n{indent}",
- indent = " ".repeat(indent_variant),
- ),
- Applicability::MachineApplicable
- );
- }
+ "remove the manual implementation...",
+ String::new(),
+ Applicability::MachineApplicable,
);
- }
+ diag.span_suggestion(
+ enum_span.shrink_to_lo(),
+ "...and instead derive it...",
+ format!("#[derive(Default)]\n{indent}", indent = " ".repeat(indent_enum),),
+ Applicability::MachineApplicable,
+ );
+ diag.span_suggestion(
+ variant_span.shrink_to_lo(),
+ "...and mark the default variant",
+ format!("#[default]\n{indent}", indent = " ".repeat(indent_variant),),
+ Applicability::MachineApplicable,
+ );
+ });
}
}
impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
- if_chain! {
- if let ItemKind::Impl(Impl {
- of_trait: Some(ref trait_ref),
- items: [child],
- self_ty,
- ..
- }) = item.kind;
- if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
- if !item.span.from_expansion();
- if let Some(def_id) = trait_ref.trait_def_id();
- if cx.tcx.is_diagnostic_item(sym::Default, def_id);
- if let impl_item_hir = child.id.hir_id();
- if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
- if let ImplItemKind::Fn(_, b) = &impl_item.kind;
- if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
- if let &Adt(adt_def, args) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind();
- if let attrs = cx.tcx.hir().attrs(item.hir_id());
- if !attrs.iter().any(|attr| attr.doc_str().is_some());
- if cx.tcx.hir().attrs(impl_item_hir).is_empty();
-
- then {
- if adt_def.is_struct() {
- check_struct(cx, item, self_ty, func_expr, adt_def, args, cx.tcx.typeck_body(*b));
- } else if adt_def.is_enum() && self.msrv.meets(msrvs::DEFAULT_ENUM_ATTRIBUTE) {
- check_enum(cx, item, func_expr, adt_def);
- }
+ if let ItemKind::Impl(Impl {
+ of_trait: Some(ref trait_ref),
+ items: [child],
+ self_ty,
+ ..
+ }) = item.kind
+ && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived)
+ && !item.span.from_expansion()
+ && let Some(def_id) = trait_ref.trait_def_id()
+ && cx.tcx.is_diagnostic_item(sym::Default, def_id)
+ && let impl_item_hir = child.id.hir_id()
+ && let Some(Node::ImplItem(impl_item)) = cx.tcx.opt_hir_node(impl_item_hir)
+ && let ImplItemKind::Fn(_, b) = &impl_item.kind
+ && let Body { value: func_expr, .. } = cx.tcx.hir().body(*b)
+ && let &Adt(adt_def, args) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind()
+ && let attrs = cx.tcx.hir().attrs(item.hir_id())
+ && !attrs.iter().any(|attr| attr.doc_str().is_some())
+ && cx.tcx.hir().attrs(impl_item_hir).is_empty()
+ {
+ if adt_def.is_struct() {
+ check_struct(cx, item, self_ty, func_expr, adt_def, args, cx.tcx.typeck_body(*b));
+ } else if adt_def.is_enum() && self.msrv.meets(msrvs::DEFAULT_ENUM_ATTRIBUTE) {
+ check_enum(cx, item, func_expr, adt_def);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 3a331564d..d8abe4110 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
use clippy_utils::{is_lint_allowed, match_def_path, paths};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
@@ -15,7 +14,7 @@ use rustc_middle::ty::{
self, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate, TraitPredicate, Ty,
TyCtxt,
};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span};
@@ -232,42 +231,37 @@ fn check_hash_peq<'tcx>(
ty: Ty<'tcx>,
hash_is_automatically_derived: bool,
) {
- if_chain! {
- if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait();
- if let Some(def_id) = trait_ref.trait_def_id();
- if cx.tcx.is_diagnostic_item(sym::Hash, def_id);
- then {
- // Look for the PartialEq implementations for `ty`
- cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
- let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
-
- if !hash_is_automatically_derived || peq_is_automatically_derived {
- return;
- }
-
- let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
-
- // Only care about `impl PartialEq<Foo> for Foo`
- // For `impl PartialEq<B> for A, input_types is [A, B]
- if trait_ref.instantiate_identity().args.type_at(1) == ty {
- span_lint_and_then(
- cx,
- DERIVED_HASH_WITH_MANUAL_EQ,
- span,
- "you are deriving `Hash` but have implemented `PartialEq` explicitly",
- |diag| {
- if let Some(local_def_id) = impl_id.as_local() {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
- diag.span_note(
- cx.tcx.hir().span(hir_id),
- "`PartialEq` implemented here"
- );
- }
+ if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait()
+ && let Some(def_id) = trait_ref.trait_def_id()
+ && cx.tcx.is_diagnostic_item(sym::Hash, def_id)
+ {
+ // Look for the PartialEq implementations for `ty`
+ cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
+ let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
+
+ if !hash_is_automatically_derived || peq_is_automatically_derived {
+ return;
+ }
+
+ let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
+
+ // Only care about `impl PartialEq<Foo> for Foo`
+ // For `impl PartialEq<B> for A, input_types is [A, B]
+ if trait_ref.instantiate_identity().args.type_at(1) == ty {
+ span_lint_and_then(
+ cx,
+ DERIVED_HASH_WITH_MANUAL_EQ,
+ span,
+ "you are deriving `Hash` but have implemented `PartialEq` explicitly",
+ |diag| {
+ if let Some(local_def_id) = impl_id.as_local() {
+ let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
+ diag.span_note(cx.tcx.hir().span(hir_id), "`PartialEq` implemented here");
}
- );
- }
- });
- }
+ },
+ );
+ }
+ });
}
}
@@ -279,49 +273,38 @@ fn check_ord_partial_ord<'tcx>(
ty: Ty<'tcx>,
ord_is_automatically_derived: bool,
) {
- if_chain! {
- if let Some(ord_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Ord);
- if let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait();
- if let Some(def_id) = &trait_ref.trait_def_id();
- if *def_id == ord_trait_def_id;
- then {
- // Look for the PartialOrd implementations for `ty`
- cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| {
- let partial_ord_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
-
- if partial_ord_is_automatically_derived == ord_is_automatically_derived {
- return;
- }
-
- let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
-
- // Only care about `impl PartialOrd<Foo> for Foo`
- // For `impl PartialOrd<B> for A, input_types is [A, B]
- if trait_ref.instantiate_identity().args.type_at(1) == ty {
- let mess = if partial_ord_is_automatically_derived {
- "you are implementing `Ord` explicitly but have derived `PartialOrd`"
- } else {
- "you are deriving `Ord` but have implemented `PartialOrd` explicitly"
- };
-
- span_lint_and_then(
- cx,
- DERIVE_ORD_XOR_PARTIAL_ORD,
- span,
- mess,
- |diag| {
- if let Some(local_def_id) = impl_id.as_local() {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
- diag.span_note(
- cx.tcx.hir().span(hir_id),
- "`PartialOrd` implemented here"
- );
- }
- }
- );
- }
- });
- }
+ if let Some(ord_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Ord)
+ && let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait()
+ && let Some(def_id) = &trait_ref.trait_def_id()
+ && *def_id == ord_trait_def_id
+ {
+ // Look for the PartialOrd implementations for `ty`
+ cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| {
+ let partial_ord_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
+
+ if partial_ord_is_automatically_derived == ord_is_automatically_derived {
+ return;
+ }
+
+ let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
+
+ // Only care about `impl PartialOrd<Foo> for Foo`
+ // For `impl PartialOrd<B> for A, input_types is [A, B]
+ if trait_ref.instantiate_identity().args.type_at(1) == ty {
+ let mess = if partial_ord_is_automatically_derived {
+ "you are implementing `Ord` explicitly but have derived `PartialOrd`"
+ } else {
+ "you are deriving `Ord` but have implemented `PartialOrd` explicitly"
+ };
+
+ span_lint_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, span, mess, |diag| {
+ if let Some(local_def_id) = impl_id.as_local() {
+ let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
+ diag.span_note(cx.tcx.hir().span(hir_id), "`PartialOrd` implemented here");
+ }
+ });
+ }
+ });
}
}
@@ -394,27 +377,27 @@ fn check_unsafe_derive_deserialize<'tcx>(
visitor.has_unsafe
}
- if_chain! {
- if let Some(trait_def_id) = trait_ref.trait_def_id();
- if match_def_path(cx, trait_def_id, &paths::SERDE_DESERIALIZE);
- if let ty::Adt(def, _) = ty.kind();
- if let Some(local_def_id) = def.did().as_local();
- let adt_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
- if !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id);
- if cx.tcx.inherent_impls(def.did())
+ if let Some(trait_def_id) = trait_ref.trait_def_id()
+ && match_def_path(cx, trait_def_id, &paths::SERDE_DESERIALIZE)
+ && let ty::Adt(def, _) = ty.kind()
+ && let Some(local_def_id) = def.did().as_local()
+ && let adt_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id)
+ && !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id)
+ && cx
+ .tcx
+ .inherent_impls(def.did())
.iter()
.map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local()))
- .any(|imp| has_unsafe(cx, imp));
- then {
- span_lint_and_help(
- cx,
- UNSAFE_DERIVE_DESERIALIZE,
- item.span,
- "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`",
- None,
- "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html"
- );
- }
+ .any(|imp| has_unsafe(cx, imp))
+ {
+ span_lint_and_help(
+ cx,
+ UNSAFE_DERIVE_DESERIALIZE,
+ item.span,
+ "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`",
+ None,
+ "consider implementing `serde::Deserialize` manually. See https://serde.rs/impl-deserialize.html",
+ );
}
}
@@ -431,12 +414,10 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
return;
}
- if_chain! {
- if let Some(header) = kind.header();
- if header.unsafety == Unsafety::Unsafe;
- then {
- self.has_unsafe = true;
- }
+ if let Some(header) = kind.header()
+ && header.unsafety == Unsafety::Unsafe
+ {
+ self.has_unsafe = true;
}
walk_fn(self, kind, decl, body_id, id);
@@ -463,30 +444,28 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
/// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint.
fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
- if_chain! {
- if let ty::Adt(adt, args) = ty.kind();
- if cx.tcx.visibility(adt.did()).is_public();
- if let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq);
- if let Some(def_id) = trait_ref.trait_def_id();
- if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id);
- let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id);
- if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]);
+ if let ty::Adt(adt, args) = ty.kind()
+ && cx.tcx.visibility(adt.did()).is_public()
+ && let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq)
+ && let Some(def_id) = trait_ref.trait_def_id()
+ && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id)
+ && let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id)
+ && !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, adt.did(),&[])
// If all of our fields implement `Eq`, we can implement `Eq` too
- if adt
+ && adt
.all_fields()
.map(|f| f.ty(cx.tcx, args))
- .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]));
- then {
- 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,
- )
- }
+ .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, adt.did(), &[]))
+ {
+ 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,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index 324b5e079..656b3d9bf 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{ExpnId, Span};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index d23aeebb5..1868d3cd3 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -4,7 +4,7 @@ use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
index 5e46b29b6..09dad5554 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
@@ -3,7 +3,7 @@ use clippy_utils::is_test_module_or_function;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::{Item, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -31,9 +31,9 @@ pub struct DisallowedNames {
}
impl DisallowedNames {
- pub fn new(disallow: FxHashSet<String>) -> Self {
+ pub fn new(disallowed_names: &[String]) -> Self {
Self {
- disallow,
+ disallow: disallowed_names.iter().cloned().collect(),
test_modules_deep: 0,
}
}
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
index 96a7f0e4f..d5205e65c 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast;
use rustc_data_structures::fx::FxHashSet;
use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use unicode_script::{Script, UnicodeScript};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
index 3578fb640..130f56b69 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -5,7 +5,7 @@ use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/doc/link_with_quotes.rs b/src/tools/clippy/clippy_lints/src/doc/link_with_quotes.rs
new file mode 100644
index 000000000..01191e811
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/doc/link_with_quotes.rs
@@ -0,0 +1,20 @@
+use std::ops::Range;
+
+use clippy_utils::diagnostics::span_lint;
+use rustc_lint::LateContext;
+
+use super::{Fragments, DOC_LINK_WITH_QUOTES};
+
+pub fn check(cx: &LateContext<'_>, trimmed_text: &str, range: Range<usize>, fragments: Fragments<'_>) {
+ if ((trimmed_text.starts_with('\'') && trimmed_text.ends_with('\''))
+ || (trimmed_text.starts_with('"') && trimmed_text.ends_with('"')))
+ && let Some(span) = fragments.span(cx, range)
+ {
+ span_lint(
+ cx,
+ DOC_LINK_WITH_QUOTES,
+ span,
+ "possible intra-doc link using quotes instead of backticks",
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/doc/markdown.rs b/src/tools/clippy/clippy_lints/src/doc/markdown.rs
new file mode 100644
index 000000000..a58219c29
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/doc/markdown.rs
@@ -0,0 +1,119 @@
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::source::snippet_with_applicability;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{Applicability, SuggestionStyle};
+use rustc_lint::LateContext;
+use rustc_span::{BytePos, Pos, Span};
+use url::Url;
+
+use crate::doc::DOC_MARKDOWN;
+
+pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) {
+ for orig_word in text.split(|c: char| c.is_whitespace() || c == '\'') {
+ // Trim punctuation as in `some comment (see foo::bar).`
+ // ^^
+ // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix.
+ let trim_pattern = |c: char| !c.is_alphanumeric() && c != ':';
+ let mut word = orig_word.trim_end_matches(trim_pattern);
+
+ // If word is immediately followed by `()`, claw it back.
+ if let Some(tmp_word) = orig_word.get(..word.len() + 2)
+ && tmp_word.ends_with("()")
+ {
+ word = tmp_word;
+ }
+
+ word = word.trim_start_matches(trim_pattern);
+
+ // Remove leading or trailing single `:` which may be part of a sentence.
+ if word.starts_with(':') && !word.starts_with("::") {
+ word = word.trim_start_matches(':');
+ }
+ if word.ends_with(':') && !word.ends_with("::") {
+ word = word.trim_end_matches(':');
+ }
+
+ if valid_idents.contains(word) || word.chars().all(|c| c == ':') {
+ continue;
+ }
+
+ // Adjust for the current word
+ let offset = word.as_ptr() as usize - text.as_ptr() as usize;
+ let span = Span::new(
+ span.lo() + BytePos::from_usize(offset),
+ span.lo() + BytePos::from_usize(offset + word.len()),
+ span.ctxt(),
+ span.parent(),
+ );
+
+ check_word(cx, word, span);
+ }
+}
+
+fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
+ /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and
+ /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case
+ /// letter (`NASA` is ok).
+ /// Plurals are also excluded (`IDs` is ok).
+ fn is_camel_case(s: &str) -> bool {
+ if s.starts_with(|c: char| c.is_ascii_digit() | c.is_ascii_lowercase()) {
+ return false;
+ }
+
+ let s = s.strip_suffix('s').unwrap_or(s);
+
+ s.chars().all(char::is_alphanumeric)
+ && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
+ && s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
+ }
+
+ fn has_underscore(s: &str) -> bool {
+ s != "_" && !s.contains("\\_") && s.contains('_')
+ }
+
+ fn has_hyphen(s: &str) -> bool {
+ s != "-" && s.contains('-')
+ }
+
+ if let Ok(url) = Url::parse(word) {
+ // try to get around the fact that `foo::bar` parses as a valid URL
+ if !url.cannot_be_a_base() {
+ span_lint(
+ cx,
+ DOC_MARKDOWN,
+ span,
+ "you should put bare URLs between `<`/`>` or make a proper Markdown link",
+ );
+
+ return;
+ }
+ }
+
+ // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343)
+ if has_underscore(word) && has_hyphen(word) {
+ return;
+ }
+
+ if has_underscore(word) || word.contains("::") || is_camel_case(word) || word.ends_with("()") {
+ let mut applicability = Applicability::MachineApplicable;
+
+ span_lint_and_then(
+ cx,
+ DOC_MARKDOWN,
+ span,
+ "item in documentation is missing backticks",
+ |diag| {
+ let snippet = snippet_with_applicability(cx, span, "..", &mut applicability);
+ diag.span_suggestion_with_style(
+ span,
+ "try",
+ format!("`{snippet}`"),
+ applicability,
+ // always show the suggestion in a separate line, since the
+ // inline presentation adds another pair of backticks
+ SuggestionStyle::ShowAlways,
+ );
+ },
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
new file mode 100644
index 000000000..4cbfa97a8
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
@@ -0,0 +1,86 @@
+use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::{is_doc_hidden, return_ty};
+use rustc_hir::{BodyId, FnSig, OwnerId, Unsafety};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_span::{sym, Span};
+
+use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC};
+
+pub fn check(
+ cx: &LateContext<'_>,
+ owner_id: OwnerId,
+ sig: &FnSig<'_>,
+ headers: DocHeaders,
+ body_id: Option<BodyId>,
+ panic_span: Option<Span>,
+ check_private_items: bool,
+) {
+ if !check_private_items && !cx.effective_visibilities.is_exported(owner_id.def_id) {
+ return; // Private functions do not require doc comments
+ }
+
+ // do not lint if any parent has `#[doc(hidden)]` attribute (#7347)
+ if !check_private_items
+ && cx
+ .tcx
+ .hir()
+ .parent_iter(owner_id.into())
+ .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id)))
+ {
+ return;
+ }
+
+ let span = cx.tcx.def_span(owner_id);
+ match (headers.safety, sig.header.unsafety) {
+ (false, Unsafety::Unsafe) => span_lint(
+ cx,
+ MISSING_SAFETY_DOC,
+ span,
+ "unsafe function's docs miss `# Safety` section",
+ ),
+ (true, Unsafety::Normal) => span_lint(
+ cx,
+ UNNECESSARY_SAFETY_DOC,
+ span,
+ "safe function's docs have unnecessary `# Safety` section",
+ ),
+ _ => (),
+ }
+ if !headers.panics && panic_span.is_some() {
+ span_lint_and_note(
+ cx,
+ MISSING_PANICS_DOC,
+ span,
+ "docs for function which may panic missing `# Panics` section",
+ panic_span,
+ "first possible panic found here",
+ );
+ }
+ if !headers.errors {
+ if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) {
+ span_lint(
+ cx,
+ MISSING_ERRORS_DOC,
+ span,
+ "docs for function returning `Result` missing `# Errors` section",
+ );
+ } else if let Some(body_id) = body_id
+ && let Some(future) = cx.tcx.lang_items().future_trait()
+ && let typeck = cx.tcx.typeck_body(body_id)
+ && let body = cx.tcx.hir().body(body_id)
+ && let ret_ty = typeck.expr_ty(body.value)
+ && implements_trait(cx, ret_ty, future, &[])
+ && let ty::Coroutine(_, subs, _) = ret_ty.kind()
+ && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result)
+ {
+ span_lint(
+ cx,
+ MISSING_ERRORS_DOC,
+ span,
+ "docs for function returning `Result` missing `# Errors` section",
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 8982fca6e..ba4527750 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -1,20 +1,16 @@
use clippy_utils::attrs::is_doc_hidden;
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::macros::{is_panic, root_macro_call_first_node};
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty};
-use if_chain::if_chain;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::Visitable;
+use clippy_utils::{is_entrypoint_fn, method_chain_args};
use pulldown_cmark::Event::{
Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
};
use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph};
use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options};
-use rustc_ast::ast::{Async, Attribute, Fn, FnRetTy, ItemKind};
+use rustc_ast::ast::Attribute;
use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::sync::Lrc;
-use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::{Applicability, Handler, SuggestionStyle};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{AnonConst, Expr};
@@ -22,20 +18,21 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
-use rustc_parse::maybe_new_parser_from_source_str;
-use rustc_parse::parser::ForceCollect;
use rustc_resolve::rustdoc::{
add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, DocFragment,
};
-use rustc_session::parse::ParseSess;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::edition::Edition;
-use rustc_span::{sym, BytePos, FileName, Pos, Span};
-use rustc_span::source_map::{FilePathMapping, SourceMap};
+use rustc_span::{sym, Span};
use std::ops::Range;
-use std::{io, thread};
use url::Url;
+mod link_with_quotes;
+mod markdown;
+mod missing_headers;
+mod needless_doctest_main;
+mod suspicious_doc_comments;
+
declare_clippy_lint! {
/// ### What it does
/// Checks for the presence of `_`, `::` or camel-case words
@@ -204,6 +201,39 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
+ /// Checks for `#[test]` in doctests unless they are marked with
+ /// either `ignore`, `no_run` or `compile_fail`.
+ ///
+ /// ### Why is this bad?
+ /// Code in examples marked as `#[test]` will somewhat
+ /// surprisingly not be run by `cargo test`. If you really want
+ /// to show how to test stuff in an example, mark it `no_run` to
+ /// make the intent clear.
+ ///
+ /// ### Examples
+ /// ```no_run
+ /// /// An example of a doctest with a `main()` function
+ /// ///
+ /// /// # Examples
+ /// ///
+ /// /// ```
+ /// /// #[test]
+ /// /// fn equality_works() {
+ /// /// assert_eq!(1_u8, 1);
+ /// /// }
+ /// /// ```
+ /// fn test_attr_in_doctest() {
+ /// unimplemented!();
+ /// }
+ /// ```
+ #[clippy::version = "1.40.0"]
+ pub TEST_ATTR_IN_DOCTEST,
+ suspicious,
+ "presence of `#[test]` in code examples"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
/// Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks)
/// outside of code blocks
/// ### Why is this bad?
@@ -261,33 +291,83 @@ declare_clippy_lint! {
"`pub fn` or `pub trait` with `# Safety` docs"
}
-#[expect(clippy::module_name_repetitions)]
+declare_clippy_lint! {
+ /// ### What it does
+ /// Detects the use of outer doc comments (`///`, `/**`) followed by a bang (`!`): `///!`
+ ///
+ /// ### Why is this bad?
+ /// Triple-slash comments (known as "outer doc comments") apply to items that follow it.
+ /// An outer doc comment followed by a bang (i.e. `///!`) has no specific meaning.
+ ///
+ /// The user most likely meant to write an inner doc comment (`//!`, `/*!`), which
+ /// applies to the parent item (i.e. the item that the comment is contained in,
+ /// usually a module or crate).
+ ///
+ /// ### Known problems
+ /// Inner doc comments can only appear before items, so there are certain cases where the suggestion
+ /// made by this lint is not valid code. For example:
+ /// ```rs
+ /// fn foo() {}
+ /// ///!
+ /// fn bar() {}
+ /// ```
+ /// This lint detects the doc comment and suggests changing it to `//!`, but an inner doc comment
+ /// is not valid at that position.
+ ///
+ /// ### Example
+ /// In this example, the doc comment is attached to the *function*, rather than the *module*.
+ /// ```no_run
+ /// pub mod util {
+ /// ///! This module contains utility functions.
+ ///
+ /// pub fn dummy() {}
+ /// }
+ /// ```
+ ///
+ /// Use instead:
+ /// ```no_run
+ /// pub mod util {
+ /// //! This module contains utility functions.
+ ///
+ /// pub fn dummy() {}
+ /// }
+ /// ```
+ #[clippy::version = "1.70.0"]
+ pub SUSPICIOUS_DOC_COMMENTS,
+ suspicious,
+ "suspicious usage of (outer) doc comments"
+}
+
#[derive(Clone)]
-pub struct DocMarkdown {
+pub struct Documentation {
valid_idents: FxHashSet<String>,
in_trait_impl: bool,
+ check_private_items: bool,
}
-impl DocMarkdown {
- pub fn new(valid_idents: FxHashSet<String>) -> Self {
+impl Documentation {
+ pub fn new(valid_idents: &[String], check_private_items: bool) -> Self {
Self {
- valid_idents,
+ valid_idents: valid_idents.iter().cloned().collect(),
in_trait_impl: false,
+ check_private_items,
}
}
}
-impl_lint_pass!(DocMarkdown => [
+impl_lint_pass!(Documentation => [
DOC_LINK_WITH_QUOTES,
DOC_MARKDOWN,
MISSING_SAFETY_DOC,
MISSING_ERRORS_DOC,
MISSING_PANICS_DOC,
NEEDLESS_DOCTEST_MAIN,
+ TEST_ATTR_IN_DOCTEST,
UNNECESSARY_SAFETY_DOC,
+ SUSPICIOUS_DOC_COMMENTS
]);
-impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
+impl<'tcx> LateLintPass<'tcx> for Documentation {
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
check_attrs(cx, &self.valid_idents, attrs);
@@ -302,13 +382,17 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
hir::ItemKind::Fn(ref sig, _, body_id) => {
if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
let body = cx.tcx.hir().body(body_id);
- let mut fpu = FindPanicUnwrap {
+
+ let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
+ missing_headers::check(
cx,
- typeck_results: cx.tcx.typeck(item.owner_id.def_id),
- panic_span: None,
- };
- fpu.visit_expr(body.value);
- lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span);
+ item.owner_id,
+ sig,
+ headers,
+ Some(body_id),
+ panic_span,
+ self.check_private_items,
+ );
}
},
hir::ItemKind::Impl(impl_) => {
@@ -346,7 +430,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
};
if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
if !in_external_macro(cx.tcx.sess, item.span) {
- lint_for_missing_headers(cx, item.owner_id, sig, headers, None, None);
+ missing_headers::check(cx, item.owner_id, sig, headers, None, None, self.check_private_items);
}
}
}
@@ -361,92 +445,17 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
}
if let hir::ImplItemKind::Fn(ref sig, body_id) = item.kind {
let body = cx.tcx.hir().body(body_id);
- let mut fpu = FindPanicUnwrap {
- cx,
- typeck_results: cx.tcx.typeck(item.owner_id.def_id),
- panic_span: None,
- };
- fpu.visit_expr(body.value);
- lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span);
- }
- }
-}
-
-fn lint_for_missing_headers(
- cx: &LateContext<'_>,
- owner_id: hir::OwnerId,
- sig: &hir::FnSig<'_>,
- headers: DocHeaders,
- body_id: Option<hir::BodyId>,
- panic_span: Option<Span>,
-) {
- if !cx.effective_visibilities.is_exported(owner_id.def_id) {
- return; // Private functions do not require doc comments
- }
-
- // do not lint if any parent has `#[doc(hidden)]` attribute (#7347)
- if cx
- .tcx
- .hir()
- .parent_iter(owner_id.into())
- .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id)))
- {
- return;
- }
- let span = cx.tcx.def_span(owner_id);
- match (headers.safety, sig.header.unsafety) {
- (false, hir::Unsafety::Unsafe) => span_lint(
- cx,
- MISSING_SAFETY_DOC,
- span,
- "unsafe function's docs miss `# Safety` section",
- ),
- (true, hir::Unsafety::Normal) => span_lint(
- cx,
- UNNECESSARY_SAFETY_DOC,
- span,
- "safe function's docs have unnecessary `# Safety` section",
- ),
- _ => (),
- }
- if !headers.panics && panic_span.is_some() {
- span_lint_and_note(
- cx,
- MISSING_PANICS_DOC,
- span,
- "docs for function which may panic missing `# Panics` section",
- panic_span,
- "first possible panic found here",
- );
- }
- if !headers.errors {
- if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) {
- span_lint(
+ let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
+ missing_headers::check(
cx,
- MISSING_ERRORS_DOC,
- span,
- "docs for function returning `Result` missing `# Errors` section",
+ item.owner_id,
+ sig,
+ headers,
+ Some(body_id),
+ panic_span,
+ self.check_private_items,
);
- } else {
- if_chain! {
- if let Some(body_id) = body_id;
- if let Some(future) = cx.tcx.lang_items().future_trait();
- let typeck = cx.tcx.typeck_body(body_id);
- let body = cx.tcx.hir().body(body_id);
- let ret_ty = typeck.expr_ty(body.value);
- if implements_trait(cx, ret_ty, future, &[]);
- if let ty::Coroutine(_, subs, _) = ret_ty.kind();
- if is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result);
- then {
- span_lint(
- cx,
- MISSING_ERRORS_DOC,
- span,
- "docs for function returning `Result` missing `# Errors` section",
- );
- }
- }
}
}
}
@@ -470,6 +479,13 @@ struct DocHeaders {
panics: bool,
}
+/// Does some pre-processing on raw, desugared `#[doc]` attributes such as parsing them and
+/// then delegates to `check_doc`.
+/// Some lints are already checked here if they can work with attributes directly and don't need
+/// to work with markdown.
+/// Others are checked elsewhere, e.g. in `check_doc` if they need access to markdown, or
+/// back in the various late lint pass methods if they need the final doc headers, like "Safety" or
+/// "Panics" sections.
fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[Attribute]) -> Option<DocHeaders> {
/// 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
@@ -483,6 +499,8 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
return None;
}
+ suspicious_doc_comments::check(cx, attrs);
+
let (fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true);
let mut doc = String::new();
for fragment in &fragments {
@@ -513,6 +531,10 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"];
+/// Checks parsed documentation.
+/// This walks the "events" (think sections of markdown) produced by `pulldown_cmark`,
+/// so lints here will generally access that information.
+/// Returns documentation headers -- whether a "Safety", "Errors", "Panic" section was found
#[allow(clippy::too_many_lines)] // Only a big match statement
fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize>)>>(
cx: &LateContext<'_>,
@@ -527,6 +549,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
let mut in_heading = false;
let mut is_rust = false;
let mut no_test = false;
+ let mut ignore = false;
let mut edition = None;
let mut ticks_unbalanced = false;
let mut text_to_check: Vec<(CowStr<'_>, Range<usize>)> = Vec::new();
@@ -542,6 +565,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
break;
} else if item == "no_test" {
no_test = true;
+ } else if item == "no_run" || item == "compile_fail" {
+ ignore = true;
}
if let Some(stripped) = item.strip_prefix("edition") {
is_rust = true;
@@ -555,6 +580,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
End(CodeBlock(_)) => {
in_code = false;
is_rust = false;
+ ignore = false;
},
Start(Link(_, url, _)) => in_link = Some(url),
End(Link(..)) => in_link = None,
@@ -581,7 +607,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
} else {
for (text, range) in text_to_check {
if let Some(span) = fragments.span(cx, range) {
- check_text(cx, valid_idents, &text, span);
+ markdown::check(cx, valid_idents, &text, span);
}
}
}
@@ -608,11 +634,11 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
if in_code {
if is_rust && !no_test {
let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition());
- check_code(cx, &text, edition, range.clone(), fragments);
+ needless_doctest_main::check(cx, &text, edition, range.clone(), fragments, ignore);
}
} else {
if in_link.is_some() {
- check_link_quotes(cx, trimmed_text, range.clone(), fragments);
+ link_with_quotes::check(cx, trimmed_text, range.clone(), fragments);
}
if let Some(link) = in_link.as_ref()
&& let Ok(url) = Url::parse(link)
@@ -629,207 +655,28 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
headers
}
-fn check_link_quotes(cx: &LateContext<'_>, trimmed_text: &str, range: Range<usize>, fragments: Fragments<'_>) {
- if trimmed_text.starts_with('\'')
- && trimmed_text.ends_with('\'')
- && let Some(span) = fragments.span(cx, range)
- {
- span_lint(
- cx,
- DOC_LINK_WITH_QUOTES,
- span,
- "possible intra-doc link using quotes instead of backticks",
- );
- }
-}
-
-fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range<usize>, fragments: Fragments<'_>) {
- fn has_needless_main(code: String, edition: Edition) -> bool {
- rustc_driver::catch_fatal_errors(|| {
- rustc_span::create_session_globals_then(edition, || {
- let filename = FileName::anon_source_code(&code);
-
- let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
- let fallback_bundle =
- rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
- let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle);
- let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
- let sess = ParseSess::with_span_handler(handler, sm);
-
- let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) {
- Ok(p) => p,
- Err(errs) => {
- drop(errs);
- return false;
- },
- };
-
- let mut relevant_main_found = false;
- loop {
- match parser.parse_item(ForceCollect::No) {
- Ok(Some(item)) => match &item.kind {
- ItemKind::Fn(box Fn {
- sig, body: Some(block), ..
- }) if item.ident.name == sym::main => {
- let is_async = matches!(sig.header.asyncness, Async::Yes { .. });
- let returns_nothing = match &sig.decl.output {
- FnRetTy::Default(..) => true,
- FnRetTy::Ty(ty) if ty.kind.is_unit() => true,
- FnRetTy::Ty(_) => false,
- };
-
- if returns_nothing && !is_async && !block.stmts.is_empty() {
- // This main function should be linted, but only if there are no other functions
- relevant_main_found = true;
- } else {
- // This main function should not be linted, we're done
- return false;
- }
- },
- // Tests with one of these items are ignored
- ItemKind::Static(..)
- | ItemKind::Const(..)
- | ItemKind::ExternCrate(..)
- | ItemKind::ForeignMod(..)
- // Another function was found; this case is ignored
- | ItemKind::Fn(..) => return false,
- _ => {},
- },
- Ok(None) => break,
- Err(e) => {
- e.cancel();
- return false;
- },
- }
- }
-
- relevant_main_found
- })
- })
- .ok()
- .unwrap_or_default()
- }
-
- let trailing_whitespace = text.len() - text.trim_end().len();
-
- // Because of the global session, we need to create a new session in a different thread with
- // the edition we need.
- let text = text.to_owned();
- if thread::spawn(move || has_needless_main(text, edition))
- .join()
- .expect("thread::spawn failed")
- && let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace)
- {
- span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
- }
-}
-
-fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) {
- for word in text.split(|c: char| c.is_whitespace() || c == '\'') {
- // Trim punctuation as in `some comment (see foo::bar).`
- // ^^
- // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix.
- let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':');
-
- // Remove leading or trailing single `:` which may be part of a sentence.
- if word.starts_with(':') && !word.starts_with("::") {
- word = word.trim_start_matches(':');
- }
- if word.ends_with(':') && !word.ends_with("::") {
- word = word.trim_end_matches(':');
- }
-
- if valid_idents.contains(word) || word.chars().all(|c| c == ':') {
- continue;
- }
-
- // Adjust for the current word
- let offset = word.as_ptr() as usize - text.as_ptr() as usize;
- let span = Span::new(
- span.lo() + BytePos::from_usize(offset),
- span.lo() + BytePos::from_usize(offset + word.len()),
- span.ctxt(),
- span.parent(),
- );
-
- check_word(cx, word, span);
- }
-}
-
-fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
- /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and
- /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case
- /// letter (`NASA` is ok).
- /// Plurals are also excluded (`IDs` is ok).
- fn is_camel_case(s: &str) -> bool {
- if s.starts_with(|c: char| c.is_ascii_digit() | c.is_ascii_lowercase()) {
- return false;
- }
-
- let s = s.strip_suffix('s').unwrap_or(s);
-
- s.chars().all(char::is_alphanumeric)
- && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
- && s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
- }
-
- fn has_underscore(s: &str) -> bool {
- s != "_" && !s.contains("\\_") && s.contains('_')
- }
-
- fn has_hyphen(s: &str) -> bool {
- s != "-" && s.contains('-')
- }
-
- if let Ok(url) = Url::parse(word) {
- // try to get around the fact that `foo::bar` parses as a valid URL
- if !url.cannot_be_a_base() {
- span_lint(
- cx,
- DOC_MARKDOWN,
- span,
- "you should put bare URLs between `<`/`>` or make a proper Markdown link",
- );
-
- return;
- }
- }
-
- // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343)
- if has_underscore(word) && has_hyphen(word) {
- return;
- }
-
- if has_underscore(word) || word.contains("::") || is_camel_case(word) {
- let mut applicability = Applicability::MachineApplicable;
-
- span_lint_and_then(
- cx,
- DOC_MARKDOWN,
- span,
- "item in documentation is missing backticks",
- |diag| {
- let snippet = snippet_with_applicability(cx, span, "..", &mut applicability);
- diag.span_suggestion_with_style(
- span,
- "try",
- format!("`{snippet}`"),
- applicability,
- // always show the suggestion in a separate line, since the
- // inline presentation adds another pair of backticks
- SuggestionStyle::ShowAlways,
- );
- },
- );
- }
-}
-
struct FindPanicUnwrap<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
panic_span: Option<Span>,
typeck_results: &'tcx ty::TypeckResults<'tcx>,
}
+impl<'a, 'tcx> FindPanicUnwrap<'a, 'tcx> {
+ pub fn find_span(
+ cx: &'a LateContext<'tcx>,
+ typeck_results: &'tcx ty::TypeckResults<'tcx>,
+ body: impl Visitable<'tcx>,
+ ) -> Option<Span> {
+ let mut vis = Self {
+ cx,
+ panic_span: None,
+ typeck_results,
+ };
+ body.visit(&mut vis);
+ vis.panic_span
+ }
+}
+
impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
type NestedFilter = nested_filter::OnlyBodies;
diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
new file mode 100644
index 000000000..c639813a3
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
@@ -0,0 +1,135 @@
+use std::ops::Range;
+use std::{io, thread};
+
+use crate::doc::{NEEDLESS_DOCTEST_MAIN, TEST_ATTR_IN_DOCTEST};
+use clippy_utils::diagnostics::span_lint;
+use rustc_ast::{CoroutineKind, Fn, FnRetTy, Item, ItemKind};
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::emitter::EmitterWriter;
+use rustc_errors::DiagCtxt;
+use rustc_lint::LateContext;
+use rustc_parse::maybe_new_parser_from_source_str;
+use rustc_parse::parser::ForceCollect;
+use rustc_session::parse::ParseSess;
+use rustc_span::edition::Edition;
+use rustc_span::source_map::{FilePathMapping, SourceMap};
+use rustc_span::{sym, FileName, Pos};
+
+use super::Fragments;
+
+fn get_test_spans(item: &Item, test_attr_spans: &mut Vec<Range<usize>>) {
+ test_attr_spans.extend(
+ item.attrs
+ .iter()
+ .find(|attr| attr.has_name(sym::test))
+ .map(|attr| attr.span.lo().to_usize()..item.ident.span.hi().to_usize()),
+ );
+}
+
+pub fn check(
+ cx: &LateContext<'_>,
+ text: &str,
+ edition: Edition,
+ range: Range<usize>,
+ fragments: Fragments<'_>,
+ ignore: bool,
+) {
+ // return whether the code contains a needless `fn main` plus a vector of byte position ranges
+ // of all `#[test]` attributes in not ignored code examples
+ fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec<Range<usize>>) {
+ rustc_driver::catch_fatal_errors(|| {
+ rustc_span::create_session_globals_then(edition, || {
+ let mut test_attr_spans = vec![];
+ let filename = FileName::anon_source_code(&code);
+
+ let fallback_bundle =
+ rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
+ let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle);
+ let dcx = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings();
+ #[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_dcx
+ let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+ let sess = ParseSess::with_dcx(dcx, sm);
+
+ let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) {
+ Ok(p) => p,
+ Err(errs) => {
+ drop(errs);
+ return (false, test_attr_spans);
+ },
+ };
+
+ let mut relevant_main_found = false;
+ let mut eligible = true;
+ loop {
+ match parser.parse_item(ForceCollect::No) {
+ Ok(Some(item)) => match &item.kind {
+ ItemKind::Fn(box Fn {
+ sig, body: Some(block), ..
+ }) if item.ident.name == sym::main => {
+ if !ignore {
+ get_test_spans(&item, &mut test_attr_spans);
+ }
+ let is_async = matches!(sig.header.coroutine_kind, Some(CoroutineKind::Async { .. }));
+ let returns_nothing = match &sig.decl.output {
+ FnRetTy::Default(..) => true,
+ FnRetTy::Ty(ty) if ty.kind.is_unit() => true,
+ FnRetTy::Ty(_) => false,
+ };
+
+ if returns_nothing && !is_async && !block.stmts.is_empty() {
+ // This main function should be linted, but only if there are no other functions
+ relevant_main_found = true;
+ } else {
+ // This main function should not be linted, we're done
+ eligible = false;
+ }
+ },
+ // Another function was found; this case is ignored for needless_doctest_main
+ ItemKind::Fn(box Fn { .. }) => {
+ eligible = false;
+ if !ignore {
+ get_test_spans(&item, &mut test_attr_spans);
+ }
+ },
+ // Tests with one of these items are ignored
+ ItemKind::Static(..)
+ | ItemKind::Const(..)
+ | ItemKind::ExternCrate(..)
+ | ItemKind::ForeignMod(..) => {
+ eligible = false;
+ },
+ _ => {},
+ },
+ Ok(None) => break,
+ Err(e) => {
+ e.cancel();
+ return (false, test_attr_spans);
+ },
+ }
+ }
+
+ (relevant_main_found & eligible, test_attr_spans)
+ })
+ })
+ .ok()
+ .unwrap_or_default()
+ }
+
+ let trailing_whitespace = text.len() - text.trim_end().len();
+
+ // Because of the global session, we need to create a new session in a different thread with
+ // the edition we need.
+ let text = text.to_owned();
+ let (has_main, test_attr_spans) = thread::spawn(move || check_code_sample(text, edition, ignore))
+ .join()
+ .expect("thread::spawn failed");
+ if has_main && let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace) {
+ span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
+ }
+ for span in test_attr_spans {
+ let span = (range.start + span.start)..(range.start + span.end);
+ if let Some(span) = fragments.span(cx, span) {
+ span_lint(cx, TEST_ATTR_IN_DOCTEST, span, "unit tests in doctest are not executed");
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs
new file mode 100644
index 000000000..d7ad30efe
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs
@@ -0,0 +1,48 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_ast::token::CommentKind;
+use rustc_ast::{AttrKind, AttrStyle, Attribute};
+use rustc_errors::Applicability;
+use rustc_lint::LateContext;
+use rustc_span::Span;
+
+use super::SUSPICIOUS_DOC_COMMENTS;
+
+pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) {
+ let replacements: Vec<_> = collect_doc_replacements(attrs);
+
+ if let Some((&(lo_span, _), &(hi_span, _))) = replacements.first().zip(replacements.last()) {
+ span_lint_and_then(
+ cx,
+ SUSPICIOUS_DOC_COMMENTS,
+ lo_span.to(hi_span),
+ "this is an outer doc comment and does not apply to the parent module or crate",
+ |diag| {
+ diag.multipart_suggestion(
+ "use an inner doc comment to document the parent module or crate",
+ replacements,
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
+ }
+}
+
+fn collect_doc_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> {
+ attrs
+ .iter()
+ .filter_map(|attr| {
+ if let AttrKind::DocComment(com_kind, sym) = attr.kind
+ && let AttrStyle::Outer = attr.style
+ && let Some(com) = sym.as_str().strip_prefix('!')
+ {
+ let sugg = match com_kind {
+ CommentKind::Line => format!("//!{com}"),
+ CommentKind::Block => format!("/*!{com}*/"),
+ };
+ Some((attr.span, sugg))
+ } else {
+ None
+ }
+ })
+ .collect()
+}
diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs
index 63f32173b..b51bb7951 100644
--- a/src/tools/clippy/clippy_lints/src/double_parens.rs
+++ b/src/tools/clippy/clippy_lints/src/double_parens.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast::{Expr, ExprKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
index 177e04dfa..124d78fc4 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item};
use clippy_utils::{get_parent_node, is_must_use_func_call};
use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
use std::borrow::Cow;
diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
index 7ff7068f0..471335c09 100644
--- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
+++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
@@ -2,7 +2,7 @@ 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, Level, LintContext};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{FileName, Span};
use std::collections::BTreeMap;
use std::path::PathBuf;
diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
index 61db1c1ab..47780cab9 100644
--- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
+++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
@@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{Expr, ExprKind};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/empty_drop.rs b/src/tools/clippy/clippy_lints/src/empty_drop.rs
index 5fcdca7cf..1d2b907b9 100644
--- a/src/tools/clippy/clippy_lints/src/empty_drop.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_drop.rs
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::peel_blocks;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Body, ExprKind, Impl, ImplItemKind, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -36,31 +35,30 @@ declare_lint_pass!(EmptyDrop => [EMPTY_DROP]);
impl LateLintPass<'_> for EmptyDrop {
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
- if_chain! {
- if let ItemKind::Impl(Impl {
- of_trait: Some(ref trait_ref),
- items: [child],
- ..
- }) = item.kind;
- if trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait();
- if let impl_item_hir = child.id.hir_id();
- if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
- if let ImplItemKind::Fn(_, b) = &impl_item.kind;
- if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
- let func_expr = peel_blocks(func_expr);
- if let ExprKind::Block(block, _) = func_expr.kind;
- if block.stmts.is_empty() && block.expr.is_none();
- then {
- span_lint_and_sugg(
- cx,
- EMPTY_DROP,
- item.span,
- "empty drop implementation",
- "try removing this impl",
- String::new(),
- Applicability::MaybeIncorrect
- );
- }
+ if let ItemKind::Impl(Impl {
+ of_trait: Some(ref trait_ref),
+ items: [child],
+ ..
+ }) = item.kind
+ && trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait()
+ && let impl_item_hir = child.id.hir_id()
+ && let Some(Node::ImplItem(impl_item)) = cx.tcx.opt_hir_node(impl_item_hir)
+ && let ImplItemKind::Fn(_, b) = &impl_item.kind
+ && let Body { value: func_expr, .. } = cx.tcx.hir().body(*b)
+ && let func_expr = peel_blocks(func_expr)
+ && let ExprKind::Block(block, _) = func_expr.kind
+ && block.stmts.is_empty()
+ && block.expr.is_none()
+ {
+ span_lint_and_sugg(
+ cx,
+ EMPTY_DROP,
+ item.span,
+ "empty drop implementation",
+ "try removing this impl",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs
index a5699727b..420888b6c 100644
--- a/src/tools/clippy/clippy_lints/src/empty_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs
@@ -3,7 +3,7 @@
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs
index 4e2a8b73c..3cf67b3ec 100644
--- a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs
@@ -4,7 +4,7 @@ use rustc_ast::ast::{Item, ItemKind, VariantData};
use rustc_errors::Applicability;
use rustc_lexer::TokenKind;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
index affd08221..b8a817e21 100644
--- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
@@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::Ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Symbol;
use std::borrow::Cow;
@@ -114,27 +114,23 @@ impl LateLintPass<'_> for EndianBytes {
return;
}
- if_chain! {
- if let ExprKind::MethodCall(method_name, receiver, args, ..) = expr.kind;
- if args.is_empty();
- let ty = cx.typeck_results().expr_ty(receiver);
- if ty.is_primitive_ty();
- if maybe_lint_endian_bytes(cx, expr, Prefix::To, method_name.ident.name, ty);
- then {
- return;
- }
+ if let ExprKind::MethodCall(method_name, receiver, args, ..) = expr.kind
+ && args.is_empty()
+ && let ty = cx.typeck_results().expr_ty(receiver)
+ && ty.is_primitive_ty()
+ && maybe_lint_endian_bytes(cx, expr, Prefix::To, method_name.ident.name, ty)
+ {
+ return;
}
- if_chain! {
- if let ExprKind::Call(function, ..) = expr.kind;
- if let ExprKind::Path(qpath) = function.kind;
- if let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id();
- if let Some(function_name) = cx.get_def_path(def_id).last();
- let ty = cx.typeck_results().expr_ty(expr);
- if ty.is_primitive_ty();
- then {
- maybe_lint_endian_bytes(cx, expr, Prefix::From, *function_name, ty);
- }
+ if let ExprKind::Call(function, ..) = expr.kind
+ && let ExprKind::Path(qpath) = function.kind
+ && let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id()
+ && let Some(function_name) = cx.get_def_path(def_id).last()
+ && let ty = cx.typeck_results().expr_ty(expr)
+ && ty.is_primitive_ty()
+ {
+ maybe_lint_endian_bytes(cx, expr, Prefix::From, *function_name, ty);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index 3e3c62e85..ce0a1dfdc 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -10,7 +10,7 @@ use rustc_hir::hir_id::HirIdSet;
use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{Block, Expr, ExprKind, Guard, HirId, Let, Pat, Stmt, StmtKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{Span, SyntaxContext, DUMMY_SP};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index 003b5fc72..30eb643c4 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -7,7 +7,7 @@ use rustc_hir::{Item, ItemKind};
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 rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index 575fead5b..3c4352942 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -6,7 +6,7 @@ use rustc_hir::{Expr, ExprKind, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::Ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -46,9 +46,12 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
pats.iter().all(unary_pattern)
}
match &pat.kind {
- PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => {
- false
- },
+ PatKind::Slice(_, _, _)
+ | PatKind::Range(_, _, _)
+ | PatKind::Binding(..)
+ | PatKind::Wild
+ | PatKind::Never
+ | PatKind::Or(_) => false,
PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x),
diff --git a/src/tools/clippy/clippy_lints/src/error_impl_error.rs b/src/tools/clippy/clippy_lints/src/error_impl_error.rs
index bc878555c..8dbb47fad 100644
--- a/src/tools/clippy/clippy_lints/src/error_impl_error.rs
+++ b/src/tools/clippy/clippy_lints/src/error_impl_error.rs
@@ -5,7 +5,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Visibility;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id())
&& error_def_id == trait_def_id
&& let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
- && let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id)
+ && let hir_id = cx.tcx.local_def_id_to_hir_id(def_id)
&& let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id())
&& ident.name == sym::Error
&& is_visible_outside_module(cx, def_id) =>
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 3d0ddca19..b77762630 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -1,15 +1,15 @@
use clippy_utils::diagnostics::span_lint_hir;
-use rustc_hir::{self, intravisit, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind};
+use rustc_hir::{intravisit, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind};
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, TraitRef, Ty};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId;
-use rustc_span::Span;
use rustc_span::symbol::kw;
+use rustc_span::Span;
use rustc_target::spec::abi::Abi;
#[derive(Copy, Clone)]
@@ -74,9 +74,9 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
let parent_id = cx
.tcx
.hir()
- .get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(fn_def_id))
+ .get_parent_item(cx.tcx.local_def_id_to_hir_id(fn_def_id))
.def_id;
- let parent_node = cx.tcx.hir().find_by_def_id(parent_id);
+ let parent_node = cx.tcx.opt_hir_node_by_def_id(parent_id);
let mut trait_self_ty = None;
if let Some(Node::Item(item)) = parent_node {
@@ -122,8 +122,8 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
}
// TODO: Replace with Map::is_argument(..) when it's fixed
-fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool {
- match map.find(id) {
+fn is_argument(tcx: TyCtxt<'_>, id: HirId) -> bool {
+ match tcx.opt_hir_node(id) {
Some(Node::Pat(Pat {
kind: PatKind::Binding(..),
..
@@ -131,7 +131,7 @@ fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool {
_ => return false,
}
- matches!(map.find_parent(id), Some(Node::Param(_)))
+ matches!(tcx.hir().find_parent(id), Some(Node::Param(_)))
}
impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
@@ -154,7 +154,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
if cmt.place.projections.is_empty() {
let map = &self.cx.tcx.hir();
- if is_argument(*map, cmt.hir_id) {
+ if is_argument(self.cx.tcx, cmt.hir_id) {
// Skip closure arguments
let parent_id = map.parent_id(cmt.hir_id);
if let Some(Node::Expr(..)) = map.find_parent(parent_id) {
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index fad8fbf04..450cee400 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -13,7 +13,7 @@ use rustc_middle::ty::{
self, Binder, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
ImplPolarity, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults,
};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
@@ -220,7 +220,8 @@ fn check_inputs(
params.len() == self_arg.map_or(0, |_| 1) + args.len()
&& params.iter().zip(self_arg.into_iter().chain(args)).all(|(p, arg)| {
matches!(
- p.pat.kind,PatKind::Binding(BindingAnnotation::NONE, id, _, None)
+ p.pat.kind,
+ PatKind::Binding(BindingAnnotation::NONE, id, _, None)
if path_to_local_id(arg, id)
)
// Only allow adjustments which change regions (i.e. re-borrowing).
@@ -247,8 +248,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<'tcx>, call_sig:
/// This is needed because rustc is unable to late bind early-bound regions in a function signature.
fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<'_>) -> bool {
fn check_region(from_region: Region<'_>, to_region: Region<'_>) -> bool {
- matches!(from_region.kind(), RegionKind::ReLateBound(..))
- && !matches!(to_region.kind(), RegionKind::ReLateBound(..))
+ matches!(from_region.kind(), RegionKind::ReBound(..)) && !matches!(to_region.kind(), RegionKind::ReBound(..))
}
fn check_subs(from_subs: &[GenericArg<'_>], to_subs: &[GenericArg<'_>]) -> bool {
@@ -290,7 +290,7 @@ fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<'
.zip(to_tys)
.any(|(from_ty, to_ty)| check_ty(from_ty, to_ty))
},
- _ => from_ty.has_late_bound_regions(),
+ _ => from_ty.has_bound_regions(),
}
}
diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
index 1d18e194d..c5f7212c4 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
@@ -3,7 +3,7 @@ use clippy_utils::{get_parent_as_impl, has_repr_attr, is_bool};
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
@@ -171,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
span: Span,
def_id: LocalDefId,
) {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
+ let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
if let Some(fn_header) = fn_kind.header()
&& fn_header.abi == Abi::Rust
&& get_parent_as_impl(cx.tcx, hir_id).map_or(true, |impl_item| impl_item.of_trait.is_none())
diff --git a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
index 83480fc5e..4b0d11c5d 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
@@ -5,7 +5,7 @@ use rustc_ast::visit::{walk_block, walk_item, Visitor};
use rustc_ast::{Block, Crate, Inline, Item, ItemKind, ModKind, NodeId};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index f976cfd3f..3a621d967 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::indent_of;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -71,40 +70,31 @@ declare_lint_pass!(ExhaustiveItems => [EXHAUSTIVE_ENUMS, EXHAUSTIVE_STRUCTS]);
impl LateLintPass<'_> for ExhaustiveItems {
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
- if_chain! {
- if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind;
- if cx.effective_visibilities.is_exported(item.owner_id.def_id);
- let attrs = cx.tcx.hir().attrs(item.hir_id());
- if !attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
- then {
- let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
- if v.fields().iter().any(|f| {
- !cx.tcx.visibility(f.def_id).is_public()
- }) {
- // skip structs with private fields
- return;
- }
- (EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive")
- } else {
- (EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive")
- };
- let suggestion_span = item.span.shrink_to_lo();
- let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
- span_lint_and_then(
- cx,
- lint,
- item.span,
- msg,
- |diag| {
- let sugg = format!("#[non_exhaustive]\n{indent}");
- diag.span_suggestion(suggestion_span,
- "try adding #[non_exhaustive]",
- sugg,
- Applicability::MaybeIncorrect);
- }
+ if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind
+ && cx.effective_visibilities.is_exported(item.owner_id.def_id)
+ && let attrs = cx.tcx.hir().attrs(item.hir_id())
+ && !attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
+ {
+ let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
+ if v.fields().iter().any(|f| !cx.tcx.visibility(f.def_id).is_public()) {
+ // skip structs with private fields
+ return;
+ }
+ (EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive")
+ } else {
+ (EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive")
+ };
+ let suggestion_span = item.span.shrink_to_lo();
+ let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
+ span_lint_and_then(cx, lint, item.span, msg, |diag| {
+ let sugg = format!("#[non_exhaustive]\n{indent}");
+ diag.span_suggestion(
+ suggestion_span,
+ "try adding #[non_exhaustive]",
+ sugg,
+ Applicability::MaybeIncorrect,
);
-
- }
+ });
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs
index e14b1c556..6603512c7 100644
--- a/src/tools/clippy/clippy_lints/src/exit.rs
+++ b/src/tools/clippy/clippy_lints/src/exit.rs
@@ -1,9 +1,8 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_entrypoint_fn;
-use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -42,19 +41,17 @@ declare_lint_pass!(Exit => [EXIT]);
impl<'tcx> LateLintPass<'tcx> for Exit {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
- if_chain! {
- if let ExprKind::Call(path_expr, _args) = e.kind;
- if let ExprKind::Path(ref path) = path_expr.kind;
- if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id();
- if cx.tcx.is_diagnostic_item(sym::process_exit, def_id);
- let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id;
- if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find_by_def_id(parent);
+ if let ExprKind::Call(path_expr, _args) = e.kind
+ && let ExprKind::Path(ref path) = path_expr.kind
+ && let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id()
+ && cx.tcx.is_diagnostic_item(sym::process_exit, def_id)
+ && let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id
+ && let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.opt_hir_node_by_def_id(parent)
// If the next item up is a function we check if it is an entry point
// and only then emit a linter warning
- if !is_entrypoint_fn(cx, parent.to_def_id());
- then {
- span_lint(cx, EXIT, e.span, "usage of `process::exit`");
- }
+ && !is_entrypoint_fn(cx, parent.to_def_id())
+ {
+ span_lint(cx, EXIT, e.span, "usage of `process::exit`");
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index 4b5bcb06a..e8c1e5db3 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -2,12 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::{find_format_args, format_args_inputs_span};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{is_expn_of, path_def_id};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, ExpnId};
declare_clippy_lint! {
@@ -16,7 +15,7 @@ declare_clippy_lint! {
/// replaced with `(e)print!()` / `(e)println!()`
///
/// ### Why is this bad?
- /// Using `(e)println! is clearer and more concise
+ /// Using `(e)println!` is clearer and more concise
///
/// ### Example
/// ```no_run
@@ -101,30 +100,28 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
/// If `kind` is a block that looks like `{ let result = $expr; result }` then
/// returns $expr. Otherwise returns `kind`.
fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>) -> &'tcx ExprKind<'hir> {
- if_chain! {
- if let ExprKind::Block(block, _label @ None) = kind;
- if let Block {
+ if let ExprKind::Block(block, _label @ None) = kind
+ && let Block {
stmts: [Stmt { kind: StmtKind::Local(local), .. }],
expr: Some(expr_end_of_block),
rules: BlockCheckMode::DefaultBlock,
..
- } = block;
+ } = block
// Find id of the local that expr_end_of_block resolves to
- if let ExprKind::Path(QPath::Resolved(None, expr_path)) = expr_end_of_block.kind;
- if let Res::Local(expr_res) = expr_path.res;
- if let Some(Node::Pat(res_pat)) = cx.tcx.hir().find(expr_res);
+ && let ExprKind::Path(QPath::Resolved(None, expr_path)) = expr_end_of_block.kind
+ && let Res::Local(expr_res) = expr_path.res
+ && let Some(Node::Pat(res_pat)) = cx.tcx.opt_hir_node(expr_res)
// Find id of the local we found in the block
- if let PatKind::Binding(BindingAnnotation::NONE, local_hir_id, _ident, None) = local.pat.kind;
+ && let PatKind::Binding(BindingAnnotation::NONE, local_hir_id, _ident, None) = local.pat.kind
// If those two are the same hir id
- if res_pat.hir_id == local_hir_id;
+ && res_pat.hir_id == local_hir_id
- if let Some(init) = local.init;
- then {
- return &init.kind;
- }
+ && let Some(init) = local.init
+ {
+ return &init.kind;
}
kind
}
diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
index d6c746901..538d29eb4 100644
--- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
+++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
@@ -10,7 +10,7 @@ use rustc_hir::{
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::Span;
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index efb69476b..044694332 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -2,11 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::{is_panic, root_macro_call_first_node};
use clippy_utils::method_chain_args;
use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, Span};
declare_clippy_lint! {
@@ -53,13 +52,13 @@ declare_lint_pass!(FallibleImplFrom => [FALLIBLE_IMPL_FROM]);
impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
// check for `impl From<???> for ..`
- if_chain! {
- if let hir::ItemKind::Impl(impl_) = &item.kind;
- if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
- if cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.skip_binder().def_id);
- then {
- lint_impl_body(cx, item.span, impl_.items);
- }
+ if let hir::ItemKind::Impl(impl_) = &item.kind
+ && let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+ && cx
+ .tcx
+ .is_diagnostic_item(sym::From, impl_trait_ref.skip_binder().def_id)
+ {
+ lint_impl_body(cx, item.span, impl_.items);
}
}
}
@@ -98,34 +97,33 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl
}
for impl_item in impl_items {
- if_chain! {
- if impl_item.ident.name == sym::from;
- if let ImplItemKind::Fn(_, body_id) =
- cx.tcx.hir().impl_item(impl_item.id).kind;
- then {
- // check the body for `begin_panic` or `unwrap`
- let body = cx.tcx.hir().body(body_id);
- let mut fpu = FindPanicUnwrap {
- lcx: cx,
- typeck_results: cx.tcx.typeck(impl_item.id.owner_id.def_id),
- result: Vec::new(),
- };
- fpu.visit_expr(body.value);
+ if impl_item.ident.name == sym::from
+ && let ImplItemKind::Fn(_, body_id) = cx.tcx.hir().impl_item(impl_item.id).kind
+ {
+ // check the body for `begin_panic` or `unwrap`
+ let body = cx.tcx.hir().body(body_id);
+ let mut fpu = FindPanicUnwrap {
+ lcx: cx,
+ typeck_results: cx.tcx.typeck(impl_item.id.owner_id.def_id),
+ result: Vec::new(),
+ };
+ fpu.visit_expr(body.value);
- // if we've found one, lint
- if !fpu.result.is_empty() {
- span_lint_and_then(
- cx,
- FALLIBLE_IMPL_FROM,
- impl_span,
- "consider implementing `TryFrom` instead",
- move |diag| {
- diag.help(
- "`From` is intended for infallible conversions only. \
- Use `TryFrom` if there's a possibility for the conversion to fail");
- diag.span_note(fpu.result, "potential failure(s)");
- });
- }
+ // if we've found one, lint
+ if !fpu.result.is_empty() {
+ span_lint_and_then(
+ cx,
+ FALLIBLE_IMPL_FROM,
+ impl_span,
+ "consider implementing `TryFrom` instead",
+ move |diag| {
+ diag.help(
+ "`From` is intended for infallible conversions only. \
+ Use `TryFrom` if there's a possibility for the conversion to fail",
+ );
+ diag.span_note(fpu.result, "potential failure(s)");
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index 506a11917..38a16c5c8 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -1,12 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::numeric_literal;
-use if_chain::if_chain;
use rustc_ast::ast::{self, LitFloatType, LitKind};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, FloatTy};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use std::fmt;
declare_clippy_lint! {
@@ -64,73 +63,70 @@ declare_lint_pass!(FloatLiteral => [EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL]);
impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
let ty = cx.typeck_results().expr_ty(expr);
- if_chain! {
- if let ty::Float(fty) = *ty.kind();
- if let hir::ExprKind::Lit(lit) = expr.kind;
- if let LitKind::Float(sym, lit_float_ty) = lit.node;
- then {
- let sym_str = sym.as_str();
- let formatter = FloatFormat::new(sym_str);
- // Try to bail out if the float is for sure fine.
- // If its within the 2 decimal digits of being out of precision we
- // check if the parsed representation is the same as the string
- // since we'll need the truncated string anyway.
- let digits = count_digits(sym_str);
- let max = max_digits(fty);
- let type_suffix = match lit_float_ty {
- LitFloatType::Suffixed(ast::FloatTy::F32) => Some("f32"),
- LitFloatType::Suffixed(ast::FloatTy::F64) => Some("f64"),
- LitFloatType::Unsuffixed => None
- };
- let (is_whole, is_inf, mut float_str) = match fty {
- FloatTy::F32 => {
- let value = sym_str.parse::<f32>().unwrap();
+ if let ty::Float(fty) = *ty.kind()
+ && let hir::ExprKind::Lit(lit) = expr.kind
+ && let LitKind::Float(sym, lit_float_ty) = lit.node
+ {
+ let sym_str = sym.as_str();
+ let formatter = FloatFormat::new(sym_str);
+ // Try to bail out if the float is for sure fine.
+ // If its within the 2 decimal digits of being out of precision we
+ // check if the parsed representation is the same as the string
+ // since we'll need the truncated string anyway.
+ let digits = count_digits(sym_str);
+ let max = max_digits(fty);
+ let type_suffix = match lit_float_ty {
+ LitFloatType::Suffixed(ast::FloatTy::F32) => Some("f32"),
+ LitFloatType::Suffixed(ast::FloatTy::F64) => Some("f64"),
+ LitFloatType::Unsuffixed => None,
+ };
+ let (is_whole, is_inf, mut float_str) = match fty {
+ FloatTy::F32 => {
+ let value = sym_str.parse::<f32>().unwrap();
- (value.fract() == 0.0, value.is_infinite(), formatter.format(value))
- },
- FloatTy::F64 => {
- let value = sym_str.parse::<f64>().unwrap();
+ (value.fract() == 0.0, value.is_infinite(), formatter.format(value))
+ },
+ FloatTy::F64 => {
+ let value = sym_str.parse::<f64>().unwrap();
+ (value.fract() == 0.0, value.is_infinite(), formatter.format(value))
+ },
+ };
- (value.fract() == 0.0, value.is_infinite(), formatter.format(value))
- },
- };
-
- if is_inf {
- return;
- }
-
- if is_whole && !sym_str.contains(|c| c == 'e' || c == 'E') {
- // Normalize the literal by stripping the fractional portion
- if sym_str.split('.').next().unwrap() != float_str {
- // If the type suffix is missing the suggestion would be
- // incorrectly interpreted as an integer so adding a `.0`
- // suffix to prevent that.
- if type_suffix.is_none() {
- float_str.push_str(".0");
- }
+ if is_inf {
+ return;
+ }
- span_lint_and_sugg(
- cx,
- LOSSY_FLOAT_LITERAL,
- expr.span,
- "literal cannot be represented as the underlying type without loss of precision",
- "consider changing the type or replacing it with",
- numeric_literal::format(&float_str, type_suffix, true),
- Applicability::MachineApplicable,
- );
+ if is_whole && !sym_str.contains(|c| c == 'e' || c == 'E') {
+ // Normalize the literal by stripping the fractional portion
+ if sym_str.split('.').next().unwrap() != float_str {
+ // If the type suffix is missing the suggestion would be
+ // incorrectly interpreted as an integer so adding a `.0`
+ // suffix to prevent that.
+ if type_suffix.is_none() {
+ float_str.push_str(".0");
}
- } else if digits > max as usize && float_str.len() < sym_str.len() {
+
span_lint_and_sugg(
cx,
- EXCESSIVE_PRECISION,
+ LOSSY_FLOAT_LITERAL,
expr.span,
- "float has excessive precision",
- "consider changing the type or truncating it to",
+ "literal cannot be represented as the underlying type without loss of precision",
+ "consider changing the type or replacing it with",
numeric_literal::format(&float_str, type_suffix, true),
Applicability::MachineApplicable,
);
}
+ } else if digits > max as usize && float_str.len() < sym_str.len() {
+ span_lint_and_sugg(
+ cx,
+ EXCESSIVE_PRECISION,
+ expr.span,
+ "float has excessive precision",
+ "consider changing the type or truncating it to",
+ numeric_literal::format(&float_str, type_suffix, true),
+ Applicability::MachineApplicable,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index 09a9d9924..c8b87e510 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -4,12 +4,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::{
eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate, numeric_literal, peel_blocks, sugg,
};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_ast::ast;
@@ -133,30 +132,25 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su
expr = inner_expr;
}
- if_chain! {
+ if let ty::Float(float_ty) = cx.typeck_results().expr_ty(expr).kind()
// if the expression is a float literal and it is unsuffixed then
// add a suffix so the suggestion is valid and unambiguous
- if let ty::Float(float_ty) = cx.typeck_results().expr_ty(expr).kind();
- if let ExprKind::Lit(lit) = &expr.kind;
- if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node;
- then {
- let op = format!(
- "{suggestion}{}{}",
- // Check for float literals without numbers following the decimal
- // separator such as `2.` and adds a trailing zero
- if sym.as_str().ends_with('.') {
- "0"
- } else {
- ""
- },
- float_ty.name_str()
- ).into();
-
- suggestion = match suggestion {
- Sugg::MaybeParen(_) => Sugg::MaybeParen(op),
- _ => Sugg::NonParen(op)
- };
- }
+ && let ExprKind::Lit(lit) = &expr.kind
+ && let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node
+ {
+ let op = format!(
+ "{suggestion}{}{}",
+ // Check for float literals without numbers following the decimal
+ // separator such as `2.` and adds a trailing zero
+ if sym.as_str().ends_with('.') { "0" } else { "" },
+ float_ty.name_str()
+ )
+ .into();
+
+ suggestion = match suggestion {
+ Sugg::MaybeParen(_) => Sugg::MaybeParen(op),
+ _ => Sugg::NonParen(op),
+ };
}
suggestion.maybe_par()
@@ -359,35 +353,59 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
) = receiver.kind
{
// check if expression of the form x * x + y * y
- if_chain! {
- if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lmul_lhs, lmul_rhs) = add_lhs.kind;
- if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, rmul_lhs, rmul_rhs) = add_rhs.kind;
- if eq_expr_value(cx, lmul_lhs, lmul_rhs);
- if eq_expr_value(cx, rmul_lhs, rmul_rhs);
- then {
- return Some(format!("{}.hypot({})", Sugg::hir(cx, lmul_lhs, "..").maybe_par(), Sugg::hir(cx, rmul_lhs, "..")));
- }
+ if let ExprKind::Binary(
+ Spanned {
+ node: BinOpKind::Mul, ..
+ },
+ lmul_lhs,
+ lmul_rhs,
+ ) = add_lhs.kind
+ && let ExprKind::Binary(
+ Spanned {
+ node: BinOpKind::Mul, ..
+ },
+ rmul_lhs,
+ rmul_rhs,
+ ) = add_rhs.kind
+ && eq_expr_value(cx, lmul_lhs, lmul_rhs)
+ && eq_expr_value(cx, rmul_lhs, rmul_rhs)
+ {
+ return Some(format!(
+ "{}.hypot({})",
+ Sugg::hir(cx, lmul_lhs, "..").maybe_par(),
+ Sugg::hir(cx, rmul_lhs, "..")
+ ));
}
// check if expression of the form x.powi(2) + y.powi(2)
- if_chain! {
- if let ExprKind::MethodCall(
- PathSegment { ident: lmethod_name, .. },
- largs_0, [largs_1, ..],
- _
- ) = &add_lhs.kind;
- if let ExprKind::MethodCall(
- PathSegment { ident: rmethod_name, .. },
- rargs_0, [rargs_1, ..],
- _
- ) = &add_rhs.kind;
- if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
- if let Some(lvalue) = constant(cx, cx.typeck_results(), largs_1);
- if let Some(rvalue) = constant(cx, cx.typeck_results(), rargs_1);
- if Int(2) == lvalue && Int(2) == rvalue;
- then {
- return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, "..").maybe_par(), Sugg::hir(cx, rargs_0, "..")));
- }
+ if let ExprKind::MethodCall(
+ PathSegment {
+ ident: lmethod_name, ..
+ },
+ largs_0,
+ [largs_1, ..],
+ _,
+ ) = &add_lhs.kind
+ && let ExprKind::MethodCall(
+ PathSegment {
+ ident: rmethod_name, ..
+ },
+ rargs_0,
+ [rargs_1, ..],
+ _,
+ ) = &add_rhs.kind
+ && lmethod_name.as_str() == "powi"
+ && rmethod_name.as_str() == "powi"
+ && let Some(lvalue) = constant(cx, cx.typeck_results(), largs_1)
+ && let Some(rvalue) = constant(cx, cx.typeck_results(), rargs_1)
+ && Int(2) == lvalue
+ && Int(2) == rvalue
+ {
+ return Some(format!(
+ "{}.hypot({})",
+ Sugg::hir(cx, largs_0, "..").maybe_par(),
+ Sugg::hir(cx, rargs_0, "..")
+ ));
}
}
@@ -411,39 +429,44 @@ fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
// TODO: Lint expressions of the form `x.exp() - y` where y > 1
// and suggest usage of `x.exp_m1() - (y - 1)` instead
fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
- if_chain! {
- if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, lhs, rhs) = expr.kind;
- if cx.typeck_results().expr_ty(lhs).is_floating_point();
- if let Some(value) = constant(cx, cx.typeck_results(), rhs);
- if F32(1.0) == value || F64(1.0) == value;
- if let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind;
- if cx.typeck_results().expr_ty(self_arg).is_floating_point();
- if path.ident.name.as_str() == "exp";
- then {
- span_lint_and_sugg(
- cx,
- IMPRECISE_FLOPS,
- expr.span,
- "(e.pow(x) - 1) can be computed more accurately",
- "consider using",
- format!(
- "{}.exp_m1()",
- Sugg::hir(cx, self_arg, "..").maybe_par()
- ),
- Applicability::MachineApplicable,
- );
- }
+ if let ExprKind::Binary(
+ Spanned {
+ node: BinOpKind::Sub, ..
+ },
+ lhs,
+ rhs,
+ ) = expr.kind
+ && cx.typeck_results().expr_ty(lhs).is_floating_point()
+ && let Some(value) = constant(cx, cx.typeck_results(), rhs)
+ && (F32(1.0) == value || F64(1.0) == value)
+ && let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind
+ && cx.typeck_results().expr_ty(self_arg).is_floating_point()
+ && path.ident.name.as_str() == "exp"
+ {
+ span_lint_and_sugg(
+ cx,
+ IMPRECISE_FLOPS,
+ expr.span,
+ "(e.pow(x) - 1) can be computed more accurately",
+ "consider using",
+ format!("{}.exp_m1()", Sugg::hir(cx, self_arg, "..").maybe_par()),
+ Applicability::MachineApplicable,
+ );
}
}
fn is_float_mul_expr<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
- if_chain! {
- if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, lhs, rhs) = &expr.kind;
- if cx.typeck_results().expr_ty(lhs).is_floating_point();
- if cx.typeck_results().expr_ty(rhs).is_floating_point();
- then {
- return Some((lhs, rhs));
- }
+ if let ExprKind::Binary(
+ Spanned {
+ node: BinOpKind::Mul, ..
+ },
+ lhs,
+ rhs,
+ ) = &expr.kind
+ && cx.typeck_results().expr_ty(lhs).is_floating_point()
+ && cx.typeck_results().expr_ty(rhs).is_floating_point()
+ {
+ return Some((lhs, rhs));
}
None
@@ -473,9 +496,13 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
if let BinOpKind::Sub = op { -sugg } else { sugg }
};
- let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) {
+ let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs)
+ && cx.typeck_results().expr_ty(rhs).is_floating_point()
+ {
(inner_lhs, Sugg::hir(cx, inner_rhs, ".."), maybe_neg_sugg(rhs))
- } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) {
+ } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs)
+ && cx.typeck_results().expr_ty(lhs).is_floating_point()
+ {
(inner_lhs, maybe_neg_sugg(inner_rhs), Sugg::hir(cx, lhs, ".."))
} else {
return;
@@ -553,60 +580,72 @@ fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a
}
fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
- if_chain! {
- if let Some(higher::If { cond, then, r#else: Some(r#else) }) = higher::If::hir(expr);
- let if_body_expr = peel_blocks(then);
- let else_body_expr = peel_blocks(r#else);
- if let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr);
- then {
- let positive_abs_sugg = (
- "manual implementation of `abs` method",
- format!("{}.abs()", Sugg::hir(cx, body, "..").maybe_par()),
- );
- let negative_abs_sugg = (
- "manual implementation of negation of `abs` method",
- format!("-{}.abs()", Sugg::hir(cx, body, "..").maybe_par()),
- );
- let sugg = if is_testing_positive(cx, cond, body) {
- if if_expr_positive {
- positive_abs_sugg
- } else {
- negative_abs_sugg
- }
- } else if is_testing_negative(cx, cond, body) {
- if if_expr_positive {
- negative_abs_sugg
- } else {
- positive_abs_sugg
- }
+ if let Some(higher::If {
+ cond,
+ then,
+ r#else: Some(r#else),
+ }) = higher::If::hir(expr)
+ && let if_body_expr = peel_blocks(then)
+ && let else_body_expr = peel_blocks(r#else)
+ && let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr)
+ {
+ let positive_abs_sugg = (
+ "manual implementation of `abs` method",
+ format!("{}.abs()", Sugg::hir(cx, body, "..").maybe_par()),
+ );
+ let negative_abs_sugg = (
+ "manual implementation of negation of `abs` method",
+ format!("-{}.abs()", Sugg::hir(cx, body, "..").maybe_par()),
+ );
+ let sugg = if is_testing_positive(cx, cond, body) {
+ if if_expr_positive {
+ positive_abs_sugg
} else {
- return;
- };
- span_lint_and_sugg(
- cx,
- SUBOPTIMAL_FLOPS,
- expr.span,
- sugg.0,
- "try",
- sugg.1,
- Applicability::MachineApplicable,
- );
- }
+ negative_abs_sugg
+ }
+ } else if is_testing_negative(cx, cond, body) {
+ if if_expr_positive {
+ negative_abs_sugg
+ } else {
+ positive_abs_sugg
+ }
+ } else {
+ return;
+ };
+ span_lint_and_sugg(
+ cx,
+ SUBOPTIMAL_FLOPS,
+ expr.span,
+ sugg.0,
+ "try",
+ sugg.1,
+ Applicability::MachineApplicable,
+ );
}
}
fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
- if_chain! {
- if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind;
- if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind;
- then {
- return method_name_a.as_str() == method_name_b.as_str() &&
- args_a.len() == args_b.len() &&
- (
- ["ln", "log2", "log10"].contains(&method_name_a.as_str()) ||
- method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])
- );
- }
+ if let ExprKind::MethodCall(
+ PathSegment {
+ ident: method_name_a, ..
+ },
+ _,
+ args_a,
+ _,
+ ) = expr_a.kind
+ && let ExprKind::MethodCall(
+ PathSegment {
+ ident: method_name_b, ..
+ },
+ _,
+ args_b,
+ _,
+ ) = expr_b.kind
+ {
+ return method_name_a.as_str() == method_name_b.as_str()
+ && args_a.len() == args_b.len()
+ && (["ln", "log2", "log10"].contains(&method_name_a.as_str())
+ || method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0]));
}
false
@@ -614,103 +653,98 @@ fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>
fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
// check if expression of the form x.logN() / y.logN()
- if_chain! {
- if let ExprKind::Binary(
- Spanned {
- node: BinOpKind::Div, ..
- },
- lhs,
- rhs,
- ) = &expr.kind;
- if are_same_base_logs(cx, lhs, rhs);
- if let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind;
- if let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind;
- then {
- span_lint_and_sugg(
- cx,
- SUBOPTIMAL_FLOPS,
- expr.span,
- "log base can be expressed more clearly",
- "consider using",
- format!("{}.log({})", Sugg::hir(cx, largs_self, "..").maybe_par(), Sugg::hir(cx, rargs_self, ".."),),
- Applicability::MachineApplicable,
- );
- }
+ if let ExprKind::Binary(
+ Spanned {
+ node: BinOpKind::Div, ..
+ },
+ lhs,
+ rhs,
+ ) = &expr.kind
+ && are_same_base_logs(cx, lhs, rhs)
+ && let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind
+ && let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind
+ {
+ span_lint_and_sugg(
+ cx,
+ SUBOPTIMAL_FLOPS,
+ expr.span,
+ "log base can be expressed more clearly",
+ "consider using",
+ format!(
+ "{}.log({})",
+ Sugg::hir(cx, largs_self, "..").maybe_par(),
+ Sugg::hir(cx, rargs_self, ".."),
+ ),
+ Applicability::MachineApplicable,
+ );
}
}
fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
- if_chain! {
- if let ExprKind::Binary(
- Spanned {
- node: BinOpKind::Div, ..
- },
- div_lhs,
- div_rhs,
- ) = &expr.kind;
- if let ExprKind::Binary(
+ if let ExprKind::Binary(
+ Spanned {
+ node: BinOpKind::Div, ..
+ },
+ div_lhs,
+ div_rhs,
+ ) = &expr.kind
+ && let ExprKind::Binary(
Spanned {
node: BinOpKind::Mul, ..
},
mul_lhs,
mul_rhs,
- ) = &div_lhs.kind;
- if let Some(rvalue) = constant(cx, cx.typeck_results(), div_rhs);
- if let Some(lvalue) = constant(cx, cx.typeck_results(), mul_rhs);
- then {
- // TODO: also check for constant values near PI/180 or 180/PI
- if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) &&
- (F32(180_f32) == lvalue || F64(180_f64) == lvalue)
+ ) = &div_lhs.kind
+ && let Some(rvalue) = constant(cx, cx.typeck_results(), div_rhs)
+ && let Some(lvalue) = constant(cx, cx.typeck_results(), mul_rhs)
+ {
+ // TODO: also check for constant values near PI/180 or 180/PI
+ if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue)
+ && (F32(180_f32) == lvalue || F64(180_f64) == lvalue)
+ {
+ let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
+ if let ExprKind::Lit(literal) = mul_lhs.kind
+ && let ast::LitKind::Float(ref value, float_type) = literal.node
+ && float_type == ast::LitFloatType::Unsuffixed
{
- let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
- if_chain! {
- if let ExprKind::Lit(literal) = mul_lhs.kind;
- if let ast::LitKind::Float(ref value, float_type) = literal.node;
- if float_type == ast::LitFloatType::Unsuffixed;
- then {
- if value.as_str().ends_with('.') {
- proposal = format!("{}0_f64.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
- } else {
- proposal = format!("{}_f64.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
- }
- }
+ if value.as_str().ends_with('.') {
+ proposal = format!("{}0_f64.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
+ } else {
+ proposal = format!("{}_f64.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
}
- span_lint_and_sugg(
- cx,
- SUBOPTIMAL_FLOPS,
- expr.span,
- "conversion to degrees can be done more accurately",
- "consider using",
- proposal,
- Applicability::MachineApplicable,
- );
- } else if
- (F32(180_f32) == rvalue || F64(180_f64) == rvalue) &&
- (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
+ }
+ span_lint_and_sugg(
+ cx,
+ SUBOPTIMAL_FLOPS,
+ expr.span,
+ "conversion to degrees can be done more accurately",
+ "consider using",
+ proposal,
+ Applicability::MachineApplicable,
+ );
+ } else if (F32(180_f32) == rvalue || F64(180_f64) == rvalue)
+ && (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
+ {
+ let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
+ if let ExprKind::Lit(literal) = mul_lhs.kind
+ && let ast::LitKind::Float(ref value, float_type) = literal.node
+ && float_type == ast::LitFloatType::Unsuffixed
{
- let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
- if_chain! {
- if let ExprKind::Lit(literal) = mul_lhs.kind;
- if let ast::LitKind::Float(ref value, float_type) = literal.node;
- if float_type == ast::LitFloatType::Unsuffixed;
- then {
- if value.as_str().ends_with('.') {
- proposal = format!("{}0_f64.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
- } else {
- proposal = format!("{}_f64.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
- }
- }
+ if value.as_str().ends_with('.') {
+ proposal = format!("{}0_f64.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
+ } else {
+ proposal = format!("{}_f64.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
}
- span_lint_and_sugg(
- cx,
- SUBOPTIMAL_FLOPS,
- expr.span,
- "conversion to radians can be done more accurately",
- "consider using",
- proposal,
- Applicability::MachineApplicable,
- );
}
+ span_lint_and_sugg(
+ cx,
+ SUBOPTIMAL_FLOPS,
+ expr.span,
+ "conversion to radians can be done more accurately",
+ "consider using",
+ proposal,
+ Applicability::MachineApplicable,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index 18ed05c1c..8a0cd155d 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -7,7 +7,7 @@ use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, Span};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 3c1f2d9d5..8af321e4d 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -8,7 +8,6 @@ use clippy_utils::macros::{
};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{implements_trait, is_type_lang_item};
-use if_chain::if_chain;
use itertools::Itertools;
use rustc_ast::{
FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions,
@@ -20,7 +19,7 @@ use rustc_hir::{Expr, ExprKind, LangItem};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_middle::ty::Ty;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::DefId;
use rustc_span::edition::Edition::Edition2021;
use rustc_span::{sym, Span, Symbol};
@@ -404,49 +403,43 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb
}
fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) {
- if_chain! {
- if !value.span.from_expansion();
- if let ExprKind::MethodCall(_, receiver, [], to_string_span) = value.kind;
- if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id);
- if is_diag_trait_item(cx, method_def_id, sym::ToString);
- let receiver_ty = cx.typeck_results().expr_ty(receiver);
- if let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display);
- let (n_needed_derefs, target) =
- count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter());
- if implements_trait(cx, target, display_trait_id, &[]);
- if let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait();
- if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
- then {
- let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]);
- if n_needed_derefs == 0 && !needs_ref {
- span_lint_and_sugg(
- cx,
- TO_STRING_IN_FORMAT_ARGS,
- to_string_span.with_lo(receiver.span.hi()),
- &format!(
- "`to_string` applied to a type that implements `Display` in `{name}!` args"
- ),
- "remove this",
- String::new(),
- Applicability::MachineApplicable,
- );
- } else {
- span_lint_and_sugg(
- cx,
- TO_STRING_IN_FORMAT_ARGS,
- value.span,
- &format!(
- "`to_string` applied to a type that implements `Display` in `{name}!` args"
- ),
- "use this",
- format!(
- "{}{:*>n_needed_derefs$}{receiver_snippet}",
- if needs_ref { "&" } else { "" },
- ""
- ),
- Applicability::MachineApplicable,
- );
- }
+ if !value.span.from_expansion()
+ && let ExprKind::MethodCall(_, receiver, [], to_string_span) = value.kind
+ && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id)
+ && is_diag_trait_item(cx, method_def_id, sym::ToString)
+ && let receiver_ty = cx.typeck_results().expr_ty(receiver)
+ && let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display)
+ && let (n_needed_derefs, target) =
+ count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter())
+ && implements_trait(cx, target, display_trait_id, &[])
+ && let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait()
+ && let Some(receiver_snippet) = snippet_opt(cx, receiver.span)
+ {
+ let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]);
+ if n_needed_derefs == 0 && !needs_ref {
+ span_lint_and_sugg(
+ cx,
+ TO_STRING_IN_FORMAT_ARGS,
+ to_string_span.with_lo(receiver.span.hi()),
+ &format!("`to_string` applied to a type that implements `Display` in `{name}!` args"),
+ "remove this",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ span_lint_and_sugg(
+ cx,
+ TO_STRING_IN_FORMAT_ARGS,
+ value.span,
+ &format!("`to_string` applied to a type that implements `Display` in `{name}!` args"),
+ "use this",
+ format!(
+ "{}{:*>n_needed_derefs$}{receiver_snippet}",
+ if needs_ref { "&" } else { "" },
+ ""
+ ),
+ Applicability::MachineApplicable,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs
index 08ee7032c..9360eb1fa 100644
--- a/src/tools/clippy/clippy_lints/src/format_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/format_impl.rs
@@ -1,12 +1,11 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::macros::{find_format_arg_expr, find_format_args, is_format_macro, root_macro_call_first_node};
use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators};
-use if_chain::if_chain;
use rustc_ast::{FormatArgsPiece, FormatTrait};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::kw;
use rustc_span::{sym, Span, Symbol};
@@ -141,27 +140,25 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl {
}
fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) {
- if_chain! {
+ if let ExprKind::MethodCall(path, self_arg, ..) = expr.kind
// Get the hir_id of the object we are calling the method on
- if let ExprKind::MethodCall(path, self_arg, ..) = expr.kind;
// Is the method to_string() ?
- if path.ident.name == sym::to_string;
+ && path.ident.name == sym::to_string
// Is the method a part of the ToString trait? (i.e. not to_string() implemented
// separately)
- 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);
+ && let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && is_diag_trait_item(cx, expr_def_id, sym::ToString)
// Is the method is called on self
- if let ExprKind::Path(QPath::Resolved(_, path)) = self_arg.kind;
- if let [segment] = path.segments;
- if segment.ident.name == kw::SelfLower;
- then {
- span_lint(
- cx,
- RECURSIVE_FORMAT_IMPL,
- expr.span,
- "using `self.to_string` in `fmt::Display` implementation will cause infinite recursion",
- );
- }
+ && let ExprKind::Path(QPath::Resolved(_, path)) = self_arg.kind
+ && let [segment] = path.segments
+ && segment.ident.name == kw::SelfLower
+ {
+ span_lint(
+ cx,
+ RECURSIVE_FORMAT_IMPL,
+ expr.span,
+ "using `self.to_string` in `fmt::Display` implementation will cause infinite recursion",
+ );
}
}
@@ -215,55 +212,53 @@ fn check_format_arg_self(cx: &LateContext<'_>, span: Span, arg: &Expr<'_>, impl_
}
fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: FormatTraitNames) {
- if_chain! {
- if let Some(macro_call) = root_macro_call_first_node(cx, expr);
- if let Some(name) = cx.tcx.get_diagnostic_name(macro_call.def_id);
- then {
- let replacement = match name {
- sym::print_macro | sym::eprint_macro => "write",
- sym::println_macro | sym::eprintln_macro => "writeln",
- _ => return,
- };
+ if let Some(macro_call) = root_macro_call_first_node(cx, expr)
+ && let Some(name) = cx.tcx.get_diagnostic_name(macro_call.def_id)
+ {
+ let replacement = match name {
+ sym::print_macro | sym::eprint_macro => "write",
+ sym::println_macro | sym::eprintln_macro => "writeln",
+ _ => return,
+ };
- let name = name.as_str().strip_suffix("_macro").unwrap();
+ let name = name.as_str().strip_suffix("_macro").unwrap();
- span_lint_and_sugg(
- cx,
- PRINT_IN_FORMAT_IMPL,
- macro_call.span,
- &format!("use of `{name}!` in `{}` impl", impl_trait.name),
- "replace with",
- if let Some(formatter_name) = impl_trait.formatter_name {
- format!("{replacement}!({formatter_name}, ..)")
- } else {
- format!("{replacement}!(..)")
- },
- Applicability::HasPlaceholders,
- );
- }
+ span_lint_and_sugg(
+ cx,
+ PRINT_IN_FORMAT_IMPL,
+ macro_call.span,
+ &format!("use of `{name}!` in `{}` impl", impl_trait.name),
+ "replace with",
+ if let Some(formatter_name) = impl_trait.formatter_name {
+ format!("{replacement}!({formatter_name}, ..)")
+ } else {
+ format!("{replacement}!(..)")
+ },
+ Applicability::HasPlaceholders,
+ );
}
}
fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Option<FormatTraitNames> {
- if_chain! {
- if impl_item.ident.name == sym::fmt;
- if let ImplItemKind::Fn(_, body_id) = impl_item.kind;
- if let Some(Impl { of_trait: Some(trait_ref),..}) = get_parent_as_impl(cx.tcx, impl_item.hir_id());
- if let Some(did) = trait_ref.trait_def_id();
- if let Some(name) = cx.tcx.get_diagnostic_name(did);
- if matches!(name, sym::Debug | sym::Display);
- then {
- let body = cx.tcx.hir().body(body_id);
- let formatter_name = body.params.get(1)
- .and_then(|param| param.pat.simple_ident())
- .map(|ident| ident.name);
+ if impl_item.ident.name == sym::fmt
+ && let ImplItemKind::Fn(_, body_id) = impl_item.kind
+ && let Some(Impl {
+ of_trait: Some(trait_ref),
+ ..
+ }) = get_parent_as_impl(cx.tcx, impl_item.hir_id())
+ && let Some(did) = trait_ref.trait_def_id()
+ && let Some(name) = cx.tcx.get_diagnostic_name(did)
+ && matches!(name, sym::Debug | sym::Display)
+ {
+ let body = cx.tcx.hir().body(body_id);
+ let formatter_name = body
+ .params
+ .get(1)
+ .and_then(|param| param.pat.simple_ident())
+ .map(|ident| ident.name);
- Some(FormatTraitNames {
- name,
- formatter_name,
- })
- } else {
- None
- }
+ Some(FormatTraitNames { name, formatter_name })
+ } else {
+ None
}
}
diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs
index ac45f5aed..3901dd984 100644
--- a/src/tools/clippy/clippy_lints/src/format_push_string.rs
+++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_lang_item;
use clippy_utils::{higher, match_def_path, paths};
use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs
index 2c9c43d3e..c3ef6f180 100644
--- a/src/tools/clippy/clippy_lints/src/formatting.rs
+++ b/src/tools/clippy/clippy_lints/src/formatting.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note};
use clippy_utils::is_span_if;
use clippy_utils::source::snippet_opt;
-use if_chain::if_chain;
-use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
+use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
@@ -145,7 +144,7 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
let eq_span = lhs.span.between(rhs.span);
if let ExprKind::Unary(op, ref sub_rhs) = rhs.kind {
if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
- let op = UnOp::to_string(op);
+ let op = op.as_str();
let eqop_span = lhs.span.between(sub_rhs.span);
if eq_snippet.ends_with('=') {
span_lint_and_note(
@@ -168,93 +167,84 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
/// Implementation of the `SUSPICIOUS_UNARY_OP_FORMATTING` lint.
fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) {
- if_chain! {
- if let ExprKind::Binary(ref binop, ref lhs, ref rhs) = expr.kind;
- if !lhs.span.from_expansion() && !rhs.span.from_expansion();
+ if let ExprKind::Binary(ref binop, ref lhs, ref rhs) = expr.kind
+ && !lhs.span.from_expansion() && !rhs.span.from_expansion()
// span between BinOp LHS and RHS
- let binop_span = lhs.span.between(rhs.span);
+ && let binop_span = lhs.span.between(rhs.span)
// if RHS is an UnOp
- if let ExprKind::Unary(op, ref un_rhs) = rhs.kind;
+ && let ExprKind::Unary(op, ref un_rhs) = rhs.kind
// from UnOp operator to UnOp operand
- let unop_operand_span = rhs.span.until(un_rhs.span);
- if let Some(binop_snippet) = snippet_opt(cx, binop_span);
- if let Some(unop_operand_snippet) = snippet_opt(cx, unop_operand_span);
- let binop_str = BinOpKind::to_string(&binop.node);
+ && let unop_operand_span = rhs.span.until(un_rhs.span)
+ && let Some(binop_snippet) = snippet_opt(cx, binop_span)
+ && let Some(unop_operand_snippet) = snippet_opt(cx, unop_operand_span)
+ && let binop_str = binop.node.as_str()
// no space after BinOp operator and space after UnOp operator
- if binop_snippet.ends_with(binop_str) && unop_operand_snippet.ends_with(' ');
- then {
- let unop_str = UnOp::to_string(op);
- let eqop_span = lhs.span.between(un_rhs.span);
- span_lint_and_help(
- cx,
- SUSPICIOUS_UNARY_OP_FORMATTING,
- eqop_span,
- &format!(
- "by not having a space between `{binop_str}` and `{unop_str}` it looks like \
- `{binop_str}{unop_str}` is a single operator"
- ),
- None,
- &format!(
- "put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"
- ),
- );
- }
+ && binop_snippet.ends_with(binop_str) && unop_operand_snippet.ends_with(' ')
+ {
+ let unop_str = op.as_str();
+ let eqop_span = lhs.span.between(un_rhs.span);
+ span_lint_and_help(
+ cx,
+ SUSPICIOUS_UNARY_OP_FORMATTING,
+ eqop_span,
+ &format!(
+ "by not having a space between `{binop_str}` and `{unop_str}` it looks like \
+ `{binop_str}{unop_str}` is a single operator"
+ ),
+ None,
+ &format!("put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"),
+ );
}
}
/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`.
fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
- if_chain! {
- if let ExprKind::If(_, then, Some(else_)) = &expr.kind;
- if is_block(else_) || is_if(else_);
- if !then.span.from_expansion() && !else_.span.from_expansion();
- if !in_external_macro(cx.sess(), expr.span);
+ if let ExprKind::If(_, then, Some(else_)) = &expr.kind
+ && (is_block(else_) || is_if(else_))
+ && !then.span.from_expansion() && !else_.span.from_expansion()
+ && !in_external_macro(cx.sess(), expr.span)
// workaround for rust-lang/rust#43081
- if expr.span.lo().0 != 0 && expr.span.hi().0 != 0;
+ && expr.span.lo().0 != 0 && expr.span.hi().0 != 0
// this will be a span from the closing ‘}’ of the “then” block (excluding) to
// the “if” of the “else if” block (excluding)
- let else_span = then.span.between(else_.span);
+ && let else_span = then.span.between(else_.span)
// the snippet should look like " else \n " with maybe comments anywhere
// it’s bad when there is a ‘\n’ after the “else”
- if let Some(else_snippet) = snippet_opt(cx, else_span);
- if let Some((pre_else, post_else)) = else_snippet.split_once("else");
- if let Some((_, post_else_post_eol)) = post_else.split_once('\n');
-
- then {
- // Allow allman style braces `} \n else \n {`
- if_chain! {
- if is_block(else_);
- if let Some((_, pre_else_post_eol)) = pre_else.split_once('\n');
- // Exactly one eol before and after the else
- if !pre_else_post_eol.contains('\n');
- if !post_else_post_eol.contains('\n');
- then {
- return;
- }
- }
-
- // Don't warn if the only thing inside post_else_post_eol is a comment block.
- let trimmed_post_else_post_eol = post_else_post_eol.trim();
- if trimmed_post_else_post_eol.starts_with("/*") && trimmed_post_else_post_eol.ends_with("*/") {
- return
- }
+ && let Some(else_snippet) = snippet_opt(cx, else_span)
+ && let Some((pre_else, post_else)) = else_snippet.split_once("else")
+ && let Some((_, post_else_post_eol)) = post_else.split_once('\n')
+ {
+ // Allow allman style braces `} \n else \n {`
+ if is_block(else_)
+ && let Some((_, pre_else_post_eol)) = pre_else.split_once('\n')
+ // Exactly one eol before and after the else
+ && !pre_else_post_eol.contains('\n')
+ && !post_else_post_eol.contains('\n')
+ {
+ return;
+ }
- let else_desc = if is_if(else_) { "if" } else { "{..}" };
- span_lint_and_note(
- cx,
- SUSPICIOUS_ELSE_FORMATTING,
- else_span,
- &format!("this is an `else {else_desc}` but the formatting might hide it"),
- None,
- &format!(
- "to remove this lint, remove the `else` or remove the new line between \
- `else` and `{else_desc}`",
- ),
- );
+ // Don't warn if the only thing inside post_else_post_eol is a comment block.
+ let trimmed_post_else_post_eol = post_else_post_eol.trim();
+ if trimmed_post_else_post_eol.starts_with("/*") && trimmed_post_else_post_eol.ends_with("*/") {
+ return;
}
+
+ let else_desc = if is_if(else_) { "if" } else { "{..}" };
+ span_lint_and_note(
+ cx,
+ SUSPICIOUS_ELSE_FORMATTING,
+ else_span,
+ &format!("this is an `else {else_desc}` but the formatting might hide it"),
+ None,
+ &format!(
+ "to remove this lint, remove the `else` or remove the new line between \
+ `else` and `{else_desc}`",
+ ),
+ );
}
}
@@ -272,61 +262,56 @@ fn indentation(cx: &EarlyContext<'_>, span: Span) -> usize {
fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
if let ExprKind::Array(ref array) = expr.kind {
for element in array {
- if_chain! {
- if let ExprKind::Binary(ref op, ref lhs, _) = element.kind;
- if has_unary_equivalent(op.node) && lhs.span.eq_ctxt(op.span);
- let space_span = lhs.span.between(op.span);
- if let Some(space_snippet) = snippet_opt(cx, space_span);
- let lint_span = lhs.span.with_lo(lhs.span.hi());
- if space_snippet.contains('\n');
- if indentation(cx, op.span) <= indentation(cx, lhs.span);
- then {
- span_lint_and_note(
- cx,
- POSSIBLE_MISSING_COMMA,
- lint_span,
- "possibly missing a comma here",
- None,
- "to remove this lint, add a comma or write the expr in a single line",
- );
- }
+ if let ExprKind::Binary(ref op, ref lhs, _) = element.kind
+ && has_unary_equivalent(op.node)
+ && lhs.span.eq_ctxt(op.span)
+ && let space_span = lhs.span.between(op.span)
+ && let Some(space_snippet) = snippet_opt(cx, space_span)
+ && let lint_span = lhs.span.with_lo(lhs.span.hi())
+ && space_snippet.contains('\n')
+ && indentation(cx, op.span) <= indentation(cx, lhs.span)
+ {
+ span_lint_and_note(
+ cx,
+ POSSIBLE_MISSING_COMMA,
+ lint_span,
+ "possibly missing a comma here",
+ None,
+ "to remove this lint, add a comma or write the expr in a single line",
+ );
}
}
}
}
fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
- if_chain! {
- if !first.span.from_expansion() && !second.span.from_expansion();
- if matches!(first.kind, ExprKind::If(..));
- if is_block(second) || is_if(second);
+ if !first.span.from_expansion() && !second.span.from_expansion()
+ && matches!(first.kind, ExprKind::If(..))
+ && (is_block(second) || is_if(second))
// Proc-macros can give weird spans. Make sure this is actually an `if`.
- if is_span_if(cx, first.span);
+ && is_span_if(cx, first.span)
// If there is a line break between the two expressions, don't lint.
// If there is a non-whitespace character, this span came from a proc-macro.
- let else_span = first.span.between(second.span);
- if let Some(else_snippet) = snippet_opt(cx, else_span);
- if !else_snippet.chars().any(|c| c == '\n' || !c.is_whitespace());
- then {
- let (looks_like, next_thing) = if is_if(second) {
- ("an `else if`", "the second `if`")
- } else {
- ("an `else {..}`", "the next block")
- };
+ && let else_span = first.span.between(second.span)
+ && let Some(else_snippet) = snippet_opt(cx, else_span)
+ && !else_snippet.chars().any(|c| c == '\n' || !c.is_whitespace())
+ {
+ let (looks_like, next_thing) = if is_if(second) {
+ ("an `else if`", "the second `if`")
+ } else {
+ ("an `else {..}`", "the next block")
+ };
- span_lint_and_note(
- cx,
- SUSPICIOUS_ELSE_FORMATTING,
- else_span,
- &format!("this looks like {looks_like} but the `else` is missing"),
- None,
- &format!(
- "to remove this lint, add the missing `else` or add a new line before {next_thing}",
- ),
- );
- }
+ span_lint_and_note(
+ cx,
+ SUSPICIOUS_ELSE_FORMATTING,
+ else_span,
+ &format!("this looks like {looks_like} but the `else` is missing"),
+ None,
+ &format!("to remove this lint, add the missing `else` or add a new line before {next_thing}",),
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
index 69bc0b726..0599e08e6 100644
--- a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
+++ b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use rustc_errors::Applicability;
use rustc_hir::Item;
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index 5477532bb..fa1f98ba0 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -12,7 +12,7 @@ use rustc_hir::{
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::ty;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::{kw, sym};
use rustc_span::{Span, Symbol};
diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
index d9138d48b..c8d10dc4b 100644
--- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
@@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{RawPtr, TypeAndMut};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
index 74a60b6a0..633ed96d6 100644
--- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
+++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
@@ -2,12 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_integer_literal;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
declare_clippy_lint! {
@@ -46,52 +45,41 @@ declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]);
impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
- if_chain! {
- if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind;
- if let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind;
+ if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind
+ && let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind
// check if the first part of the path is some integer primitive
- if let TyKind::Path(ty_qpath) = &ty.kind;
- let ty_res = cx.qpath_res(ty_qpath, ty.hir_id);
- if let def::Res::PrimTy(prim_ty) = ty_res;
- if matches!(prim_ty, PrimTy::Int(_) | PrimTy::Uint(_));
+ && let TyKind::Path(ty_qpath) = &ty.kind
+ && let ty_res = cx.qpath_res(ty_qpath, ty.hir_id)
+ && let def::Res::PrimTy(prim_ty) = ty_res
+ && matches!(prim_ty, PrimTy::Int(_) | PrimTy::Uint(_))
// check if the second part of the path indeed calls the associated
// function `from_str_radix`
- if pathseg.ident.name.as_str() == "from_str_radix";
+ && pathseg.ident.name.as_str() == "from_str_radix"
// check if the second argument is a primitive `10`
- if is_integer_literal(radix, 10);
+ && is_integer_literal(radix, 10)
+ {
+ let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind {
+ let ty = cx.typeck_results().expr_ty(expr);
+ if is_ty_stringish(cx, ty) { expr } else { &src }
+ } else {
+ &src
+ };
- then {
- let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind {
- let ty = cx.typeck_results().expr_ty(expr);
- if is_ty_stringish(cx, ty) {
- expr
- } else {
- &src
- }
- } else {
- &src
- };
+ let sugg =
+ Sugg::hir_with_applicability(cx, expr, "<string>", &mut Applicability::MachineApplicable).maybe_par();
- let sugg = Sugg::hir_with_applicability(
- cx,
- expr,
- "<string>",
- &mut Applicability::MachineApplicable
- ).maybe_par();
-
- span_lint_and_sugg(
- cx,
- FROM_STR_RADIX_10,
- exp.span,
- "this call to `from_str_radix` can be replaced with a call to `str::parse`",
- "try",
- format!("{sugg}.parse::<{}>()", prim_ty.name_str()),
- Applicability::MaybeIncorrect
- );
- }
+ span_lint_and_sugg(
+ cx,
+ FROM_STR_RADIX_10,
+ exp.span,
+ "this call to `from_str_radix` can be replaced with a call to `str::parse`",
+ "try",
+ format!("{sugg}.parse::<{}>()", prim_ty.name_str()),
+ Applicability::MaybeIncorrect,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
index ee66c841e..8fba41c0e 100644
--- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
@@ -5,18 +5,10 @@ use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, GenericParam, Generics, HirId, ImplItem, ImplItemKind, TraitItem, TraitItemKind};
use rustc_lint::LateContext;
-use rustc_span::symbol::Ident;
-use rustc_span::{BytePos, Span};
use super::IMPL_TRAIT_IN_PARAMS;
-fn report(
- cx: &LateContext<'_>,
- param: &GenericParam<'_>,
- ident: &Ident,
- generics: &Generics<'_>,
- first_param_span: Span,
-) {
+fn report(cx: &LateContext<'_>, param: &GenericParam<'_>, generics: &Generics<'_>) {
// No generics with nested generics, and no generics like FnMut(x)
span_lint_and_then(
cx,
@@ -35,12 +27,7 @@ fn report(
);
} else {
diag.span_suggestion_with_style(
- Span::new(
- first_param_span.lo() - rustc_span::BytePos(1),
- ident.span.hi(),
- ident.span.ctxt(),
- ident.span.parent(),
- ),
+ generics.span,
"add a type parameter",
format!("<{{ /* Generic name */ }}: {}>", &param.name.ident().as_str()[5..]),
rustc_errors::Applicability::HasPlaceholders,
@@ -52,54 +39,47 @@ fn report(
}
pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) {
- if_chain! {
- if let FnKind::ItemFn(ident, generics, _) = kind;
- if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public();
- if !is_in_test_function(cx.tcx, hir_id);
- then {
- for param in generics.params {
- if param.is_impl_trait() {
- report(cx, param, ident, generics, body.params[0].span);
- };
- }
+ if let FnKind::ItemFn(_, generics, _) = kind
+ && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public()
+ && !is_in_test_function(cx.tcx, hir_id)
+ {
+ for param in generics.params {
+ if param.is_impl_trait() {
+ report(cx, param, generics);
+ };
}
}
}
pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
- if_chain! {
- if let ImplItemKind::Fn(_, body_id) = impl_item.kind;
- if let hir::Node::Item(item) = cx.tcx.hir().get_parent(impl_item.hir_id());
- if let hir::ItemKind::Impl(impl_) = item.kind;
- if let hir::Impl { of_trait, .. } = *impl_;
- if of_trait.is_none();
- let body = cx.tcx.hir().body(body_id);
- if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public();
- if !is_in_test_function(cx.tcx, impl_item.hir_id());
- then {
- for param in impl_item.generics.params {
- if param.is_impl_trait() {
- report(cx, param, &impl_item.ident, impl_item.generics, body.params[0].span);
- }
+ if let ImplItemKind::Fn(_, body_id) = impl_item.kind
+ && let hir::Node::Item(item) = cx.tcx.hir().get_parent(impl_item.hir_id())
+ && let hir::ItemKind::Impl(impl_) = item.kind
+ && let hir::Impl { of_trait, .. } = *impl_
+ && of_trait.is_none()
+ && let body = cx.tcx.hir().body(body_id)
+ && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public()
+ && !is_in_test_function(cx.tcx, impl_item.hir_id())
+ {
+ for param in impl_item.generics.params {
+ if param.is_impl_trait() {
+ report(cx, param, impl_item.generics);
}
}
}
}
pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, avoid_breaking_exported_api: bool) {
- if_chain! {
- if !avoid_breaking_exported_api;
- if let TraitItemKind::Fn(_, _) = trait_item.kind;
- if let hir::Node::Item(item) = cx.tcx.hir().get_parent(trait_item.hir_id());
+ if !avoid_breaking_exported_api
+ && let TraitItemKind::Fn(_, _) = trait_item.kind
+ && let hir::Node::Item(item) = cx.tcx.hir().get_parent(trait_item.hir_id())
// ^^ (Will always be a trait)
- if !item.vis_span.is_empty(); // Is public
- if !is_in_test_function(cx.tcx, trait_item.hir_id());
- then {
- for param in trait_item.generics.params {
- if param.is_impl_trait() {
- let sp = trait_item.ident.span.with_hi(trait_item.ident.span.hi() + BytePos(1));
- report(cx, param, &trait_item.ident, trait_item.generics, sp.shrink_to_hi());
- }
+ && !item.vis_span.is_empty() // Is public
+ && !is_in_test_function(cx.tcx, trait_item.hir_id())
+ {
+ for param in trait_item.generics.params {
+ if param.is_impl_trait() {
+ report(cx, param, trait_item.generics);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
index 18f7368da..bf96c0d62 100644
--- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
@@ -43,15 +43,13 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
// Body must be &(mut) <self_data>.name
// self_data is not necessarily self, to also lint sub-getters, etc…
- let block_expr = if_chain! {
- if let ExprKind::Block(block,_) = body.value.kind;
- if block.stmts.is_empty();
- if let Some(block_expr) = block.expr;
- then {
- block_expr
- } else {
- return;
- }
+ let block_expr = if let ExprKind::Block(block, _) = body.value.kind
+ && block.stmts.is_empty()
+ && let Some(block_expr) = block.expr
+ {
+ block_expr
+ } else {
+ return;
};
let expr_span = block_expr.span;
@@ -61,14 +59,12 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
} else {
block_expr
};
- let (self_data, used_ident) = if_chain! {
- if let ExprKind::Field(self_data, ident) = expr.kind;
- if ident.name.as_str() != name;
- then {
- (self_data, ident)
- } else {
- return;
- }
+ let (self_data, used_ident) = if let ExprKind::Field(self_data, ident) = expr.kind
+ && ident.name.as_str() != name
+ {
+ (self_data, ident)
+ } else {
+ return;
};
let mut used_field = None;
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index 3f5cceec7..96da2ec2a 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -9,7 +9,7 @@ mod too_many_lines;
use rustc_hir as hir;
use rustc_hir::intravisit;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
@@ -407,7 +407,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
span: Span,
def_id: LocalDefId,
) {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
+ let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold);
too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold);
not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id);
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
index 485235514..f1200c2ed 100644
--- a/src/tools/clippy/clippy_lints/src/functions/result.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -23,7 +23,7 @@ fn result_err_ty<'tcx>(
&& let hir::FnRetTy::Return(hir_ty) = decl.output
&& let ty = cx
.tcx
- .erase_late_bound_regions(cx.tcx.fn_sig(id).instantiate_identity().output())
+ .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(id).instantiate_identity().output())
&& is_type_diagnostic_item(cx, ty, sym::Result)
&& let ty::Adt(_, args) = ty.kind()
{
@@ -86,59 +86,60 @@ fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: S
}
fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) {
- if_chain! {
- if let Adt(adt, subst) = err_ty.kind();
- if let Some(local_def_id) = err_ty.ty_adt_def().expect("already checked this is adt").did().as_local();
- if let Some(hir::Node::Item(item)) = cx
- .tcx
- .hir()
- .find_by_def_id(local_def_id);
- if let hir::ItemKind::Enum(ref def, _) = item.kind;
- then {
- let variants_size = AdtVariantInfo::new(cx, *adt, subst);
- if let Some((first_variant, variants)) = variants_size.split_first()
- && first_variant.size >= large_err_threshold
- {
- span_lint_and_then(
- cx,
- RESULT_LARGE_ERR,
- hir_ty_span,
- "the `Err`-variant returned from this function is very large",
- |diag| {
- diag.span_label(
- def.variants[first_variant.ind].span,
- format!("the largest variant contains at least {} bytes", variants_size[0].size),
- );
+ if let Adt(adt, subst) = err_ty.kind()
+ && let Some(local_def_id) = err_ty
+ .ty_adt_def()
+ .expect("already checked this is adt")
+ .did()
+ .as_local()
+ && let Some(hir::Node::Item(item)) = cx.tcx.opt_hir_node_by_def_id(local_def_id)
+ && let hir::ItemKind::Enum(ref def, _) = item.kind
+ {
+ let variants_size = AdtVariantInfo::new(cx, *adt, subst);
+ if let Some((first_variant, variants)) = variants_size.split_first()
+ && first_variant.size >= large_err_threshold
+ {
+ span_lint_and_then(
+ cx,
+ RESULT_LARGE_ERR,
+ hir_ty_span,
+ "the `Err`-variant returned from this function is very large",
+ |diag| {
+ diag.span_label(
+ def.variants[first_variant.ind].span,
+ format!("the largest variant contains at least {} bytes", variants_size[0].size),
+ );
- for variant in variants {
- if variant.size >= large_err_threshold {
- let variant_def = &def.variants[variant.ind];
- diag.span_label(
- variant_def.span,
- format!("the variant `{}` contains at least {} bytes", variant_def.ident, variant.size),
- );
- }
+ for variant in variants {
+ if variant.size >= large_err_threshold {
+ let variant_def = &def.variants[variant.ind];
+ diag.span_label(
+ variant_def.span,
+ format!(
+ "the variant `{}` contains at least {} bytes",
+ variant_def.ident, variant.size
+ ),
+ );
}
-
- diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
}
- );
- }
+
+ diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
+ },
+ );
}
- else {
- let ty_size = approx_ty_size(cx, err_ty);
- if ty_size >= large_err_threshold {
- span_lint_and_then(
- cx,
- RESULT_LARGE_ERR,
- hir_ty_span,
- "the `Err`-variant returned from this function is very large",
- |diag: &mut Diagnostic| {
- diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes"));
- diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
- },
- );
- }
+ } else {
+ let ty_size = approx_ty_size(cx, err_ty);
+ if ty_size >= large_err_threshold {
+ span_lint_and_then(
+ cx,
+ RESULT_LARGE_ERR,
+ hir_ty_span,
+ "the `Err`-variant returned from this function is very large",
+ |diag: &mut Diagnostic| {
+ diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes"));
+ diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index eee5b7540..9fb59a320 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -5,7 +5,7 @@ use rustc_hir::{Body, FnDecl};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span};
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
if let FnKind::Closure = kind {
return;
}
- let ret_ty = return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(fn_def_id).expect_owner());
+ let ret_ty = return_ty(cx, cx.tcx.local_def_id_to_hir_id(fn_def_id).expect_owner());
if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind() {
let preds = cx.tcx.explicit_item_bounds(def_id);
let mut is_future = false;
diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
index e614a8f69..5e354209c 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
@@ -1,12 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{higher, SpanlessEq};
-use if_chain::if_chain;
use rustc_errors::Diagnostic;
use rustc_hir::intravisit::{self as visit, Visitor};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -127,15 +126,13 @@ impl<'tcx, 'l> ArmVisitor<'tcx, 'l> {
}
fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
- if_chain! {
- if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
- if path.ident.as_str() == "lock";
- let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
- if is_type_diagnostic_item(cx, ty, sym::Mutex);
- then {
- Some(self_arg)
- } else {
- None
- }
+ if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
+ && path.ident.as_str() == "lock"
+ && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
+ && is_type_diagnostic_item(cx, ty, sym::Mutex)
+ {
+ Some(self_arg)
+ } else {
+ None
}
}
diff --git a/src/tools/clippy/clippy_lints/src/if_not_else.rs b/src/tools/clippy/clippy_lints/src/if_not_else.rs
index cae561f78..4dc1ff837 100644
--- a/src/tools/clippy/clippy_lints/src/if_not_else.rs
+++ b/src/tools/clippy/clippy_lints/src/if_not_else.rs
@@ -6,7 +6,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_else_clause;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index 66c10ab22..cd6c46a71 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -9,7 +9,7 @@ use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
index 76bdfb94e..0a2fd0c66 100644
--- a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
@@ -3,7 +3,7 @@ use hir::{Node, PatKind};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs b/src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs
new file mode 100644
index 000000000..940adbae4
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs
@@ -0,0 +1,106 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::implements_trait;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::{Item, ItemKind, Path, TraitRef};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Ty;
+use rustc_session::declare_lint_pass;
+use rustc_span::symbol::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// This lint is concerned with the semantics of `Borrow` and `Hash` for a
+ /// type that implements all three of `Hash`, `Borrow<str>` and `Borrow<[u8]>`
+ /// as it is impossible to satisfy the semantics of Borrow and `Hash` for
+ /// both `Borrow<str>` and `Borrow<[u8]>`.
+ ///
+ /// ### Why is this bad?
+ ///
+ /// When providing implementations for `Borrow<T>`, one should consider whether the different
+ /// implementations should act as facets or representations of the underlying type. Generic code
+ /// typically uses `Borrow<T>` when it relies on the identical behavior of these additional trait
+ /// implementations. These traits will likely appear as additional trait bounds.
+ ///
+ /// In particular `Eq`, `Ord` and `Hash` must be equivalent for borrowed and owned values:
+ /// `x.borrow() == y.borrow()` should give the same result as `x == y`.
+ /// It follows then that the following equivalence must hold:
+ /// `hash(x) == hash((x as Borrow<[u8]>).borrow()) == hash((x as Borrow<str>).borrow())`
+ ///
+ /// Unfortunately it doesn't hold as `hash("abc") != hash("abc".as_bytes())`.
+ /// This happens because the `Hash` impl for str passes an additional `0xFF` byte to
+ /// the hasher to avoid collisions. For example, given the tuples `("a", "bc")`, and `("ab", "c")`,
+ /// the two tuples would have the same hash value if the `0xFF` byte was not added.
+ ///
+ /// ### Example
+ ///
+ /// ```
+ /// use std::borrow::Borrow;
+ /// use std::hash::{Hash, Hasher};
+ ///
+ /// struct ExampleType {
+ /// data: String
+ /// }
+ ///
+ /// impl Hash for ExampleType {
+ /// fn hash<H: Hasher>(&self, state: &mut H) {
+ /// self.data.hash(state);
+ /// }
+ /// }
+ ///
+ /// impl Borrow<str> for ExampleType {
+ /// fn borrow(&self) -> &str {
+ /// &self.data
+ /// }
+ /// }
+ ///
+ /// impl Borrow<[u8]> for ExampleType {
+ /// fn borrow(&self) -> &[u8] {
+ /// self.data.as_bytes()
+ /// }
+ /// }
+ /// ```
+ /// As a consequence, hashing a `&ExampleType` and hashing the result of the two
+ /// borrows will result in different values.
+ ///
+ #[clippy::version = "1.76.0"]
+ pub IMPL_HASH_BORROW_WITH_STR_AND_BYTES,
+ correctness,
+ "ensures that the semantics of `Borrow` for `Hash` are satisfied when `Borrow<str>` and `Borrow<[u8]>` are implemented"
+}
+
+declare_lint_pass!(ImplHashWithBorrowStrBytes => [IMPL_HASH_BORROW_WITH_STR_AND_BYTES]);
+
+impl LateLintPass<'_> for ImplHashWithBorrowStrBytes {
+ /// We are emitting this lint at the Hash impl of a type that implements all
+ /// three of `Hash`, `Borrow<str>` and `Borrow<[u8]>`.
+ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+ if let ItemKind::Impl(imp) = item.kind
+ && let Some(TraitRef {path: Path {span, res, ..}, ..}) = imp.of_trait
+ && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+ && let Some(hash_id) = cx.tcx.get_diagnostic_item(sym::Hash)
+ && Res::Def(DefKind::Trait, hash_id) == *res
+ && let Some(borrow_id) = cx.tcx.get_diagnostic_item(sym::Borrow)
+ // since we are in the `Hash` impl, we don't need to check for that.
+ // we need only to check for `Borrow<str>` and `Borrow<[u8]>`
+ && implements_trait(cx, ty, borrow_id, &[cx.tcx.types.str_.into()])
+ && implements_trait(cx, ty, borrow_id, &[Ty::new_slice(cx.tcx, cx.tcx.types.u8).into()])
+ {
+ span_lint_and_then(
+ cx,
+ IMPL_HASH_BORROW_WITH_STR_AND_BYTES,
+ *span,
+ "the semantics of `Borrow<T>` around `Hash` can't be satisfied when both `Borrow<str>` and `Borrow<[u8]>` are implemented",
+ |diag| {
+ diag.note("the `Borrow` semantics require that `Hash` must behave the same for all implementations of Borrow<T>");
+ diag.note(
+ "however, the hash implementations of a string (`str`) and the bytes of a string `[u8]` do not behave the same ..."
+ );
+ diag.note("... as (`hash(\"abc\") != hash(\"abc\".as_bytes())`");
+ diag.help("consider either removing one of the `Borrow` implementations (`Borrow<str>` or `Borrow<[u8]>`) ...");
+ diag.help("... or not implementing `Hash` for this type");
+ },
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index eaf80de38..43eb6a9b8 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -9,11 +9,9 @@ use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{Ty, TypeckResults};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
-
-use if_chain::if_chain;
+use rustc_span::Span;
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_opt};
@@ -337,42 +335,38 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't
}
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
- if_chain! {
- if let ExprKind::Call(fun, args) = e.kind;
- if let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind;
- if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind;
- if let Some(ty_did) = ty_path.res.opt_def_id();
- then {
- if self.target.ty() != self.maybe_typeck_results.unwrap().expr_ty(e) {
- return;
- }
+ if let ExprKind::Call(fun, args) = e.kind
+ && let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind
+ && let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind
+ && let Some(ty_did) = ty_path.res.opt_def_id()
+ {
+ if self.target.ty() != self.maybe_typeck_results.unwrap().expr_ty(e) {
+ return;
+ }
- if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) {
- if method.ident.name == sym::new {
- self.suggestions
- .insert(e.span, "HashMap::default()".to_string());
- } else if method.ident.name == sym!(with_capacity) {
- self.suggestions.insert(
- e.span,
- format!(
- "HashMap::with_capacity_and_hasher({}, Default::default())",
- snippet(self.cx, args[0].span, "capacity"),
- ),
- );
- }
- } else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) {
- if method.ident.name == sym::new {
- self.suggestions
- .insert(e.span, "HashSet::default()".to_string());
- } else if method.ident.name == sym!(with_capacity) {
- self.suggestions.insert(
- e.span,
- format!(
- "HashSet::with_capacity_and_hasher({}, Default::default())",
- snippet(self.cx, args[0].span, "capacity"),
- ),
- );
- }
+ if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) {
+ if method.ident.name == sym::new {
+ self.suggestions.insert(e.span, "HashMap::default()".to_string());
+ } else if method.ident.name == sym!(with_capacity) {
+ self.suggestions.insert(
+ e.span,
+ format!(
+ "HashMap::with_capacity_and_hasher({}, Default::default())",
+ snippet(self.cx, args[0].span, "capacity"),
+ ),
+ );
+ }
+ } else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) {
+ if method.ident.name == sym::new {
+ self.suggestions.insert(e.span, "HashSet::default()".to_string());
+ } else if method.ident.name == sym!(with_capacity) {
+ self.suggestions.insert(
+ e.span,
+ format!(
+ "HashSet::with_capacity_and_hasher({}, Default::default())",
+ snippet(self.cx, args[0].span, "capacity"),
+ ),
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index c6bcf3ba4..d68c5c4ba 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -8,7 +8,7 @@ use rustc_hir::intravisit::FnKind;
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::{Span, SyntaxContext};
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
index 24f62490f..cc74844f2 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
@@ -2,13 +2,12 @@ use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::get_parent_expr;
use clippy_utils::source::snippet_with_context;
-use if_chain::if_chain;
use rustc_ast::ast::{LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{Int, IntTy, Ty, Uint, UintTy};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -40,42 +39,58 @@ declare_lint_pass!(ImplicitSaturatingAdd => [IMPLICIT_SATURATING_ADD]);
impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if_chain! {
- if let ExprKind::If(cond, then, None) = expr.kind;
- if let ExprKind::DropTemps(expr1) = cond.kind;
- if let Some((c, op_node, l)) = get_const(cx, expr1);
- if let BinOpKind::Ne | BinOpKind::Lt = op_node;
- if let ExprKind::Block(block, None) = then.kind;
- if let Block {
+ if let ExprKind::If(cond, then, None) = expr.kind
+ && let ExprKind::DropTemps(expr1) = cond.kind
+ && let Some((c, op_node, l)) = get_const(cx, expr1)
+ && let BinOpKind::Ne | BinOpKind::Lt = op_node
+ && let ExprKind::Block(block, None) = then.kind
+ && let Block {
stmts:
- [Stmt
- { kind: StmtKind::Expr(ex) | StmtKind::Semi(ex), .. }],
- expr: None, ..} |
- Block { stmts: [], expr: Some(ex), ..} = block;
- if let ExprKind::AssignOp(op1, target, value) = ex.kind;
- let ty = cx.typeck_results().expr_ty(target);
- if Some(c) == get_int_max(ty);
- let ctxt = expr.span.ctxt();
- if ex.span.ctxt() == ctxt;
- if expr1.span.ctxt() == ctxt;
- if clippy_utils::SpanlessEq::new(cx).eq_expr(l, target);
- if BinOpKind::Add == op1.node;
- if let ExprKind::Lit(lit) = value.kind;
- if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
- if block.expr.is_none();
- then {
- let mut app = Applicability::MachineApplicable;
- let code = snippet_with_context(cx, target.span, ctxt, "_", &mut app).0;
- let sugg = if let Some(parent) = get_parent_expr(cx, expr)
- && let ExprKind::If(_cond, _then, Some(else_)) = parent.kind
- && else_.hir_id == expr.hir_id
- {
- format!("{{{code} = {code}.saturating_add(1); }}")
- } else {
- format!("{code} = {code}.saturating_add(1);")
- };
- span_lint_and_sugg(cx, IMPLICIT_SATURATING_ADD, expr.span, "manual saturating add detected", "use instead", sugg, app);
+ [
+ Stmt {
+ kind: StmtKind::Expr(ex) | StmtKind::Semi(ex),
+ ..
+ },
+ ],
+ expr: None,
+ ..
}
+ | Block {
+ stmts: [],
+ expr: Some(ex),
+ ..
+ } = block
+ && let ExprKind::AssignOp(op1, target, value) = ex.kind
+ && let ty = cx.typeck_results().expr_ty(target)
+ && Some(c) == get_int_max(ty)
+ && let ctxt = expr.span.ctxt()
+ && ex.span.ctxt() == ctxt
+ && expr1.span.ctxt() == ctxt
+ && clippy_utils::SpanlessEq::new(cx).eq_expr(l, target)
+ && BinOpKind::Add == op1.node
+ && let ExprKind::Lit(lit) = value.kind
+ && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
+ && block.expr.is_none()
+ {
+ let mut app = Applicability::MachineApplicable;
+ let code = snippet_with_context(cx, target.span, ctxt, "_", &mut app).0;
+ let sugg = if let Some(parent) = get_parent_expr(cx, expr)
+ && let ExprKind::If(_cond, _then, Some(else_)) = parent.kind
+ && else_.hir_id == expr.hir_id
+ {
+ format!("{{{code} = {code}.saturating_add(1); }}")
+ } else {
+ format!("{code} = {code}.saturating_add(1);")
+ };
+ span_lint_and_sugg(
+ cx,
+ IMPLICIT_SATURATING_ADD,
+ expr.span,
+ "manual saturating add detected",
+ "use instead",
+ sugg,
+ app,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index 859404289..81df1a889 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::{higher, is_integer_literal, peel_blocks_with_stmt, SpanlessEq};
-use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -46,83 +45,76 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
if expr.span.from_expansion() {
return;
}
- if_chain! {
- if let Some(higher::If { cond, then, r#else: None }) = higher::If::hir(expr);
+ if let Some(higher::If { cond, then, r#else: None }) = higher::If::hir(expr)
// Check if the conditional expression is a binary operation
- if let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind;
+ && let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind
// Ensure that the binary operator is >, !=, or <
- if BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node;
+ && (BinOpKind::Ne == cond_op.node || BinOpKind::Gt == cond_op.node || BinOpKind::Lt == cond_op.node)
// Check if assign operation is done
- if let Some(target) = subtracts_one(cx, then);
+ && let Some(target) = subtracts_one(cx, then)
// Extracting out the variable name
- if let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind;
-
- then {
- // Handle symmetric conditions in the if statement
- let (cond_var, cond_num_val) = if SpanlessEq::new(cx).eq_expr(cond_left, target) {
- if BinOpKind::Gt == cond_op.node || BinOpKind::Ne == cond_op.node {
- (cond_left, cond_right)
- } else {
- return;
- }
- } else if SpanlessEq::new(cx).eq_expr(cond_right, target) {
- if BinOpKind::Lt == cond_op.node || BinOpKind::Ne == cond_op.node {
- (cond_right, cond_left)
- } else {
- return;
- }
+ && let ExprKind::Path(QPath::Resolved(_, ares_path)) = target.kind
+ {
+ // Handle symmetric conditions in the if statement
+ let (cond_var, cond_num_val) = if SpanlessEq::new(cx).eq_expr(cond_left, target) {
+ if BinOpKind::Gt == cond_op.node || BinOpKind::Ne == cond_op.node {
+ (cond_left, cond_right)
} else {
return;
- };
-
- // Check if the variable in the condition statement is an integer
- if !cx.typeck_results().expr_ty(cond_var).is_integral() {
+ }
+ } else if SpanlessEq::new(cx).eq_expr(cond_right, target) {
+ if BinOpKind::Lt == cond_op.node || BinOpKind::Ne == cond_op.node {
+ (cond_right, cond_left)
+ } else {
return;
}
+ } else {
+ return;
+ };
- // Get the variable name
- let var_name = ares_path.segments[0].ident.name.as_str();
- match cond_num_val.kind {
- ExprKind::Lit(cond_lit) => {
- // Check if the constant is zero
- if let LitKind::Int(0, _) = cond_lit.node {
- if cx.typeck_results().expr_ty(cond_left).is_signed() {
- } else {
- print_lint_and_sugg(cx, var_name, expr);
- };
- }
- },
- ExprKind::Path(QPath::TypeRelative(_, name)) => {
- if_chain! {
- if name.ident.as_str() == "MIN";
- if let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id);
- if let Some(impl_id) = cx.tcx.impl_of_method(const_id);
- if let None = cx.tcx.impl_trait_ref(impl_id); // An inherent impl
- if cx.tcx.type_of(impl_id).instantiate_identity().is_integral();
- then {
- print_lint_and_sugg(cx, var_name, expr)
- }
- }
- },
- ExprKind::Call(func, []) => {
- if_chain! {
- if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind;
- if name.ident.as_str() == "min_value";
- if let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id);
- if let Some(impl_id) = cx.tcx.impl_of_method(func_id);
- if let None = cx.tcx.impl_trait_ref(impl_id); // An inherent impl
- if cx.tcx.type_of(impl_id).instantiate_identity().is_integral();
- then {
- print_lint_and_sugg(cx, var_name, expr)
- }
- }
- },
- _ => (),
- }
+ // Check if the variable in the condition statement is an integer
+ if !cx.typeck_results().expr_ty(cond_var).is_integral() {
+ return;
+ }
+
+ // Get the variable name
+ let var_name = ares_path.segments[0].ident.name.as_str();
+ match cond_num_val.kind {
+ ExprKind::Lit(cond_lit) => {
+ // Check if the constant is zero
+ if let LitKind::Int(0, _) = cond_lit.node {
+ if cx.typeck_results().expr_ty(cond_left).is_signed() {
+ } else {
+ print_lint_and_sugg(cx, var_name, expr);
+ };
+ }
+ },
+ ExprKind::Path(QPath::TypeRelative(_, name)) => {
+ if name.ident.as_str() == "MIN"
+ && let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_method(const_id)
+ && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl
+ && cx.tcx.type_of(impl_id).instantiate_identity().is_integral()
+ {
+ print_lint_and_sugg(cx, var_name, expr);
+ }
+ },
+ ExprKind::Call(func, []) => {
+ if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind
+ && name.ident.as_str() == "min_value"
+ && let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_method(func_id)
+ && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl
+ && cx.tcx.type_of(impl_id).instantiate_identity().is_integral()
+ {
+ print_lint_and_sugg(cx, var_name, expr);
+ }
+ },
+ _ => (),
}
}
}
@@ -135,18 +127,14 @@ fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Exp
(BinOpKind::Sub == op1.node && is_integer_literal(value, 1)).then_some(target)
},
ExprKind::Assign(target, value, _) => {
- if_chain! {
- if let ExprKind::Binary(ref op1, left1, right1) = value.kind;
- if BinOpKind::Sub == op1.node;
-
- if SpanlessEq::new(cx).eq_expr(left1, target);
-
- if is_integer_literal(right1, 1);
- then {
- Some(target)
- } else {
- None
- }
+ if let ExprKind::Binary(ref op1, left1, right1) = value.kind
+ && BinOpKind::Sub == op1.node
+ && SpanlessEq::new(cx).eq_expr(left1, target)
+ && is_integer_literal(right1, 1)
+ {
+ Some(target)
+ } else {
+ None
}
},
_ => None,
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index ff27a5d66..0f5a9ea5d 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -10,7 +10,7 @@ use rustc_hir::{
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, ClauseKind, Generics, Ty, TyCtxt};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
@@ -43,9 +43,9 @@ declare_clippy_lint! {
/// Box::new(123)
/// }
/// ```
- #[clippy::version = "1.73.0"]
+ #[clippy::version = "1.74.0"]
pub IMPLIED_BOUNDS_IN_IMPLS,
- nursery,
+ complexity,
"specifying bounds that are implied by other bounds in `impl Trait` type"
}
declare_lint_pass!(ImpliedBoundsInImpls => [IMPLIED_BOUNDS_IN_IMPLS]);
@@ -194,6 +194,15 @@ fn is_same_generics<'tcx>(
.enumerate()
.skip(1) // skip `Self` implicit arg
.all(|(arg_index, arg)| {
+ if [
+ implied_by_generics.host_effect_index,
+ implied_generics.host_effect_index,
+ ]
+ .contains(&Some(arg_index))
+ {
+ // skip host effect params in determining whether generics are same
+ return true;
+ }
if let Some(ty) = arg.as_type() {
if let &ty::Param(ty::ParamTy { index, .. }) = ty.kind()
// `index == 0` means that it's referring to `Self`,
diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
index a84f7351a..1075975f0 100644
--- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
-use if_chain::if_chain;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use rustc_hir::{self as hir, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::Symbol;
use std::fmt::{self, Write as _};
@@ -66,54 +65,53 @@ declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRU
impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if_chain! {
- if !expr.span.from_expansion();
- if let ExprKind::Struct(qpath, fields, base) = expr.kind;
- let ty = cx.typeck_results().expr_ty(expr);
- if let Some(adt_def) = ty.ty_adt_def();
- if adt_def.is_struct();
- if let Some(variant) = adt_def.variants().iter().next();
- if fields.iter().all(|f| f.is_shorthand);
- then {
- let mut def_order_map = FxHashMap::default();
- for (idx, field) in variant.fields.iter().enumerate() {
- def_order_map.insert(field.name, idx);
- }
+ if !expr.span.from_expansion()
+ && let ExprKind::Struct(qpath, fields, base) = expr.kind
+ && let ty = cx.typeck_results().expr_ty(expr)
+ && let Some(adt_def) = ty.ty_adt_def()
+ && adt_def.is_struct()
+ && let Some(variant) = adt_def.variants().iter().next()
+ && fields.iter().all(|f| f.is_shorthand)
+ {
+ let mut def_order_map = FxHashMap::default();
+ for (idx, field) in variant.fields.iter().enumerate() {
+ def_order_map.insert(field.name, idx);
+ }
- if is_consistent_order(fields, &def_order_map) {
- return;
- }
+ if is_consistent_order(fields, &def_order_map) {
+ return;
+ }
- let mut ordered_fields: Vec<_> = fields.iter().map(|f| f.ident.name).collect();
- ordered_fields.sort_unstable_by_key(|id| def_order_map[id]);
+ let mut ordered_fields: Vec<_> = fields.iter().map(|f| f.ident.name).collect();
+ ordered_fields.sort_unstable_by_key(|id| def_order_map[id]);
- let mut fields_snippet = String::new();
- let (last_ident, idents) = ordered_fields.split_last().unwrap();
- for ident in idents {
- let _: fmt::Result = write!(fields_snippet, "{ident}, ");
- }
- fields_snippet.push_str(&last_ident.to_string());
+ let mut fields_snippet = String::new();
+ let (last_ident, idents) = ordered_fields.split_last().unwrap();
+ for ident in idents {
+ let _: fmt::Result = write!(fields_snippet, "{ident}, ");
+ }
+ fields_snippet.push_str(&last_ident.to_string());
- let base_snippet = if let Some(base) = base {
- format!(", ..{}", snippet(cx, base.span, ".."))
- } else {
- String::new()
- };
+ let base_snippet = if let Some(base) = base {
+ format!(", ..{}", snippet(cx, base.span, ".."))
+ } else {
+ String::new()
+ };
- let sugg = format!("{} {{ {fields_snippet}{base_snippet} }}",
- snippet(cx, qpath.span(), ".."),
- );
+ let sugg = format!(
+ "{} {{ {fields_snippet}{base_snippet} }}",
+ snippet(cx, qpath.span(), ".."),
+ );
- span_lint_and_sugg(
- cx,
- INCONSISTENT_STRUCT_CONSTRUCTOR,
- expr.span,
- "struct constructor field order is inconsistent with struct definition field order",
- "try",
- sugg,
- Applicability::MachineApplicable,
- )
- }
+ span_lint_and_sugg(
+ cx,
+ INCONSISTENT_STRUCT_CONSTRUCTOR,
+ expr.span,
+ "struct constructor field order is inconsistent with struct definition field order",
+ "try",
+ sugg,
+ Applicability::MachineApplicable,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index c2f1f18e3..5417c13d0 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -4,7 +4,6 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLet;
use clippy_utils::ty::is_copy;
use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local};
-use if_chain::if_chain;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -12,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::Ident;
use rustc_span::Span;
@@ -70,20 +69,17 @@ impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]);
impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if_chain! {
- 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 self.msrv.meets(msrvs::SLICE_PATTERNS);
-
- let found_slices = find_slice_values(cx, let_pat);
- if !found_slices.is_empty();
- let filtered_slices = filter_lintable_slices(cx, found_slices, self.max_suggested_slice, if_then);
- if !filtered_slices.is_empty();
- then {
- for slice in filtered_slices.values() {
- lint_slice(cx, slice);
- }
+ if (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some())
+ && let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr)
+ && !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id)
+ && self.msrv.meets(msrvs::SLICE_PATTERNS)
+ && let found_slices = find_slice_values(cx, let_pat)
+ && !found_slices.is_empty()
+ && let filtered_slices = filter_lintable_slices(cx, found_slices, self.max_suggested_slice, if_then)
+ && !filtered_slices.is_empty()
+ {
+ for slice in filtered_slices.values() {
+ lint_slice(cx, slice);
}
}
}
@@ -245,28 +241,26 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
max_suggested_slice,
} = *self;
- if_chain! {
+ if let Some(use_info) = slice_lint_info.get_mut(&local_id)
// Check if this is even a local we're interested in
- if let Some(use_info) = slice_lint_info.get_mut(&local_id);
- let map = cx.tcx.hir();
+ && let map = cx.tcx.hir()
// Checking for slice indexing
- let parent_id = map.parent_id(expr.hir_id);
- if let Some(hir::Node::Expr(parent_expr)) = map.find(parent_id);
- if let hir::ExprKind::Index(_, index_expr, _) = parent_expr.kind;
- if let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr);
- if let Ok(index_value) = index_value.try_into();
- if index_value < max_suggested_slice;
+ && let parent_id = map.parent_id(expr.hir_id)
+ && let Some(hir::Node::Expr(parent_expr)) = cx.tcx.opt_hir_node(parent_id)
+ && let hir::ExprKind::Index(_, index_expr, _) = parent_expr.kind
+ && let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr)
+ && let Ok(index_value) = index_value.try_into()
+ && index_value < max_suggested_slice
// Make sure that this slice index is read only
- let maybe_addrof_id = map.parent_id(parent_id);
- if let Some(hir::Node::Expr(maybe_addrof_expr)) = map.find(maybe_addrof_id);
- if let hir::ExprKind::AddrOf(_kind, hir::Mutability::Not, _inner_expr) = maybe_addrof_expr.kind;
- then {
- use_info.index_use.push((index_value, map.span(parent_expr.hir_id)));
- return;
- }
+ && let maybe_addrof_id = map.parent_id(parent_id)
+ && let Some(hir::Node::Expr(maybe_addrof_expr)) = cx.tcx.opt_hir_node(maybe_addrof_id)
+ && let hir::ExprKind::AddrOf(_kind, hir::Mutability::Not, _inner_expr) = maybe_addrof_expr.kind
+ {
+ use_info.index_use.push((index_value, map.span(parent_expr.hir_id)));
+ return;
}
// The slice was used for something other than indexing
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index 1ce7d85d3..0ae03d101 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -7,7 +7,7 @@ use rustc_ast::ast::RangeLimits;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
new file mode 100644
index 000000000..955f90d42
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
@@ -0,0 +1,95 @@
+use crate::methods::method_call;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::peel_blocks;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::declare_lint_pass;
+use rustc_span::{sym, BytePos, Span};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks if both `.write(true)` and `.append(true)` methods are called
+ /// on a same `OpenOptions`.
+ ///
+ /// ### Why is this bad?
+ /// `.append(true)` already enables `write(true)`, making this one
+ /// superflous.
+ ///
+ /// ### Example
+ /// ```no_run
+ /// # use std::fs::OpenOptions;
+ /// let _ = OpenOptions::new()
+ /// .write(true)
+ /// .append(true)
+ /// .create(true)
+ /// .open("file.json");
+ /// ```
+ /// Use instead:
+ /// ```no_run
+ /// # use std::fs::OpenOptions;
+ /// let _ = OpenOptions::new()
+ /// .append(true)
+ /// .create(true)
+ /// .open("file.json");
+ /// ```
+ #[clippy::version = "1.76.0"]
+ pub INEFFECTIVE_OPEN_OPTIONS,
+ suspicious,
+ "usage of both `write(true)` and `append(true)` on same `OpenOptions`"
+}
+
+declare_lint_pass!(IneffectiveOpenOptions => [INEFFECTIVE_OPEN_OPTIONS]);
+
+fn index_if_arg_is_boolean(args: &[Expr<'_>], call_span: Span) -> Option<Span> {
+ if let [arg] = args
+ && let ExprKind::Lit(lit) = peel_blocks(arg).kind
+ && lit.node == LitKind::Bool(true)
+ {
+ // The `.` is not included in the span so we cheat a little bit to include it as well.
+ Some(call_span.with_lo(call_span.lo() - BytePos(1)))
+ } else {
+ None
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ let Some(("open", mut receiver, [_arg], _, _)) = method_call(expr) else {
+ return;
+ };
+ let receiver_ty = cx.typeck_results().expr_ty(receiver);
+ match receiver_ty.peel_refs().kind() {
+ ty::Adt(adt, _) if cx.tcx.is_diagnostic_item(sym::FsOpenOptions, adt.did()) => {},
+ _ => return,
+ }
+
+ let mut append = None;
+ let mut write = None;
+
+ while let Some((name, recv, args, _, span)) = method_call(receiver) {
+ if name == "append" {
+ append = index_if_arg_is_boolean(args, span);
+ } else if name == "write" {
+ write = index_if_arg_is_boolean(args, span);
+ }
+ receiver = recv;
+ }
+
+ if let Some(write_span) = write
+ && append.is_some()
+ {
+ span_lint_and_sugg(
+ cx,
+ INEFFECTIVE_OPEN_OPTIONS,
+ write_span,
+ "unnecessary use of `.write(true)` because there is `.append(true)`",
+ "remove `.write(true)`",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index e9c53671a..9ad027358 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -3,7 +3,7 @@ use clippy_utils::higher;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::{sym, Symbol};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
index a61a64161..e4781752e 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::{Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
use std::collections::hash_map::Entry;
@@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
&& !is_lint_allowed(
cx,
MULTIPLE_INHERENT_IMPL,
- cx.tcx.hir().local_def_id_to_hir_id(id),
+ cx.tcx.local_def_id_to_hir_id(id),
)
}) {
for impl_id in impl_ids.iter().map(|id| id.expect_local()) {
@@ -117,12 +117,12 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
/// Gets the span for the given impl block unless it's not being considered by the lint.
fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option<Span> {
- let id = cx.tcx.hir().local_def_id_to_hir_id(id);
+ let id = cx.tcx.local_def_id_to_hir_id(id);
if let Node::Item(&Item {
kind: ItemKind::Impl(impl_item),
span,
..
- }) = cx.tcx.hir().get(id)
+ }) = cx.tcx.hir_node(id)
{
(!span.from_expansion()
&& impl_item.generics.params.is_empty()
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index fe5eb5cca..ca2ac6030 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::{implements_trait, is_type_lang_item};
use clippy_utils::{return_ty, trait_ref_of_method};
use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem, Unsafety};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
use rustc_target::spec::abi::Abi;
diff --git a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
index 269311a67..e48656380 100644
--- a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
+++ b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
@@ -4,7 +4,7 @@ use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use std::borrow::Cow;
use std::cmp::Reverse;
use std::collections::BinaryHeap;
diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
index 899126565..bc236c5c7 100644
--- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
+++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
@@ -6,7 +6,7 @@ use rustc_ast::ast::Attribute;
use rustc_errors::Applicability;
use rustc_hir::{TraitFn, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, Symbol};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
index 32b2cb438..655f4b82a 100644
--- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
+++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
@@ -6,7 +6,7 @@ use clippy_utils::ty;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::sym;
@@ -89,27 +89,17 @@ impl LateLintPass<'_> for InstantSubtraction {
rhs,
) = expr.kind
{
- if_chain! {
- if is_instant_now_call(cx, lhs);
-
- if is_an_instant(cx, rhs);
- if let Some(sugg) = Sugg::hir_opt(cx, rhs);
-
- then {
- print_manual_instant_elapsed_sugg(cx, expr, sugg)
- } else {
- if_chain! {
- if !expr.span.from_expansion();
- if self.msrv.meets(msrvs::TRY_FROM);
-
- if is_an_instant(cx, lhs);
- if is_a_duration(cx, rhs);
-
- then {
- print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr)
- }
- }
- }
+ if is_instant_now_call(cx, lhs)
+ && is_an_instant(cx, rhs)
+ && let Some(sugg) = Sugg::hir_opt(cx, rhs)
+ {
+ print_manual_instant_elapsed_sugg(cx, expr, sugg);
+ } else if !expr.span.from_expansion()
+ && self.msrv.meets(msrvs::TRY_FROM)
+ && is_an_instant(cx, lhs)
+ && is_a_duration(cx, rhs)
+ {
+ print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
index 9ffcee07d..b8e0eef7c 100644
--- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs
+++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
@@ -6,7 +6,7 @@ use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind};
use rustc_ast::token;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
index de82935e6..8bcd9b532 100644
--- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -2,7 +2,7 @@ use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, IntTy, UintTy};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
use clippy_utils::comparisons;
diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
index 90048d96c..a9f1612ff 100644
--- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
+++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
@@ -6,9 +6,9 @@ use clippy_utils::source::is_present_in_source;
use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case};
use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::Span;
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::Symbol;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
@@ -436,7 +436,7 @@ impl LateLintPass<'_> for ItemNameRepetitions {
{
match item.kind {
ItemKind::Enum(def, _) => check_variant(cx, self.enum_threshold, &def, item_name, item.span),
- ItemKind::Struct(VariantData::Struct(fields, _), _) => {
+ ItemKind::Struct(VariantData::Struct { fields, .. }, _) => {
check_fields(cx, self.struct_threshold, item, fields);
},
_ => (),
diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
index 9605d76fb..39223c204 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
@@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_hir;
use rustc_hir::{Block, ItemKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
index 35e01862c..3614fb8cc 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
@@ -4,7 +4,7 @@ use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro};
use rustc_errors::{Applicability, SuggestionStyle};
use rustc_hir::{HirId, Item, ItemKind, Mod};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::hygiene::AstPass;
use rustc_span::{sym, ExpnKind};
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index 505aadd1a..b9fad7265 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -4,7 +4,7 @@ use clippy_utils::ty::implements_trait;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
declare_clippy_lint! {
@@ -71,7 +71,7 @@ fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefI
if sig.decl.implicit_self.has_implicit_self() {
let ret_ty = cx
.tcx
- .erase_late_bound_regions(cx.tcx.fn_sig(fn_id).instantiate_identity().output());
+ .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(fn_id).instantiate_identity().output());
let ret_ty = cx
.tcx
.try_normalize_erasing_regions(cx.param_env, ret_ty)
diff --git a/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs b/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs
new file mode 100644
index 000000000..8110c1970
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs
@@ -0,0 +1,78 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::higher::ForLoop;
+use clippy_utils::match_any_def_paths;
+use clippy_utils::paths::{
+ HASHMAP_DRAIN, HASHMAP_ITER, HASHMAP_ITER_MUT, HASHMAP_KEYS, HASHMAP_VALUES, HASHMAP_VALUES_MUT, HASHSET_DRAIN,
+ HASHSET_ITER_TY,
+};
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// This is a restriction lint which prevents the use of hash types (i.e., `HashSet` and `HashMap`) in for loops.
+ ///
+ /// ### Why is this bad?
+ /// Because hash types are unordered, when iterated through such as in a for loop, the values are returned in
+ /// an undefined order. As a result, on redundant systems this may cause inconsistencies and anomalies.
+ /// In addition, the unknown order of the elements may reduce readability or introduce other undesired
+ /// side effects.
+ ///
+ /// ### Example
+ /// ```no_run
+ /// let my_map = std::collections::HashMap::<i32, String>::new();
+ /// for (key, value) in my_map { /* ... */ }
+ /// ```
+ /// Use instead:
+ /// ```no_run
+ /// let my_map = std::collections::HashMap::<i32, String>::new();
+ /// let mut keys = my_map.keys().clone().collect::<Vec<_>>();
+ /// keys.sort();
+ /// for key in keys {
+ /// let value = &my_map[key];
+ /// }
+ /// ```
+ #[clippy::version = "1.75.0"]
+ pub ITER_OVER_HASH_TYPE,
+ restriction,
+ "iterating over unordered hash-based types (`HashMap` and `HashSet`)"
+}
+
+declare_lint_pass!(IterOverHashType => [ITER_OVER_HASH_TYPE]);
+
+impl LateLintPass<'_> for IterOverHashType {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>) {
+ if let Some(for_loop) = ForLoop::hir(expr)
+ && !for_loop.body.span.from_expansion()
+ && let ty = cx.typeck_results().expr_ty(for_loop.arg).peel_refs()
+ && let Some(adt) = ty.ty_adt_def()
+ && let did = adt.did()
+ && (match_any_def_paths(
+ cx,
+ did,
+ &[
+ &HASHMAP_KEYS,
+ &HASHMAP_VALUES,
+ &HASHMAP_VALUES_MUT,
+ &HASHMAP_ITER,
+ &HASHMAP_ITER_MUT,
+ &HASHMAP_DRAIN,
+ &HASHSET_ITER_TY,
+ &HASHSET_DRAIN,
+ ],
+ )
+ .is_some()
+ || is_type_diagnostic_item(cx, ty, sym::HashMap)
+ || is_type_diagnostic_item(cx, ty, sym::HashSet))
+ {
+ span_lint(
+ cx,
+ ITER_OVER_HASH_TYPE,
+ expr.span,
+ "iteration over unordered hash-based type",
+ );
+ };
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 3c291f255..3a5756482 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -7,7 +7,7 @@ use rustc_errors::Applicability;
use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, Symbol};
use std::iter;
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index a4f3d4983..b561054b5 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, ConstKind};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{BytePos, Pos, Span};
declare_clippy_lint! {
@@ -47,43 +46,40 @@ impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]);
impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
- if_chain! {
- if !item.span.from_expansion();
- if let ItemKind::Const(_, generics, _) = &item.kind;
+ if !item.span.from_expansion()
+ && let ItemKind::Const(_, generics, _) = &item.kind
// Since static items may not have generics, skip generic const items.
// FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it
// doesn't account for empty where-clauses that only consist of keyword `where` IINM.
- if generics.params.is_empty() && !generics.has_where_clause_predicates;
- let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
- if let ty::Array(element_type, cst) = ty.kind();
- if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind();
- if let Ok(element_count) = element_count.try_to_target_usize(cx.tcx);
- if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes());
- if self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size);
-
- then {
- let hi_pos = item.ident.span.lo() - BytePos::from_usize(1);
- let sugg_span = Span::new(
- hi_pos - BytePos::from_usize("const".len()),
- hi_pos,
- item.span.ctxt(),
- item.span.parent(),
- );
- span_lint_and_then(
- cx,
- LARGE_CONST_ARRAYS,
- item.span,
- "large array defined as const",
- |diag| {
- diag.span_suggestion(
- sugg_span,
- "make this a static item",
- "static",
- Applicability::MachineApplicable,
- );
- }
- );
- }
+ && generics.params.is_empty() && !generics.has_where_clause_predicates
+ && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+ && let ty::Array(element_type, cst) = ty.kind()
+ && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind()
+ && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx)
+ && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
+ && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size)
+ {
+ let hi_pos = item.ident.span.lo() - BytePos::from_usize(1);
+ let sugg_span = Span::new(
+ hi_pos - BytePos::from_usize("const".len()),
+ hi_pos,
+ item.span.ctxt(),
+ item.span.parent(),
+ );
+ span_lint_and_then(
+ cx,
+ LARGE_CONST_ARRAYS,
+ item.span,
+ "large array defined as const",
+ |diag| {
+ diag.span_suggestion(
+ sugg_span,
+ "make this a static item",
+ "static",
+ Applicability::MachineApplicable,
+ );
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index 0bf9b8718..6feb18855 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -8,7 +8,7 @@ use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{Adt, Ty};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs
index 26a727852..eb7570e9b 100644
--- a/src/tools/clippy/clippy_lints/src/large_futures.rs
+++ b/src/tools/clippy/clippy_lints/src/large_futures.rs
@@ -4,7 +4,7 @@ use clippy_utils::ty::implements_trait;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_target::abi::Size;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs
index 566901de3..1b5981ecc 100644
--- a/src/tools/clippy/clippy_lints/src/large_include_file.rs
+++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs
@@ -4,7 +4,7 @@ use clippy_utils::macros::root_macro_call_first_node;
use rustc_ast::LitKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -50,37 +50,35 @@ impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]);
impl LateLintPass<'_> for LargeIncludeFile {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
- if_chain! {
- if let Some(macro_call) = root_macro_call_first_node(cx, expr);
- if !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id);
- if cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
- || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id);
- if let ExprKind::Lit(lit) = &expr.kind;
- then {
- let len = match &lit.node {
- // include_bytes
- LitKind::ByteStr(bstr, _) => bstr.len(),
- // include_str
- LitKind::Str(sym, _) => sym.as_str().len(),
- _ => return,
- };
+ if let Some(macro_call) = root_macro_call_first_node(cx, expr)
+ && !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id)
+ && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
+ || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id))
+ && let ExprKind::Lit(lit) = &expr.kind
+ {
+ let len = match &lit.node {
+ // include_bytes
+ LitKind::ByteStr(bstr, _) => bstr.len(),
+ // include_str
+ LitKind::Str(sym, _) => sym.as_str().len(),
+ _ => return,
+ };
- if len as u64 <= self.max_file_size {
- return;
- }
-
- span_lint_and_note(
- cx,
- LARGE_INCLUDE_FILE,
- expr.span,
- "attempted to include a large file",
- None,
- &format!(
- "the configuration allows a maximum size of {} bytes",
- self.max_file_size
- ),
- );
+ if len as u64 <= self.max_file_size {
+ return;
}
+
+ span_lint_and_note(
+ cx,
+ LARGE_INCLUDE_FILE,
+ expr.span,
+ "attempted to include a large file",
+ None,
+ &format!(
+ "the configuration allows a maximum size of {} bytes",
+ self.max_file_size
+ ),
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
index 5e312ab72..fd33ba91b 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
@@ -4,7 +4,7 @@ use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, ConstKind};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs
index 33636eb68..b397180a6 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs
@@ -6,7 +6,7 @@ use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, FnDecl};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 0f17d2676..8c032b170 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -2,22 +2,21 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the
use clippy_utils::source::snippet_with_context;
use clippy_utils::sugg::Sugg;
use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators};
-use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::{
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
- ImplicitSelfKind, Item, ItemKind, LangItem, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef,
- TyKind, TypeBindingKind,
+ ImplicitSelfKind, Item, ItemKind, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef,
+ TyKind, TypeBindingKind, OpaqueTyOrigin,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{Span, Symbol};
+use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
+use rustc_span::{Span, Symbol};
declare_clippy_lint! {
/// ### What it does
@@ -132,37 +131,33 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
}
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
- if_chain! {
- if item.ident.name == sym::len;
- if let ImplItemKind::Fn(sig, _) = &item.kind;
- if sig.decl.implicit_self.has_implicit_self();
- if sig.decl.inputs.len() == 1;
- if cx.effective_visibilities.is_exported(item.owner_id.def_id);
- if matches!(sig.decl.output, FnRetTy::Return(_));
- if let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id());
- if imp.of_trait.is_none();
- if let TyKind::Path(ty_path) = &imp.self_ty.kind;
- if let Some(ty_id) = cx.qpath_res(ty_path, imp.self_ty.hir_id).opt_def_id();
- if let Some(local_id) = ty_id.as_local();
- let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
- if !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id);
- if let Some(output) = parse_len_output(
- cx,
- cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder()
- );
- then {
- let (name, kind) = match cx.tcx.hir().find(ty_hir_id) {
- Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"),
- Some(Node::Item(x)) => match x.kind {
- ItemKind::Struct(..) => (x.ident.name, "struct"),
- ItemKind::Enum(..) => (x.ident.name, "enum"),
- ItemKind::Union(..) => (x.ident.name, "union"),
- _ => (x.ident.name, "type"),
- }
- _ => return,
- };
- check_for_is_empty(cx, sig.span, sig.decl.implicit_self, output, ty_id, name, kind)
- }
+ if item.ident.name == sym::len
+ && let ImplItemKind::Fn(sig, _) = &item.kind
+ && sig.decl.implicit_self.has_implicit_self()
+ && sig.decl.inputs.len() == 1
+ && cx.effective_visibilities.is_exported(item.owner_id.def_id)
+ && matches!(sig.decl.output, FnRetTy::Return(_))
+ && let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id())
+ && imp.of_trait.is_none()
+ && let TyKind::Path(ty_path) = &imp.self_ty.kind
+ && let Some(ty_id) = cx.qpath_res(ty_path, imp.self_ty.hir_id).opt_def_id()
+ && let Some(local_id) = ty_id.as_local()
+ && let ty_hir_id = cx.tcx.local_def_id_to_hir_id(local_id)
+ && !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id)
+ && let Some(output) =
+ parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder())
+ {
+ let (name, kind) = match cx.tcx.opt_hir_node(ty_hir_id) {
+ Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"),
+ Some(Node::Item(x)) => match x.kind {
+ ItemKind::Struct(..) => (x.ident.name, "struct"),
+ ItemKind::Enum(..) => (x.ident.name, "enum"),
+ ItemKind::Union(..) => (x.ident.name, "union"),
+ _ => (x.ident.name, "type"),
+ },
+ _ => return,
+ };
+ check_for_is_empty(cx, sig.span, sig.decl.implicit_self, output, ty_id, name, kind);
}
}
@@ -294,8 +289,10 @@ fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&
kind: ItemKind::OpaqueTy(opaque),
..
} = item
- && opaque.bounds.len() == 1
- && let GenericBound::LangItemTrait(LangItem::Future, _, _, generic_args) = &opaque.bounds[0]
+ && let OpaqueTyOrigin::AsyncFn(_) = opaque.origin
+ && let [GenericBound::Trait(trait_ref, _)] = &opaque.bounds
+ && let Some(segment) = trait_ref.trait_ref.path.segments.last()
+ && let Some(generic_args) = segment.args
&& generic_args.bindings.len() == 1
&& let TypeBindingKind::Equality {
term:
diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
index 2f6f36c39..270162ae7 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -2,12 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::path_to_local_id;
use clippy_utils::source::snippet;
use clippy_utils::visitors::is_local_used;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::{BindingAnnotation, Mutability};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -61,76 +60,85 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
let mut it = block.stmts.iter().peekable();
while let Some(stmt) = it.next() {
- if_chain! {
- if let Some(expr) = it.peek();
- if let hir::StmtKind::Local(local) = stmt.kind;
- if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind;
- if let hir::StmtKind::Expr(if_) = expr.kind;
- if let hir::ExprKind::If(hir::Expr { kind: hir::ExprKind::DropTemps(cond), ..}, then, else_) = if_.kind;
- if !is_local_used(cx, *cond, canonical_id);
- if let hir::ExprKind::Block(then, _) = then.kind;
- if let Some(value) = check_assign(cx, canonical_id, then);
- if !is_local_used(cx, value, canonical_id);
- then {
- let span = stmt.span.to(if_.span);
+ if let Some(expr) = it.peek()
+ && let hir::StmtKind::Local(local) = stmt.kind
+ && let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind
+ && let hir::StmtKind::Expr(if_) = expr.kind
+ && let hir::ExprKind::If(
+ hir::Expr {
+ kind: hir::ExprKind::DropTemps(cond),
+ ..
+ },
+ then,
+ else_,
+ ) = if_.kind
+ && !is_local_used(cx, *cond, canonical_id)
+ && let hir::ExprKind::Block(then, _) = then.kind
+ && let Some(value) = check_assign(cx, canonical_id, then)
+ && !is_local_used(cx, value, canonical_id)
+ {
+ let span = stmt.span.to(if_.span);
- let has_interior_mutability = !cx.typeck_results().node_type(canonical_id).is_freeze(
- cx.tcx,
- cx.param_env,
- );
- if has_interior_mutability { return; }
+ let has_interior_mutability = !cx
+ .typeck_results()
+ .node_type(canonical_id)
+ .is_freeze(cx.tcx, cx.param_env);
+ if has_interior_mutability {
+ return;
+ }
- let (default_multi_stmts, default) = if let Some(else_) = else_ {
- if let hir::ExprKind::Block(else_, _) = else_.kind {
- if let Some(default) = check_assign(cx, canonical_id, else_) {
- (else_.stmts.len() > 1, default)
- } else if let Some(default) = local.init {
- (true, default)
- } else {
- continue;
- }
+ let (default_multi_stmts, default) = if let Some(else_) = else_ {
+ if let hir::ExprKind::Block(else_, _) = else_.kind {
+ if let Some(default) = check_assign(cx, canonical_id, else_) {
+ (else_.stmts.len() > 1, default)
+ } else if let Some(default) = local.init {
+ (true, default)
} else {
continue;
}
- } else if let Some(default) = local.init {
- (false, default)
} else {
continue;
- };
+ }
+ } else if let Some(default) = local.init {
+ (false, default)
+ } else {
+ continue;
+ };
- let mutability = match mode {
- BindingAnnotation(_, Mutability::Mut) => "<mut> ",
- _ => "",
- };
+ let mutability = match mode {
+ BindingAnnotation(_, Mutability::Mut) => "<mut> ",
+ _ => "",
+ };
- // FIXME: this should not suggest `mut` if we can detect that the variable is not
- // use mutably after the `if`
+ // FIXME: this should not suggest `mut` if we can detect that the variable is not
+ // use mutably after the `if`
- let sug = format!(
- "let {mutability}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};",
- name=ident.name,
- cond=snippet(cx, cond.span, "_"),
- then=if then.stmts.len() > 1 { " ..;" } else { "" },
- else=if default_multi_stmts { " ..;" } else { "" },
- value=snippet(cx, value.span, "<value>"),
- default=snippet(cx, default.span, "<default>"),
- );
- span_lint_and_then(cx,
- USELESS_LET_IF_SEQ,
- span,
- "`if _ { .. } else { .. }` is an expression",
- |diag| {
- diag.span_suggestion(
- span,
- "it is more idiomatic to write",
- sug,
- Applicability::HasPlaceholders,
- );
- if !mutability.is_empty() {
- diag.note("you might not need `mut` at all");
- }
- });
- }
+ let sug = format!(
+ "let {mutability}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};",
+ name=ident.name,
+ cond=snippet(cx, cond.span, "_"),
+ then=if then.stmts.len() > 1 { " ..;" } else { "" },
+ else=if default_multi_stmts { " ..;" } else { "" },
+ value=snippet(cx, value.span, "<value>"),
+ default=snippet(cx, default.span, "<default>"),
+ );
+ span_lint_and_then(
+ cx,
+ USELESS_LET_IF_SEQ,
+ span,
+ "`if _ { .. } else { .. }` is an expression",
+ |diag| {
+ diag.span_suggestion(
+ span,
+ "it is more idiomatic to write",
+ sug,
+ Applicability::HasPlaceholders,
+ );
+ if !mutability.is_empty() {
+ diag.note("you might not need `mut` at all");
+ }
+ },
+ );
}
}
}
@@ -141,20 +149,23 @@ fn check_assign<'tcx>(
decl: hir::HirId,
block: &'tcx hir::Block<'_>,
) -> Option<&'tcx hir::Expr<'tcx>> {
- if_chain! {
- if block.expr.is_none();
- if let Some(expr) = block.stmts.iter().last();
- if let hir::StmtKind::Semi(expr) = expr.kind;
- if let hir::ExprKind::Assign(var, value, _) = expr.kind;
- if path_to_local_id(var, decl);
- then {
- if block.stmts.iter().take(block.stmts.len()-1).any(|stmt| is_local_used(cx, stmt, decl)) {
- None
- } else {
- Some(value)
- }
- } else {
+ if block.expr.is_none()
+ && let Some(expr) = block.stmts.iter().last()
+ && let hir::StmtKind::Semi(expr) = expr.kind
+ && let hir::ExprKind::Assign(var, value, _) = expr.kind
+ && path_to_local_id(var, decl)
+ {
+ if block
+ .stmts
+ .iter()
+ .take(block.stmts.len() - 1)
+ .any(|stmt| is_local_used(cx, stmt, decl))
+ {
None
+ } else {
+ Some(value)
}
+ } else {
+ None
}
}
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 04f23a213..606c2ed72 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -5,7 +5,7 @@ use rustc_hir::{Local, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{GenericArgKind, IsSuggestable};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{BytePos, Span};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
index 79d728a02..5f3f9b43f 100644
--- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet;
use rustc_hir::{Local, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -27,27 +27,25 @@ declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]);
impl LateLintPass<'_> for UnderscoreTyped {
fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
- if_chain! {
- if !in_external_macro(cx.tcx.sess, local.span);
- if let Some(ty) = local.ty; // Ensure that it has a type defined
- if let TyKind::Infer = &ty.kind; // that type is '_'
- if local.span.eq_ctxt(ty.span);
- then {
- // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized,
- // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty`
- if snippet(cx, ty.span, "_").trim() != "_" {
- return;
- }
-
- span_lint_and_help(
- cx,
- LET_WITH_TYPE_UNDERSCORE,
- local.span,
- "variable declared with type underscore",
- Some(ty.span.with_lo(local.pat.span.hi())),
- "remove the explicit type `_` declaration"
- )
+ if !in_external_macro(cx.tcx.sess, local.span)
+ && let Some(ty) = local.ty // Ensure that it has a type defined
+ && let TyKind::Infer = &ty.kind // that type is '_'
+ && local.span.eq_ctxt(ty.span)
+ {
+ // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized,
+ // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty`
+ if snippet(cx, ty.span, "_").trim() != "_" {
+ return;
}
+
+ span_lint_and_help(
+ cx,
+ LET_WITH_TYPE_UNDERSCORE,
+ local.span,
+ "variable declared with type underscore",
+ Some(ty.span.with_lo(local.pat.span.hi())),
+ "remove the explicit type `_` declaration",
+ );
};
}
}
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index ab978a677..7758d6a58 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -50,9 +50,10 @@ extern crate clippy_utils;
#[macro_use]
extern crate declare_clippy_lint;
+use std::collections::BTreeMap;
+
use rustc_data_structures::fx::FxHashSet;
use rustc_lint::{Lint, LintId};
-use rustc_session::Session;
#[cfg(feature = "internal")]
pub mod deprecated_lints;
@@ -75,7 +76,7 @@ mod assertions_on_result_states;
mod async_yields_async;
mod attrs;
mod await_holding_invalid;
-mod blocks_in_if_conditions;
+mod blocks_in_conditions;
mod bool_assert_comparison;
mod bool_to_int_with_if;
mod booleans;
@@ -145,6 +146,7 @@ mod if_let_mutex;
mod if_not_else;
mod if_then_some_else_none;
mod ignored_unit_patterns;
+mod impl_hash_with_borrow_str_and_bytes;
mod implicit_hasher;
mod implicit_return;
mod implicit_saturating_add;
@@ -153,6 +155,7 @@ mod implied_bounds_in_impls;
mod inconsistent_struct_constructor;
mod index_refutable_slice;
mod indexing_slicing;
+mod ineffective_open_options;
mod infinite_iter;
mod inherent_impl;
mod inherent_to_string;
@@ -165,6 +168,7 @@ mod item_name_repetitions;
mod items_after_statements;
mod items_after_test_module;
mod iter_not_returning_iterator;
+mod iter_over_hash_type;
mod iter_without_into_iter;
mod large_const_arrays;
mod large_enum_variant;
@@ -288,6 +292,7 @@ mod ref_option_ref;
mod ref_patterns;
mod reference;
mod regex;
+mod repeat_vec_with_capacity;
mod reserve_after_initialization;
mod return_self_not_must_use;
mod returns;
@@ -308,7 +313,6 @@ mod slow_vector_initialization;
mod std_instead_of_core;
mod strings;
mod strlen_on_c_strings;
-mod suspicious_doc_comments;
mod suspicious_operation_groupings;
mod suspicious_trait_impl;
mod suspicious_xor_used_as_pow;
@@ -325,6 +329,7 @@ mod tuple_array_conversions;
mod types;
mod undocumented_unsafe_blocks;
mod unicode;
+mod uninhabited_references;
mod uninit_vec;
mod unit_return_expecting_ord;
mod unit_types;
@@ -492,11 +497,84 @@ fn register_categories(store: &mut rustc_lint::LintStore) {
groups.register(store);
}
-/// Register all lints and lint groups with the rustc plugin registry
+/// Register all lints and lint groups with the rustc lint store
///
/// Used in `./src/driver.rs`.
#[expect(clippy::too_many_lines)]
-pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &'static Conf) {
+pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
+ let Conf {
+ ref absolute_paths_allowed_crates,
+ absolute_paths_max_segments,
+ accept_comment_above_attributes,
+ accept_comment_above_statement,
+ allow_dbg_in_tests,
+ allow_expect_in_tests,
+ allow_mixed_uninlined_format_args,
+ allow_one_hash_in_raw_strings,
+ allow_print_in_tests,
+ allow_private_module_inception,
+ allow_unwrap_in_tests,
+ ref allowed_dotfiles,
+ ref allowed_idents_below_min_chars,
+ ref allowed_scripts,
+ ref arithmetic_side_effects_allowed_binary,
+ ref arithmetic_side_effects_allowed_unary,
+ ref arithmetic_side_effects_allowed,
+ array_size_threshold,
+ avoid_breaking_exported_api,
+ ref await_holding_invalid_types,
+ cargo_ignore_publish,
+ cognitive_complexity_threshold,
+ ref disallowed_macros,
+ ref disallowed_methods,
+ ref disallowed_names,
+ ref disallowed_types,
+ ref doc_valid_idents,
+ enable_raw_pointer_heuristic_for_send,
+ enforce_iter_loop_reborrow,
+ ref enforced_import_renames,
+ enum_variant_name_threshold,
+ enum_variant_size_threshold,
+ excessive_nesting_threshold,
+ future_size_threshold,
+ ref ignore_interior_mutability,
+ large_error_threshold,
+ literal_representation_threshold,
+ matches_for_let_else,
+ max_fn_params_bools,
+ max_include_file_size,
+ max_struct_bools,
+ max_suggested_slice_pattern_length,
+ max_trait_bounds,
+ min_ident_chars_threshold,
+ missing_docs_in_crate_items,
+ ref msrv,
+ pass_by_value_size_limit,
+ semicolon_inside_block_ignore_singleline,
+ semicolon_outside_block_ignore_multiline,
+ single_char_binding_names_threshold,
+ stack_size_threshold,
+ ref standard_macro_braces,
+ struct_field_name_threshold,
+ suppress_restriction_lint_in_const,
+ too_large_for_stack,
+ too_many_arguments_threshold,
+ too_many_lines_threshold,
+ trivial_copy_size_limit,
+ type_complexity_threshold,
+ unnecessary_box_size,
+ unreadable_literal_lint_fractions,
+ upper_case_acronyms_aggressive,
+ vec_box_size_threshold,
+ verbose_bit_mask_threshold,
+ warn_on_all_wildcard_imports,
+ check_private_items,
+
+ blacklisted_names: _,
+ cyclomatic_complexity_threshold: _,
+ } = *conf;
+ let msrv = || msrv.clone();
+
register_removed_non_tool_lints(store);
register_categories(store);
@@ -521,7 +599,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| {
Box::new(utils::internal_lints::compiler_lint_functions::CompilerLintFunctions::new())
});
- store.register_late_pass(|_| Box::new(utils::internal_lints::if_chain_style::IfChainStyle));
store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths));
store.register_late_pass(|_| {
Box::<utils::internal_lints::interning_defined_symbol::InterningDefinedSymbol>::default()
@@ -537,9 +614,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
});
}
- let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone();
- let arithmetic_side_effects_allowed_binary = conf.arithmetic_side_effects_allowed_binary.clone();
- let arithmetic_side_effects_allowed_unary = conf.arithmetic_side_effects_allowed_unary.clone();
store.register_late_pass(move |_| {
Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(
arithmetic_side_effects_allowed
@@ -557,16 +631,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_early_pass(|| Box::<utils::format_args_collector::FormatArgsCollector>::default());
store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
store.register_late_pass(|_| Box::new(utils::author::Author));
- let await_holding_invalid_types = conf.await_holding_invalid_types.clone();
store.register_late_pass(move |_| {
Box::new(await_holding_invalid::AwaitHolding::new(
await_holding_invalid_types.clone(),
))
});
store.register_late_pass(|_| Box::new(serde_api::SerdeApi));
- let vec_box_size_threshold = conf.vec_box_size_threshold;
- let type_complexity_threshold = conf.type_complexity_threshold;
- let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
store.register_late_pass(move |_| {
Box::new(types::Types::new(
vec_box_size_threshold,
@@ -588,7 +658,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::<significant_drop_tightening::SignificantDropTightening<'_>>::default());
store.register_late_pass(|_| Box::new(len_zero::LenZero));
store.register_late_pass(|_| Box::new(attrs::Attributes));
- store.register_late_pass(|_| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
+ store.register_late_pass(|_| Box::new(blocks_in_conditions::BlocksInConditions));
store.register_late_pass(|_| Box::new(unicode::Unicode));
store.register_late_pass(|_| Box::new(uninit_vec::UninitVec));
store.register_late_pass(|_| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
@@ -599,19 +669,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor));
store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
-
- let msrv = || conf.msrv.clone();
- 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;
- let suppress_restriction_lint_in_const = conf.suppress_restriction_lint_in_const;
store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv())));
- let allowed_dotfiles = conf
- .allowed_dotfiles
- .iter()
- .cloned()
- .chain(methods::DEFAULT_ALLOWED_DOTFILES.iter().copied().map(ToOwned::to_owned))
- .collect::<FxHashSet<_>>();
store.register_late_pass(move |_| {
Box::new(methods::Methods::new(
avoid_breaking_exported_api,
@@ -622,7 +680,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
))
});
store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv())));
- let matches_for_let_else = conf.matches_for_let_else;
store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv())));
store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv())));
store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv())));
@@ -639,7 +696,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv())));
store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount));
store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod));
- let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length;
store.register_late_pass(move |_| {
Box::new(index_refutable_slice::IndexRefutableSlice::new(
max_suggested_slice_pattern_length,
@@ -648,7 +704,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
});
store.register_late_pass(|_| Box::<shadow::Shadow>::default());
store.register_late_pass(|_| Box::new(unit_types::UnitTypes));
- let enforce_iter_loop_reborrow = conf.enforce_iter_loop_reborrow;
store.register_late_pass(move |_| Box::new(loops::Loops::new(msrv(), enforce_iter_loop_reborrow)));
store.register_late_pass(|_| Box::<main_recursion::MainRecursion>::default());
store.register_late_pass(|_| Box::new(lifetimes::Lifetimes));
@@ -662,18 +717,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(no_effect::NoEffect));
store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment));
store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv())));
- let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
store.register_late_pass(move |_| {
Box::new(cognitive_complexity::CognitiveComplexity::new(
cognitive_complexity_threshold,
))
});
- let too_large_for_stack = conf.too_large_for_stack;
store.register_late_pass(move |_| Box::new(escape::BoxedLocal { too_large_for_stack }));
store.register_late_pass(move |_| {
Box::new(vec::UselessVec {
too_large_for_stack,
msrv: msrv(),
+ span_to_lint_map: BTreeMap::new(),
})
});
store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented));
@@ -684,18 +738,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
store.register_late_pass(|_| Box::<regex::Regex>::default());
- let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone())));
store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator));
store.register_late_pass(|_| Box::new(format::UselessFormat));
store.register_late_pass(|_| Box::new(swap::Swap));
store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional));
store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default());
- let disallowed_names = conf.disallowed_names.iter().cloned().collect::<FxHashSet<_>>();
- store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone())));
- let too_many_arguments_threshold = conf.too_many_arguments_threshold;
- let too_many_lines_threshold = conf.too_many_lines_threshold;
- let large_error_threshold = conf.large_error_threshold;
+ store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names)));
store.register_late_pass(move |_| {
Box::new(functions::Functions::new(
too_many_arguments_threshold,
@@ -704,9 +753,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
avoid_breaking_exported_api,
))
});
- let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
- let missing_docs_in_crate_items = conf.missing_docs_in_crate_items;
- store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
+ store.register_late_pass(move |_| Box::new(doc::Documentation::new(doc_valid_idents, check_private_items)));
store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply));
store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq));
store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
@@ -716,17 +763,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk));
store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl));
store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount));
- let enum_variant_size_threshold = conf.enum_variant_size_threshold;
store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)));
store.register_late_pass(|_| Box::new(explicit_write::ExplicitWrite));
store.register_late_pass(|_| Box::new(needless_pass_by_value::NeedlessPassByValue));
- let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
- conf.trivial_copy_size_limit,
- conf.pass_by_value_size_limit,
- conf.avoid_breaking_exported_api,
- &sess.target,
- );
- store.register_late_pass(move |_| Box::new(pass_by_ref_or_value));
+ store.register_late_pass(move |tcx| {
+ Box::new(pass_by_ref_or_value::PassByRefOrValue::new(
+ trivial_copy_size_limit,
+ pass_by_value_size_limit,
+ avoid_breaking_exported_api,
+ tcx.sess.target.pointer_width,
+ ))
+ });
store.register_late_pass(|_| Box::new(ref_option_ref::RefOptionRef));
store.register_late_pass(|_| Box::new(infinite_iter::InfiniteIter));
store.register_late_pass(|_| Box::new(inline_fn_without_body::InlineFnWithoutBody));
@@ -746,7 +793,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
suppress_restriction_lint_in_const,
))
});
- let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
store.register_late_pass(move |_| Box::new(non_copy_const::NonCopyConst::new(ignore_interior_mutability.clone())));
store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));
@@ -755,10 +801,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(assertions_on_constants::AssertionsOnConstants));
store.register_late_pass(|_| Box::new(assertions_on_result_states::AssertionsOnResultStates));
store.register_late_pass(|_| Box::new(inherent_to_string::InherentToString));
- let max_trait_bounds = conf.max_trait_bounds;
store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds, msrv())));
store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain));
- let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone())));
store.register_early_pass(|| Box::new(reference::DerefAddrOf));
store.register_early_pass(|| Box::new(double_parens::DoubleParens));
@@ -779,21 +823,16 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_early_pass(|| Box::new(redundant_else::RedundantElse));
store.register_late_pass(|_| Box::new(create_dir::CreateDir));
store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType));
- let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
store.register_early_pass(move || {
Box::new(literal_representation::LiteralDigitGrouping::new(
- literal_representation_lint_fraction_readability,
+ unreadable_literal_lint_fractions,
))
});
- let literal_representation_threshold = conf.literal_representation_threshold;
store.register_early_pass(move || {
Box::new(literal_representation::DecimalLiteralRepresentation::new(
literal_representation_threshold,
))
});
- let enum_variant_name_threshold = conf.enum_variant_name_threshold;
- let struct_field_name_threshold = conf.struct_field_name_threshold;
- let allow_private_module_inception = conf.allow_private_module_inception;
store.register_late_pass(move |_| {
Box::new(item_name_repetitions::ItemNameRepetitions::new(
enum_variant_name_threshold,
@@ -803,7 +842,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
))
});
store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));
- let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
store.register_late_pass(move |_| {
Box::new(upper_case_acronyms::UpperCaseAcronyms::new(
avoid_breaking_exported_api,
@@ -815,15 +853,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
store.register_late_pass(|_| Box::new(exit::Exit));
store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome));
- let array_size_threshold = u128::from(conf.array_size_threshold);
- store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold)));
- store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold)));
+ store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold.into())));
+ store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold.into())));
store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
store.register_late_pass(|_| Box::new(as_conversions::AsConversions));
store.register_late_pass(|_| Box::new(let_underscore::LetUnderscore));
store.register_early_pass(|| Box::<single_component_path_imports::SingleComponentPathImports>::default());
- let max_fn_params_bools = conf.max_fn_params_bools;
- let max_struct_bools = conf.max_struct_bools;
store.register_late_pass(move |_| {
Box::new(excessive_bools::ExcessiveBools::new(
max_struct_bools,
@@ -831,36 +866,30 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
))
});
store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap));
- let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
store.register_late_pass(|_| Box::<redundant_pub_crate::RedundantPubCrate>::default());
store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress));
store.register_late_pass(|_| Box::<dereference::Dereferencing<'_>>::default());
store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse));
store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend));
- let future_size_threshold = conf.future_size_threshold;
store.register_late_pass(move |_| Box::new(large_futures::LargeFuture::new(future_size_threshold)));
store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex));
store.register_late_pass(|_| Box::new(if_not_else::IfNotElse));
store.register_late_pass(|_| Box::new(equatable_if_let::PatternEquality));
store.register_late_pass(|_| Box::new(manual_async_fn::ManualAsyncFn));
store.register_late_pass(|_| Box::new(panic_in_result_fn::PanicInResultFn));
- let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
store.register_early_pass(move || {
Box::new(non_expressive_names::NonExpressiveNames {
single_char_binding_names_threshold,
})
});
- let macro_matcher = conf.standard_macro_braces.iter().cloned().collect::<FxHashSet<_>>();
- store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(&macro_matcher)));
+ store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(standard_macro_braces)));
store.register_late_pass(|_| Box::<macro_use::MacroUseImports>::default());
store.register_late_pass(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch));
store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult));
store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync));
- let disallowed_macros = conf.disallowed_macros.clone();
store.register_late_pass(move |_| Box::new(disallowed_macros::DisallowedMacros::new(disallowed_macros.clone())));
- let disallowed_methods = conf.disallowed_methods.clone();
store.register_late_pass(move |_| Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
@@ -875,36 +904,30 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison));
store.register_early_pass(move || Box::new(module_style::ModStyle));
store.register_late_pass(|_| Box::<unused_async::UnusedAsync>::default());
- let disallowed_types = conf.disallowed_types.clone();
store.register_late_pass(move |_| Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
- let import_renames = conf.enforced_import_renames.clone();
store.register_late_pass(move |_| {
Box::new(missing_enforced_import_rename::ImportRename::new(
- import_renames.clone(),
+ enforced_import_renames.clone(),
))
});
- let scripts = conf.allowed_scripts.clone();
- store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(&scripts)));
+ store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(allowed_scripts)));
store.register_late_pass(|_| Box::new(strlen_on_c_strings::StrlenOnCStrings));
store.register_late_pass(move |_| Box::new(self_named_constructors::SelfNamedConstructors));
store.register_late_pass(move |_| Box::new(iter_not_returning_iterator::IterNotReturningIterator));
store.register_late_pass(move |_| Box::new(manual_assert::ManualAssert));
- let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
store.register_late_pass(move |_| {
Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(
enable_raw_pointer_heuristic_for_send,
))
});
- let accept_comment_above_statement = conf.accept_comment_above_statement;
- let accept_comment_above_attributes = conf.accept_comment_above_attributes;
store.register_late_pass(move |_| {
Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(
accept_comment_above_statement,
accept_comment_above_attributes,
))
});
- let allow_mixed_uninlined = conf.allow_mixed_uninlined_format_args;
- store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined)));
+ store
+ .register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined_format_args)));
store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit));
@@ -914,11 +937,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv())));
store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation));
store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default());
- let allow_dbg_in_tests = conf.allow_dbg_in_tests;
store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
- let allow_print_in_tests = conf.allow_print_in_tests;
store.register_late_pass(move |_| Box::new(write::Write::new(allow_print_in_tests)));
- let cargo_ignore_publish = conf.cargo_ignore_publish;
store.register_late_pass(move |_| {
Box::new(cargo::Cargo {
ignore_publish: cargo_ignore_publish,
@@ -929,7 +949,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
store.register_early_pass(|| Box::new(pub_use::PubUse));
store.register_late_pass(|_| Box::new(format_push_string::FormatPushString));
- 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));
@@ -942,7 +961,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv())));
store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv())));
- let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
store.register_late_pass(|_| Box::<std_instead_of_core::StdReexports>::default());
store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(msrv())));
@@ -959,8 +977,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
- let semicolon_inside_block_ignore_singleline = conf.semicolon_inside_block_ignore_singleline;
- let semicolon_outside_block_ignore_multiline = conf.semicolon_outside_block_ignore_multiline;
store.register_late_pass(move |_| {
Box::new(semicolon_block::SemicolonBlock::new(
semicolon_inside_block_ignore_singleline,
@@ -983,7 +999,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute));
store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv())));
store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct));
- let unnecessary_box_size = conf.unnecessary_box_size;
store.register_late_pass(move |_| {
Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(
avoid_breaking_exported_api,
@@ -993,8 +1008,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(lines_filter_map_ok::LinesFilterMapOk));
store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule));
store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
- store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments));
- let excessive_nesting_threshold = conf.excessive_nesting_threshold;
store.register_early_pass(move || {
Box::new(excessive_nesting::ExcessiveNesting {
excessive_nesting_threshold,
@@ -1010,15 +1023,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(redundant_type_annotations::RedundantTypeAnnotations));
store.register_late_pass(|_| Box::new(arc_with_non_send_sync::ArcWithNonSendSync));
store.register_late_pass(|_| Box::new(needless_if::NeedlessIf));
- let allowed_idents_below_min_chars = conf.allowed_idents_below_min_chars.clone();
- let min_ident_chars_threshold = conf.min_ident_chars_threshold;
store.register_late_pass(move |_| {
Box::new(min_ident_chars::MinIdentChars {
allowed_idents_below_min_chars: allowed_idents_below_min_chars.clone(),
min_ident_chars_threshold,
})
});
- let stack_size_threshold = conf.stack_size_threshold;
store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(stack_size_threshold)));
store.register_late_pass(|_| Box::new(single_range_in_vec_init::SingleRangeInVecInit));
store.register_late_pass(move |_| {
@@ -1033,10 +1043,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
def_id_to_usage: rustc_data_structures::fx::FxHashMap::default(),
})
});
- let needless_raw_string_hashes_allow_one = conf.allow_one_hash_in_raw_strings;
store.register_early_pass(move || {
Box::new(raw_strings::RawStrings {
- needless_raw_string_hashes_allow_one,
+ allow_one_hash_in_raw_strings,
})
});
store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns));
@@ -1045,8 +1054,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(manual_float_methods::ManualFloatMethods));
store.register_late_pass(|_| Box::new(four_forward_slashes::FourForwardSlashes));
store.register_late_pass(|_| Box::new(error_impl_error::ErrorImplError));
- let absolute_paths_max_segments = conf.absolute_paths_max_segments;
- let absolute_paths_allowed_crates = conf.absolute_paths_allowed_crates.clone();
store.register_late_pass(move |_| {
Box::new(absolute_paths::AbsolutePaths {
absolute_paths_max_segments,
@@ -1066,6 +1073,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
});
store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(msrv())));
store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter));
+ store.register_late_pass(|_| Box::new(iter_over_hash_type::IterOverHashType));
+ store.register_late_pass(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes));
+ store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity));
+ store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences));
+ store.register_late_pass(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions));
// add lints here, do not remove this comment, it's used in `new_lint`
}
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 7517003be..ffef84d1f 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -18,10 +18,10 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter as middle_nested_filter;
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
-use rustc_span::Span;
use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
@@ -195,7 +195,7 @@ fn check_fn_inner<'tcx>(
.iter()
// In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
// `Node::GenericParam`.
- .filter_map(|&def_id| cx.tcx.hir().get_by_def_id(def_id).ident())
+ .filter_map(|&def_id| cx.tcx.hir_node_by_def_id(def_id).ident())
.map(|ident| ident.to_string())
.collect::<Vec<_>>()
.join(", ");
@@ -310,20 +310,17 @@ fn elision_suggestions(
// elision doesn't work for explicit self types, see rust-lang/rust#69064
fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>) -> bool {
- if_chain! {
- if let Some(ident) = ident;
- if ident.name == kw::SelfLower;
- if !func.implicit_self.has_implicit_self();
-
- if let Some(self_ty) = func.inputs.first();
- then {
- let mut visitor = RefVisitor::new(cx);
- visitor.visit_ty(self_ty);
-
- !visitor.all_lts().is_empty()
- } else {
- false
- }
+ if let Some(ident) = ident
+ && ident.name == kw::SelfLower
+ && !func.implicit_self.has_implicit_self()
+ && let Some(self_ty) = func.inputs.first()
+ {
+ let mut visitor = RefVisitor::new(cx);
+ visitor.visit_ty(self_ty);
+
+ !visitor.all_lts().is_empty()
+ } else {
+ false
}
}
diff --git a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
index 0a5f5a80c..8a0955147 100644
--- a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
@@ -4,7 +4,7 @@ use clippy_utils::{is_diag_item_method, is_trait_method, match_def_path, path_to
use rustc_errors::Applicability;
use rustc_hir::{Body, Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -53,18 +53,45 @@ declare_clippy_lint! {
#[clippy::version = "1.70.0"]
pub LINES_FILTER_MAP_OK,
suspicious,
- "filtering `std::io::Lines` with `filter_map()` or `flat_map()` might cause an infinite loop"
+ "filtering `std::io::Lines` with `filter_map()`, `flat_map()`, or `flatten()` might cause an infinite loop"
}
declare_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]);
impl LateLintPass<'_> for LinesFilterMapOk {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind
+ if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind
&& is_trait_method(cx, expr, sym::Iterator)
- && (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map")
+ && let fm_method_str = fm_method.ident.as_str()
+ && matches!(fm_method_str, "filter_map" | "flat_map" | "flatten")
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines)
+ && should_lint(cx, fm_args, fm_method_str)
{
- let lint = match &fm_arg.kind {
+ span_lint_and_then(
+ cx,
+ LINES_FILTER_MAP_OK,
+ fm_span,
+ &format!("`{fm_method_str}()` will run forever if the iterator repeatedly produces an `Err`",),
+ |diag| {
+ diag.span_note(
+ fm_receiver.span,
+ "this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error");
+ diag.span_suggestion(
+ fm_span,
+ "replace with",
+ "map_while(Result::ok)",
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
+ }
+ }
+}
+
+fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> bool {
+ match args {
+ [] => method_str == "flatten",
+ [fm_arg] => {
+ match &fm_arg.kind {
// Detect `Result::ok`
ExprKind::Path(qpath) => cx
.qpath_res(qpath, fm_arg.hir_id)
@@ -86,29 +113,8 @@ impl LateLintPass<'_> for LinesFilterMapOk {
}
},
_ => false,
- };
- if lint {
- span_lint_and_then(
- cx,
- LINES_FILTER_MAP_OK,
- fm_span,
- &format!(
- "`{}()` will run forever if the iterator repeatedly produces an `Err`",
- fm_method.ident
- ),
- |diag| {
- diag.span_note(
- fm_receiver.span,
- "this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error");
- diag.span_suggestion(
- fm_span,
- "replace with",
- "map_while(Result::ok)",
- Applicability::MaybeIncorrect,
- );
- },
- );
}
- }
+ },
+ _ => false,
}
}
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index 2c14bb72a..f33151cf4 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -4,13 +4,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::numeric_literal::{NumericLiteral, Radix};
use clippy_utils::source::snippet_opt;
-use if_chain::if_chain;
use rustc_ast::ast::{Expr, ExprKind, LitKind};
use rustc_ast::token;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::Span;
use std::iter;
@@ -255,56 +254,48 @@ impl LiteralDigitGrouping {
}
fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
- if_chain! {
- if let Some(src) = snippet_opt(cx, span);
- if let Ok(lit_kind) = LitKind::from_token_lit(lit);
- if let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind);
- then {
- if !Self::check_for_mistyped_suffix(cx, span, &mut num_lit) {
- return;
- }
+ if let Some(src) = snippet_opt(cx, span)
+ && let Ok(lit_kind) = LitKind::from_token_lit(lit)
+ && let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind)
+ {
+ if !Self::check_for_mistyped_suffix(cx, span, &mut num_lit) {
+ return;
+ }
+
+ if Self::is_literal_uuid_formatted(&num_lit) {
+ return;
+ }
- if Self::is_literal_uuid_formatted(&num_lit) {
- return;
+ let result = (|| {
+ let integral_group_size = Self::get_group_size(num_lit.integer.split('_'), num_lit.radix, true)?;
+ if let Some(fraction) = num_lit.fraction {
+ let fractional_group_size =
+ Self::get_group_size(fraction.rsplit('_'), num_lit.radix, self.lint_fraction_readability)?;
+
+ let consistent = Self::parts_consistent(
+ integral_group_size,
+ fractional_group_size,
+ num_lit.integer.len(),
+ fraction.len(),
+ );
+ if !consistent {
+ return Err(WarningType::InconsistentDigitGrouping);
+ };
}
- let result = (|| {
-
- let integral_group_size = Self::get_group_size(num_lit.integer.split('_'), num_lit.radix, true)?;
- if let Some(fraction) = num_lit.fraction {
- let fractional_group_size = Self::get_group_size(
- fraction.rsplit('_'),
- num_lit.radix,
- self.lint_fraction_readability)?;
-
- let consistent = Self::parts_consistent(integral_group_size,
- fractional_group_size,
- num_lit.integer.len(),
- fraction.len());
- if !consistent {
- return Err(WarningType::InconsistentDigitGrouping);
- };
- }
+ Ok(())
+ })();
- Ok(())
- })();
-
-
- if let Err(warning_type) = result {
- let should_warn = match warning_type {
- | WarningType::UnreadableLiteral
- | WarningType::InconsistentDigitGrouping
- | WarningType::UnusualByteGroupings
- | WarningType::LargeDigitGroups => {
- !span.from_expansion()
- }
- WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => {
- true
- }
- };
- if should_warn {
- warning_type.display(num_lit.format(), cx, span);
- }
+ if let Err(warning_type) = result {
+ let should_warn = match warning_type {
+ WarningType::UnreadableLiteral
+ | WarningType::InconsistentDigitGrouping
+ | WarningType::UnusualByteGroupings
+ | WarningType::LargeDigitGroups => !span.from_expansion(),
+ WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => true,
+ };
+ if should_warn {
+ warning_type.display(num_lit.format(), cx, span);
}
}
}
@@ -478,20 +469,18 @@ impl DecimalLiteralRepresentation {
}
fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
// Lint integral literals.
- if_chain! {
- if let Ok(lit_kind) = LitKind::from_token_lit(lit);
- if let LitKind::Int(val, _) = lit_kind;
- if let Some(src) = snippet_opt(cx, span);
- if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind);
- if num_lit.radix == Radix::Decimal;
- if val >= u128::from(self.threshold);
- then {
- let hex = format!("{val:#X}");
- let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
- let _: Result<(), ()> = Self::do_lint(num_lit.integer).map_err(|warning_type| {
- warning_type.display(num_lit.format(), cx, span);
- });
- }
+ if let Ok(lit_kind) = LitKind::from_token_lit(lit)
+ && let LitKind::Int(val, _) = lit_kind
+ && let Some(src) = snippet_opt(cx, span)
+ && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind)
+ && num_lit.radix == Radix::Decimal
+ && val >= u128::from(self.threshold)
+ {
+ let hex = format!("{val:#X}");
+ let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
+ let _: Result<(), ()> = Self::do_lint(num_lit.integer).map_err(|warning_type| {
+ warning_type.display(num_lit.format(), cx, span);
+ });
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
index 1953ee8a7..277062a84 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
@@ -2,7 +2,6 @@ use super::{make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{get_enclosing_block, is_integer_const};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_block, walk_expr};
use rustc_hir::{Expr, Pat};
@@ -30,59 +29,57 @@ pub(super) fn check<'tcx>(
let mut initialize_visitor = InitializeVisitor::new(cx, expr, id);
walk_block(&mut initialize_visitor, block);
- if_chain! {
- if let Some((name, ty, initializer)) = initialize_visitor.get_result();
- if is_integer_const(cx, initializer, 0);
- then {
- let mut applicability = Applicability::MaybeIncorrect;
- let span = expr.span.with_hi(arg.span.hi());
+ if let Some((name, ty, initializer)) = initialize_visitor.get_result()
+ && is_integer_const(cx, initializer, 0)
+ {
+ let mut applicability = Applicability::MaybeIncorrect;
+ let span = expr.span.with_hi(arg.span.hi());
- let int_name = match ty.map(Ty::kind) {
- // usize or inferred
- Some(ty::Uint(UintTy::Usize)) | None => {
- span_lint_and_sugg(
- cx,
- EXPLICIT_COUNTER_LOOP,
- span,
- &format!("the variable `{name}` is used as a loop counter"),
- "consider using",
- format!(
- "for ({name}, {}) in {}.enumerate()",
- snippet_with_applicability(cx, pat.span, "item", &mut applicability),
- make_iterator_snippet(cx, arg, &mut applicability),
- ),
- applicability,
- );
- return;
- }
- Some(ty::Int(int_ty)) => int_ty.name_str(),
- Some(ty::Uint(uint_ty)) => uint_ty.name_str(),
- _ => return,
- };
+ let int_name = match ty.map(Ty::kind) {
+ // usize or inferred
+ Some(ty::Uint(UintTy::Usize)) | None => {
+ span_lint_and_sugg(
+ cx,
+ EXPLICIT_COUNTER_LOOP,
+ span,
+ &format!("the variable `{name}` is used as a loop counter"),
+ "consider using",
+ format!(
+ "for ({name}, {}) in {}.enumerate()",
+ snippet_with_applicability(cx, pat.span, "item", &mut applicability),
+ make_iterator_snippet(cx, arg, &mut applicability),
+ ),
+ applicability,
+ );
+ return;
+ },
+ Some(ty::Int(int_ty)) => int_ty.name_str(),
+ Some(ty::Uint(uint_ty)) => uint_ty.name_str(),
+ _ => return,
+ };
- span_lint_and_then(
- cx,
- EXPLICIT_COUNTER_LOOP,
- span,
- &format!("the variable `{name}` is used as a loop counter"),
- |diag| {
- diag.span_suggestion(
- span,
- "consider using",
- format!(
- "for ({name}, {}) in (0_{int_name}..).zip({})",
- snippet_with_applicability(cx, pat.span, "item", &mut applicability),
- make_iterator_snippet(cx, arg, &mut applicability),
- ),
- applicability,
- );
+ span_lint_and_then(
+ cx,
+ EXPLICIT_COUNTER_LOOP,
+ span,
+ &format!("the variable `{name}` is used as a loop counter"),
+ |diag| {
+ diag.span_suggestion(
+ span,
+ "consider using",
+ format!(
+ "for ({name}, {}) in (0_{int_name}..).zip({})",
+ snippet_with_applicability(cx, pat.span, "item", &mut applicability),
+ make_iterator_snippet(cx, arg, &mut applicability),
+ ),
+ applicability,
+ );
- diag.note(format!(
- "`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`"
- ));
- },
- );
- }
+ diag.note(format!(
+ "`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`"
+ ));
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index 1c2b7a169..c79800608 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -118,7 +118,7 @@ fn is_ref_iterable<'tcx>(
.liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder())
&& let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output
&& let param_env = cx.tcx.param_env(fn_id)
- && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, &[])
+ && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, fn_id, &[])
&& let Some(into_iter_ty) =
make_normalized_projection_with_regions(cx.tcx, param_env, trait_id, sym!(IntoIter), [req_self_ty])
&& let req_res_ty = normalize_with_regions(cx.tcx, param_env, req_res_ty)
diff --git a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
new file mode 100644
index 000000000..9b88dd76e
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
@@ -0,0 +1,125 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::{fn_def_id, is_lint_allowed};
+use hir::intravisit::{walk_expr, Visitor};
+use hir::{Expr, ExprKind, FnRetTy, FnSig, Node};
+use rustc_ast::Label;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+
+use super::INFINITE_LOOP;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &Expr<'_>,
+ loop_block: &'tcx hir::Block<'_>,
+ label: Option<Label>,
+) {
+ if is_lint_allowed(cx, INFINITE_LOOP, expr.hir_id) {
+ return;
+ }
+
+ // Skip check if this loop is not in a function/method/closure. (In some weird case)
+ let Some(parent_fn_ret) = get_parent_fn_ret_ty(cx, expr) else {
+ return;
+ };
+ // Or, its parent function is already returning `Never`
+ if matches!(
+ parent_fn_ret,
+ FnRetTy::Return(hir::Ty {
+ kind: hir::TyKind::Never,
+ ..
+ })
+ ) {
+ return;
+ }
+
+ let mut loop_visitor = LoopVisitor {
+ cx,
+ label,
+ is_finite: false,
+ loop_depth: 0,
+ };
+ loop_visitor.visit_block(loop_block);
+
+ let is_finite_loop = loop_visitor.is_finite;
+
+ if !is_finite_loop {
+ span_lint_and_then(cx, INFINITE_LOOP, expr.span, "infinite loop detected", |diag| {
+ if let FnRetTy::DefaultReturn(ret_span) = parent_fn_ret {
+ diag.span_suggestion(
+ ret_span,
+ "if this is intentional, consider specifing `!` as function return",
+ " -> !",
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ diag.help("if this is not intended, try adding a `break` or `return` condition in the loop");
+ }
+ });
+ }
+}
+
+fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<FnRetTy<'tcx>> {
+ for (_, parent_node) in cx.tcx.hir().parent_iter(expr.hir_id) {
+ match parent_node {
+ Node::Item(hir::Item {
+ kind: hir::ItemKind::Fn(FnSig { decl, .. }, _, _),
+ ..
+ })
+ | Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(FnSig { decl, .. }, _),
+ ..
+ })
+ | Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(FnSig { decl, .. }, _),
+ ..
+ })
+ | Node::Expr(Expr {
+ kind: ExprKind::Closure(hir::Closure { fn_decl: decl, .. }),
+ ..
+ }) => return Some(decl.output),
+ _ => (),
+ }
+ }
+ None
+}
+
+struct LoopVisitor<'hir, 'tcx> {
+ cx: &'hir LateContext<'tcx>,
+ label: Option<Label>,
+ loop_depth: usize,
+ is_finite: bool,
+}
+
+impl<'hir> Visitor<'hir> for LoopVisitor<'hir, '_> {
+ fn visit_expr(&mut self, ex: &'hir Expr<'_>) {
+ match &ex.kind {
+ ExprKind::Break(hir::Destination { label, .. }, ..) => {
+ // Assuming breaks the loop when `loop_depth` is 0,
+ // as it could only means this `break` breaks current loop or any of its upper loop.
+ // Or, the depth is not zero but the label is matched.
+ if self.loop_depth == 0 || (label.is_some() && *label == self.label) {
+ self.is_finite = true;
+ }
+ },
+ ExprKind::Ret(..) => self.is_finite = true,
+ ExprKind::Loop(..) => {
+ self.loop_depth += 1;
+ walk_expr(self, ex);
+ self.loop_depth = self.loop_depth.saturating_sub(1);
+ },
+ _ => {
+ // Calls to a function that never return
+ if let Some(did) = fn_def_id(self.cx, ex) {
+ let fn_ret_ty = self.cx.tcx.fn_sig(did).skip_binder().output().skip_binder();
+ if fn_ret_ty.is_never() {
+ self.is_finite = true;
+ return;
+ }
+ }
+ walk_expr(self, ex);
+ },
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
index a9a9058c9..d484ce40d 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
@@ -4,7 +4,6 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::implements_trait;
use clippy_utils::{higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::lang_items::LangItem;
@@ -23,77 +22,79 @@ pub(super) fn check<'tcx>(
let inner_expr = peel_blocks_with_stmt(body);
// Check for the specific case that the result is returned and optimize suggestion for that (more
// cases can be added later)
- if_chain! {
- if let Some(higher::If { cond, then, r#else: None, }) = higher::If::hir(inner_expr);
- if let Some(binding_id) = get_binding(pat);
- if let ExprKind::Block(block, _) = then.kind;
- if let [stmt] = block.stmts;
- if let StmtKind::Semi(semi) = stmt.kind;
- if let ExprKind::Ret(Some(ret_value)) = semi.kind;
- if let ExprKind::Call(ctor, [inner_ret]) = ret_value.kind;
- if is_res_lang_ctor(cx, path_res(cx, ctor), LangItem::OptionSome);
- if path_res(cx, inner_ret) == Res::Local(binding_id);
- if let Some((last_stmt, last_ret)) = last_stmt_and_ret(cx, expr);
- then {
- let mut applicability = Applicability::MachineApplicable;
- let mut snippet = make_iterator_snippet(cx, arg, &mut applicability);
- // Checks if `pat` is a single reference to a binding (`&x`)
- let is_ref_to_binding =
- matches!(pat.kind, PatKind::Ref(inner, _) if matches!(inner.kind, PatKind::Binding(..)));
- // If `pat` is not a binding or a reference to a binding (`x` or `&x`)
- // we need to map it to the binding returned by the function (i.e. `.map(|(x, _)| x)`)
- if !(matches!(pat.kind, PatKind::Binding(..)) || is_ref_to_binding) {
- snippet.push_str(
- &format!(
- ".map(|{}| {})",
- snippet_with_applicability(cx, pat.span, "..", &mut applicability),
- snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability),
- )[..],
- );
- }
- let ty = cx.typeck_results().expr_ty(inner_ret);
- if cx.tcx.lang_items().copy_trait().map_or(false, |id| implements_trait(cx, ty, id, &[])) {
- snippet.push_str(
- &format!(
- ".find(|{}{}| {})",
- "&".repeat(1 + usize::from(is_ref_to_binding)),
- snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability),
- snippet_with_applicability(cx, cond.span, "..", &mut applicability),
- )[..],
- );
- if is_ref_to_binding {
- snippet.push_str(".copied()");
- }
- } else {
- applicability = Applicability::MaybeIncorrect;
- snippet.push_str(
- &format!(
- ".find(|{}| {})",
- snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability),
- snippet_with_applicability(cx, cond.span, "..", &mut applicability),
- )[..],
- );
+ if let Some(higher::If {
+ cond,
+ then,
+ r#else: None,
+ }) = higher::If::hir(inner_expr)
+ && let Some(binding_id) = get_binding(pat)
+ && let ExprKind::Block(block, _) = then.kind
+ && let [stmt] = block.stmts
+ && let StmtKind::Semi(semi) = stmt.kind
+ && let ExprKind::Ret(Some(ret_value)) = semi.kind
+ && let ExprKind::Call(ctor, [inner_ret]) = ret_value.kind
+ && is_res_lang_ctor(cx, path_res(cx, ctor), LangItem::OptionSome)
+ && path_res(cx, inner_ret) == Res::Local(binding_id)
+ && let Some((last_stmt, last_ret)) = last_stmt_and_ret(cx, expr)
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let mut snippet = make_iterator_snippet(cx, arg, &mut applicability);
+ // Checks if `pat` is a single reference to a binding (`&x`)
+ let is_ref_to_binding =
+ matches!(pat.kind, PatKind::Ref(inner, _) if matches!(inner.kind, PatKind::Binding(..)));
+ // If `pat` is not a binding or a reference to a binding (`x` or `&x`)
+ // we need to map it to the binding returned by the function (i.e. `.map(|(x, _)| x)`)
+ if !(matches!(pat.kind, PatKind::Binding(..)) || is_ref_to_binding) {
+ snippet.push_str(
+ &format!(
+ ".map(|{}| {})",
+ snippet_with_applicability(cx, pat.span, "..", &mut applicability),
+ snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability),
+ )[..],
+ );
+ }
+ let ty = cx.typeck_results().expr_ty(inner_ret);
+ if cx
+ .tcx
+ .lang_items()
+ .copy_trait()
+ .map_or(false, |id| implements_trait(cx, ty, id, &[]))
+ {
+ snippet.push_str(
+ &format!(
+ ".find(|{}{}| {})",
+ "&".repeat(1 + usize::from(is_ref_to_binding)),
+ snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability),
+ snippet_with_applicability(cx, cond.span, "..", &mut applicability),
+ )[..],
+ );
+ if is_ref_to_binding {
+ snippet.push_str(".copied()");
}
- // Extends to `last_stmt` to include semicolon in case of `return None;`
- let lint_span = span.to(last_stmt.span).to(last_ret.span);
- span_lint_and_then(
- cx,
- MANUAL_FIND,
- lint_span,
- "manual implementation of `Iterator::find`",
- |diag| {
- if applicability == Applicability::MaybeIncorrect {
- diag.note("you may need to dereference some variables");
- }
- diag.span_suggestion(
- lint_span,
- "replace with an iterator",
- snippet,
- applicability,
- );
- },
+ } else {
+ applicability = Applicability::MaybeIncorrect;
+ snippet.push_str(
+ &format!(
+ ".find(|{}| {})",
+ snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability),
+ snippet_with_applicability(cx, cond.span, "..", &mut applicability),
+ )[..],
);
}
+ // Extends to `last_stmt` to include semicolon in case of `return None;`
+ let lint_span = span.to(last_stmt.span).to(last_ret.span);
+ span_lint_and_then(
+ cx,
+ MANUAL_FIND,
+ lint_span,
+ "manual implementation of `Iterator::find`",
+ |diag| {
+ if applicability == Applicability::MaybeIncorrect {
+ diag.note("you may need to dereference some variables");
+ }
+ diag.span_suggestion(lint_span, "replace with an iterator", snippet, applicability);
+ },
+ );
}
}
@@ -124,34 +125,30 @@ fn last_stmt_and_ret<'tcx>(
if let Some(ret) = block.expr {
return Some((last_stmt, ret));
}
- if_chain! {
- if let [.., snd_last, _] = block.stmts;
- if let StmtKind::Semi(last_expr) = last_stmt.kind;
- if let ExprKind::Ret(Some(ret)) = last_expr.kind;
- then {
- return Some((snd_last, ret));
- }
+ if let [.., snd_last, _] = block.stmts
+ && let StmtKind::Semi(last_expr) = last_stmt.kind
+ && let ExprKind::Ret(Some(ret)) = last_expr.kind
+ {
+ return Some((snd_last, ret));
}
}
None
}
let mut parent_iter = cx.tcx.hir().parent_iter(expr.hir_id);
- if_chain! {
+ if let Some((node_hir, Node::Stmt(..))) = parent_iter.next()
// This should be the loop
- if let Some((node_hir, Node::Stmt(..))) = parent_iter.next();
// This should be the function body
- if let Some((_, Node::Block(block))) = parent_iter.next();
- if let Some((last_stmt, last_ret)) = extract(block);
- if last_stmt.hir_id == node_hir;
- if is_res_lang_ctor(cx, path_res(cx, last_ret), LangItem::OptionNone);
- if let Some((_, Node::Expr(_block))) = parent_iter.next();
+ && let Some((_, Node::Block(block))) = parent_iter.next()
+ && let Some((last_stmt, last_ret)) = extract(block)
+ && last_stmt.hir_id == node_hir
+ && is_res_lang_ctor(cx, path_res(cx, last_ret), LangItem::OptionNone)
+ && let Some((_, Node::Expr(_block))) = parent_iter.next()
// This includes the function header
- if let Some((_, func)) = parent_iter.next();
- if func.fn_kind().is_some();
- then {
- Some((block.stmts.last().unwrap(), last_ret))
- } else {
- None
- }
+ && let Some((_, func)) = parent_iter.next()
+ && func.fn_kind().is_some()
+ {
+ Some((block.stmts.last().unwrap(), last_ret))
+ } else {
+ None
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
index 124a35f8f..a726b1169 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -3,7 +3,6 @@ use super::MANUAL_FLATTEN;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::visitors::is_local_used;
use clippy_utils::{higher, path_to_local_id, peel_blocks_with_stmt};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, Pat, PatKind};
@@ -21,66 +20,51 @@ pub(super) fn check<'tcx>(
span: Span,
) {
let inner_expr = peel_blocks_with_stmt(body);
- if_chain! {
- if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None })
- = higher::IfLet::hir(cx, inner_expr);
+ if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None })
+ = higher::IfLet::hir(cx, inner_expr)
// Ensure match_expr in `if let` statement is the same as the pat from the for-loop
- if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind;
- if path_to_local_id(let_expr, pat_hir_id);
+ && let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind
+ && path_to_local_id(let_expr, pat_hir_id)
// Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
- if let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind;
- if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id);
- if let Some(variant_id) = cx.tcx.opt_parent(ctor_id);
- let some_ctor = cx.tcx.lang_items().option_some_variant() == Some(variant_id);
- let ok_ctor = cx.tcx.lang_items().result_ok_variant() == Some(variant_id);
- if some_ctor || ok_ctor;
+ && let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind
+ && let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id)
+ && let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
+ && let some_ctor = cx.tcx.lang_items().option_some_variant() == Some(variant_id)
+ && let ok_ctor = cx.tcx.lang_items().result_ok_variant() == Some(variant_id)
+ && (some_ctor || ok_ctor)
// Ensure expr in `if let` is not used afterwards
- if !is_local_used(cx, if_then, pat_hir_id);
- then {
- let if_let_type = if some_ctor { "Some" } else { "Ok" };
- // Prepare the error message
- let msg = format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used");
+ && !is_local_used(cx, if_then, pat_hir_id)
+ {
+ let if_let_type = if some_ctor { "Some" } else { "Ok" };
+ // Prepare the error message
+ let msg =
+ format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used");
- // Prepare the help message
- let mut applicability = Applicability::MaybeIncorrect;
- let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability);
- let copied = match cx.typeck_results().expr_ty(let_expr).kind() {
- ty::Ref(_, inner, _) => match inner.kind() {
- ty::Ref(..) => ".copied()",
- _ => ""
- }
- _ => ""
- };
+ // Prepare the help message
+ let mut applicability = Applicability::MaybeIncorrect;
+ let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability);
+ let copied = match cx.typeck_results().expr_ty(let_expr).kind() {
+ ty::Ref(_, inner, _) => match inner.kind() {
+ ty::Ref(..) => ".copied()",
+ _ => "",
+ },
+ _ => "",
+ };
- let sugg = format!("{arg_snippet}{copied}.flatten()");
+ let sugg = format!("{arg_snippet}{copied}.flatten()");
- // If suggestion is not a one-liner, it won't be shown inline within the error message. In that case,
- // it will be shown in the extra `help` message at the end, which is why the first `help_msg` needs
- // to refer to the correct relative position of the suggestion.
- let help_msg = if sugg.contains('\n') {
- "remove the `if let` statement in the for loop and then..."
- } else {
- "...and remove the `if let` statement in the for loop"
- };
+ // If suggestion is not a one-liner, it won't be shown inline within the error message. In that
+ // case, it will be shown in the extra `help` message at the end, which is why the first
+ // `help_msg` needs to refer to the correct relative position of the suggestion.
+ let help_msg = if sugg.contains('\n') {
+ "remove the `if let` statement in the for loop and then..."
+ } else {
+ "...and remove the `if let` statement in the for loop"
+ };
- span_lint_and_then(
- cx,
- MANUAL_FLATTEN,
- span,
- &msg,
- |diag| {
- diag.span_suggestion(
- arg.span,
- "try",
- sugg,
- applicability,
- );
- diag.span_help(
- inner_expr.span,
- help_msg,
- );
- }
- );
- }
+ span_lint_and_then(cx, MANUAL_FLATTEN, span, &msg, |diag| {
+ diag.span_suggestion(arg.span, "try", sugg, applicability);
+ diag.span_help(inner_expr.span, help_msg);
+ });
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index d3fd0e863..fda6c9749 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -4,7 +4,6 @@ use clippy_utils::source::snippet;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_copy;
use clippy_utils::{get_enclosing_block, higher, path_to_local, sugg};
-use if_chain::if_chain;
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_hir::intravisit::walk_block;
@@ -13,7 +12,6 @@ use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
use rustc_span::symbol::sym;
use std::fmt::Display;
-use std::iter::Iterator;
/// Checks for `for` loops that sequentially copy items from one slice-like
/// object to another.
@@ -59,22 +57,31 @@ pub(super) fn check<'tcx>(
.map(|o| {
o.and_then(|(lhs, rhs)| {
let rhs = fetch_cloned_expr(rhs);
- if_chain! {
- if let ExprKind::Index(base_left, idx_left, _) = lhs.kind;
- if let ExprKind::Index(base_right, idx_right, _) = rhs.kind;
- if let Some(ty) = get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_left));
- if get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_right)).is_some();
- if let Some((start_left, offset_left)) = get_details_from_idx(cx, idx_left, &starts);
- if let Some((start_right, offset_right)) = get_details_from_idx(cx, idx_right, &starts);
+ if let ExprKind::Index(base_left, idx_left, _) = lhs.kind
+ && let ExprKind::Index(base_right, idx_right, _) = rhs.kind
+ && let Some(ty) = get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_left))
+ && get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_right)).is_some()
+ && let Some((start_left, offset_left)) = get_details_from_idx(cx, idx_left, &starts)
+ && let Some((start_right, offset_right)) = get_details_from_idx(cx, idx_right, &starts)
// Source and destination must be different
- if path_to_local(base_left) != path_to_local(base_right);
- then {
- Some((ty, IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left },
- IndexExpr { base: base_right, idx: start_right, idx_offset: offset_right }))
- } else {
- None
- }
+ && path_to_local(base_left) != path_to_local(base_right)
+ {
+ Some((
+ ty,
+ IndexExpr {
+ base: base_left,
+ idx: start_left,
+ idx_offset: offset_left,
+ },
+ IndexExpr {
+ base: base_right,
+ idx: start_right,
+ idx_offset: offset_right,
+ },
+ ))
+ } else {
+ None
}
})
})
@@ -118,23 +125,19 @@ fn build_manual_memcpy_suggestion<'tcx>(
}
let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
- if_chain! {
- if let ExprKind::MethodCall(method, recv, [], _) = end.kind;
- if method.ident.name == sym::len;
- if path_to_local(recv) == path_to_local(base);
- then {
- if sugg.to_string() == end_str {
- sugg::EMPTY.into()
- } else {
- sugg
- }
+ if let ExprKind::MethodCall(method, recv, [], _) = end.kind
+ && method.ident.name == sym::len
+ && path_to_local(recv) == path_to_local(base)
+ {
+ if sugg.to_string() == end_str {
+ sugg::EMPTY.into()
} else {
- match limits {
- ast::RangeLimits::Closed => {
- sugg + &sugg::ONE.into()
- },
- ast::RangeLimits::HalfOpen => sugg,
- }
+ sugg
+ }
+ } else {
+ match limits {
+ ast::RangeLimits::Closed => sugg + &sugg::ONE.into(),
+ ast::RangeLimits::HalfOpen => sugg,
}
}
};
@@ -174,7 +177,9 @@ fn build_manual_memcpy_suggestion<'tcx>(
let dst_base_str = snippet(cx, dst.base.span, "???");
let src_base_str = snippet(cx, src.base.span, "???");
- let dst = if dst_offset == sugg::EMPTY && dst_limit == sugg::EMPTY {
+ let dst = if (dst_offset == sugg::EMPTY && dst_limit == sugg::EMPTY)
+ || is_array_length_equal_to_range(cx, start, end, dst.base)
+ {
dst_base_str
} else {
format!("{dst_base_str}[{}..{}]", dst_offset.maybe_par(), dst_limit.maybe_par()).into()
@@ -186,11 +191,13 @@ fn build_manual_memcpy_suggestion<'tcx>(
"clone_from_slice"
};
- format!(
- "{dst}.{method_str}(&{src_base_str}[{}..{}]);",
- src_offset.maybe_par(),
- src_limit.maybe_par()
- )
+ let src = if is_array_length_equal_to_range(cx, start, end, src.base) {
+ src_base_str
+ } else {
+ format!("{src_base_str}[{}..{}]", src_offset.maybe_par(), src_limit.maybe_par()).into()
+ };
+
+ format!("{dst}.{method_str}(&{src});")
}
/// a wrapper of `Sugg`. Besides what `Sugg` do, this removes unnecessary `0`;
@@ -331,10 +338,12 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti
}
fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
- if_chain! {
- if let ExprKind::MethodCall(method, arg, [], _) = expr.kind;
- if method.ident.name == sym::clone;
- then { arg } else { expr }
+ if let ExprKind::MethodCall(method, arg, [], _) = expr.kind
+ && method.ident.name == sym::clone
+ {
+ arg
+ } else {
+ expr
}
}
@@ -446,3 +455,34 @@ fn get_loop_counters<'a, 'tcx>(
.into()
})
}
+
+fn is_array_length_equal_to_range(cx: &LateContext<'_>, start: &Expr<'_>, end: &Expr<'_>, arr: &Expr<'_>) -> bool {
+ fn extract_lit_value(expr: &Expr<'_>) -> Option<u128> {
+ if let ExprKind::Lit(lit) = expr.kind
+ && let ast::LitKind::Int(value, _) = lit.node
+ {
+ Some(value)
+ } else {
+ None
+ }
+ }
+
+ let arr_ty = cx.typeck_results().expr_ty(arr).peel_refs();
+
+ if let ty::Array(_, s) = arr_ty.kind() {
+ let size: u128 = if let Some(size) = s.try_eval_target_usize(cx.tcx, cx.param_env) {
+ size.into()
+ } else {
+ return false;
+ };
+
+ let range = match (extract_lit_value(start), extract_lit_value(end)) {
+ (Some(start_value), Some(end_value)) => end_value - start_value,
+ _ => return false,
+ };
+
+ size == range
+ } else {
+ false
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
index 7b7d19c75..e405829b2 100644
--- a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
@@ -31,26 +31,30 @@ fn unpack_cond<'tcx>(cond: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
}
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
- if_chain! {
- if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind;
- if let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind;
- if [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name);
- if let ty::Adt(def, _args) = cx.typeck_results().expr_ty(callee).kind();
- if cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did());
- then {
- span_lint_and_sugg(
- cx,
- MISSING_SPIN_LOOP,
- body.span,
- "busy-waiting loop should at least have a spin loop hint",
- "try",
- (if is_no_std_crate(cx) {
- "{ core::hint::spin_loop() }"
- } else {
- "{ std::hint::spin_loop() }"
- }).into(),
- Applicability::MachineApplicable
- );
- }
+ if let ExprKind::Block(
+ Block {
+ stmts: [], expr: None, ..
+ },
+ _,
+ ) = body.kind
+ && let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind
+ && [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name)
+ && let ty::Adt(def, _args) = cx.typeck_results().expr_ty(callee).kind()
+ && cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did())
+ {
+ span_lint_and_sugg(
+ cx,
+ MISSING_SPIN_LOOP,
+ body.span,
+ "busy-waiting loop should at least have a spin loop hint",
+ "try",
+ (if is_no_std_crate(cx) {
+ "{ core::hint::spin_loop() }"
+ } else {
+ "{ std::hint::spin_loop() }"
+ })
+ .into(),
+ Applicability::MachineApplicable,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 67c80fb83..3c9bde86b 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -3,6 +3,7 @@ mod explicit_counter_loop;
mod explicit_into_iter_loop;
mod explicit_iter_loop;
mod for_kv_map;
+mod infinite_loop;
mod iter_next_loop;
mod manual_find;
mod manual_flatten;
@@ -24,7 +25,7 @@ use clippy_config::msrvs::Msrv;
use clippy_utils::higher;
use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::Span;
use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor};
@@ -635,6 +636,48 @@ declare_clippy_lint! {
"checking for emptiness of a `Vec` in the loop condition and popping an element in the body"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for infinite loops in a function where the return type is not `!`
+ /// and lint accordingly.
+ ///
+ /// ### Why is this bad?
+ /// A loop should be gently exited somewhere, or at least mark its parent function as
+ /// never return (`!`).
+ ///
+ /// ### Example
+ /// ```no_run,ignore
+ /// fn run_forever() {
+ /// loop {
+ /// // do something
+ /// }
+ /// }
+ /// ```
+ /// If infinite loops are as intended:
+ /// ```no_run,ignore
+ /// fn run_forever() -> ! {
+ /// loop {
+ /// // do something
+ /// }
+ /// }
+ /// ```
+ /// Otherwise add a `break` or `return` condition:
+ /// ```no_run,ignore
+ /// fn run_forever() {
+ /// loop {
+ /// // do something
+ /// if condition {
+ /// break;
+ /// }
+ /// }
+ /// }
+ /// ```
+ #[clippy::version = "1.75.0"]
+ pub INFINITE_LOOP,
+ restriction,
+ "possibly unintended infinite loop"
+}
+
pub struct Loops {
msrv: Msrv,
enforce_iter_loop_reborrow: bool,
@@ -669,6 +712,7 @@ impl_lint_pass!(Loops => [
MANUAL_FIND,
MANUAL_WHILE_LET_SOME,
UNUSED_ENUMERATE_INDEX,
+ INFINITE_LOOP,
]);
impl<'tcx> LateLintPass<'tcx> for Loops {
@@ -707,10 +751,11 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
// check for `loop { if let {} else break }` that could be `while let`
// (also matches an explicit "match" instead of "if let")
// (even if the "match" or "if let" is used for declaration)
- if let ExprKind::Loop(block, _, LoopSource::Loop, _) = expr.kind {
+ if let ExprKind::Loop(block, label, LoopSource::Loop, _) = expr.kind {
// also check for empty `loop {}` statements, skipping those in #[panic_handler]
empty_loop::check(cx, expr, block);
while_let_loop::check(cx, expr, block);
+ infinite_loop::check(cx, expr, block, label);
}
while_let_on_iterator::check(cx, expr);
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index 2c12d9582..c4e60e98a 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -1,7 +1,6 @@
use super::MUT_RANGE_BOUND;
use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::{get_enclosing_block, higher, path_to_local};
-use if_chain::if_chain;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind};
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
@@ -12,19 +11,17 @@ use rustc_middle::ty;
use rustc_span::Span;
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
- if_chain! {
- if let Some(higher::Range {
- start: Some(start),
- end: Some(end),
- ..
- }) = higher::Range::hir(arg);
- let (mut_id_start, mut_id_end) = (check_for_mutability(cx, start), check_for_mutability(cx, end));
- if mut_id_start.is_some() || mut_id_end.is_some();
- then {
- let (span_low, span_high) = check_for_mutation(cx, body, mut_id_start, mut_id_end);
- mut_warn_with_span(cx, span_low);
- mut_warn_with_span(cx, span_high);
- }
+ if let Some(higher::Range {
+ start: Some(start),
+ end: Some(end),
+ ..
+ }) = higher::Range::hir(arg)
+ && let (mut_id_start, mut_id_end) = (check_for_mutability(cx, start), check_for_mutability(cx, end))
+ && (mut_id_start.is_some() || mut_id_end.is_some())
+ {
+ let (span_low, span_high) = check_for_mutation(cx, body, mut_id_start, mut_id_end);
+ mut_warn_with_span(cx, span_low);
+ mut_warn_with_span(cx, span_high);
}
}
@@ -42,13 +39,11 @@ fn mut_warn_with_span(cx: &LateContext<'_>, span: Option<Span>) {
}
fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId> {
- if_chain! {
- if let Some(hir_id) = path_to_local(bound);
- if let Node::Pat(pat) = cx.tcx.hir().get(hir_id);
- if let PatKind::Binding(BindingAnnotation::MUT, ..) = pat.kind;
- then {
- return Some(hir_id);
- }
+ if let Some(hir_id) = path_to_local(bound)
+ && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
+ && let PatKind::Binding(BindingAnnotation::MUT, ..) = pat.kind
+ {
+ return Some(hir_id);
}
None
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index c4af46b8f..4acf46f73 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -4,7 +4,6 @@ use clippy_utils::source::snippet;
use clippy_utils::ty::has_iter_method;
use clippy_utils::visitors::is_local_used;
use clippy_utils::{contains_name, higher, is_integer_const, sugg, SpanlessEq};
-use if_chain::if_chain;
use rustc_ast::ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def::{DefKind, Res};
@@ -14,8 +13,7 @@ use rustc_lint::LateContext;
use rustc_middle::middle::region;
use rustc_middle::ty::{self, Ty};
use rustc_span::symbol::{sym, Symbol};
-use std::iter::{self, Iterator};
-use std::mem;
+use std::{iter, mem};
/// Checks for looping over a range and then indexing a sequence with it.
/// The iteratee must be a range literal.
@@ -187,15 +185,13 @@ pub(super) fn check<'tcx>(
}
fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool {
- if_chain! {
- if let ExprKind::MethodCall(method, recv, [], _) = expr.kind;
- if method.ident.name == sym::len;
- if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind;
- if path.segments.len() == 1;
- if path.segments[0].ident.name == var;
- then {
- return true;
- }
+ if let ExprKind::MethodCall(method, recv, [], _) = expr.kind
+ && method.ident.name == sym::len
+ && let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind
+ && path.segments.len() == 1
+ && path.segments[0].ident.name == var
+ {
+ return true;
}
false
@@ -207,17 +203,15 @@ fn is_end_eq_array_len<'tcx>(
limits: ast::RangeLimits,
indexed_ty: Ty<'tcx>,
) -> bool {
- if_chain! {
- if let ExprKind::Lit(lit) = end.kind;
- if let ast::LitKind::Int(end_int, _) = lit.node;
- if let ty::Array(_, arr_len_const) = indexed_ty.kind();
- if let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env);
- then {
- return match limits {
- ast::RangeLimits::Closed => end_int + 1 >= arr_len.into(),
- ast::RangeLimits::HalfOpen => end_int >= arr_len.into(),
- };
- }
+ if let ExprKind::Lit(lit) = end.kind
+ && let ast::LitKind::Int(end_int, _) = lit.node
+ && let ty::Array(_, arr_len_const) = indexed_ty.kind()
+ && let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env)
+ {
+ return match limits {
+ ast::RangeLimits::Closed => end_int + 1 >= arr_len.into(),
+ ast::RangeLimits::HalfOpen => end_int >= arr_len.into(),
+ };
}
false
@@ -248,51 +242,49 @@ struct VarVisitor<'a, 'tcx> {
impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool {
- if_chain! {
+ if let ExprKind::Path(ref seqpath) = seqexpr.kind
// the indexed container is referenced by a name
- if let ExprKind::Path(ref seqpath) = seqexpr.kind;
- if let QPath::Resolved(None, seqvar) = *seqpath;
- if seqvar.segments.len() == 1;
- if is_local_used(self.cx, idx, self.var);
- then {
- if self.prefer_mutable {
- self.indexed_mut.insert(seqvar.segments[0].ident.name);
- }
- let index_used_directly = matches!(idx.kind, ExprKind::Path(_));
- let res = self.cx.qpath_res(seqpath, seqexpr.hir_id);
- match res {
- Res::Local(hir_id) => {
- let parent_def_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
- let extent = self
- .cx
- .tcx
- .region_scope_tree(parent_def_id)
- .var_scope(hir_id.local_id)
- .unwrap();
- if index_used_directly {
- self.indexed_directly.insert(
- seqvar.segments[0].ident.name,
- (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)),
- );
- } else {
- self.indexed_indirectly
- .insert(seqvar.segments[0].ident.name, Some(extent));
- }
- return false; // no need to walk further *on the variable*
- },
- Res::Def(DefKind::Static(_) | DefKind::Const, ..) => {
- if index_used_directly {
- self.indexed_directly.insert(
- seqvar.segments[0].ident.name,
- (None, self.cx.typeck_results().node_type(seqexpr.hir_id)),
- );
- } else {
- self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None);
- }
- return false; // no need to walk further *on the variable*
- },
- _ => (),
- }
+ && let QPath::Resolved(None, seqvar) = *seqpath
+ && seqvar.segments.len() == 1
+ && is_local_used(self.cx, idx, self.var)
+ {
+ if self.prefer_mutable {
+ self.indexed_mut.insert(seqvar.segments[0].ident.name);
+ }
+ let index_used_directly = matches!(idx.kind, ExprKind::Path(_));
+ let res = self.cx.qpath_res(seqpath, seqexpr.hir_id);
+ match res {
+ Res::Local(hir_id) => {
+ let parent_def_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
+ let extent = self
+ .cx
+ .tcx
+ .region_scope_tree(parent_def_id)
+ .var_scope(hir_id.local_id)
+ .unwrap();
+ if index_used_directly {
+ self.indexed_directly.insert(
+ seqvar.segments[0].ident.name,
+ (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)),
+ );
+ } else {
+ self.indexed_indirectly
+ .insert(seqvar.segments[0].ident.name, Some(extent));
+ }
+ return false; // no need to walk further *on the variable*
+ },
+ Res::Def(DefKind::Static(_) | DefKind::Const, ..) => {
+ if index_used_directly {
+ self.indexed_directly.insert(
+ seqvar.segments[0].ident.name,
+ (None, self.cx.typeck_results().node_type(seqexpr.hir_id)),
+ );
+ } else {
+ self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None);
+ }
+ return false; // no need to walk further *on the variable*
+ },
+ _ => (),
}
}
true
@@ -301,42 +293,36 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
- if_chain! {
+ if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind
// a range index op
- if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind;
- if let Some(trait_id) = self
+ && let Some(trait_id) = self
.cx
.typeck_results()
.type_dependent_def_id(expr.hir_id)
- .and_then(|def_id| self.cx.tcx.trait_of_item(def_id));
- if (meth.ident.name == sym::index && self.cx.tcx.lang_items().index_trait() == Some(trait_id))
- || (meth.ident.name == sym::index_mut && self.cx.tcx.lang_items().index_mut_trait() == Some(trait_id));
- if !self.check(args_1, args_0, expr);
- then {
- return;
- }
+ .and_then(|def_id| self.cx.tcx.trait_of_item(def_id))
+ && ((meth.ident.name == sym::index && self.cx.tcx.lang_items().index_trait() == Some(trait_id))
+ || (meth.ident.name == sym::index_mut && self.cx.tcx.lang_items().index_mut_trait() == Some(trait_id)))
+ && !self.check(args_1, args_0, expr)
+ {
+ return;
}
- if_chain! {
+ if let ExprKind::Index(seqexpr, idx, _) = expr.kind
// an index op
- if let ExprKind::Index(seqexpr, idx, _) = expr.kind;
- if !self.check(idx, seqexpr, expr);
- then {
- return;
- }
+ && !self.check(idx, seqexpr, expr)
+ {
+ return;
}
- if_chain! {
+ if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind
// directly using a variable
- if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind;
- if let Res::Local(local_id) = path.res;
- then {
- if local_id == self.var {
- self.nonindex = true;
- } else {
- // not the correct variable, but still a variable
- self.referenced.insert(path.segments[0].ident.name);
- }
+ && let Res::Local(local_id) = path.res
+ {
+ if local_id == self.var {
+ self.nonindex = true;
+ } else {
+ // not the correct variable, but still a variable
+ self.referenced.insert(path.segments[0].ident.name);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index cc054cb46..62bc66319 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -8,7 +8,7 @@ use rustc_errors::Applicability;
use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind};
use rustc_lint::LateContext;
use rustc_span::{sym, Span};
-use std::iter::{once, Iterator};
+use std::iter::once;
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index 5fffb27cd..c245eaf1a 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::path_to_local;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
@@ -12,7 +11,6 @@ use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Nod
use rustc_lint::LateContext;
use rustc_span::symbol::sym;
use rustc_span::SyntaxContext;
-use std::iter::Iterator;
/// Detects for loop pushing the same item into a Vec
pub(super) fn check<'tcx>(
@@ -44,54 +42,50 @@ pub(super) fn check<'tcx>(
// Determine whether it is safe to lint the body
let mut same_item_push_visitor = SameItemPushVisitor::new(cx);
walk_expr(&mut same_item_push_visitor, body);
- if_chain! {
- if same_item_push_visitor.should_lint();
- if let Some((vec, pushed_item, ctxt)) = same_item_push_visitor.vec_push;
- let vec_ty = cx.typeck_results().expr_ty(vec);
- let ty = vec_ty.walk().nth(1).unwrap().expect_ty();
- if cx
+ if same_item_push_visitor.should_lint()
+ && let Some((vec, pushed_item, ctxt)) = same_item_push_visitor.vec_push
+ && let vec_ty = cx.typeck_results().expr_ty(vec)
+ && let ty = vec_ty.walk().nth(1).unwrap().expect_ty()
+ && cx
.tcx
.lang_items()
.clone_trait()
- .map_or(false, |id| implements_trait(cx, ty, id, &[]));
- then {
- // Make sure that the push does not involve possibly mutating values
- match pushed_item.kind {
- ExprKind::Path(ref qpath) => {
- match cx.qpath_res(qpath, pushed_item.hir_id) {
- // immutable bindings that are initialized with literal or constant
- Res::Local(hir_id) => {
- let node = cx.tcx.hir().get(hir_id);
- if_chain! {
- if let Node::Pat(pat) = node;
- if let PatKind::Binding(bind_ann, ..) = pat.kind;
- if !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut));
- let parent_node = cx.tcx.hir().parent_id(hir_id);
- if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node);
- if let Some(init) = parent_let_expr.init;
- then {
- match init.kind {
- // immutable bindings that are initialized with literal
- ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt),
- // immutable bindings that are initialized with constant
- ExprKind::Path(ref path) => {
- if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) {
- emit_lint(cx, vec, pushed_item, ctxt);
- }
- }
- _ => {},
+ .map_or(false, |id| implements_trait(cx, ty, id, &[]))
+ {
+ // Make sure that the push does not involve possibly mutating values
+ match pushed_item.kind {
+ ExprKind::Path(ref qpath) => {
+ match cx.qpath_res(qpath, pushed_item.hir_id) {
+ // immutable bindings that are initialized with literal or constant
+ Res::Local(hir_id) => {
+ let node = cx.tcx.hir_node(hir_id);
+ if let Node::Pat(pat) = node
+ && let PatKind::Binding(bind_ann, ..) = pat.kind
+ && !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut))
+ && let parent_node = cx.tcx.hir().parent_id(hir_id)
+ && let Some(Node::Local(parent_let_expr)) = cx.tcx.opt_hir_node(parent_node)
+ && let Some(init) = parent_let_expr.init
+ {
+ match init.kind {
+ // immutable bindings that are initialized with literal
+ ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt),
+ // immutable bindings that are initialized with constant
+ ExprKind::Path(ref path) => {
+ if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) {
+ emit_lint(cx, vec, pushed_item, ctxt);
}
- }
+ },
+ _ => {},
}
- },
- // constant
- Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item, ctxt),
- _ => {},
- }
- },
- ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt),
- _ => {},
- }
+ }
+ },
+ // constant
+ Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item, ctxt),
+ _ => {},
+ }
+ },
+ ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt),
+ _ => {},
}
}
}
@@ -118,16 +112,14 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> {
}
fn should_lint(&self) -> bool {
- if_chain! {
- if !self.non_deterministic_expr;
- if !self.multiple_pushes;
- if let Some((vec, _, _)) = self.vec_push;
- if let Some(hir_id) = path_to_local(vec);
- then {
- !self.used_locals.contains(&hir_id)
- } else {
- false
- }
+ if !self.non_deterministic_expr
+ && !self.multiple_pushes
+ && let Some((vec, _, _)) = self.vec_push
+ && let Some(hir_id) = path_to_local(vec)
+ {
+ !self.used_locals.contains(&hir_id)
+ } else {
+ false
}
}
}
@@ -180,18 +172,16 @@ fn get_vec_push<'tcx>(
cx: &LateContext<'tcx>,
stmt: &'tcx Stmt<'_>,
) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)> {
- if_chain! {
+ if let StmtKind::Semi(semi_stmt) = &stmt.kind
// Extract method being called
- if let StmtKind::Semi(semi_stmt) = &stmt.kind;
- if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind;
+ && let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind
// Figure out the parameters for the method call
- if let Some(pushed_item) = args.first();
+ && let Some(pushed_item) = args.first()
// Check that the method being called is push() on a Vec
- if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
- if path.ident.name.as_str() == "push";
- then {
- return Some((self_expr, pushed_item, semi_stmt.span.ctxt()))
- }
+ && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec)
+ && path.ident.name.as_str() == "push"
+ {
+ return Some((self_expr, pushed_item, semi_stmt.span.ctxt()));
}
None
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
index dfb800ccf..4773a1454 100644
--- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
@@ -1,8 +1,7 @@
use super::SINGLE_ELEMENT_LOOP;
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{indent_of, snippet_with_applicability};
+use clippy_utils::source::{indent_of, snippet, snippet_with_applicability};
use clippy_utils::visitors::contains_break_or_continue;
-use if_chain::if_chain;
use rustc_ast::util::parser::PREC_PREFIX;
use rustc_ast::Mutability;
use rustc_errors::Applicability;
@@ -66,27 +65,42 @@ pub(super) fn check<'tcx>(
ExprKind::Array([arg]) if cx.tcx.sess.edition() >= Edition::Edition2021 => (arg, ""),
_ => return,
};
- if_chain! {
- if let ExprKind::Block(block, _) = body.kind;
- if !block.stmts.is_empty();
- if !contains_break_or_continue(body);
- then {
- let mut applicability = Applicability::MachineApplicable;
- let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);
- let mut arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability);
- let mut block_str = snippet_with_applicability(cx, block.span, "..", &mut applicability).into_owned();
- block_str.remove(0);
- block_str.pop();
- let indent = " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0));
+ if let ExprKind::Block(block, _) = body.kind
+ && !block.stmts.is_empty()
+ && !contains_break_or_continue(body)
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);
+ let mut arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability);
+ let mut block_str = snippet_with_applicability(cx, block.span, "..", &mut applicability).into_owned();
+ block_str.remove(0);
+ block_str.pop();
+ let indent = " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0));
- // Reference iterator from `&(mut) []` or `[].iter(_mut)()`.
- if !prefix.is_empty() && (
+ // Reference iterator from `&(mut) []` or `[].iter(_mut)()`.
+ if !prefix.is_empty()
+ && (
// Precedence of internal expression is less than or equal to precedence of `&expr`.
arg_expression.precedence().order() <= PREC_PREFIX || is_range_literal(arg_expression)
- ) {
- arg_snip = format!("({arg_snip})").into();
- }
+ )
+ {
+ arg_snip = format!("({arg_snip})").into();
+ }
+ if clippy_utils::higher::Range::hir(arg_expression).is_some() {
+ let range_expr = snippet(cx, arg_expression.span, "?").to_string();
+
+ let sugg = snippet(cx, arg_expression.span, "..");
+ span_lint_and_sugg(
+ cx,
+ SINGLE_ELEMENT_LOOP,
+ arg.span,
+ format!("this loops only once with `{pat_snip}` being `{range_expr}`").as_str(),
+ "did you mean to iterate over the range instead?",
+ sugg.to_string(),
+ Applicability::Unspecified,
+ );
+ } else {
span_lint_and_sugg(
cx,
SINGLE_ELEMENT_LOOP,
@@ -95,7 +109,7 @@ pub(super) fn check<'tcx>(
"try",
format!("{{\n{indent}let {pat_snip} = {prefix}{arg_snip};{block_str}}}"),
applicability,
- )
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 0a2bd89eb..e685274ad 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -1,6 +1,5 @@
use clippy_utils::ty::{has_iter_method, implements_trait};
use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg};
-use if_chain::if_chain;
use rustc_ast::ast::{LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, walk_local, walk_pat, walk_stmt, Visitor};
@@ -10,7 +9,6 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Ty};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Symbol};
-use std::iter::Iterator;
#[derive(Debug, PartialEq, Eq)]
enum IncrementVisitorVarState {
@@ -145,20 +143,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
fn visit_local(&mut self, l: &'tcx Local<'_>) {
// Look for declarations of the variable
- if_chain! {
- if l.pat.hir_id == self.var_id;
- if let PatKind::Binding(.., ident, _) = l.pat.kind;
- then {
- let ty = l.ty.map(|_| self.cx.typeck_results().pat_ty(l.pat));
+ if l.pat.hir_id == self.var_id
+ && let PatKind::Binding(.., ident, _) = l.pat.kind
+ {
+ let ty = l.ty.map(|_| self.cx.typeck_results().pat_ty(l.pat));
- self.state = l.init.map_or(InitializeVisitorState::Declared(ident.name, ty), |init| {
- InitializeVisitorState::Initialized {
- initializer: init,
- ty,
- name: ident.name,
- }
- })
- }
+ self.state = l.init.map_or(InitializeVisitorState::Declared(ident.name, ty), |init| {
+ InitializeVisitorState::Initialized {
+ initializer: init,
+ ty,
+ name: ident.name,
+ }
+ });
}
walk_local(self, l);
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
index 7f24f3c5d..9fd9b7a16 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
@@ -2,7 +2,6 @@ use super::WHILE_IMMUTABLE_CONDITION;
use clippy_utils::consts::constant;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::usage::mutated_variables;
-use if_chain::if_chain;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefIdMap;
use rustc_hir::intravisit::{walk_expr, Visitor};
@@ -95,20 +94,18 @@ struct VarCollectorVisitor<'a, 'tcx> {
impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
fn insert_def_id(&mut self, ex: &'tcx Expr<'_>) {
- if_chain! {
- if let ExprKind::Path(ref qpath) = ex.kind;
- if let QPath::Resolved(None, _) = *qpath;
- then {
- match self.cx.qpath_res(qpath, ex.hir_id) {
- Res::Local(hir_id) => {
- self.ids.insert(hir_id);
- },
- Res::Def(DefKind::Static(_), def_id) => {
- let mutable = self.cx.tcx.is_mutable_static(def_id);
- self.def_ids.insert(def_id, mutable);
- },
- _ => {},
- }
+ if let ExprKind::Path(ref qpath) = ex.kind
+ && let QPath::Resolved(None, _) = *qpath
+ {
+ match self.cx.qpath_res(qpath, ex.hir_id) {
+ Res::Local(hir_id) => {
+ self.ids.insert(hir_id);
+ },
+ Res::Def(DefKind::Static(_), def_id) => {
+ let mutable = self.cx.tcx.is_mutable_static(def_id);
+ self.def_ids.insert(def_id, mutable);
+ },
+ _ => {},
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index 5153070cf..21b9efba5 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::visitors::is_res_used;
use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutable, is_res_lang_ctor, is_trait_method};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::intravisit::{walk_expr, Visitor};
@@ -15,59 +14,53 @@ use rustc_span::symbol::sym;
use rustc_span::Symbol;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- let (scrutinee_expr, iter_expr_struct, iter_expr, some_pat, loop_expr) = if_chain! {
- if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr);
+ if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr)
// check for `Some(..)` pattern
- if let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind;
- if is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome);
+ && let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind
+ && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
// check for call to `Iterator::next`
- if let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind;
- if method_name.ident.name == sym::next;
- if is_trait_method(cx, let_expr, sym::Iterator);
- if let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr);
+ && let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind
+ && method_name.ident.name == sym::next
+ && is_trait_method(cx, let_expr, sym::Iterator)
+ && let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr)
// get the loop containing the match expression
- if !uses_iter(cx, &iter_expr_struct, if_then);
- then {
- (let_expr, iter_expr_struct, iter_expr, some_pat, expr)
+ && !uses_iter(cx, &iter_expr_struct, if_then)
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let loop_var = if let Some(some_pat) = some_pat.first() {
+ if is_refutable(cx, some_pat) {
+ // Refutable patterns don't work with for loops.
+ return;
+ }
+ snippet_with_applicability(cx, some_pat.span, "..", &mut applicability)
} else {
- return;
- }
- };
-
- let mut applicability = Applicability::MachineApplicable;
- let loop_var = if let Some(some_pat) = some_pat.first() {
- if is_refutable(cx, some_pat) {
- // Refutable patterns don't work with for loops.
- return;
- }
- snippet_with_applicability(cx, some_pat.span, "..", &mut applicability)
- } else {
- "_".into()
- };
+ "_".into()
+ };
- // If the iterator is a field or the iterator is accessed after the loop is complete it needs to be
- // borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used
- // afterwards a mutable borrow of a field isn't necessary.
- let by_ref = if cx.typeck_results().expr_ty(iter_expr).ref_mutability() == Some(Mutability::Mut)
- || !iter_expr_struct.can_move
- || !iter_expr_struct.fields.is_empty()
- || needs_mutable_borrow(cx, &iter_expr_struct, loop_expr)
- {
- ".by_ref()"
- } else {
- ""
- };
+ // If the iterator is a field or the iterator is accessed after the loop is complete it needs to be
+ // borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used
+ // afterwards a mutable borrow of a field isn't necessary.
+ let by_ref = if cx.typeck_results().expr_ty(iter_expr).ref_mutability() == Some(Mutability::Mut)
+ || !iter_expr_struct.can_move
+ || !iter_expr_struct.fields.is_empty()
+ || needs_mutable_borrow(cx, &iter_expr_struct, expr)
+ {
+ ".by_ref()"
+ } else {
+ ""
+ };
- let iterator = snippet_with_applicability(cx, iter_expr.span, "_", &mut applicability);
- span_lint_and_sugg(
- cx,
- WHILE_LET_ON_ITERATOR,
- expr.span.with_hi(scrutinee_expr.span.hi()),
- "this loop could be written as a `for` loop",
- "try",
- format!("for {loop_var} in {iterator}{by_ref}"),
- applicability,
- );
+ let iterator = snippet_with_applicability(cx, iter_expr.span, "_", &mut applicability);
+ span_lint_and_sugg(
+ cx,
+ WHILE_LET_ON_ITERATOR,
+ expr.span.with_hi(let_expr.span.hi()),
+ "this loop could be written as a `for` loop",
+ "try",
+ format!("for {loop_var} in {iterator}{by_ref}"),
+ applicability,
+ );
+ }
}
#[derive(Debug)]
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index 9b158f18f..8d3e7520a 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -1,15 +1,15 @@
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::source::snippet;
use hir::def::{DefKind, Res};
-use if_chain::if_chain;
use rustc_ast::ast;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::edition::Edition;
use rustc_span::{sym, Span};
+use std::collections::BTreeMap;
declare_clippy_lint! {
/// ### What it does
@@ -89,30 +89,26 @@ impl MacroUseImports {
impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if_chain! {
- if cx.sess().opts.edition >= Edition::Edition2018;
- if let hir::ItemKind::Use(path, _kind) = &item.kind;
- let hir_id = item.hir_id();
- let attrs = cx.tcx.hir().attrs(hir_id);
- if let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use));
- if let Some(id) = path.res.iter().find_map(|res| match res {
+ if cx.sess().opts.edition >= Edition::Edition2018
+ && let hir::ItemKind::Use(path, _kind) = &item.kind
+ && let hir_id = item.hir_id()
+ && let attrs = cx.tcx.hir().attrs(hir_id)
+ && let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use))
+ && let Some(id) = path.res.iter().find_map(|res| match res {
Res::Def(DefKind::Mod, id) => Some(id),
_ => None,
- });
- if !id.is_local();
- then {
- for kid in cx.tcx.module_children(id) {
- if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res {
- let span = mac_attr.span;
- let def_path = cx.tcx.def_path_str(mac_id);
- self.imports.push((def_path, span, hir_id));
- }
- }
- } else {
- if item.span.from_expansion() {
- self.push_unique_macro_pat_ty(cx, item.span);
+ })
+ && !id.is_local()
+ {
+ for kid in cx.tcx.module_children(id) {
+ if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res {
+ let span = mac_attr.span;
+ let def_path = cx.tcx.def_path_str(mac_id);
+ self.imports.push((def_path, span, hir_id));
}
}
+ } else if item.span.from_expansion() {
+ self.push_unique_macro_pat_ty(cx, item.span);
}
}
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
@@ -141,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
}
}
fn check_crate_post(&mut self, cx: &LateContext<'_>) {
- let mut used = FxHashMap::default();
+ let mut used = BTreeMap::new();
let mut check_dup = vec![];
for (import, span, hir_id) in &self.imports {
let found_idx = self.mac_refs.iter().position(|mac| import.ends_with(&mac.name));
@@ -190,20 +186,16 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
}
}
- let mut suggestions = vec![];
- for ((root, span, hir_id), path) in used {
- if path.len() == 1 {
- suggestions.push((span, format!("{root}::{}", path[0]), hir_id));
- } else {
- suggestions.push((span, format!("{root}::{{{}}}", path.join(", ")), hir_id));
- }
- }
-
// If mac_refs is not empty we have encountered an import we could not handle
// such as `std::prelude::v1::foo` or some other macro that expands to an import.
if self.mac_refs.is_empty() {
- for (span, import, hir_id) in suggestions {
- let help = format!("use {import};");
+ for ((root, span, hir_id), path) in used {
+ let import = if let [single] = &path[..] {
+ format!("{root}::{single}")
+ } else {
+ format!("{root}::{{{}}}", path.join(", "))
+ };
+
span_lint_hir_and_then(
cx,
MACRO_USE_IMPORTS,
@@ -214,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
diag.span_suggestion(
*span,
"remove the attribute and import the macro directly, try",
- help,
+ format!("use {import};"),
Applicability::MaybeIncorrect,
);
},
diff --git a/src/tools/clippy/clippy_lints/src/main_recursion.rs b/src/tools/clippy/clippy_lints/src/main_recursion.rs
index 20333c150..a381b35cf 100644
--- a/src/tools/clippy/clippy_lints/src/main_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/main_recursion.rs
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet;
use clippy_utils::{is_entrypoint_fn, is_no_std_crate};
-use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -43,21 +42,19 @@ impl LateLintPass<'_> for MainRecursion {
return;
}
- if_chain! {
- if let ExprKind::Call(func, _) = &expr.kind;
- if let ExprKind::Path(QPath::Resolved(_, path)) = &func.kind;
- if let Some(def_id) = path.res.opt_def_id();
- if is_entrypoint_fn(cx, def_id);
- then {
- span_lint_and_help(
- cx,
- MAIN_RECURSION,
- func.span,
- &format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")),
- None,
- "consider using another function for this recursion"
- )
- }
+ if let ExprKind::Call(func, _) = &expr.kind
+ && let ExprKind::Path(QPath::Resolved(_, path)) = &func.kind
+ && let Some(def_id) = path.res.opt_def_id()
+ && is_entrypoint_fn(cx, def_id)
+ {
+ span_lint_and_help(
+ cx,
+ MAIN_RECURSION,
+ func.span,
+ &format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")),
+ None,
+ "consider using another function for this recursion",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index 9a3da975f..4f6a2cf01 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -5,7 +5,7 @@ use clippy_utils::{is_else_clause, peel_blocks_with_stmt, span_extract_comment,
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 998de38a9..eaaaea0be 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
@@ -8,7 +7,7 @@ use rustc_hir::{
ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind,
};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span};
@@ -47,61 +46,57 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
span: Span,
def_id: LocalDefId,
) {
- if_chain! {
- if let Some(header) = kind.header();
- if !header.asyncness.is_async();
+ if let Some(header) = kind.header()
+ && !header.asyncness.is_async()
// Check that this function returns `impl Future`
- if let FnRetTy::Return(ret_ty) = decl.output;
- if let Some((trait_ref, output_lifetimes)) = future_trait_ref(cx, ret_ty);
- if let Some(output) = future_output_ty(trait_ref);
- if captures_all_lifetimes(decl.inputs, &output_lifetimes);
+ && let FnRetTy::Return(ret_ty) = decl.output
+ && let Some((trait_ref, output_lifetimes)) = future_trait_ref(cx, ret_ty)
+ && let Some(output) = future_output_ty(trait_ref)
+ && captures_all_lifetimes(decl.inputs, &output_lifetimes)
// Check that the body of the function consists of one async block
- if let ExprKind::Block(block, _) = body.value.kind;
- if block.stmts.is_empty();
- if let Some(closure_body) = desugared_async_block(cx, block);
- if let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) =
- cx.tcx.hir().get_by_def_id(def_id);
- then {
- let header_span = span.with_hi(ret_ty.span.hi());
-
- span_lint_and_then(
- cx,
- MANUAL_ASYNC_FN,
- header_span,
- "this function can be simplified using the `async fn` syntax",
- |diag| {
- if_chain! {
- if let Some(vis_snip) = snippet_opt(cx, *vis_span);
- if let Some(header_snip) = snippet_opt(cx, header_span);
- if let Some(ret_pos) = position_before_rarrow(&header_snip);
- if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output);
- then {
- let header_snip = if vis_snip.is_empty() {
- format!("async {}", &header_snip[..ret_pos])
- } else {
- format!("{} async {}", vis_snip, &header_snip[vis_snip.len() + 1..ret_pos])
- };
-
- let help = format!("make the function `async` and {ret_sugg}");
- diag.span_suggestion(
- header_span,
- help,
- format!("{header_snip}{ret_snip}"),
- Applicability::MachineApplicable
- );
-
- let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span));
- diag.span_suggestion(
- block.span,
- "move the body of the async block to the enclosing function",
- body_snip,
- Applicability::MachineApplicable
- );
- }
- }
- },
- );
- }
+ && let ExprKind::Block(block, _) = body.value.kind
+ && block.stmts.is_empty()
+ && let Some(closure_body) = desugared_async_block(cx, block)
+ && let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) =
+ cx.tcx.hir_node_by_def_id(def_id)
+ {
+ let header_span = span.with_hi(ret_ty.span.hi());
+
+ span_lint_and_then(
+ cx,
+ MANUAL_ASYNC_FN,
+ header_span,
+ "this function can be simplified using the `async fn` syntax",
+ |diag| {
+ if let Some(vis_snip) = snippet_opt(cx, *vis_span)
+ && let Some(header_snip) = snippet_opt(cx, header_span)
+ && let Some(ret_pos) = position_before_rarrow(&header_snip)
+ && let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output)
+ {
+ let header_snip = if vis_snip.is_empty() {
+ format!("async {}", &header_snip[..ret_pos])
+ } else {
+ format!("{} async {}", vis_snip, &header_snip[vis_snip.len() + 1..ret_pos])
+ };
+
+ let help = format!("make the function `async` and {ret_sugg}");
+ diag.span_suggestion(
+ header_span,
+ help,
+ format!("{header_snip}{ret_snip}"),
+ Applicability::MachineApplicable,
+ );
+
+ let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span));
+ diag.span_suggestion(
+ block.span,
+ "move the body of the async block to the enclosing function",
+ body_snip,
+ Applicability::MachineApplicable,
+ );
+ }
+ },
+ );
}
}
}
@@ -110,48 +105,44 @@ fn future_trait_ref<'tcx>(
cx: &LateContext<'tcx>,
ty: &'tcx Ty<'tcx>,
) -> Option<(&'tcx TraitRef<'tcx>, Vec<LifetimeName>)> {
- if_chain! {
- if let TyKind::OpaqueDef(item_id, bounds, false) = ty.kind;
- let item = cx.tcx.hir().item(item_id);
- if let ItemKind::OpaqueTy(opaque) = &item.kind;
- if let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| {
+ if let TyKind::OpaqueDef(item_id, bounds, false) = ty.kind
+ && let item = cx.tcx.hir().item(item_id)
+ && let ItemKind::OpaqueTy(opaque) = &item.kind
+ && let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| {
if let GenericBound::Trait(poly, _) = bound {
Some(&poly.trait_ref)
} else {
None
}
- });
- if trait_ref.trait_def_id() == cx.tcx.lang_items().future_trait();
- then {
- let output_lifetimes = bounds
- .iter()
- .filter_map(|bound| {
- if let GenericArg::Lifetime(lt) = bound {
- Some(lt.res)
- } else {
- None
- }
- })
- .collect();
-
- return Some((trait_ref, output_lifetimes));
- }
+ })
+ && trait_ref.trait_def_id() == cx.tcx.lang_items().future_trait()
+ {
+ let output_lifetimes = bounds
+ .iter()
+ .filter_map(|bound| {
+ if let GenericArg::Lifetime(lt) = bound {
+ Some(lt.res)
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ return Some((trait_ref, output_lifetimes));
}
None
}
fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'tcx>> {
- if_chain! {
- if let Some(segment) = trait_ref.path.segments.last();
- if let Some(args) = segment.args;
- if args.bindings.len() == 1;
- let binding = &args.bindings[0];
- if binding.ident.name == sym::Output;
- if let TypeBindingKind::Equality { term: Term::Ty(output) } = binding.kind;
- then {
- return Some(output);
- }
+ if let Some(segment) = trait_ref.path.segments.last()
+ && let Some(args) = segment.args
+ && args.bindings.len() == 1
+ && let binding = &args.bindings[0]
+ && binding.ident.name == sym::Output
+ && let TypeBindingKind::Equality { term: Term::Ty(output) } = binding.kind
+ {
+ return Some(output);
}
None
@@ -181,31 +172,26 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName])
}
fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
- if_chain! {
- if let Some(block_expr) = block.expr;
- if let Expr {
+ if let Some(block_expr) = block.expr
+ && let Expr {
kind: ExprKind::Closure(&Closure { body, .. }),
..
- } = block_expr;
- let closure_body = cx.tcx.hir().body(body);
- if closure_body.coroutine_kind == Some(CoroutineKind::Async(CoroutineSource::Block));
- then {
- return Some(closure_body);
- }
+ } = block_expr
+ && let closure_body = cx.tcx.hir().body(body)
+ && closure_body.coroutine_kind == Some(CoroutineKind::Async(CoroutineSource::Block))
+ {
+ return Some(closure_body);
}
None
}
fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, String)> {
- match output.kind {
- TyKind::Tup(tys) if tys.is_empty() => {
- let sugg = "remove the return type";
- Some((sugg, String::new()))
- },
- _ => {
- let sugg = "return the output of the future directly";
- snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {snip}")))
- },
+ if let TyKind::Tup([]) = output.kind {
+ let sugg = "remove the return type";
+ Some((sugg, String::new()))
+ } else {
+ let sugg = "return the output of the future directly";
+ snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {snip}")))
}
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index cd614c895..96c652283 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -8,7 +8,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -53,32 +53,30 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits {
return;
}
- if_chain! {
- if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind;
- if let BinOpKind::Mul = &bin_op.node;
- if !in_external_macro(cx.sess(), expr.span);
- let ctxt = expr.span.ctxt();
- if left_expr.span.ctxt() == ctxt;
- if right_expr.span.ctxt() == ctxt;
- if let Some((real_ty, resolved_ty, other_expr)) = get_one_size_of_ty(cx, left_expr, right_expr);
- if matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_));
- if let ExprKind::Lit(lit) = &other_expr.kind;
- if let LitKind::Int(8, _) = lit.node;
- then {
- let mut app = Applicability::MachineApplicable;
- let ty_snip = snippet_with_context(cx, real_ty.span, ctxt, "..", &mut app).0;
- let sugg = create_sugg(cx, expr, format!("{ty_snip}::BITS"));
-
- span_lint_and_sugg(
- cx,
- MANUAL_BITS,
- expr.span,
- "usage of `mem::size_of::<T>()` to obtain the size of `T` in bits",
- "consider using",
- sugg,
- app,
- );
- }
+ if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind
+ && let BinOpKind::Mul = &bin_op.node
+ && !in_external_macro(cx.sess(), expr.span)
+ && let ctxt = expr.span.ctxt()
+ && left_expr.span.ctxt() == ctxt
+ && right_expr.span.ctxt() == ctxt
+ && let Some((real_ty, resolved_ty, other_expr)) = get_one_size_of_ty(cx, left_expr, right_expr)
+ && matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_))
+ && let ExprKind::Lit(lit) = &other_expr.kind
+ && let LitKind::Int(8, _) = lit.node
+ {
+ let mut app = Applicability::MachineApplicable;
+ let ty_snip = snippet_with_context(cx, real_ty.span, ctxt, "..", &mut app).0;
+ let sugg = create_sugg(cx, expr, format!("{ty_snip}::BITS"));
+
+ span_lint_and_sugg(
+ cx,
+ MANUAL_BITS,
+ expr.span,
+ "usage of `mem::size_of::<T>()` to obtain the size of `T` in bits",
+ "consider using",
+ sugg,
+ app,
+ );
}
}
@@ -98,22 +96,22 @@ fn get_one_size_of_ty<'tcx>(
}
fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>)> {
- if_chain! {
- if let ExprKind::Call(count_func, _func_args) = expr.kind;
- if let ExprKind::Path(ref count_func_qpath) = count_func.kind;
-
- if let QPath::Resolved(_, count_func_path) = count_func_qpath;
- if let Some(segment_zero) = count_func_path.segments.first();
- if let Some(args) = segment_zero.args;
- if let Some(GenericArg::Type(real_ty)) = args.args.first();
-
- if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
- if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id);
- then {
- cx.typeck_results().node_args(count_func.hir_id).types().next().map(|resolved_ty| (*real_ty, resolved_ty))
- } else {
- None
- }
+ if let ExprKind::Call(count_func, _func_args) = expr.kind
+ && let ExprKind::Path(ref count_func_qpath) = count_func.kind
+ && let QPath::Resolved(_, count_func_path) = count_func_qpath
+ && let Some(segment_zero) = count_func_path.segments.first()
+ && let Some(args) = segment_zero.args
+ && let Some(GenericArg::Type(real_ty)) = args.args.first()
+ && let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id()
+ && cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id)
+ {
+ cx.typeck_results()
+ .node_args(count_func.hir_id)
+ .types()
+ .next()
+ .map(|resolved_ty| (*real_ty, resolved_ty))
+ } else {
+ None
}
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index 09c90e38e..385fe387a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -14,7 +14,7 @@ use rustc_hir::def::Res;
use rustc_hir::{Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::sym;
use rustc_span::Span;
use std::ops::Deref;
diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
index f923e0ac8..72cf1d7a3 100644
--- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
@@ -6,7 +6,7 @@ use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Constness, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
index 472b4eb90..252b3a83a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
@@ -6,7 +6,7 @@ use clippy_utils::{is_trait_method, path_to_local_id};
use rustc_errors::Applicability;
use rustc_hir::{BindingAnnotation, ExprKind, Local, Node, PatKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index 468f41707..e433c5a3b 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -8,7 +8,7 @@ use rustc_ast::LitKind::{Byte, Char};
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::DefId;
use rustc_span::{sym, Span};
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 170a040d4..92dc4d57a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -5,18 +5,15 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLetOrMatch;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::visitors::{Descend, Visitable};
-use clippy_utils::{is_lint_allowed, pat_and_expr_can_be_question_mark, peel_blocks};
+use clippy_utils::{is_lint_allowed, is_never_expr, pat_and_expr_can_be_question_mark, peel_blocks};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{Expr, ExprKind, HirId, ItemId, Local, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind, Ty};
+use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::declare_tool_lint;
+
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
-use std::ops::ControlFlow;
use std::slice;
declare_clippy_lint! {
@@ -51,7 +48,7 @@ declare_clippy_lint! {
}
impl<'tcx> QuestionMark {
- pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
+ pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) {
if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) {
return;
}
@@ -67,7 +64,7 @@ impl<'tcx> QuestionMark {
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => {
if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then)
&& let Some(if_else) = if_else
- && expr_diverges(cx, if_else)
+ && is_never_expr(cx, if_else).is_some()
&& let qm_allowed = is_lint_allowed(cx, QUESTION_MARK, stmt.hir_id)
&& (qm_allowed || pat_and_expr_can_be_question_mark(cx, let_pat, if_else).is_none())
{
@@ -91,10 +88,9 @@ impl<'tcx> QuestionMark {
return;
}
let check_types = self.matches_behaviour == MatchLintBehaviour::WellKnownTypes;
- let diverging_arm_opt = arms
- .iter()
- .enumerate()
- .find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types));
+ let diverging_arm_opt = arms.iter().enumerate().find(|(_, arm)| {
+ is_never_expr(cx, arm.body).is_some() && pat_allowed_for_else(cx, arm.pat, check_types)
+ });
let Some((idx, diverging_arm)) = diverging_arm_opt else {
return;
};
@@ -272,104 +268,6 @@ fn replace_in_pattern(
sn_pat.into_owned()
}
-/// Check whether an expression is divergent. May give false negatives.
-fn expr_diverges(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- struct V<'cx, 'tcx> {
- cx: &'cx LateContext<'tcx>,
- res: ControlFlow<(), Descend>,
- }
- impl<'tcx> Visitor<'tcx> for V<'_, '_> {
- fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
- fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
- if let Some(ty) = cx.typeck_results().expr_ty_opt(expr) {
- return ty.is_never();
- }
- false
- }
-
- if self.res.is_break() {
- return;
- }
-
- // We can't just call is_never on expr and be done, because the type system
- // sometimes coerces the ! type to something different before we can get
- // our hands on it. So instead, we do a manual search. We do fall back to
- // is_never in some places when there is no better alternative.
- self.res = match e.kind {
- ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => ControlFlow::Break(()),
- ExprKind::Call(call, _) => {
- if is_never(self.cx, e) || is_never(self.cx, call) {
- ControlFlow::Break(())
- } else {
- ControlFlow::Continue(Descend::Yes)
- }
- },
- ExprKind::MethodCall(..) => {
- if is_never(self.cx, e) {
- ControlFlow::Break(())
- } else {
- ControlFlow::Continue(Descend::Yes)
- }
- },
- ExprKind::If(if_expr, if_then, if_else) => {
- let else_diverges = if_else.map_or(false, |ex| expr_diverges(self.cx, ex));
- let diverges =
- expr_diverges(self.cx, if_expr) || (else_diverges && expr_diverges(self.cx, if_then));
- if diverges {
- ControlFlow::Break(())
- } else {
- ControlFlow::Continue(Descend::No)
- }
- },
- ExprKind::Match(match_expr, match_arms, _) => {
- let diverges = expr_diverges(self.cx, match_expr)
- || match_arms.iter().all(|arm| {
- let guard_diverges = arm.guard.as_ref().map_or(false, |g| expr_diverges(self.cx, g.body()));
- guard_diverges || expr_diverges(self.cx, arm.body)
- });
- if diverges {
- ControlFlow::Break(())
- } else {
- ControlFlow::Continue(Descend::No)
- }
- },
-
- // Don't continue into loops or labeled blocks, as they are breakable,
- // and we'd have to start checking labels.
- ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => ControlFlow::Continue(Descend::No),
-
- // Default: descend
- _ => ControlFlow::Continue(Descend::Yes),
- };
- if let ControlFlow::Continue(Descend::Yes) = self.res {
- walk_expr(self, e);
- }
- }
-
- fn visit_local(&mut self, local: &'tcx Local<'_>) {
- // Don't visit the else block of a let/else statement as it will not make
- // the statement divergent even though the else block is divergent.
- if let Some(init) = local.init {
- self.visit_expr(init);
- }
- }
-
- // Avoid unnecessary `walk_*` calls.
- fn visit_ty(&mut self, _: &'tcx Ty<'tcx>) {}
- fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {}
- fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {}
- // Avoid monomorphising all `visit_*` functions.
- fn visit_nested_item(&mut self, _: ItemId) {}
- }
-
- let mut v = V {
- cx,
- res: ControlFlow::Continue(Descend::Yes),
- };
- expr.visit(&mut v);
- v.res.is_break()
-}
-
fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: bool) -> bool {
// Check whether the pattern contains any bindings, as the
// binding might potentially be used in the body.
diff --git a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
index 23f47c86f..5732bdda7 100644
--- a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
@@ -6,7 +6,7 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind, Mutability, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index fc8f23630..d2ac0ad83 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -9,7 +9,7 @@ use rustc_errors::Applicability;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::{self as hir, Expr, ExprKind, QPath};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::{sym, Span};
@@ -103,7 +103,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
if let ast::ItemKind::Struct(variant_data, _) = &item.kind {
let (fields, delimiter) = match variant_data {
- ast::VariantData::Struct(fields, _) => (&**fields, '{'),
+ ast::VariantData::Struct { fields, .. } => (&**fields, '{'),
ast::VariantData::Tuple(fields, _) => (&**fields, '('),
ast::VariantData::Unit(_) => return,
};
@@ -118,7 +118,6 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
if let Some(Ok(field)) = iter.next()
&& iter.next().is_none()
&& field.ty.kind.is_unit()
- && field.ident.map_or(true, |name| name.as_str().starts_with('_'))
{
span_lint_and_then(
cx,
@@ -158,7 +157,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
{
let mut iter = def.variants.iter().filter_map(|v| {
(matches!(v.data, hir::VariantData::Unit(_, _))
- && v.ident.as_str().starts_with('_')
&& is_doc_hidden(cx.tcx.hir().attrs(v.hir_id))
&& !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive))
.then_some((v.def_id, v.span))
@@ -173,9 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if let ExprKind::Path(QPath::Resolved(None, p)) = &e.kind
- && let [.., name] = p.segments
&& let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res
- && name.ident.as_str().starts_with('_')
{
let variant_id = cx.tcx.parent(id);
let enum_id = cx.tcx.parent(variant_id);
@@ -192,7 +188,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
.contains(&(enum_id.to_def_id(), variant_id.to_def_id()))
})
{
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(enum_id);
+ let hir_id = cx.tcx.local_def_id_to_hir_id(enum_id);
span_lint_hir_and_then(
cx,
MANUAL_NON_EXHAUSTIVE,
diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
index d24bfe182..d585290f7 100644
--- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
@@ -6,7 +6,7 @@ use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{Span, DUMMY_SP};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index bc8372fbd..71a83a68d 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -7,7 +7,7 @@ use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
// Also ensures the const is nonzero since zero can't be a divisor
&& const1 == const2 && const2 == const3
&& let Some(hir_id) = path_to_local(expr3)
- && let Some(Node::Pat(_)) = cx.tcx.hir().find(hir_id)
+ && let Some(Node::Pat(_)) = cx.tcx.opt_hir_node(hir_id)
{
// Apply only to params or locals with annotated types
match cx.tcx.hir().find_parent(hir_id) {
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 2f8682d04..1fe247dac 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -9,7 +9,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::ExprKind::Assign;
use rustc_lint::{LateContext, LateLintPass};
use rustc_semver::RustcVersion;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::sym;
const ACCEPTABLE_METHODS: [&[&str]; 5] = [
diff --git a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
index 3b97d1659..1de686dbc 100644
--- a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
@@ -5,7 +5,7 @@ use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
index f8afae0e1..781db4b97 100644
--- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
@@ -4,7 +4,7 @@ use rustc_errors::Applicability::MachineApplicable;
use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, symbol, Span};
declare_clippy_lint! {
@@ -108,18 +108,16 @@ fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, args: &[Expr<'_
let arg_kind = &args[0].kind;
if let ExprKind::Path(qpath) = &func.kind {
- if let QPath::TypeRelative(_, _) = qpath {
- // String::from(...) or String::try_from(...)
- if let QPath::TypeRelative(ty, path_seg) = qpath
- && [sym::from, sym::try_from].contains(&path_seg.ident.name)
- && let TyKind::Path(qpath) = &ty.kind
- && let QPath::Resolved(_, path) = qpath
- && let [path_seg] = path.segments
- && path_seg.ident.name == sym::String
- && is_expr_kind_empty_str(arg_kind)
- {
- warn_then_suggest(cx, span);
- }
+ // String::from(...) or String::try_from(...)
+ if let QPath::TypeRelative(ty, path_seg) = qpath
+ && [sym::from, sym::try_from].contains(&path_seg.ident.name)
+ && let TyKind::Path(qpath) = &ty.kind
+ && let QPath::Resolved(_, path) = qpath
+ && let [path_seg] = path.segments
+ && path_seg.ident.name == sym::String
+ && is_expr_kind_empty_str(arg_kind)
+ {
+ warn_then_suggest(cx, span);
} else if let QPath::Resolved(_, path) = qpath {
// From::from(...) or TryFrom::try_from(...)
if let [path_seg1, path_seg2] = path.segments
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 9a9e6af50..7b04fd28b 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -4,14 +4,13 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::usage::mutated_variables;
use clippy_utils::{eq_expr_value, higher, match_def_path, paths};
-use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_hir::def::Res;
use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::Span;
@@ -71,55 +70,61 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
return;
}
- if_chain! {
- if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
- if let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind;
- if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id);
- if let ExprKind::Path(target_path) = &target_arg.kind;
- then {
- let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) {
- StripKind::Prefix
- } else if match_def_path(cx, method_def_id, &paths::STR_ENDS_WITH) {
- StripKind::Suffix
- } else {
- return;
- };
- let target_res = cx.qpath_res(target_path, target_arg.hir_id);
- if target_res == Res::Err {
- return;
- };
-
- if_chain! {
- if let Res::Local(hir_id) = target_res;
- if let Some(used_mutably) = mutated_variables(then, cx);
- if used_mutably.contains(&hir_id);
- then {
- return;
- }
- }
-
- let strippings = find_stripping(cx, strip_kind, target_res, pattern, then);
- if !strippings.is_empty() {
+ if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr)
+ && let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind
+ && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id)
+ && let ExprKind::Path(target_path) = &target_arg.kind
+ {
+ let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) {
+ StripKind::Prefix
+ } else if match_def_path(cx, method_def_id, &paths::STR_ENDS_WITH) {
+ StripKind::Suffix
+ } else {
+ return;
+ };
+ let target_res = cx.qpath_res(target_path, target_arg.hir_id);
+ if target_res == Res::Err {
+ return;
+ };
+
+ if let Res::Local(hir_id) = target_res
+ && let Some(used_mutably) = mutated_variables(then, cx)
+ && used_mutably.contains(&hir_id)
+ {
+ return;
+ }
- let kind_word = match strip_kind {
- StripKind::Prefix => "prefix",
- StripKind::Suffix => "suffix",
- };
+ let strippings = find_stripping(cx, strip_kind, target_res, pattern, then);
+ if !strippings.is_empty() {
+ let kind_word = match strip_kind {
+ StripKind::Prefix => "prefix",
+ StripKind::Suffix => "suffix",
+ };
- let test_span = expr.span.until(then.span);
- span_lint_and_then(cx, MANUAL_STRIP, strippings[0], &format!("stripping a {kind_word} manually"), |diag| {
+ let test_span = expr.span.until(then.span);
+ span_lint_and_then(
+ cx,
+ MANUAL_STRIP,
+ strippings[0],
+ &format!("stripping a {kind_word} manually"),
+ |diag| {
diag.span_note(test_span, format!("the {kind_word} was tested here"));
multispan_sugg(
diag,
&format!("try using the `strip_{kind_word}` method"),
- vec![(test_span,
- format!("if let Some(<stripped>) = {}.strip_{kind_word}({}) ",
- snippet(cx, target_arg.span, ".."),
- snippet(cx, pattern.span, "..")))]
- .into_iter().chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))),
+ vec![(
+ test_span,
+ format!(
+ "if let Some(<stripped>) = {}.strip_{kind_word}({}) ",
+ snippet(cx, target_arg.span, ".."),
+ snippet(cx, pattern.span, "..")
+ ),
+ )]
+ .into_iter()
+ .chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))),
);
- });
- }
+ },
+ );
}
}
}
@@ -129,15 +134,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
// Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise.
fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
- if_chain! {
- if let ExprKind::MethodCall(_, arg, [], _) = expr.kind;
- if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if match_def_path(cx, method_def_id, &paths::STR_LEN);
- then {
- Some(arg)
- } else {
- None
- }
+ if let ExprKind::MethodCall(_, arg, [], _) = expr.kind
+ && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && match_def_path(cx, method_def_id, &paths::STR_LEN)
+ {
+ Some(arg)
+ } else {
+ None
}
}
@@ -201,36 +204,38 @@ fn find_stripping<'tcx>(
impl<'a, 'tcx> Visitor<'tcx> for StrippingFinder<'a, 'tcx> {
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
- if_chain! {
- if is_ref_str(self.cx, ex);
- let unref = peel_ref(ex);
- if let ExprKind::Index(indexed, index, _) = &unref.kind;
- if let Some(higher::Range { start, end, .. }) = higher::Range::hir(index);
- if let ExprKind::Path(path) = &indexed.kind;
- if self.cx.qpath_res(path, ex.hir_id) == self.target;
- then {
- match (self.strip_kind, start, end) {
- (StripKind::Prefix, Some(start), None) => {
- if eq_pattern_length(self.cx, self.pattern, start) {
- self.results.push(ex.span);
- return;
- }
- },
- (StripKind::Suffix, None, Some(end)) => {
- if_chain! {
- if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, left, right) = end.kind;
- if let Some(left_arg) = len_arg(self.cx, left);
- if let ExprKind::Path(left_path) = &left_arg.kind;
- if self.cx.qpath_res(left_path, left_arg.hir_id) == self.target;
- if eq_pattern_length(self.cx, self.pattern, right);
- then {
- self.results.push(ex.span);
- return;
- }
- }
- },
- _ => {}
- }
+ if is_ref_str(self.cx, ex)
+ && let unref = peel_ref(ex)
+ && let ExprKind::Index(indexed, index, _) = &unref.kind
+ && let Some(higher::Range { start, end, .. }) = higher::Range::hir(index)
+ && let ExprKind::Path(path) = &indexed.kind
+ && self.cx.qpath_res(path, ex.hir_id) == self.target
+ {
+ match (self.strip_kind, start, end) {
+ (StripKind::Prefix, Some(start), None) => {
+ if eq_pattern_length(self.cx, self.pattern, start) {
+ self.results.push(ex.span);
+ return;
+ }
+ },
+ (StripKind::Suffix, None, Some(end)) => {
+ if let ExprKind::Binary(
+ Spanned {
+ node: BinOpKind::Sub, ..
+ },
+ left,
+ right,
+ ) = end.kind
+ && let Some(left_arg) = len_arg(self.cx, left)
+ && let ExprKind::Path(left_path) = &left_arg.kind
+ && self.cx.qpath_res(left_path, left_arg.hir_id) == self.target
+ && eq_pattern_length(self.cx, self.pattern, right)
+ {
+ self.results.push(ex.span);
+ return;
+ }
+ },
+ _ => {},
}
}
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index 817d072b9..3b82c50a8 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -2,12 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{iter_input_pats, method_chain_args};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, Span};
declare_clippy_lint! {
@@ -163,16 +162,14 @@ fn unit_closure<'tcx>(
cx: &LateContext<'tcx>,
expr: &hir::Expr<'_>,
) -> Option<(&'tcx hir::Param<'tcx>, &'tcx hir::Expr<'tcx>)> {
- if_chain! {
- if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = expr.kind;
- let body = cx.tcx.hir().body(body);
- let body_expr = &body.value;
- if fn_decl.inputs.len() == 1;
- if is_unit_expression(cx, body_expr);
- if let Some(binding) = iter_input_pats(fn_decl, body).next();
- then {
- return Some((binding, body_expr));
- }
+ if let hir::ExprKind::Closure(&hir::Closure { fn_decl, body, .. }) = expr.kind
+ && let body = cx.tcx.hir().body(body)
+ && let body_expr = &body.value
+ && fn_decl.inputs.len() == 1
+ && is_unit_expression(cx, body_expr)
+ && let Some(binding) = iter_input_pats(fn_decl, body).next()
+ {
+ return Some((binding, body_expr));
}
None
}
diff --git a/src/tools/clippy/clippy_lints/src/match_result_ok.rs b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
index 841c020f2..62cedc884 100644
--- a/src/tools/clippy/clippy_lints/src/match_result_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
@@ -2,11 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{higher, is_res_lang_ctor};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem, PatKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -56,33 +55,31 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
return;
};
- if_chain! {
- if let ExprKind::MethodCall(ok_path, recv, [], ..) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
- if let PatKind::TupleStruct(ref pat_path, [ok_pat], _) = let_pat.kind; //get operation
- if ok_path.ident.as_str() == "ok";
- if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
- if is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome);
- let ctxt = expr.span.ctxt();
- if let_expr.span.ctxt() == ctxt;
- if let_pat.span.ctxt() == ctxt;
- then {
- let mut applicability = Applicability::MachineApplicable;
- let some_expr_string = snippet_with_context(cx, ok_pat.span, ctxt, "", &mut applicability).0;
- let trimmed_ok = snippet_with_context(cx, recv.span, ctxt, "", &mut applicability).0;
- let sugg = format!(
- "{ifwhile} let Ok({some_expr_string}) = {}",
- trimmed_ok.trim().trim_end_matches('.'),
- );
- span_lint_and_sugg(
- cx,
- MATCH_RESULT_OK,
- expr.span.with_hi(let_expr.span.hi()),
- "matching on `Some` with `ok()` is redundant",
- &format!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"),
- sugg,
- applicability,
- );
- }
+ if let ExprKind::MethodCall(ok_path, recv, [], ..) = let_expr.kind //check is expr.ok() has type Result<T,E>.ok(, _)
+ && let PatKind::TupleStruct(ref pat_path, [ok_pat], _) = let_pat.kind //get operation
+ && ok_path.ident.as_str() == "ok"
+ && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
+ && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
+ && let ctxt = expr.span.ctxt()
+ && let_expr.span.ctxt() == ctxt
+ && let_pat.span.ctxt() == ctxt
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let some_expr_string = snippet_with_context(cx, ok_pat.span, ctxt, "", &mut applicability).0;
+ let trimmed_ok = snippet_with_context(cx, recv.span, ctxt, "", &mut applicability).0;
+ let sugg = format!(
+ "{ifwhile} let Ok({some_expr_string}) = {}",
+ trimmed_ok.trim().trim_end_matches('.'),
+ );
+ span_lint_and_sugg(
+ cx,
+ MATCH_RESULT_OK,
+ expr.span.with_hi(let_expr.span.hi()),
+ "matching on `Some` with `ok()` is redundant",
+ &format!("consider matching on `Ok({some_expr_string})` and removing the call to `ok` instead"),
+ sugg,
+ applicability,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
index 29b935fb6..48fc5746b 100644
--- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
@@ -5,7 +5,6 @@ use clippy_utils::visitors::is_local_used;
use clippy_utils::{
is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq,
};
-use if_chain::if_chain;
use rustc_errors::MultiSpan;
use rustc_hir::LangItem::OptionNone;
use rustc_hir::{Arm, Expr, Guard, HirId, Let, Pat, PatKind};
@@ -40,76 +39,73 @@ fn check_arm<'tcx>(
outer_else_body: Option<&'tcx Expr<'tcx>>,
) {
let inner_expr = peel_blocks_with_stmt(outer_then_body);
- if_chain! {
- if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr);
- if let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner {
+ if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr)
+ && let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner {
IfLetOrMatch::IfLet(scrutinee, pat, _, els) => Some((scrutinee, pat, els)),
- IfLetOrMatch::Match(scrutinee, arms, ..) => if_chain! {
+ IfLetOrMatch::Match(scrutinee, arms, ..) => if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none())
// if there are more than two arms, collapsing would be non-trivial
- if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none());
// one of the arms must be "wild-like"
- if let Some(wild_idx) = arms.iter().rposition(|a| arm_is_wild_like(cx, a));
- then {
- let (then, els) = (&arms[1 - wild_idx], &arms[wild_idx]);
- Some((scrutinee, then.pat, Some(els.body)))
- } else {
- None
- }
+ && let Some(wild_idx) = arms.iter().rposition(|a| arm_is_wild_like(cx, a))
+ {
+ let (then, els) = (&arms[1 - wild_idx], &arms[wild_idx]);
+ Some((scrutinee, then.pat, Some(els.body)))
+ } else {
+ None
},
- };
- if outer_pat.span.eq_ctxt(inner_scrutinee.span);
+ }
+ && outer_pat.span.eq_ctxt(inner_scrutinee.span)
// match expression must be a local binding
// match <local> { .. }
- if let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee));
- if !pat_contains_or(inner_then_pat);
+ && let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee))
+ && !pat_contains_or(inner_then_pat)
// the binding must come from the pattern of the containing match arm
// ..<local>.. => match <local> { .. }
- if let (Some(binding_span), is_innermost_parent_pat_struct)
- = find_pat_binding_and_is_innermost_parent_pat_struct(outer_pat, binding_id);
+ && let (Some(binding_span), is_innermost_parent_pat_struct)
+ = find_pat_binding_and_is_innermost_parent_pat_struct(outer_pat, binding_id)
// the "else" branches must be equal
- if match (outer_else_body, inner_else_body) {
+ && match (outer_else_body, inner_else_body) {
(None, None) => true,
(None, Some(e)) | (Some(e), None) => is_unit_expr(e),
(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(
+ && 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 {
+ && match inner {
IfLetOrMatch::IfLet(_, _, body, els) => {
!is_local_used(cx, body, binding_id) && els.map_or(true, |e| !is_local_used(cx, e, binding_id))
},
IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| is_local_used(cx, arm, binding_id)),
- };
- then {
- let msg = format!(
- "this `{}` can be collapsed into the outer `{}`",
- if matches!(inner, IfLetOrMatch::Match(..)) { "match" } else { "if let" },
- if outer_is_match { "match" } else { "if let" },
- );
- // collapsing patterns need an explicit field name in struct pattern matching
- // ex: Struct {x: Some(1)}
- let replace_msg = if is_innermost_parent_pat_struct {
- format!(", prefixed by {}:", snippet(cx, binding_span, "their field name"))
+ }
+ {
+ let msg = format!(
+ "this `{}` can be collapsed into the outer `{}`",
+ if matches!(inner, IfLetOrMatch::Match(..)) {
+ "match"
} else {
- String::new()
- };
- span_lint_and_then(
- cx,
- COLLAPSIBLE_MATCH,
- inner_expr.span,
- &msg,
- |diag| {
- let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]);
- help_span.push_span_label(binding_span, "replace this binding");
- help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}"));
- diag.span_help(help_span, "the outer pattern can be modified to include the inner pattern");
- },
+ "if let"
+ },
+ if outer_is_match { "match" } else { "if let" },
+ );
+ // collapsing patterns need an explicit field name in struct pattern matching
+ // ex: Struct {x: Some(1)}
+ let replace_msg = if is_innermost_parent_pat_struct {
+ format!(", prefixed by {}:", snippet(cx, binding_span, "their field name"))
+ } else {
+ String::new()
+ };
+ span_lint_and_then(cx, COLLAPSIBLE_MATCH, inner_expr.span, &msg, |diag| {
+ let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]);
+ help_span.push_span_label(binding_span, "replace this binding");
+ help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}"));
+ diag.span_help(
+ help_span,
+ "the outer pattern can be modified to include the inner pattern",
);
- }
+ });
}
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs b/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
index 3329f93b7..c8a48246e 100644
--- a/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
@@ -8,38 +8,35 @@ use rustc_lint::LateContext;
use super::INFALLIBLE_DESTRUCTURING_MATCH;
pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool {
- if_chain! {
- if !local.span.from_expansion();
- if let Some(expr) = local.init;
- if let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind;
- if arms.len() == 1 && arms[0].guard.is_none();
- if let PatKind::TupleStruct(
- QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
- if args.len() == 1;
- if let PatKind::Binding(binding, arg, ..) = strip_pat_refs(&args[0]).kind;
- let body = peel_blocks(arms[0].body);
- if path_to_local_id(body, arg);
-
- then {
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- INFALLIBLE_DESTRUCTURING_MATCH,
- local.span,
- "you seem to be trying to use `match` to destructure a single infallible pattern. \
- Consider using `let`",
- "try",
- format!(
- "let {}({}{}) = {};",
- snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
- if binding.0 == ByRef::Yes { "ref " } else { "" },
- snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
- snippet_with_applicability(cx, target.span, "..", &mut applicability),
- ),
- applicability,
- );
- return true;
- }
+ if !local.span.from_expansion()
+ && let Some(expr) = local.init
+ && let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind
+ && arms.len() == 1
+ && arms[0].guard.is_none()
+ && let PatKind::TupleStruct(QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind
+ && args.len() == 1
+ && let PatKind::Binding(binding, arg, ..) = strip_pat_refs(&args[0]).kind
+ && let body = peel_blocks(arms[0].body)
+ && path_to_local_id(body, arg)
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ INFALLIBLE_DESTRUCTURING_MATCH,
+ local.span,
+ "you seem to be trying to use `match` to destructure a single infallible pattern. \
+ Consider using `let`",
+ "try",
+ format!(
+ "let {}({}{}) = {};",
+ snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
+ if binding.0 == ByRef::Yes { "ref " } else { "" },
+ snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
+ snippet_with_applicability(cx, target.span, "..", &mut applicability),
+ ),
+ applicability,
+ );
+ return true;
}
false
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
index cdb51c33a..619ec8312 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
@@ -21,19 +21,19 @@ fn get_cond_expr<'tcx>(
expr: &'tcx Expr<'_>,
ctxt: SyntaxContext,
) -> Option<SomeExpr<'tcx>> {
- if_chain! {
- if let Some(block_expr) = peels_blocks_incl_unsafe_opt(expr);
- if let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind;
- if let PatKind::Binding(_,target, ..) = pat.kind;
- if is_some_expr(cx, target, ctxt, then_expr) && is_none_expr(cx, else_expr)
- || is_none_expr(cx, then_expr) && is_some_expr(cx, target, ctxt, else_expr); // check that one expr resolves to `Some(x)`, the other to `None`
- then {
- return Some(SomeExpr {
- expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()),
- needs_unsafe_block: contains_unsafe_block(cx, expr),
- needs_negated: is_none_expr(cx, then_expr) // if the `then_expr` resolves to `None`, need to negate the cond
- })
- }
+ if let Some(block_expr) = peels_blocks_incl_unsafe_opt(expr)
+ && let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind
+ && let PatKind::Binding(_, target, ..) = pat.kind
+ && (is_some_expr(cx, target, ctxt, then_expr) && is_none_expr(cx, else_expr)
+ || is_none_expr(cx, then_expr) && is_some_expr(cx, target, ctxt, else_expr))
+ // check that one expr resolves to `Some(x)`, the other to `None`
+ {
+ return Some(SomeExpr {
+ expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()),
+ needs_unsafe_block: contains_unsafe_block(cx, expr),
+ needs_negated: is_none_expr(cx, then_expr), /* if the `then_expr` resolves to `None`, need to negate the
+ * cond */
+ });
};
None
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
index b94501bf0..3e79cabd7 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -4,7 +4,6 @@ use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::usage::contains_return_break_continue_macro;
use clippy_utils::{is_res_lang_ctor, path_to_local_id, sugg};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::LangItem::{OptionNone, ResultErr};
@@ -16,65 +15,57 @@ use super::MANUAL_UNWRAP_OR;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
let ty = cx.typeck_results().expr_ty(scrutinee);
- if_chain! {
- if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::Option) {
- Some("Option")
- } else if is_type_diagnostic_item(cx, ty, sym::Result) {
- Some("Result")
- } else {
- None
- };
- if let Some(or_arm) = applicable_or_arm(cx, arms);
- if let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span);
- if let Some(indent) = indent_of(cx, expr.span);
- if constant_simple(cx, cx.typeck_results(), or_arm.body).is_some();
- then {
- let reindented_or_body =
- reindent_multiline(or_body_snippet.into(), true, Some(indent));
+ if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::Option) {
+ Some("Option")
+ } else if is_type_diagnostic_item(cx, ty, sym::Result) {
+ Some("Result")
+ } else {
+ None
+ } && let Some(or_arm) = applicable_or_arm(cx, arms)
+ && let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span)
+ && let Some(indent) = indent_of(cx, expr.span)
+ && constant_simple(cx, cx.typeck_results(), or_arm.body).is_some()
+ {
+ let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent));
- let mut app = Applicability::MachineApplicable;
- let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par();
- span_lint_and_sugg(
- cx,
- MANUAL_UNWRAP_OR, expr.span,
- &format!("this pattern reimplements `{ty_name}::unwrap_or`"),
- "replace with",
- format!(
- "{suggestion}.unwrap_or({reindented_or_body})",
- ),
- app,
- );
- }
+ let mut app = Applicability::MachineApplicable;
+ let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par();
+ span_lint_and_sugg(
+ cx,
+ MANUAL_UNWRAP_OR,
+ expr.span,
+ &format!("this pattern reimplements `{ty_name}::unwrap_or`"),
+ "replace with",
+ format!("{suggestion}.unwrap_or({reindented_or_body})",),
+ app,
+ );
}
}
fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> {
- if_chain! {
- if arms.len() == 2;
- if arms.iter().all(|arm| arm.guard.is_none());
- if let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| {
- match arm.pat.kind {
- PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
- PatKind::TupleStruct(ref qpath, [pat], _) =>
- matches!(pat.kind, PatKind::Wild)
- && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr),
- _ => false,
- }
- });
- let unwrap_arm = &arms[1 - idx];
- if let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = unwrap_arm.pat.kind;
- if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, unwrap_arm.pat.hir_id);
- if let Some(variant_id) = cx.tcx.opt_parent(ctor_id);
- if cx.tcx.lang_items().option_some_variant() == Some(variant_id)
- || cx.tcx.lang_items().result_ok_variant() == Some(variant_id);
- if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind;
- if path_to_local_id(unwrap_arm.body, binding_hir_id);
- if cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty();
- if !contains_return_break_continue_macro(or_arm.body);
- then {
- Some(or_arm)
- } else {
- None
- }
+ if arms.len() == 2
+ && arms.iter().all(|arm| arm.guard.is_none())
+ && let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| match arm.pat.kind {
+ PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
+ PatKind::TupleStruct(ref qpath, [pat], _) => {
+ matches!(pat.kind, PatKind::Wild)
+ && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr)
+ },
+ _ => false,
+ })
+ && let unwrap_arm = &arms[1 - idx]
+ && let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = unwrap_arm.pat.kind
+ && let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, unwrap_arm.pat.hir_id)
+ && let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
+ && (cx.tcx.lang_items().option_some_variant() == Some(variant_id)
+ || cx.tcx.lang_items().result_ok_variant() == Some(variant_id))
+ && let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind
+ && path_to_local_id(unwrap_arm.body, binding_hir_id)
+ && cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty()
+ && !contains_return_break_continue_macro(or_arm.body)
+ {
+ Some(or_arm)
+ } else {
+ None
}
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
index 781ee138c..0627e458d 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -127,32 +127,30 @@ where
let closure_expr_snip = some_expr.to_snippet_with_context(cx, expr_ctxt, &mut app);
let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind {
- if_chain! {
- if !some_expr.needs_unsafe_block;
- if let Some(func) = can_pass_as_func(cx, id, some_expr.expr);
- if func.span.eq_ctxt(some_expr.expr.span);
- then {
- snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
- } else {
- if path_to_local_id(some_expr.expr, id)
- && !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id)
- && binding_ref.is_some()
- {
- return None;
- }
+ if !some_expr.needs_unsafe_block
+ && let Some(func) = can_pass_as_func(cx, id, some_expr.expr)
+ && func.span.eq_ctxt(some_expr.expr.span)
+ {
+ snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
+ } else {
+ if path_to_local_id(some_expr.expr, id)
+ && !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id)
+ && binding_ref.is_some()
+ {
+ return None;
+ }
- // `ref` and `ref mut` annotations were handled earlier.
- let annotation = if matches!(annotation, BindingAnnotation::MUT) {
- "mut "
- } else {
- ""
- };
+ // `ref` and `ref mut` annotations were handled earlier.
+ let annotation = if matches!(annotation, BindingAnnotation::MUT) {
+ "mut "
+ } else {
+ ""
+ };
- if some_expr.needs_unsafe_block {
- format!("|{annotation}{some_binding}| unsafe {{ {closure_expr_snip} }}")
- } else {
- format!("|{annotation}{some_binding}| {closure_expr_snip}")
- }
+ if some_expr.needs_unsafe_block {
+ format!("|{annotation}{some_binding}| unsafe {{ {closure_expr_snip} }}")
+ } else {
+ format!("|{annotation}{some_binding}| {closure_expr_snip}")
}
}
} else if !is_wild_none && explicit_ref.is_none() {
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
index d51cca040..3f737da92 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
@@ -26,18 +26,16 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
let output_ty = cx.typeck_results().expr_ty(expr);
let input_ty = cx.typeck_results().expr_ty(ex);
- let cast = if_chain! {
- if let ty::Adt(_, args) = input_ty.kind();
- let input_ty = args.type_at(0);
- if let ty::Adt(_, args) = output_ty.kind();
- let output_ty = args.type_at(0);
- if let ty::Ref(_, output_ty, _) = *output_ty.kind();
- if input_ty != output_ty;
- then {
- ".map(|x| x as _)"
- } else {
- ""
- }
+ let cast = if let ty::Adt(_, args) = input_ty.kind()
+ && let input_ty = args.type_at(0)
+ && let ty::Adt(_, args) = output_ty.kind()
+ && let output_ty = args.type_at(0)
+ && let ty::Ref(_, output_ty, _) = *output_ty.kind()
+ && input_ty != output_ty
+ {
+ ".map(|x| x as _)"
+ } else {
+ ""
};
let mut applicability = Applicability::MachineApplicable;
@@ -67,17 +65,16 @@ fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
// Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
- if_chain! {
- if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind;
- if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome);
- if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind;
- if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind;
- if is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome);
- if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind;
- if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
- then {
- return Some(mutabl)
- }
+ if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind
+ && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome)
+ && let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind
+ && let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind
+ && is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome)
+ && let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind
+ && path2.segments.len() == 1
+ && ident.name == path2.segments[0].ident.name
+ {
+ return Some(mutabl);
}
None
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
index e2ddf11ab..56123326f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
@@ -76,79 +76,80 @@ where
),
>,
{
- if_chain! {
- if !span_contains_comment(cx.sess().source_map(), expr.span);
- if iter.len() >= 2;
- if cx.typeck_results().expr_ty(expr).is_bool();
- if let Some((_, last_pat_opt, last_expr, _)) = iter.next_back();
- let iter_without_last = iter.clone();
- if let Some((first_attrs, _, first_expr, first_guard)) = iter.next();
- if let Some(b0) = find_bool_lit(&first_expr.kind);
- if let Some(b1) = find_bool_lit(&last_expr.kind);
- if b0 != b1;
- if first_guard.is_none() || iter.len() == 0;
- if first_attrs.is_empty();
- if iter
- .all(|arm| {
- find_bool_lit(&arm.2.kind).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty()
- });
- then {
- if let Some(last_pat) = last_pat_opt {
- if !is_wild(last_pat) {
- return false;
- }
+ if !span_contains_comment(cx.sess().source_map(), expr.span)
+ && iter.len() >= 2
+ && cx.typeck_results().expr_ty(expr).is_bool()
+ && let Some((_, last_pat_opt, last_expr, _)) = iter.next_back()
+ && let iter_without_last = iter.clone()
+ && let Some((first_attrs, _, first_expr, first_guard)) = iter.next()
+ && let Some(b0) = find_bool_lit(&first_expr.kind)
+ && let Some(b1) = find_bool_lit(&last_expr.kind)
+ && b0 != b1
+ && (first_guard.is_none() || iter.len() == 0)
+ && first_attrs.is_empty()
+ && iter.all(|arm| find_bool_lit(&arm.2.kind).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty())
+ {
+ if let Some(last_pat) = last_pat_opt {
+ if !is_wild(last_pat) {
+ return false;
}
+ }
- for arm in iter_without_last.clone() {
- if let Some(pat) = arm.1 {
- if !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, pat.hir_id) && is_some(pat.kind) {
- return false;
- }
+ for arm in iter_without_last.clone() {
+ if let Some(pat) = arm.1 {
+ if !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, pat.hir_id) && is_some(pat.kind) {
+ return false;
}
}
+ }
- // The suggestion may be incorrect, because some arms can have `cfg` attributes
- // evaluated into `false` and so such arms will be stripped before.
- let mut applicability = Applicability::MaybeIncorrect;
- let pat = {
- use itertools::Itertools as _;
- iter_without_last
- .filter_map(|arm| {
- let pat_span = arm.1?.span;
- Some(snippet_with_applicability(cx, pat_span, "..", &mut applicability))
- })
- .join(" | ")
- };
- let pat_and_guard = if let Some(Guard::If(g)) = first_guard {
- format!("{pat} if {}", snippet_with_applicability(cx, g.span, "..", &mut applicability))
- } else {
- pat
- };
-
- // strip potential borrows (#6503), but only if the type is a reference
- let mut ex_new = ex;
- if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind {
- if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() {
- ex_new = ex_inner;
- }
- };
- span_lint_and_sugg(
- cx,
- MATCH_LIKE_MATCHES_MACRO,
- expr.span,
- &format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }),
- "try",
- format!(
- "{}matches!({}, {pat_and_guard})",
- if b0 { "" } else { "!" },
- snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
- ),
- applicability,
- );
- true
+ // The suggestion may be incorrect, because some arms can have `cfg` attributes
+ // evaluated into `false` and so such arms will be stripped before.
+ let mut applicability = Applicability::MaybeIncorrect;
+ let pat = {
+ use itertools::Itertools as _;
+ iter_without_last
+ .filter_map(|arm| {
+ let pat_span = arm.1?.span;
+ Some(snippet_with_applicability(cx, pat_span, "..", &mut applicability))
+ })
+ .join(" | ")
+ };
+ let pat_and_guard = if let Some(Guard::If(g)) = first_guard {
+ format!(
+ "{pat} if {}",
+ snippet_with_applicability(cx, g.span, "..", &mut applicability)
+ )
} else {
- false
- }
+ pat
+ };
+
+ // strip potential borrows (#6503), but only if the type is a reference
+ let mut ex_new = ex;
+ if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind {
+ if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() {
+ ex_new = ex_inner;
+ }
+ };
+ span_lint_and_sugg(
+ cx,
+ MATCH_LIKE_MATCHES_MACRO,
+ expr.span,
+ &format!(
+ "{} expression looks like `matches!` macro",
+ if is_if_let { "if let .. else" } else { "match" }
+ ),
+ "try",
+ format!(
+ "{}matches!({}, {pat_and_guard})",
+ if b0 { "" } else { "!" },
+ snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
+ ),
+ applicability,
+ );
+ true
+ } else {
+ false
}
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs b/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs
index bd53ebd48..dd71560e1 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem};
use rustc_lint::LateContext;
@@ -10,39 +9,29 @@ use rustc_span::sym;
use super::MATCH_ON_VEC_ITEMS;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) {
- if_chain! {
- if let Some(idx_expr) = is_vec_indexing(cx, scrutinee);
- if let ExprKind::Index(vec, idx, _) = idx_expr.kind;
-
- then {
- // FIXME: could be improved to suggest surrounding every pattern with Some(_),
- // but only when `or_patterns` are stabilized.
- span_lint_and_sugg(
- cx,
- MATCH_ON_VEC_ITEMS,
- scrutinee.span,
- "indexing into a vector may panic",
- "try",
- format!(
- "{}.get({})",
- snippet(cx, vec.span, ".."),
- snippet(cx, idx.span, "..")
- ),
- Applicability::MaybeIncorrect
- );
- }
+ if let Some(idx_expr) = is_vec_indexing(cx, scrutinee)
+ && let ExprKind::Index(vec, idx, _) = idx_expr.kind
+ {
+ // FIXME: could be improved to suggest surrounding every pattern with Some(_),
+ // but only when `or_patterns` are stabilized.
+ span_lint_and_sugg(
+ cx,
+ MATCH_ON_VEC_ITEMS,
+ scrutinee.span,
+ "indexing into a vector may panic",
+ "try",
+ format!("{}.get({})", snippet(cx, vec.span, ".."), snippet(cx, idx.span, "..")),
+ Applicability::MaybeIncorrect,
+ );
}
}
fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
- if_chain! {
- if let ExprKind::Index(array, index, _) = expr.kind;
- if is_vector(cx, array);
- if !is_full_range(cx, index);
-
- then {
- return Some(expr);
- }
+ if let ExprKind::Index(array, index, _) = expr.kind
+ && is_vector(cx, array)
+ && !is_full_range(cx, index)
+ {
+ return Some(expr);
}
None
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 6fc79fadd..c823d07e2 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::source::snippet;
use clippy_utils::{is_lint_allowed, path_to_local, search_same, SpanlessEq, SpanlessHash};
use core::cmp::Ordering;
@@ -66,25 +66,23 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
let mut local_map: HirIdMap<HirId> = HirIdMap::default();
let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
- if_chain! {
- if let Some(a_id) = path_to_local(a);
- if let Some(b_id) = path_to_local(b);
- let entry = match local_map.entry(a_id) {
+ if let Some(a_id) = path_to_local(a)
+ && let Some(b_id) = path_to_local(b)
+ && let entry = match local_map.entry(a_id) {
HirIdMapEntry::Vacant(entry) => entry,
// check if using the same bindings as before
HirIdMapEntry::Occupied(entry) => return *entry.get() == b_id,
- };
- // the names technically don't have to match; this makes the lint more conservative
- if cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id);
- if cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b);
- if pat_contains_local(lhs.pat, a_id);
- if pat_contains_local(rhs.pat, b_id);
- then {
- entry.insert(b_id);
- true
- } else {
- false
}
+ // the names technically don't have to match; this makes the lint more conservative
+ && cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id)
+ && cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b)
+ && pat_contains_local(lhs.pat, a_id)
+ && pat_contains_local(rhs.pat, b_id)
+ {
+ entry.insert(b_id);
+ true
+ } else {
+ false
}
};
// Arms with a guard are ignored, those can’t always be merged together
@@ -106,9 +104,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
if !cx.tcx.features().non_exhaustive_omitted_patterns_lint
|| is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id)
{
- span_lint_and_then(
+ span_lint_hir_and_then(
cx,
MATCH_SAME_ARMS,
+ arm1.hir_id,
arm1.span,
"this match arm has an identical body to the `_` wildcard arm",
|diag| {
@@ -126,9 +125,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
(arm2, arm1)
};
- span_lint_and_then(
+ span_lint_hir_and_then(
cx,
MATCH_SAME_ARMS,
+ keep_arm.hir_id,
keep_arm.span,
"this match arm has an identical body to another arm",
|diag| {
@@ -152,6 +152,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
#[derive(Clone, Copy)]
enum NormalizedPat<'a> {
Wild,
+ Never,
Struct(Option<DefId>, &'a [(Symbol, Self)]),
Tuple(Option<DefId>, &'a [Self]),
Or(&'a [Self]),
@@ -223,7 +224,7 @@ fn iter_matching_struct_fields<'a>(
Iter(left.iter(), right.iter())
}
-#[expect(clippy::similar_names)]
+#[expect(clippy::similar_names, clippy::too_many_lines)]
impl<'a> NormalizedPat<'a> {
fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self {
match pat.kind {
@@ -231,6 +232,7 @@ impl<'a> NormalizedPat<'a> {
PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Ref(pat, _) => {
Self::from_pat(cx, arena, pat)
},
+ PatKind::Never => Self::Never,
PatKind::Struct(ref path, fields, _) => {
let fields =
arena.alloc_from_iter(fields.iter().map(|f| (f.ident.name, Self::from_pat(cx, arena, f.pat))));
@@ -334,7 +336,7 @@ impl<'a> NormalizedPat<'a> {
/// type.
fn has_overlapping_values(&self, other: &Self) -> bool {
match (*self, *other) {
- (Self::Wild, _) | (_, Self::Wild) => true,
+ (Self::Wild, _) | (_, Self::Wild) | (Self::Never, Self::Never) => true,
(Self::Or(pats), ref other) | (ref other, Self::Or(pats)) => {
pats.iter().any(|pat| pat.has_overlapping_values(other))
},
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
index 675a85ae5..bd38648bc 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -20,21 +20,16 @@ enum CaseMethod {
}
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
- if_chain! {
- if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(scrutinee).kind();
- if let ty::Str = ty.kind();
- then {
- let mut visitor = MatchExprVisitor {
- cx,
- case_method: None,
- };
-
- visitor.visit_expr(scrutinee);
-
- if let Some(case_method) = visitor.case_method {
- if let Some((bad_case_span, bad_case_sym)) = verify_case(&case_method, arms) {
- lint(cx, &case_method, bad_case_span, bad_case_sym.as_str());
- }
+ if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(scrutinee).kind()
+ && let ty::Str = ty.kind()
+ {
+ let mut visitor = MatchExprVisitor { cx, case_method: None };
+
+ visitor.visit_expr(scrutinee);
+
+ if let Some(case_method) = visitor.case_method {
+ if let Some((bad_case_span, bad_case_sym)) = verify_case(&case_method, arms) {
+ lint(cx, &case_method, bad_case_span, bad_case_sym.as_str());
}
}
}
@@ -88,17 +83,15 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(
};
for arm in arms {
- if_chain! {
- if let PatKind::Lit(Expr {
- kind: ExprKind::Lit(lit),
- ..
- }) = arm.pat.kind;
- if let LitKind::Str(symbol, _) = lit.node;
- let input = symbol.as_str();
- if !case_check(input);
- then {
- return Some((lit.span, symbol));
- }
+ if let PatKind::Lit(Expr {
+ kind: ExprKind::Lit(lit),
+ ..
+ }) = arm.pat.kind
+ && let LitKind::Str(symbol, _) = lit.node
+ && let input = symbol.as_str()
+ && !case_check(input)
+ {
+ return Some((lit.span, symbol));
}
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
index a2903e52a..8a4c0ab90 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
@@ -34,20 +34,19 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'
}
}
}
- if_chain! {
- if matching_wild;
- if let Some(macro_call) = root_macro_call(peel_blocks_with_stmt(arm.body).span);
- if is_panic(cx, macro_call.def_id);
- then {
- // `Err(_)` or `Err(_e)` arm with `panic!` found
- span_lint_and_note(cx,
- MATCH_WILD_ERR_ARM,
- arm.pat.span,
- &format!("`Err({ident_bind_name})` matches all errors"),
- None,
- "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable",
- );
- }
+ if matching_wild
+ && let Some(macro_call) = root_macro_call(peel_blocks_with_stmt(arm.body).span)
+ && is_panic(cx, macro_call.def_id)
+ {
+ // `Err(_)` or `Err(_e)` arm with `panic!` found
+ span_lint_and_note(
+ cx,
+ MATCH_WILD_ERR_ARM,
+ arm.pat.span,
+ &format!("`Err({ident_bind_name})` matches all errors"),
+ None,
+ "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index dea46d4d3..4c7568f39 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -31,7 +31,7 @@ use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
use rustc_lexer::TokenKind;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{Span, SpanData, SyntaxContext};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
index 8f0083f81..8199366d1 100644
--- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
@@ -150,7 +150,7 @@ where
#[test]
fn test_overlapping() {
- use rustc_span::source_map::DUMMY_SP;
+ use rustc_span::DUMMY_SP;
let sp = |s, e| SpannedRange {
span: DUMMY_SP,
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
index 4a44d596a..f57b22374 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::path_to_local;
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::source::snippet;
use clippy_utils::visitors::{for_each_expr, is_local_used};
use rustc_ast::{BorrowKind, LitKind};
use rustc_errors::Applicability;
@@ -8,7 +8,8 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, Guard, MatchSource, Node, Pat, PatKind};
use rustc_lint::LateContext;
use rustc_span::symbol::Ident;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
+use std::borrow::Cow;
use std::ops::ControlFlow;
use super::REDUNDANT_GUARDS;
@@ -41,7 +42,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
(PatKind::Ref(..), None) | (_, Some(_)) => continue,
_ => arm.pat.span,
};
- emit_redundant_guards(cx, outer_arm, if_expr.span, pat_span, &binding, arm.guard);
+ emit_redundant_guards(
+ cx,
+ outer_arm,
+ if_expr.span,
+ snippet(cx, pat_span, "<binding>"),
+ &binding,
+ arm.guard,
+ );
}
// `Some(x) if let Some(2) = x`
else if let Guard::IfLet(let_expr) = guard
@@ -52,7 +60,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
(PatKind::Ref(..), None) | (_, Some(_)) => continue,
_ => let_expr.pat.span,
};
- emit_redundant_guards(cx, outer_arm, let_expr.span, pat_span, &binding, None);
+ emit_redundant_guards(
+ cx,
+ outer_arm,
+ let_expr.span,
+ snippet(cx, pat_span, "<binding>"),
+ &binding,
+ None,
+ );
}
// `Some(x) if x == Some(2)`
// `Some(x) if Some(2) == x`
@@ -78,11 +93,76 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
(ExprKind::AddrOf(..), None) | (_, Some(_)) => continue,
_ => pat.span,
};
- emit_redundant_guards(cx, outer_arm, if_expr.span, pat_span, &binding, None);
+ emit_redundant_guards(
+ cx,
+ outer_arm,
+ if_expr.span,
+ snippet(cx, pat_span, "<binding>"),
+ &binding,
+ None,
+ );
+ } else if let Guard::If(if_expr) = guard
+ && let ExprKind::MethodCall(path, recv, args, ..) = if_expr.kind
+ && let Some(binding) = get_pat_binding(cx, recv, outer_arm)
+ {
+ check_method_calls(cx, outer_arm, path.ident.name, recv, args, if_expr, &binding);
}
}
}
+fn check_method_calls<'tcx>(
+ cx: &LateContext<'tcx>,
+ arm: &Arm<'tcx>,
+ method: Symbol,
+ recv: &Expr<'_>,
+ args: &[Expr<'_>],
+ if_expr: &Expr<'_>,
+ binding: &PatBindingInfo,
+) {
+ let ty = cx.typeck_results().expr_ty(recv).peel_refs();
+ let slice_like = ty.is_slice() || ty.is_array();
+
+ let sugg = if method == sym!(is_empty) {
+ // `s if s.is_empty()` becomes ""
+ // `arr if arr.is_empty()` becomes []
+
+ if ty.is_str() {
+ r#""""#.into()
+ } else if slice_like {
+ "[]".into()
+ } else {
+ return;
+ }
+ } else if slice_like
+ && let Some(needle) = args.first()
+ && let ExprKind::AddrOf(.., needle) = needle.kind
+ && let ExprKind::Array(needles) = needle.kind
+ && needles.iter().all(|needle| expr_can_be_pat(cx, needle))
+ {
+ // `arr if arr.starts_with(&[123])` becomes [123, ..]
+ // `arr if arr.ends_with(&[123])` becomes [.., 123]
+ // `arr if arr.starts_with(&[])` becomes [..] (why would anyone write this?)
+
+ let mut sugg = snippet(cx, needle.span, "<needle>").into_owned();
+
+ if needles.is_empty() {
+ sugg.insert_str(1, "..");
+ } else if method == sym!(starts_with) {
+ sugg.insert_str(sugg.len() - 1, ", ..");
+ } else if method == sym!(ends_with) {
+ sugg.insert_str(1, ".., ");
+ } else {
+ return;
+ }
+
+ sugg.into()
+ } else {
+ return;
+ };
+
+ emit_redundant_guards(cx, arm, if_expr.span, sugg, binding, None);
+}
+
struct PatBindingInfo {
span: Span,
byref_ident: Option<Ident>,
@@ -134,19 +214,16 @@ fn emit_redundant_guards<'tcx>(
cx: &LateContext<'tcx>,
outer_arm: &Arm<'tcx>,
guard_span: Span,
- pat_span: Span,
+ binding_replacement: Cow<'static, str>,
pat_binding: &PatBindingInfo,
inner_guard: Option<Guard<'_>>,
) {
- let mut app = Applicability::MaybeIncorrect;
-
span_lint_and_then(
cx,
REDUNDANT_GUARDS,
guard_span.source_callsite(),
"redundant guard",
|diag| {
- let binding_replacement = snippet_with_applicability(cx, pat_span, "<binding_repl>", &mut app);
let suggestion_span = match *pat_binding {
PatBindingInfo {
span,
@@ -170,14 +247,11 @@ fn emit_redundant_guards<'tcx>(
Guard::IfLet(l) => ("if let", l.span),
};
- format!(
- " {prefix} {}",
- snippet_with_applicability(cx, span, "<guard>", &mut app),
- )
+ format!(" {prefix} {}", snippet(cx, span, "<guard>"))
}),
),
],
- app,
+ Applicability::MaybeIncorrect,
);
},
);
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index 9a7c00823..2582f7edc 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -5,7 +5,6 @@ use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr};
use clippy_utils::{higher, is_expn_of, is_trait_method};
-use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
@@ -35,15 +34,13 @@ pub(super) fn check_if_let<'tcx>(
// Extract the generic arguments out of a type
fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
- if_chain! {
- if let ty::Adt(_, subs) = ty.kind();
- if let Some(sub) = subs.get(index);
- if let GenericArgKind::Type(sub_ty) = sub.unpack();
- then {
- Some(sub_ty)
- } else {
- None
- }
+ if let ty::Adt(_, subs) = ty.kind()
+ && let Some(sub) = subs.get(index)
+ && let GenericArgKind::Type(sub_ty) = sub.unpack()
+ {
+ Some(sub_ty)
+ } else {
+ None
}
}
@@ -142,14 +139,12 @@ fn find_sugg_for_if_let<'tcx>(
let needs_drop = needs_ordered_drop(cx, check_ty) || any_temporaries_need_ordered_drop(cx, let_expr);
// check that `while_let_on_iterator` lint does not trigger
- if_chain! {
- if keyword == "while";
- if let ExprKind::MethodCall(method_path, ..) = let_expr.kind;
- if method_path.ident.name == sym::next;
- if is_trait_method(cx, let_expr, sym::Iterator);
- then {
- return;
- }
+ if keyword == "while"
+ && let ExprKind::MethodCall(method_path, ..) = let_expr.kind
+ && method_path.ident.name == sym::next
+ && is_trait_method(cx, let_expr, sym::Iterator)
+ {
+ return;
}
let result_expr = match &let_expr.kind {
diff --git a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
index 4efe93d4b..316b2f63e 100644
--- a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
@@ -6,25 +6,22 @@ use rustc_middle::ty;
use super::REST_PAT_IN_FULLY_BOUND_STRUCTS;
pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) {
- if_chain! {
- if !pat.span.from_expansion();
- if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind;
- if let Some(def_id) = path.res.opt_def_id();
- let ty = cx.tcx.type_of(def_id).instantiate_identity();
- if let ty::Adt(def, _) = ty.kind();
- if def.is_struct() || def.is_union();
- if fields.len() == def.non_enum_variant().fields.len();
- if !def.non_enum_variant().is_field_list_non_exhaustive();
-
- then {
- span_lint_and_help(
- cx,
- REST_PAT_IN_FULLY_BOUND_STRUCTS,
- pat.span,
- "unnecessary use of `..` pattern in struct binding. All fields were already bound",
- None,
- "consider removing `..` from this binding",
- );
- }
+ if !pat.span.from_expansion()
+ && let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind
+ && let Some(def_id) = path.res.opt_def_id()
+ && let ty = cx.tcx.type_of(def_id).instantiate_identity()
+ && let ty::Adt(def, _) = ty.kind()
+ && (def.is_struct() || def.is_union())
+ && fields.len() == def.non_enum_variant().fields.len()
+ && !def.non_enum_variant().is_field_list_non_exhaustive()
+ {
+ span_lint_and_help(
+ cx,
+ REST_PAT_IN_FULLY_BOUND_STRUCTS,
+ pat.span,
+ "unnecessary use of `..` pattern in struct binding. All fields were already bound",
+ None,
+ "consider removing `..` from this binding",
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 48efd0230..86c414daf 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -89,50 +89,52 @@ fn report_single_pattern(
});
let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat);
- let (msg, sugg) = if_chain! {
- if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind;
- let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex));
- if let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait();
- if let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait();
- if ty.is_integral() || ty.is_char() || ty.is_str()
- || (implements_trait(cx, ty, spe_trait_id, &[])
- && implements_trait(cx, ty, pe_trait_id, &[ty.into()]));
- then {
- // scrutinee derives PartialEq and the pattern is a constant.
- let pat_ref_count = match pat.kind {
- // string literals are already a reference.
- PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. }) if lit.node.is_str() => pat_ref_count + 1,
- _ => pat_ref_count,
- };
- // References are only implicitly added to the pattern, so no overflow here.
- // e.g. will work: match &Some(_) { Some(_) => () }
- // will not: match Some(_) { &Some(_) => () }
- let ref_count_diff = ty_ref_count - pat_ref_count;
-
- // Try to remove address of expressions first.
- let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff);
- let ref_count_diff = ref_count_diff - removed;
-
- let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`";
- let sugg = format!(
- "if {} == {}{} {}{els_str}",
- snippet(cx, ex.span, ".."),
- // PartialEq for different reference counts may not exist.
- "&".repeat(ref_count_diff),
- snippet(cx, arms[0].pat.span, ".."),
- expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app),
- );
- (msg, sugg)
- } else {
- let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`";
- let sugg = format!(
- "if let {} = {} {}{els_str}",
- snippet(cx, arms[0].pat.span, ".."),
- snippet(cx, ex.span, ".."),
- expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app),
- );
- (msg, sugg)
- }
+ let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind
+ && let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex))
+ && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
+ && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
+ && (ty.is_integral()
+ || ty.is_char()
+ || ty.is_str()
+ || (implements_trait(cx, ty, spe_trait_id, &[]) && implements_trait(cx, ty, pe_trait_id, &[ty.into()])))
+ {
+ // scrutinee derives PartialEq and the pattern is a constant.
+ let pat_ref_count = match pat.kind {
+ // string literals are already a reference.
+ PatKind::Lit(Expr {
+ kind: ExprKind::Lit(lit),
+ ..
+ }) if lit.node.is_str() => pat_ref_count + 1,
+ _ => pat_ref_count,
+ };
+ // References are only implicitly added to the pattern, so no overflow here.
+ // e.g. will work: match &Some(_) { Some(_) => () }
+ // will not: match Some(_) { &Some(_) => () }
+ let ref_count_diff = ty_ref_count - pat_ref_count;
+
+ // Try to remove address of expressions first.
+ let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff);
+ let ref_count_diff = ref_count_diff - removed;
+
+ let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`";
+ let sugg = format!(
+ "if {} == {}{} {}{els_str}",
+ snippet(cx, ex.span, ".."),
+ // PartialEq for different reference counts may not exist.
+ "&".repeat(ref_count_diff),
+ snippet(cx, arms[0].pat.span, ".."),
+ expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app),
+ );
+ (msg, sugg)
+ } else {
+ let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`";
+ let sugg = format!(
+ "if let {} = {} {}{els_str}",
+ snippet(cx, arms[0].pat.span, ".."),
+ snippet(cx, ex.span, ".."),
+ expr_block(cx, arms[0].body, ctxt, "..", Some(expr.span), &mut app),
+ );
+ (msg, sugg)
};
span_lint_and_sugg(cx, lint, expr.span, msg, "try", sugg, app);
diff --git a/src/tools/clippy/clippy_lints/src/matches/try_err.rs b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
index 0fd6f533d..dd489fc25 100644
--- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::ResultErr;
use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath};
@@ -22,59 +21,57 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
// #[allow(unreachable_code)]
// val,
// };
- if_chain! {
- if let ExprKind::Call(match_fun, [try_arg, ..]) = scrutinee.kind;
- if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
- if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..));
- if let ExprKind::Call(err_fun, [err_arg, ..]) = try_arg.kind;
- if is_res_lang_ctor(cx, path_res(cx, err_fun), ResultErr);
- if let Some(return_ty) = find_return_type(cx, &expr.kind);
- then {
- let prefix;
- let suffix;
- let err_ty;
+ if let ExprKind::Call(match_fun, [try_arg, ..]) = scrutinee.kind
+ && let ExprKind::Path(ref match_fun_path) = match_fun.kind
+ && matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..))
+ && let ExprKind::Call(err_fun, [err_arg, ..]) = try_arg.kind
+ && is_res_lang_ctor(cx, path_res(cx, err_fun), ResultErr)
+ && let Some(return_ty) = find_return_type(cx, &expr.kind)
+ {
+ let prefix;
+ let suffix;
+ let err_ty;
- if let Some(ty) = result_error_type(cx, return_ty) {
- prefix = "Err(";
- suffix = ")";
- err_ty = ty;
- } else if let Some(ty) = poll_result_error_type(cx, return_ty) {
- prefix = "Poll::Ready(Err(";
- suffix = "))";
- err_ty = ty;
- } else if let Some(ty) = poll_option_result_error_type(cx, return_ty) {
- prefix = "Poll::Ready(Some(Err(";
- suffix = ")))";
- err_ty = ty;
- } else {
- return;
- };
+ if let Some(ty) = result_error_type(cx, return_ty) {
+ prefix = "Err(";
+ suffix = ")";
+ err_ty = ty;
+ } else if let Some(ty) = poll_result_error_type(cx, return_ty) {
+ prefix = "Poll::Ready(Err(";
+ suffix = "))";
+ err_ty = ty;
+ } else if let Some(ty) = poll_option_result_error_type(cx, return_ty) {
+ prefix = "Poll::Ready(Some(Err(";
+ suffix = ")))";
+ err_ty = ty;
+ } else {
+ return;
+ };
- let expr_err_ty = cx.typeck_results().expr_ty(err_arg);
- let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt());
- let mut applicability = Applicability::MachineApplicable;
- let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability);
- let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) {
- "" // already returns
- } else {
- "return "
- };
- let suggestion = if err_ty == expr_err_ty {
- format!("{ret_prefix}{prefix}{origin_snippet}{suffix}")
- } else {
- format!("{ret_prefix}{prefix}{origin_snippet}.into(){suffix}")
- };
+ let expr_err_ty = cx.typeck_results().expr_ty(err_arg);
+ let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt());
+ let mut applicability = Applicability::MachineApplicable;
+ let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability);
+ let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) {
+ "" // already returns
+ } else {
+ "return "
+ };
+ let suggestion = if err_ty == expr_err_ty {
+ format!("{ret_prefix}{prefix}{origin_snippet}{suffix}")
+ } else {
+ format!("{ret_prefix}{prefix}{origin_snippet}.into(){suffix}")
+ };
- span_lint_and_sugg(
- cx,
- TRY_ERR,
- expr.span,
- "returning an `Err(_)` with the `?` operator",
- "try",
- suggestion,
- applicability,
- );
- }
+ span_lint_and_sugg(
+ cx,
+ TRY_ERR,
+ expr.span,
+ "returning an `Err(_)` with the `?` operator",
+ "try",
+ suggestion,
+ applicability,
+ );
}
}
@@ -92,51 +89,42 @@ fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> O
/// Extracts the error type from Result<T, E>.
fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
- if_chain! {
- if let ty::Adt(_, subst) = ty.kind();
- if is_type_diagnostic_item(cx, ty, sym::Result);
- then {
- Some(subst.type_at(1))
- } else {
- None
- }
+ if let ty::Adt(_, subst) = ty.kind()
+ && is_type_diagnostic_item(cx, ty, sym::Result)
+ {
+ Some(subst.type_at(1))
+ } else {
+ None
}
}
/// Extracts the error type from Poll<Result<T, E>>.
fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
- if_chain! {
- if let ty::Adt(def, subst) = ty.kind();
- if cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did());
- let ready_ty = subst.type_at(0);
-
- if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
- if cx.tcx.is_diagnostic_item(sym::Result, ready_def.did());
- then {
- Some(ready_subst.type_at(1))
- } else {
- None
- }
+ if let ty::Adt(def, subst) = ty.kind()
+ && cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did())
+ && let ready_ty = subst.type_at(0)
+ && let ty::Adt(ready_def, ready_subst) = ready_ty.kind()
+ && cx.tcx.is_diagnostic_item(sym::Result, ready_def.did())
+ {
+ Some(ready_subst.type_at(1))
+ } else {
+ None
}
}
/// Extracts the error type from Poll<Option<Result<T, E>>>.
fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
- if_chain! {
- if let ty::Adt(def, subst) = ty.kind();
- if cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did());
- let ready_ty = subst.type_at(0);
-
- if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
- if cx.tcx.is_diagnostic_item(sym::Option, ready_def.did());
- let some_ty = ready_subst.type_at(0);
-
- if let ty::Adt(some_def, some_subst) = some_ty.kind();
- if cx.tcx.is_diagnostic_item(sym::Result, some_def.did());
- then {
- Some(some_subst.type_at(1))
- } else {
- None
- }
+ if let ty::Adt(def, subst) = ty.kind()
+ && cx.tcx.lang_items().get(LangItem::Poll) == Some(def.did())
+ && let ready_ty = subst.type_at(0)
+ && let ty::Adt(ready_def, ready_subst) = ready_ty.kind()
+ && cx.tcx.is_diagnostic_item(sym::Option, ready_def.did())
+ && let some_ty = ready_subst.type_at(0)
+ && let ty::Adt(some_def, some_subst) = some_ty.kind()
+ && cx.tcx.is_diagnostic_item(sym::Result, some_def.did())
+ {
+ Some(some_subst.type_at(1))
+ } else {
+ None
}
}
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index 760c8f59c..c22f76484 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -4,15 +4,14 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_non_aggregate_primitive_type;
use clippy_utils::{is_default_equivalent, is_res_lang_ctor, path_res, peel_ref_operators};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::Span;
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::sym;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
@@ -125,17 +124,37 @@ fn check_replace_option_with_none(cx: &LateContext<'_>, dest: &Expr<'_>, expr_sp
}
fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) {
- if_chain! {
+ if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(src.hir_id)
// check if replacement is mem::MaybeUninit::uninit().assume_init()
- if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(src.hir_id);
- if cx.tcx.is_diagnostic_item(sym::assume_init, method_def_id);
- then {
+ && cx.tcx.is_diagnostic_item(sym::assume_init, method_def_id)
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ MEM_REPLACE_WITH_UNINIT,
+ expr_span,
+ "replacing with `mem::MaybeUninit::uninit().assume_init()`",
+ "consider using",
+ format!(
+ "std::ptr::read({})",
+ snippet_with_applicability(cx, dest.span, "", &mut applicability)
+ ),
+ applicability,
+ );
+ return;
+ }
+
+ if let ExprKind::Call(repl_func, []) = src.kind
+ && let ExprKind::Path(ref repl_func_qpath) = repl_func.kind
+ && let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id()
+ {
+ if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
MEM_REPLACE_WITH_UNINIT,
expr_span,
- "replacing with `mem::MaybeUninit::uninit().assume_init()`",
+ "replacing with `mem::uninitialized()`",
"consider using",
format!(
"std::ptr::read({})",
@@ -143,40 +162,17 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'
),
applicability,
);
- return;
- }
- }
-
- if_chain! {
- if let ExprKind::Call(repl_func, []) = src.kind;
- if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
- if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
- then {
- if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) {
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- MEM_REPLACE_WITH_UNINIT,
- expr_span,
- "replacing with `mem::uninitialized()`",
- "consider using",
- format!(
- "std::ptr::read({})",
- snippet_with_applicability(cx, dest.span, "", &mut applicability)
- ),
- applicability,
- );
- } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) &&
- !cx.typeck_results().expr_ty(src).is_primitive() {
- span_lint_and_help(
- cx,
- MEM_REPLACE_WITH_UNINIT,
- expr_span,
- "replacing with `mem::zeroed()`",
- None,
- "consider using a default value or the `take_mut` crate instead",
- );
- }
+ } else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id)
+ && !cx.typeck_results().expr_ty(src).is_primitive()
+ {
+ span_lint_and_help(
+ cx,
+ MEM_REPLACE_WITH_UNINIT,
+ expr_span,
+ "replacing with `mem::zeroed()`",
+ None,
+ "consider using a default value or the `take_mut` crate instead",
+ );
}
}
}
@@ -222,21 +218,19 @@ impl MemReplace {
impl<'tcx> LateLintPass<'tcx> for MemReplace {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if_chain! {
+ if let ExprKind::Call(func, [dest, src]) = expr.kind
// Check that `expr` is a call to `mem::replace()`
- if let ExprKind::Call(func, [dest, src]) = expr.kind;
- if let ExprKind::Path(ref func_qpath) = func.kind;
- if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
- if cx.tcx.is_diagnostic_item(sym::mem_replace, def_id);
- then {
- // Check that second argument is `Option::None`
- if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) {
- check_replace_option_with_none(cx, dest, expr.span);
- } else if self.msrv.meets(msrvs::MEM_TAKE) {
- check_replace_with_default(cx, src, dest, expr.span);
- }
- check_replace_with_uninit(cx, src, dest, expr.span);
+ && let ExprKind::Path(ref func_qpath) = func.kind
+ && let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id()
+ && cx.tcx.is_diagnostic_item(sym::mem_replace, def_id)
+ {
+ // Check that second argument is `Option::None`
+ if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) {
+ check_replace_option_with_none(cx, dest, expr.span);
+ } else if self.msrv.meets(msrvs::MEM_TAKE) {
+ check_replace_with_default(cx, src, dest, expr.span);
}
+ check_replace_with_uninit(cx, src, dest, expr.span);
}
}
extract_msrv_attr!(LateContext);
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index 3a8cc4174..08bfa2e00 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -3,7 +3,6 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and
use clippy_utils::peel_blocks;
use clippy_utils::source::{snippet, snippet_with_context};
use clippy_utils::visitors::find_all_ret_expressions;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@@ -70,57 +69,50 @@ pub(crate) trait BindInsteadOfMap {
closure_expr: &hir::Expr<'_>,
closure_args_span: Span,
) -> bool {
- if_chain! {
- if let hir::ExprKind::Call(some_expr, [inner_expr]) = closure_expr.kind;
- if let hir::ExprKind::Path(QPath::Resolved(_, path)) = some_expr.kind;
- if Self::is_variant(cx, path.res);
- if !contains_return(inner_expr);
- if let Some(msg) = Self::lint_msg(cx);
- then {
- let mut app = Applicability::MachineApplicable;
- let some_inner_snip = snippet_with_context(cx, inner_expr.span, closure_expr.span.ctxt(), "_", &mut app).0;
-
- let closure_args_snip = snippet(cx, closure_args_span, "..");
- let option_snip = snippet(cx, recv.span, "..");
- let note = format!("{option_snip}.{}({closure_args_snip} {some_inner_snip})", Self::GOOD_METHOD_NAME);
- span_lint_and_sugg(
- cx,
- BIND_INSTEAD_OF_MAP,
- expr.span,
- &msg,
- "try",
- note,
- app,
- );
- true
- } else {
- false
- }
+ if let hir::ExprKind::Call(some_expr, [inner_expr]) = closure_expr.kind
+ && let hir::ExprKind::Path(QPath::Resolved(_, path)) = some_expr.kind
+ && Self::is_variant(cx, path.res)
+ && !contains_return(inner_expr)
+ && let Some(msg) = Self::lint_msg(cx)
+ {
+ let mut app = Applicability::MachineApplicable;
+ let some_inner_snip = snippet_with_context(cx, inner_expr.span, closure_expr.span.ctxt(), "_", &mut app).0;
+
+ let closure_args_snip = snippet(cx, closure_args_span, "..");
+ let option_snip = snippet(cx, recv.span, "..");
+ let note = format!(
+ "{option_snip}.{}({closure_args_snip} {some_inner_snip})",
+ Self::GOOD_METHOD_NAME
+ );
+ span_lint_and_sugg(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, "try", note, app);
+ true
+ } else {
+ false
}
}
fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) -> bool {
let mut suggs = Vec::new();
let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| {
- if_chain! {
- if !ret_expr.span.from_expansion();
- if let hir::ExprKind::Call(func_path, [arg]) = ret_expr.kind;
- if let hir::ExprKind::Path(QPath::Resolved(_, path)) = func_path.kind;
- if Self::is_variant(cx, path.res);
- if !contains_return(arg);
- then {
- suggs.push((ret_expr.span, arg.span.source_callsite()));
- true
- } else {
- false
- }
+ if !ret_expr.span.from_expansion()
+ && let hir::ExprKind::Call(func_path, [arg]) = ret_expr.kind
+ && let hir::ExprKind::Path(QPath::Resolved(_, path)) = func_path.kind
+ && Self::is_variant(cx, path.res)
+ && !contains_return(arg)
+ {
+ suggs.push((ret_expr.span, arg.span.source_callsite()));
+ true
+ } else {
+ false
}
});
- let (span, msg) = if_chain! {
- if can_sugg;
- if let hir::ExprKind::MethodCall(segment, ..) = expr.kind;
- if let Some(msg) = Self::lint_msg(cx);
- then { (segment.ident.span, msg) } else { return false; }
+ let (span, msg) = if can_sugg
+ && let hir::ExprKind::MethodCall(segment, ..) = expr.kind
+ && let Some(msg) = Self::lint_msg(cx)
+ {
+ (segment.ident.span, msg)
+ } else {
+ return false;
};
span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, |diag| {
multispan_sugg_with_applicability(
@@ -139,11 +131,12 @@ pub(crate) trait BindInsteadOfMap {
/// Lint use of `_.and_then(|x| Some(y))` for `Option`s
fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool {
- if_chain! {
- if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def();
- if let Some(vid) = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM);
- if adt.did() == cx.tcx.parent(vid);
- then {} else { return false; }
+ if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
+ && let Some(vid) = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM)
+ && adt.did() == cx.tcx.parent(vid)
+ {
+ } else {
+ return false;
}
match arg.kind {
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
index 35370355f..4a2124c74 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
@@ -3,7 +3,6 @@ use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::is_local_used;
use clippy_utils::{path_to_local_id, peel_blocks, peel_ref_operators, strip_pat_refs};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind};
use rustc_lint::LateContext;
@@ -18,53 +17,50 @@ pub(super) fn check<'tcx>(
filter_recv: &'tcx Expr<'_>,
filter_arg: &'tcx Expr<'_>,
) {
- if_chain! {
- if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind;
- let body = cx.tcx.hir().body(body);
- if let [param] = body.params;
- if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind;
- if let ExprKind::Binary(ref op, l, r) = body.value.kind;
- if op.node == BinOpKind::Eq;
- if is_type_diagnostic_item(cx,
- cx.typeck_results().expr_ty(filter_recv).peel_refs(),
- sym::SliceIter);
- let operand_is_arg = |expr| {
+ if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind
+ && let body = cx.tcx.hir().body(body)
+ && let [param] = body.params
+ && let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind
+ && let ExprKind::Binary(ref op, l, r) = body.value.kind
+ && op.node == BinOpKind::Eq
+ && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv).peel_refs(), sym::SliceIter)
+ && let operand_is_arg = (|expr| {
let expr = peel_ref_operators(cx, peel_blocks(expr));
path_to_local_id(expr, arg_id)
- };
- let needle = if operand_is_arg(l) {
+ })
+ && let needle = if operand_is_arg(l) {
r
} else if operand_is_arg(r) {
l
} else {
return;
- };
- if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
- if !is_local_used(cx, needle, arg_id);
- then {
- let haystack = if let ExprKind::MethodCall(path, receiver, [], _) =
- filter_recv.kind {
- let p = path.ident.name;
- if p == sym::iter || p == sym::iter_mut {
- receiver
- } else {
- filter_recv
- }
+ }
+ && ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind()
+ && !is_local_used(cx, needle, arg_id)
+ {
+ let haystack = if let ExprKind::MethodCall(path, receiver, [], _) = filter_recv.kind {
+ let p = path.ident.name;
+ if p == sym::iter || p == sym::iter_mut {
+ receiver
} else {
filter_recv
- };
- let mut applicability = Applicability::MaybeIncorrect;
- span_lint_and_sugg(
- cx,
- NAIVE_BYTECOUNT,
- expr.span,
- "you appear to be counting bytes the naive way",
- "consider using the bytecount crate",
- format!("bytecount::count({}, {})",
- snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
- snippet_with_applicability(cx, needle.span, "..", &mut applicability)),
- applicability,
- );
- }
+ }
+ } else {
+ filter_recv
+ };
+ let mut applicability = Applicability::MaybeIncorrect;
+ span_lint_and_sugg(
+ cx,
+ NAIVE_BYTECOUNT,
+ expr.span,
+ "you appear to be counting bytes the naive way",
+ "consider using the bytecount crate",
+ format!(
+ "bytecount::count({}, {})",
+ snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
+ snippet_with_applicability(cx, needle.span, "..", &mut applicability)
+ ),
+ applicability,
+ );
};
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
index 649fc46e4..34159f2d1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_lang_item;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -14,23 +13,24 @@ pub(super) fn check<'tcx>(
count_recv: &'tcx hir::Expr<'_>,
bytes_recv: &'tcx hir::Expr<'_>,
) {
- if_chain! {
- if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id);
- if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id);
- if cx.tcx.type_of(impl_id).instantiate_identity().is_str();
- let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs();
- if ty.is_str() || is_type_lang_item(cx, ty, hir::LangItem::String);
- then {
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- BYTES_COUNT_TO_LEN,
- expr.span,
- "using long and hard to read `.bytes().count()`",
- "consider calling `.len()` instead",
- format!("{}.len()", snippet_with_applicability(cx, bytes_recv.span, "..", &mut applicability)),
- applicability
- );
- }
+ if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_method(bytes_id)
+ && cx.tcx.type_of(impl_id).instantiate_identity().is_str()
+ && let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs()
+ && (ty.is_str() || is_type_lang_item(cx, ty, hir::LangItem::String))
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ BYTES_COUNT_TO_LEN,
+ expr.span,
+ "using long and hard to read `.bytes().count()`",
+ "consider calling `.len()` instead",
+ format!(
+ "{}.len()",
+ snippet_with_applicability(cx, bytes_recv.span, "..", &mut applicability)
+ ),
+ applicability,
+ );
};
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
index d5897822e..a37087d0a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
use clippy_utils::ty::is_type_lang_item;
-use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem};
@@ -27,51 +26,54 @@ pub(super) fn check<'tcx>(
}
}
- if_chain! {
- if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- if cx.tcx.type_of(impl_id).instantiate_identity().is_str();
- if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind;
- if (2..=6).contains(&ext_literal.as_str().len());
- let ext_str = ext_literal.as_str();
- if ext_str.starts_with('.');
- if ext_str.chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit())
- || ext_str.chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit());
- let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs();
- if recv_ty.is_str() || is_type_lang_item(cx, recv_ty, LangItem::String);
- then {
- span_lint_and_then(
- cx,
- CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
- recv.span.to(call_span),
- "case-sensitive file extension comparison",
- |diag| {
- diag.help("consider using a case-insensitive comparison instead");
- if let Some(mut recv_source) = snippet_opt(cx, recv.span) {
-
- if !cx.typeck_results().expr_ty(recv).is_ref() {
- recv_source = format!("&{recv_source}");
- }
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && cx.tcx.type_of(impl_id).instantiate_identity().is_str()
+ && let ExprKind::Lit(Spanned {
+ node: LitKind::Str(ext_literal, ..),
+ ..
+ }) = arg.kind
+ && (2..=6).contains(&ext_literal.as_str().len())
+ && let ext_str = ext_literal.as_str()
+ && ext_str.starts_with('.')
+ && (ext_str.chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit())
+ || ext_str.chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit()))
+ && let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs()
+ && (recv_ty.is_str() || is_type_lang_item(cx, recv_ty, LangItem::String))
+ {
+ span_lint_and_then(
+ cx,
+ CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+ recv.span.to(call_span),
+ "case-sensitive file extension comparison",
+ |diag| {
+ diag.help("consider using a case-insensitive comparison instead");
+ if let Some(mut recv_source) = snippet_opt(cx, recv.span) {
+ if !cx.typeck_results().expr_ty(recv).is_ref() {
+ recv_source = format!("&{recv_source}");
+ }
- let suggestion_source = reindent_multiline(
- format!(
- "std::path::Path::new({})
- .extension()
- .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))",
- recv_source, ext_str.strip_prefix('.').unwrap()).into(),
- true,
- Some(indent_of(cx, call_span).unwrap_or(0) + 4)
- );
+ let suggestion_source = reindent_multiline(
+ format!(
+ "std::path::Path::new({})
+ .extension()
+ .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))",
+ recv_source,
+ ext_str.strip_prefix('.').unwrap()
+ )
+ .into(),
+ true,
+ Some(indent_of(cx, call_span).unwrap_or(0) + 4),
+ );
- diag.span_suggestion(
- recv.span.to(call_span),
- "use std::path::Path",
- suggestion_source,
- Applicability::MaybeIncorrect,
- );
- }
+ diag.span_suggestion(
+ recv.span.to(call_span),
+ "use std::path::Path",
+ suggestion_source,
+ Applicability::MaybeIncorrect,
+ );
}
- );
- }
+ },
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
index 0e41f3c21..c99cec067 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{method_chain_args, path_def_id};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, Lint};
@@ -15,34 +14,34 @@ pub(super) fn check(
lint: &'static Lint,
suggest: &str,
) -> bool {
- if_chain! {
- if let Some(args) = method_chain_args(info.chain, chain_methods);
- if let hir::ExprKind::Call(fun, [arg_char]) = info.other.kind;
- if let Some(id) = path_def_id(cx, fun).map(|ctor_id| cx.tcx.parent(ctor_id));
- if Some(id) == cx.tcx.lang_items().option_some_variant();
- then {
- let mut applicability = Applicability::MachineApplicable;
- let self_ty = cx.typeck_results().expr_ty_adjusted(args[0].0).peel_refs();
+ if let Some(args) = method_chain_args(info.chain, chain_methods)
+ && let hir::ExprKind::Call(fun, [arg_char]) = info.other.kind
+ && let Some(id) = path_def_id(cx, fun).map(|ctor_id| cx.tcx.parent(ctor_id))
+ && Some(id) == cx.tcx.lang_items().option_some_variant()
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let self_ty = cx.typeck_results().expr_ty_adjusted(args[0].0).peel_refs();
- if *self_ty.kind() != ty::Str {
- return false;
- }
+ if *self_ty.kind() != ty::Str {
+ return false;
+ }
- span_lint_and_sugg(
- cx,
- lint,
- info.expr.span,
- &format!("you should use the `{suggest}` method"),
- "like this",
- format!("{}{}.{suggest}({})",
- if info.eq { "" } else { "!" },
- snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
- snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)),
- applicability,
- );
+ span_lint_and_sugg(
+ cx,
+ lint,
+ info.expr.span,
+ &format!("you should use the `{suggest}` method"),
+ "like this",
+ format!(
+ "{}{}.{suggest}({})",
+ if info.eq { "" } else { "!" },
+ snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
+ snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)
+ ),
+ applicability,
+ );
- return true;
- }
+ return true;
}
false
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
index c9d50a5b0..d07e45434 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::method_chain_args;
use clippy_utils::source::snippet_with_applicability;
-use if_chain::if_chain;
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -15,28 +14,28 @@ pub(super) fn check(
lint: &'static Lint,
suggest: &str,
) -> bool {
- if_chain! {
- if let Some(args) = method_chain_args(info.chain, chain_methods);
- if let hir::ExprKind::Lit(lit) = info.other.kind;
- if let ast::LitKind::Char(c) = lit.node;
- then {
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- lint,
- info.expr.span,
- &format!("you should use the `{suggest}` method"),
- "like this",
- format!("{}{}.{suggest}('{}')",
- if info.eq { "" } else { "!" },
- snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
- c.escape_default()),
- applicability,
- );
+ if let Some(args) = method_chain_args(info.chain, chain_methods)
+ && let hir::ExprKind::Lit(lit) = info.other.kind
+ && let ast::LitKind::Char(c) = lit.node
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ lint,
+ info.expr.span,
+ &format!("you should use the `{suggest}` method"),
+ "like this",
+ format!(
+ "{}{}.{suggest}('{}')",
+ if info.eq { "" } else { "!" },
+ snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
+ c.escape_default()
+ ),
+ applicability,
+ );
- true
- } else {
- false
- }
+ true
+ } else {
+ false
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
index eb4f003d3..532bbbeaf 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
@@ -61,7 +61,7 @@ pub(super) fn check(
// ? is a Call, makes sure not to rec *x?, but rather (*x)?
ExprKind::Call(hir_callee, _) => matches!(
hir_callee.kind,
- ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _))
+ ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, ..))
),
ExprKind::MethodCall(_, self_arg, ..) if expr.hir_id == self_arg.hir_id => true,
ExprKind::Match(_, _, MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar)
diff --git a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
index a8d4dd5e4..dc978c8a5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
@@ -16,30 +16,27 @@ pub(super) fn check(
err_span: Span,
msrv: &Msrv,
) {
- if_chain! {
- if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
+ if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
// Test the version to make sure the lint can be showed (expect_err has been
// introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982)
- if msrv.meets(msrvs::EXPECT_ERR);
+ && msrv.meets(msrvs::EXPECT_ERR)
// Grabs the `Result<T, E>` type
- let result_type = cx.typeck_results().expr_ty(recv);
+ && let result_type = cx.typeck_results().expr_ty(recv)
// Tests if the T type in a `Result<T, E>` is not None
- if let Some(data_type) = get_data_type(cx, result_type);
+ && let Some(data_type) = get_data_type(cx, result_type)
// Tests if the T type in a `Result<T, E>` implements debug
- if has_debug_impl(cx, data_type);
-
- then {
- span_lint_and_sugg(
- cx,
- ERR_EXPECT,
- err_span.to(expect_span),
- "called `.err().expect()` on a `Result` value",
- "try",
- "expect_err".to_string(),
- Applicability::MachineApplicable
+ && has_debug_impl(cx, data_type)
+ {
+ span_lint_and_sugg(
+ cx,
+ ERR_EXPECT,
+ err_span.to(expect_span),
+ "called `.err().expect()` on a `Result` value",
+ "try",
+ "expect_err".to_string(),
+ Applicability::MachineApplicable,
);
- }
};
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index a49970b53..f0fc92579 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -6,8 +6,8 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_span::Span;
use rustc_span::symbol::sym;
+use rustc_span::Span;
use std::borrow::Cow;
use super::EXPECT_FUN_CALL;
diff --git a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
index 495b26652..460ec7b36 100644
--- a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem};
use rustc_lint::LateContext;
@@ -11,35 +10,33 @@ use super::EXTEND_WITH_DRAIN;
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
- if_chain! {
- if is_type_diagnostic_item(cx, ty, sym::Vec);
+ if is_type_diagnostic_item(cx, ty, sym::Vec)
//check source object
- if let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind;
- if src_method.ident.as_str() == "drain";
- let src_ty = cx.typeck_results().expr_ty(drain_vec);
+ && let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind
+ && src_method.ident.as_str() == "drain"
+ && let src_ty = cx.typeck_results().expr_ty(drain_vec)
//check if actual src type is mutable for code suggestion
- let immutable = src_ty.is_mutable_ptr();
- let src_ty = src_ty.peel_refs();
- if is_type_diagnostic_item(cx, src_ty, sym::Vec);
+ && let immutable = src_ty.is_mutable_ptr()
+ && let src_ty = src_ty.peel_refs()
+ && is_type_diagnostic_item(cx, src_ty, sym::Vec)
//check drain range
- if let src_ty_range = cx.typeck_results().expr_ty(drain_arg).peel_refs();
- if is_type_lang_item(cx, src_ty_range, LangItem::RangeFull);
- then {
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- EXTEND_WITH_DRAIN,
- expr.span,
- "use of `extend` instead of `append` for adding the full range of a second vector",
- "try",
- format!(
- "{}.append({}{})",
- snippet_with_applicability(cx, recv.span, "..", &mut applicability),
- if immutable { "" } else { "&mut " },
- snippet_with_applicability(cx, drain_vec.span, "..", &mut applicability)
- ),
- applicability,
- );
- }
+ && let src_ty_range = cx.typeck_results().expr_ty(drain_arg).peel_refs()
+ && is_type_lang_item(cx, src_ty_range, LangItem::RangeFull)
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ EXTEND_WITH_DRAIN,
+ expr.span,
+ "use of `extend` instead of `append` for adding the full range of a second vector",
+ "try",
+ format!(
+ "{}.append({}{})",
+ snippet_with_applicability(cx, recv.span, "..", &mut applicability),
+ if immutable { "" } else { "&mut " },
+ snippet_with_applicability(cx, drain_vec.span, "..", &mut applicability)
+ ),
+ applicability,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
index 7818be811..b05361ab2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::get_parent_expr;
use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::{sym, Span};
@@ -19,21 +18,19 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
let verb: &str;
let lint_unary: &str;
let help_unary: &str;
- if_chain! {
- if let Some(parent) = get_parent_expr(cx, expr);
- if let hir::ExprKind::Unary(op, _) = parent.kind;
- if op == hir::UnOp::Not;
- then {
- lint_unary = "!";
- verb = "denies";
- help_unary = "";
- span = parent.span;
- } else {
- lint_unary = "";
- verb = "covers";
- help_unary = "!";
- span = expr.span;
- }
+ if let Some(parent) = get_parent_expr(cx, expr)
+ && let hir::ExprKind::Unary(op, _) = parent.kind
+ && op == hir::UnOp::Not
+ {
+ lint_unary = "!";
+ verb = "denies";
+ help_unary = "";
+ span = parent.span;
+ } else {
+ lint_unary = "";
+ verb = "covers";
+ help_unary = "!";
+ span = expr.span;
}
let lint_msg = format!("`{lint_unary}FileType::is_file()` only {verb} regular files");
let help_msg = format!("use `{help_unary}FileType::is_dir()` instead");
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 5bb8c7a6b..844ab40ca 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -4,15 +4,14 @@ use clippy_utils::source::{indent_of, reindent_multiline, snippet};
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{higher, is_trait_method, path_to_local_id, peel_blocks, SpanlessEq};
use hir::{Body, HirId, MatchSource, Pat};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp};
use rustc_lint::LateContext;
use rustc_middle::ty::adjustment::Adjust;
-use rustc_span::Span;
use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::Span;
use std::borrow::Cow;
use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP};
@@ -29,13 +28,11 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) ->
let arg_id = body.params[0].pat.hir_id;
match closure_expr.kind {
hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
- if_chain! {
- if ident.name == method_name;
- if let hir::ExprKind::Path(path) = &receiver.kind;
- if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id);
- then {
- return arg_id == *local
- }
+ if ident.name == method_name
+ && let hir::ExprKind::Path(path) = &receiver.kind
+ && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id)
+ {
+ return arg_id == *local;
}
false
},
@@ -139,11 +136,9 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
&& path_to_local_id(map_arg_peeled, map_param_id))
&& let eq_fallback = (|a: &Expr<'_>, b: &Expr<'_>| {
// in `filter(|x| ..)`, replace `*x` with `x`
- let a_path = if_chain! {
- if !is_filter_param_ref;
- if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
- then { expr_path } else { a }
- };
+ let a_path = if !is_filter_param_ref
+ && let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind
+ { expr_path } else { a };
// let the filter closure arg and the map closure arg be equal
path_to_local_id(a_path, filter_param_id)
&& path_to_local_id(b, map_param_id)
@@ -305,87 +300,98 @@ pub(super) fn check(
return;
}
- if_chain! {
- if is_trait_method(cx, map_recv, sym::Iterator);
+ if is_trait_method(cx, map_recv, sym::Iterator)
// filter(|x| ...is_some())...
- if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind;
- let filter_body = cx.tcx.hir().body(filter_body_id);
- if let [filter_param] = filter_body.params;
+ && let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind
+ && let filter_body = cx.tcx.hir().body(filter_body_id)
+ && let [filter_param] = filter_body.params
// optional ref pattern: `filter(|&x| ..)`
- let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
+ && let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
(ref_pat, true)
} else {
(filter_param.pat, false)
- };
-
- if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
- if let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id);
+ }
- if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind;
- let map_body = cx.tcx.hir().body(map_body_id);
- if let [map_param] = map_body.params;
- if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
+ && let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind
+ && let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id)
- if let Some(check_result) =
- offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref);
+ && let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind
+ && let map_body = cx.tcx.hir().body(map_body_id)
+ && let [map_param] = map_body.params
+ && let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind
- then {
- let span = filter_span.with_hi(expr.span.hi());
- let (filter_name, lint) = if is_find {
- ("find", MANUAL_FIND_MAP)
- } else {
- ("filter", MANUAL_FILTER_MAP)
- };
- let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`");
+ && let Some(check_result) =
+ offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref)
+ {
+ let span = filter_span.with_hi(expr.span.hi());
+ let (filter_name, lint) = if is_find {
+ ("find", MANUAL_FIND_MAP)
+ } else {
+ ("filter", MANUAL_FILTER_MAP)
+ };
+ let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`");
- let (sugg, note_and_span, applicability) = match check_result {
- CheckResult::Method { map_arg, method, side_effect_expr_span } => {
- let (to_opt, deref) = match method {
- CalledMethod::ResultIsOk => (".ok()", String::new()),
- CalledMethod::OptionIsSome => {
- let derefs = cx.typeck_results()
- .expr_adjustments(map_arg)
- .iter()
- .filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
- .count();
+ let (sugg, note_and_span, applicability) = match check_result {
+ CheckResult::Method {
+ map_arg,
+ method,
+ side_effect_expr_span,
+ } => {
+ let (to_opt, deref) = match method {
+ CalledMethod::ResultIsOk => (".ok()", String::new()),
+ CalledMethod::OptionIsSome => {
+ let derefs = cx
+ .typeck_results()
+ .expr_adjustments(map_arg)
+ .iter()
+ .filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
+ .count();
- ("", "*".repeat(derefs))
- }
- };
+ ("", "*".repeat(derefs))
+ },
+ };
- let sugg = format!(
- "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})",
- snippet(cx, map_arg.span, ".."),
- );
- let (note_and_span, applicability) = if let Some(span) = side_effect_expr_span {
- let note = "the suggestion might change the behavior of the program when merging `filter` and `map`, \
- because this expression potentially contains side effects and will only execute once";
+ let sugg = format!(
+ "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})",
+ snippet(cx, map_arg.span, ".."),
+ );
+ let (note_and_span, applicability) = if let Some(span) = side_effect_expr_span {
+ let note = "the suggestion might change the behavior of the program when merging `filter` and `map`, \
+ because this expression potentially contains side effects and will only execute once";
- (Some((note, span)), Applicability::MaybeIncorrect)
- } else {
- (None, Applicability::MachineApplicable)
- };
+ (Some((note, span)), Applicability::MaybeIncorrect)
+ } else {
+ (None, Applicability::MachineApplicable)
+ };
- (sugg, note_and_span, applicability)
- }
- CheckResult::PatternMatching { variant_span, variant_ident } => {
- let pat = snippet(cx, variant_span, "<pattern>");
+ (sugg, note_and_span, applicability)
+ },
+ CheckResult::PatternMatching {
+ variant_span,
+ variant_ident,
+ } => {
+ let pat = snippet(cx, variant_span, "<pattern>");
- (format!("{filter_name}_map(|{map_param_ident}| match {map_param_ident} {{ \
- {pat} => Some({variant_ident}), \
- _ => None \
- }})"), None, Applicability::MachineApplicable)
- }
- };
- span_lint_and_then(cx, lint, span, &msg, |diag| {
- diag.span_suggestion(span, "try", sugg, applicability);
+ (
+ format!(
+ "{filter_name}_map(|{map_param_ident}| match {map_param_ident} {{ \
+ {pat} => Some({variant_ident}), \
+ _ => None \
+ }})"
+ ),
+ None,
+ Applicability::MachineApplicable,
+ )
+ },
+ };
+ span_lint_and_then(cx, lint, span, &msg, |diag| {
+ diag.span_suggestion(span, "try", sugg, applicability);
- if let Some((note, span)) = note_and_span {
- diag.span_note(span, note);
- }
- });
- }
+ if let Some((note, span)) = note_and_span {
+ diag.span_note(span, note);
+ }
+ });
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
index 9950c4428..2e43d19a6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
@@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
closure.def_id.to_def_id(),
Binder::bind_with_vars(
cx.typeck_results().node_type(param_ty.hir_id),
- cx.tcx.late_bound_vars(cx.tcx.hir().local_def_id_to_hir_id(closure.def_id)),
+ cx.tcx.late_bound_vars(cx.tcx.local_def_id_to_hir_id(closure.def_id)),
),
)
&& is_copy(cx, param_ty)
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
index ac7bc9bcc..9251130a3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
@@ -44,7 +44,7 @@ pub(super) fn check<'tcx>(
// add note if not multi-line
span_lint_and_then(cx, FILTER_NEXT, expr.span, msg, |diag| {
let (applicability, pat) = if let Some(id) = path_to_local(recv)
- && let Some(hir::Node::Pat(pat)) = cx.tcx.hir().find(id)
+ && let Some(hir::Node::Pat(pat)) = cx.tcx.opt_hir_node(id)
&& let hir::PatKind::Binding(BindingAnnotation(_, Mutability::Not), _, ident, _) = pat.kind
{
(Applicability::Unspecified, Some((pat.span, ident)))
diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
index 4040d3a5f..917a8e33e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::implements_trait;
use clippy_utils::{is_path_diagnostic_item, sugg};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -12,28 +11,25 @@ use rustc_span::sym;
use super::FROM_ITER_INSTEAD_OF_COLLECT;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func: &hir::Expr<'_>) {
- if_chain! {
- if is_path_diagnostic_item(cx, func, sym::from_iter_fn);
- let ty = cx.typeck_results().expr_ty(expr);
- let arg_ty = cx.typeck_results().expr_ty(&args[0]);
- if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
-
- if implements_trait(cx, arg_ty, iter_id, &[]);
- then {
- // `expr` implements `FromIterator` trait
- let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par();
- let turbofish = extract_turbofish(cx, expr, ty);
- let sugg = format!("{iter_expr}.collect::<{turbofish}>()");
- span_lint_and_sugg(
- cx,
- FROM_ITER_INSTEAD_OF_COLLECT,
- expr.span,
- "usage of `FromIterator::from_iter`",
- "use `.collect()` instead of `::from_iter()`",
- sugg,
- Applicability::MaybeIncorrect,
- );
- }
+ if is_path_diagnostic_item(cx, func, sym::from_iter_fn)
+ && let ty = cx.typeck_results().expr_ty(expr)
+ && let arg_ty = cx.typeck_results().expr_ty(&args[0])
+ && let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
+ && implements_trait(cx, arg_ty, iter_id, &[])
+ {
+ // `expr` implements `FromIterator` trait
+ let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par();
+ let turbofish = extract_turbofish(cx, expr, ty);
+ let sugg = format!("{iter_expr}.collect::<{turbofish}>()");
+ span_lint_and_sugg(
+ cx,
+ FROM_ITER_INSTEAD_OF_COLLECT,
+ expr.span,
+ "usage of `FromIterator::from_iter`",
+ "use `.collect()` instead of `::from_iter()`",
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
}
}
@@ -43,41 +39,43 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) ->
}
let call_site = expr.span.source_callsite();
- if_chain! {
- if let Some(snippet) = snippet_opt(cx, call_site);
- let snippet_split = snippet.split("::").collect::<Vec<_>>();
- if let Some((_, elements)) = snippet_split.split_last();
-
- then {
- if_chain! {
- if let [type_specifier, _] = snippet_split.as_slice();
- if let Some(type_specifier) = strip_angle_brackets(type_specifier);
- if let Some((type_specifier, ..)) = type_specifier.split_once(" as ");
- then {
- type_specifier.to_string()
- } else {
- // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
- if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) {
- // remove the type specifier from the path elements
- let without_ts = elements.iter().filter_map(|e| {
- if e == type_specifier { None } else { Some((*e).to_string()) }
- }).collect::<Vec<_>>();
- // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
- format!("{}{type_specifier}", without_ts.join("::"))
- } else {
- // type is not explicitly specified so wildcards are needed
- // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
- let ty_str = ty.to_string();
- let start = ty_str.find('<').unwrap_or(0);
- let end = ty_str.find('>').unwrap_or(ty_str.len());
- let nb_wildcard = ty_str[start..end].split(',').count();
- let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
- format!("{}<{wildcards}>", elements.join("::"))
- }
- }
- }
+ if let Some(snippet) = snippet_opt(cx, call_site)
+ && let snippet_split = snippet.split("::").collect::<Vec<_>>()
+ && let Some((_, elements)) = snippet_split.split_last()
+ {
+ if let [type_specifier, _] = snippet_split.as_slice()
+ && let Some(type_specifier) = strip_angle_brackets(type_specifier)
+ && let Some((type_specifier, ..)) = type_specifier.split_once(" as ")
+ {
+ type_specifier.to_string()
} else {
- ty.to_string()
+ // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
+ if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) {
+ // remove the type specifier from the path elements
+ let without_ts = elements
+ .iter()
+ .filter_map(|e| {
+ if e == type_specifier {
+ None
+ } else {
+ Some((*e).to_string())
+ }
+ })
+ .collect::<Vec<_>>();
+ // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
+ format!("{}{type_specifier}", without_ts.join("::"))
+ } else {
+ // type is not explicitly specified so wildcards are needed
+ // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
+ let ty_str = ty.to_string();
+ let start = ty_str.find('<').unwrap_or(0);
+ let end = ty_str.find('>').unwrap_or(ty_str.len());
+ let nb_wildcard = ty_str[start..end].split(',').count();
+ let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
+ format!("{}<{wildcards}>", elements.join("::"))
+ }
}
+ } else {
+ ty.to_string()
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
index 2e1dd3ec6..e1f1e4893 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_first.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -17,37 +16,38 @@ pub(super) fn check<'tcx>(
recv: &'tcx hir::Expr<'_>,
arg: &'tcx hir::Expr<'_>,
) {
- if_chain! {
- if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- let identity = cx.tcx.type_of(impl_id).instantiate_identity();
- if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind;
- then {
- if identity.is_slice() {
- let mut app = Applicability::MachineApplicable;
- let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app);
- span_lint_and_sugg(
- cx,
- GET_FIRST,
- expr.span,
- &format!("accessing first element with `{slice_name}.get(0)`"),
- "try",
- format!("{slice_name}.first()"),
- app,
- );
- } else if is_type_diagnostic_item(cx, identity, sym::VecDeque){
- let mut app = Applicability::MachineApplicable;
- let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app);
- span_lint_and_sugg(
- cx,
- GET_FIRST,
- expr.span,
- &format!("accessing first element with `{slice_name}.get(0)`"),
- "try",
- format!("{slice_name}.front()"),
- app,
- );
- }
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && let identity = cx.tcx.type_of(impl_id).instantiate_identity()
+ && let hir::ExprKind::Lit(Spanned {
+ node: LitKind::Int(0, _),
+ ..
+ }) = arg.kind
+ {
+ if identity.is_slice() {
+ let mut app = Applicability::MachineApplicable;
+ let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app);
+ span_lint_and_sugg(
+ cx,
+ GET_FIRST,
+ expr.span,
+ &format!("accessing first element with `{slice_name}.get(0)`"),
+ "try",
+ format!("{slice_name}.first()"),
+ app,
+ );
+ } else if is_type_diagnostic_item(cx, identity, sym::VecDeque) {
+ let mut app = Applicability::MachineApplicable;
+ let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app);
+ span_lint_and_sugg(
+ cx,
+ GET_FIRST,
+ expr.span,
+ &format!("accessing first element with `{slice_name}.get(0)`"),
+ "try",
+ format!("{slice_name}.front()"),
+ app,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index e91ce64d8..78a553eb8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::{implements_trait, peel_mid_ty_refs};
use clippy_utils::{is_diag_item_method, is_diag_trait_item};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -11,34 +10,32 @@ use rustc_span::sym;
use super::IMPLICIT_CLONE;
pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
- if_chain! {
- if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if is_clone_like(cx, method_name, method_def_id);
- let return_type = cx.typeck_results().expr_ty(expr);
- let input_type = cx.typeck_results().expr_ty(recv);
- let (input_type, ref_count) = peel_mid_ty_refs(input_type);
- if !(ref_count > 0 && is_diag_trait_item(cx, method_def_id, sym::ToOwned));
- if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()));
- if return_type == input_type;
- if let Some(clone_trait) = cx.tcx.lang_items().clone_trait();
- if implements_trait(cx, return_type, clone_trait, &[]);
- then {
- let mut app = Applicability::MachineApplicable;
- let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
- span_lint_and_sugg(
- cx,
- IMPLICIT_CLONE,
- expr.span,
- &format!("implicitly cloning a `{ty_name}` by calling `{method_name}` on its dereferenced type"),
- "consider using",
- if ref_count > 1 {
- format!("({}{recv_snip}).clone()", "*".repeat(ref_count - 1))
- } else {
- format!("{recv_snip}.clone()")
- },
- app,
- );
- }
+ if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && is_clone_like(cx, method_name, method_def_id)
+ && let return_type = cx.typeck_results().expr_ty(expr)
+ && let input_type = cx.typeck_results().expr_ty(recv)
+ && let (input_type, ref_count) = peel_mid_ty_refs(input_type)
+ && !(ref_count > 0 && is_diag_trait_item(cx, method_def_id, sym::ToOwned))
+ && let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()))
+ && return_type == input_type
+ && let Some(clone_trait) = cx.tcx.lang_items().clone_trait()
+ && implements_trait(cx, return_type, clone_trait, &[])
+ {
+ let mut app = Applicability::MachineApplicable;
+ let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
+ span_lint_and_sugg(
+ cx,
+ IMPLICIT_CLONE,
+ expr.span,
+ &format!("implicitly cloning a `{ty_name}` by calling `{method_name}` on its dereferenced type"),
+ "consider using",
+ if ref_count > 1 {
+ format!("({}{recv_snip}).clone()", "*".repeat(ref_count - 1))
+ } else {
+ format!("{recv_snip}.clone()")
+ },
+ app,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
index 6686d42c9..efc3ddd20 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{is_type_lang_item, walk_ptrs_ty_depth};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -18,37 +17,36 @@ pub fn check(
receiver: &hir::Expr<'_>,
args: &[hir::Expr<'_>],
) {
- if_chain! {
- if args.is_empty() && method_name == sym::to_string;
- if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if cx.tcx.is_diagnostic_item(sym::to_string_method, to_string_meth_did);
- if let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id);
- let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver);
- let self_ty = args.type_at(0);
- let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty);
- if deref_count >= 1;
- if specializes_tostring(cx, deref_self_ty);
- then {
- span_lint_and_then(
- cx,
- INEFFICIENT_TO_STRING,
- expr.span,
- &format!("calling `to_string` on `{arg_ty}`"),
- |diag| {
- diag.help(format!(
- "`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`"
- ));
- let mut applicability = Applicability::MachineApplicable;
- let arg_snippet = snippet_with_applicability(cx, receiver.span, "..", &mut applicability);
- diag.span_suggestion(
- expr.span,
- "try dereferencing the receiver",
- format!("({}{arg_snippet}).to_string()", "*".repeat(deref_count)),
- applicability,
- );
- },
- );
- }
+ if args.is_empty()
+ && method_name == sym::to_string
+ && let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && cx.tcx.is_diagnostic_item(sym::to_string_method, to_string_meth_did)
+ && let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id)
+ && let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver)
+ && let self_ty = args.type_at(0)
+ && let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty)
+ && deref_count >= 1
+ && specializes_tostring(cx, deref_self_ty)
+ {
+ span_lint_and_then(
+ cx,
+ INEFFICIENT_TO_STRING,
+ expr.span,
+ &format!("calling `to_string` on `{arg_ty}`"),
+ |diag| {
+ diag.help(format!(
+ "`{self_ty}` implements `ToString` through a slower blanket impl, but `{deref_self_ty}` has a fast specialization of `ToString`"
+ ));
+ let mut applicability = Applicability::MachineApplicable;
+ let arg_snippet = snippet_with_applicability(cx, receiver.span, "..", &mut applicability);
+ diag.span_suggestion(
+ expr.span,
+ "try dereferencing the receiver",
+ format!("({}{arg_snippet}).to_string()", "*".repeat(deref_count)),
+ applicability,
+ );
+ },
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
index bbd964c10..80160d17c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
@@ -1,13 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_trait_method;
use clippy_utils::ty::has_iter_method;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
-use rustc_span::Span;
use rustc_span::symbol::{sym, Symbol};
+use rustc_span::Span;
use super::INTO_ITER_ON_REF;
@@ -19,24 +18,20 @@ pub(super) fn check(
receiver: &hir::Expr<'_>,
) {
let self_ty = cx.typeck_results().expr_ty_adjusted(receiver);
- if_chain! {
- if let ty::Ref(..) = self_ty.kind();
- if method_name == sym::into_iter;
- if is_trait_method(cx, expr, sym::IntoIterator);
- if let Some((kind, method_name)) = ty_has_iter_method(cx, self_ty);
- then {
- span_lint_and_sugg(
- cx,
- INTO_ITER_ON_REF,
- method_span,
- &format!(
- "this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`",
- ),
- "call directly",
- method_name.to_string(),
- Applicability::MachineApplicable,
- );
- }
+ if let ty::Ref(..) = self_ty.kind()
+ && method_name == sym::into_iter
+ && is_trait_method(cx, expr, sym::IntoIterator)
+ && let Some((kind, method_name)) = ty_has_iter_method(cx, self_ty)
+ {
+ span_lint_and_sugg(
+ cx,
+ INTO_ITER_ON_REF,
+ method_span,
+ &format!("this `.into_iter()` call is equivalent to `.{method_name}()` and will not consume the `{kind}`",),
+ "call directly",
+ method_name.to_string(),
+ Applicability::MachineApplicable,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
index bde6f92b0..dd741cd43 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
@@ -1,7 +1,6 @@
use crate::methods::utils::derefs_to_slice;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -10,22 +9,21 @@ use rustc_span::sym;
use super::ITER_CLONED_COLLECT;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) {
- if_chain! {
- if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec);
- if let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv));
- if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite());
-
- then {
- span_lint_and_sugg(
- cx,
- ITER_CLONED_COLLECT,
- to_replace,
- &format!("called `iter().{method_name}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
- more readable"),
- "try",
- ".to_vec()".to_string(),
- Applicability::MachineApplicable,
- );
- }
+ if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec)
+ && let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv))
+ && let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite())
+ {
+ span_lint_and_sugg(
+ cx,
+ ITER_CLONED_COLLECT,
+ to_replace,
+ &format!(
+ "called `iter().{method_name}().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
+ more readable"
+ ),
+ "try",
+ ".to_vec()".to_string(),
+ Applicability::MachineApplicable,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index 625325d4c..e1b934d36 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -1,6 +1,7 @@
#![allow(unused_imports)]
use super::ITER_KV_MAP;
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::ty::is_type_diagnostic_item;
@@ -21,65 +22,59 @@ pub(super) fn check<'tcx>(
expr: &'tcx Expr<'tcx>, // .iter().map(|(_, v_| v))
recv: &'tcx Expr<'tcx>, // hashmap
m_arg: &'tcx Expr<'tcx>, // |(_, v)| v
+ msrv: &Msrv,
) {
- if_chain! {
- if !expr.span.from_expansion();
- if let ExprKind::Closure(c) = m_arg.kind;
- if let Body {params: [p], value: body_expr, coroutine_kind: _ } = cx.tcx.hir().body(c.body);
- if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind;
-
- let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) {
+ if map_type == "into_iter" && !msrv.meets(msrvs::INTO_KEYS) {
+ return;
+ }
+ if !expr.span.from_expansion()
+ && let ExprKind::Closure(c) = m_arg.kind
+ && let Body {
+ params: [p],
+ value: body_expr,
+ coroutine_kind: _,
+ } = cx.tcx.hir().body(c.body)
+ && let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind
+ && let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) {
(key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value),
(PatKind::Binding(ann, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", ann, key),
_ => return,
- };
-
- let ty = cx.typeck_results().expr_ty(recv);
- if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap);
-
- then {
- let mut applicability = rustc_errors::Applicability::MachineApplicable;
- let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability);
- let into_prefix = if map_type == "into_iter" {"into_"} else {""};
-
- if_chain! {
- if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind;
- if let [local_ident] = path.segments;
- if local_ident.ident.as_str() == bound_ident.as_str();
+ }
+ && let ty = cx.typeck_results().expr_ty(recv)
+ && (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap))
+ {
+ let mut applicability = rustc_errors::Applicability::MachineApplicable;
+ let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability);
+ let into_prefix = if map_type == "into_iter" { "into_" } else { "" };
- then {
- span_lint_and_sugg(
- cx,
- ITER_KV_MAP,
- expr.span,
- &format!("iterating on a map's {replacement_kind}s"),
- "try",
- format!("{recv_snippet}.{into_prefix}{replacement_kind}s()"),
- applicability,
- );
- } else {
- let ref_annotation = if annotation.0 == ByRef::Yes {
- "ref "
- } else {
- ""
- };
- let mut_annotation = if annotation.1 == Mutability::Mut {
- "mut "
- } else {
- ""
- };
- span_lint_and_sugg(
- cx,
- ITER_KV_MAP,
- expr.span,
- &format!("iterating on a map's {replacement_kind}s"),
- "try",
- format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})",
- snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)),
- applicability,
- );
- }
- }
+ if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind
+ && let [local_ident] = path.segments
+ && local_ident.ident.as_str() == bound_ident.as_str()
+ {
+ span_lint_and_sugg(
+ cx,
+ ITER_KV_MAP,
+ expr.span,
+ &format!("iterating on a map's {replacement_kind}s"),
+ "try",
+ format!("{recv_snippet}.{into_prefix}{replacement_kind}s()"),
+ applicability,
+ );
+ } else {
+ let ref_annotation = if annotation.0 == ByRef::Yes { "ref " } else { "" };
+ let mut_annotation = if annotation.1 == Mutability::Mut { "mut " } else { "" };
+ span_lint_and_sugg(
+ cx,
+ ITER_KV_MAP,
+ expr.span,
+ &format!("iterating on a map's {replacement_kind}s"),
+ "try",
+ format!(
+ "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})",
+ snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)
+ ),
+ applicability,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
index 8f885e9f7..fd4650e1e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
@@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{get_parent_expr, higher};
-use if_chain::if_chain;
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -26,29 +25,36 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() {
// caller is a Slice
- if_chain! {
- if let hir::ExprKind::Index(caller_var, index_expr, _) = &caller_expr.kind;
- if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
- = higher::Range::hir(index_expr);
- if let hir::ExprKind::Lit(start_lit) = &start_expr.kind;
- if let ast::LitKind::Int(start_idx, _) = start_lit.node;
- then {
- let mut applicability = Applicability::MachineApplicable;
- let suggest = if start_idx == 0 {
- format!("{}.first()", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability))
- } else {
- format!("{}.get({start_idx})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability))
- };
- span_lint_and_sugg(
- cx,
- ITER_NEXT_SLICE,
- expr.span,
- "using `.iter().next()` on a Slice without end index",
- "try calling",
- suggest,
- applicability,
- );
- }
+ if let hir::ExprKind::Index(caller_var, index_expr, _) = &caller_expr.kind
+ && let Some(higher::Range {
+ start: Some(start_expr),
+ end: None,
+ limits: ast::RangeLimits::HalfOpen,
+ }) = higher::Range::hir(index_expr)
+ && let hir::ExprKind::Lit(start_lit) = &start_expr.kind
+ && let ast::LitKind::Int(start_idx, _) = start_lit.node
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let suggest = if start_idx == 0 {
+ format!(
+ "{}.first()",
+ snippet_with_applicability(cx, caller_var.span, "..", &mut applicability)
+ )
+ } else {
+ format!(
+ "{}.get({start_idx})",
+ snippet_with_applicability(cx, caller_var.span, "..", &mut applicability)
+ )
+ };
+ span_lint_and_sugg(
+ cx,
+ ITER_NEXT_SLICE,
+ expr.span,
+ "using `.iter().next()` on a Slice without end index",
+ "try calling",
+ suggest,
+ applicability,
+ );
}
} else if is_vec_or_array(cx, caller_expr) {
// caller is a Vec or an Array
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
index 39af52141..d1215290d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
@@ -19,18 +19,16 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
expr.span.trim_start(recv.span).unwrap(),
"called `skip(..).next()` on an iterator",
|diag| {
- if_chain! {
- if let Some(id) = path_to_local(recv);
- if let Node::Pat(pat) = cx.tcx.hir().get(id);
- if let PatKind::Binding(ann, _, _, _) = pat.kind;
- if ann != BindingAnnotation::MUT;
- then {
- application = Applicability::Unspecified;
- diag.span_help(
- pat.span,
- format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
- );
- }
+ if let Some(id) = path_to_local(recv)
+ && let Node::Pat(pat) = cx.tcx.hir_node(id)
+ && let PatKind::Binding(ann, _, _, _) = pat.kind
+ && ann != BindingAnnotation::MUT
+ {
+ application = Applicability::Unspecified;
+ diag.span_help(
+ pat.span,
+ format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
+ );
}
diag.span_suggestion(
diff --git a/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs
new file mode 100644
index 000000000..02f28779c
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs
@@ -0,0 +1,52 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::expr_or_init;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
+use rustc_span::Span;
+
+use super::JOIN_ABSOLUTE_PATHS;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx Expr<'tcx>, join_arg: &'tcx Expr<'tcx>, expr_span: Span) {
+ let ty = cx.typeck_results().expr_ty(recv).peel_refs();
+ if (is_type_diagnostic_item(cx, ty, sym::Path) || is_type_diagnostic_item(cx, ty, sym::PathBuf))
+ && let ExprKind::Lit(spanned) = expr_or_init(cx, join_arg).kind
+ && let LitKind::Str(symbol, _) = spanned.node
+ && let sym_str = symbol.as_str()
+ && sym_str.starts_with(['/', '\\'])
+ {
+ span_lint_and_then(
+ cx,
+ JOIN_ABSOLUTE_PATHS,
+ join_arg.span,
+ "argument to `Path::join` starts with a path separator",
+ |diag| {
+ let arg_str = snippet_opt(cx, spanned.span).unwrap_or_else(|| "..".to_string());
+
+ let no_separator = if sym_str.starts_with('/') {
+ arg_str.replacen('/', "", 1)
+ } else {
+ arg_str.replacen('\\', "", 1)
+ };
+
+ diag.note("joining a path starting with separator will replace the path instead")
+ .span_suggestion(
+ spanned.span,
+ "if this is unintentional, try removing the starting separator",
+ no_separator,
+ Applicability::Unspecified,
+ )
+ .span_suggestion(
+ expr_span,
+ "if this is intentional, try using `Path::new` instead",
+ format!("PathBuf::from({arg_str})"),
+ Applicability::Unspecified,
+ );
+ },
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
index 3031193e5..b1af0083e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::{ResultErr, ResultOk};
use rustc_hir::{Expr, ExprKind, PatKind};
@@ -18,30 +17,26 @@ pub(super) fn check<'tcx>(
or_expr: &'tcx Expr<'_>,
map_expr: &'tcx Expr<'_>,
) {
- if_chain! {
- if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Option);
- if let ExprKind::Call(err_path, [err_arg]) = or_expr.kind;
- if is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr);
- if is_ok_wrapping(cx, map_expr);
- if let Some(recv_snippet) = snippet_opt(cx, recv.span);
- if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span);
- if let Some(indent) = indent_of(cx, expr.span);
- then {
- let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4));
- span_lint_and_sugg(
- cx,
- MANUAL_OK_OR,
- expr.span,
- "this pattern reimplements `Option::ok_or`",
- "replace with",
- format!(
- "{recv_snippet}.ok_or({reindented_err_arg_snippet})"
- ),
- Applicability::MachineApplicable,
- );
- }
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Option)
+ && let ExprKind::Call(err_path, [err_arg]) = or_expr.kind
+ && is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr)
+ && is_ok_wrapping(cx, map_expr)
+ && let Some(recv_snippet) = snippet_opt(cx, recv.span)
+ && let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span)
+ && let Some(indent) = indent_of(cx, expr.span)
+ {
+ let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4));
+ span_lint_and_sugg(
+ cx,
+ MANUAL_OK_OR,
+ expr.span,
+ "this pattern reimplements `Option::ok_or`",
+ "replace with",
+ format!("{recv_snippet}.ok_or({reindented_err_arg_snippet})"),
+ Applicability::MachineApplicable,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
index 540425eef..04bdbc1ea 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{match_def_path, path_def_id};
-use if_chain::if_chain;
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -69,16 +68,14 @@ enum MinMax {
fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> {
// `T::max_value()` `T::min_value()` inherent methods
- if_chain! {
- if let hir::ExprKind::Call(func, args) = &expr.kind;
- if args.is_empty();
- if let hir::ExprKind::Path(hir::QPath::TypeRelative(_, segment)) = &func.kind;
- then {
- match segment.ident.as_str() {
- "max_value" => return Some(MinMax::Max),
- "min_value" => return Some(MinMax::Min),
- _ => {}
- }
+ if let hir::ExprKind::Call(func, args) = &expr.kind
+ && args.is_empty()
+ && let hir::ExprKind::Path(hir::QPath::TypeRelative(_, segment)) = &func.kind
+ {
+ match segment.ident.as_str() {
+ "max_value" => return Some(MinMax::Max),
+ "min_value" => return Some(MinMax::Min),
+ _ => {},
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
index ab13d30d8..61e74369c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
@@ -3,7 +3,6 @@ use clippy_utils::is_path_diagnostic_item;
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
-use if_chain::if_chain;
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem};
@@ -55,43 +54,42 @@ pub(super) fn check(
take_self_arg: &Expr<'_>,
take_arg: &Expr<'_>,
) {
- if_chain! {
- if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind;
- if is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat);
- if is_type_lang_item(cx, cx.typeck_results().expr_ty(collect_expr), LangItem::String);
- if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id);
- if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
- if cx.tcx.trait_of_item(take_id) == Some(iter_trait_id);
- if let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg);
- let ctxt = collect_expr.span.ctxt();
- if ctxt == take_expr.span.ctxt();
- if ctxt == take_self_arg.span.ctxt();
- then {
- let mut app = Applicability::MachineApplicable;
- let count_snip = snippet_with_context(cx, take_arg.span, ctxt, "..", &mut app).0;
+ if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind
+ && is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat)
+ && is_type_lang_item(cx, cx.typeck_results().expr_ty(collect_expr), LangItem::String)
+ && let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id)
+ && let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
+ && cx.tcx.trait_of_item(take_id) == Some(iter_trait_id)
+ && let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg)
+ && let ctxt = collect_expr.span.ctxt()
+ && ctxt == take_expr.span.ctxt()
+ && ctxt == take_self_arg.span.ctxt()
+ {
+ let mut app = Applicability::MachineApplicable;
+ let count_snip = snippet_with_context(cx, take_arg.span, ctxt, "..", &mut app).0;
- let val_str = match repeat_kind {
- RepeatKind::Char(_) if repeat_arg.span.ctxt() != ctxt => return,
- RepeatKind::Char('\'') => r#""'""#.into(),
- RepeatKind::Char('"') => r#""\"""#.into(),
- RepeatKind::Char(_) =>
- match snippet_with_applicability(cx, repeat_arg.span, "..", &mut app) {
- Cow::Owned(s) => Cow::Owned(format!("\"{}\"", &s[1..s.len() - 1])),
- s @ Cow::Borrowed(_) => s,
- },
- RepeatKind::String =>
- Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app).maybe_par().to_string().into(),
- };
+ let val_str = match repeat_kind {
+ RepeatKind::Char(_) if repeat_arg.span.ctxt() != ctxt => return,
+ RepeatKind::Char('\'') => r#""'""#.into(),
+ RepeatKind::Char('"') => r#""\"""#.into(),
+ RepeatKind::Char(_) => match snippet_with_applicability(cx, repeat_arg.span, "..", &mut app) {
+ Cow::Owned(s) => Cow::Owned(format!("\"{}\"", &s[1..s.len() - 1])),
+ s @ Cow::Borrowed(_) => s,
+ },
+ RepeatKind::String => Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app)
+ .maybe_par()
+ .to_string()
+ .into(),
+ };
- span_lint_and_sugg(
- cx,
- MANUAL_STR_REPEAT,
- collect_expr.span,
- "manual implementation of `str::repeat` using iterators",
- "try",
- format!("{val_str}.repeat({count_snip})"),
- app
- )
- }
+ span_lint_and_sugg(
+ cx,
+ MANUAL_STR_REPEAT,
+ collect_expr.span,
+ "manual implementation of `str::repeat` using iterators",
+ "try",
+ format!("{val_str}.repeat({count_snip})"),
+ app,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs
index 51145afda..f93edded7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs
@@ -1,14 +1,14 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_from_proc_macro;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::implements_trait;
+use clippy_utils::{is_from_proc_macro, is_trait_method};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_span::Span;
+use rustc_span::{sym, Span};
use super::MANUAL_TRY_FOLD;
@@ -22,6 +22,7 @@ pub(super) fn check<'tcx>(
) {
if !in_external_macro(cx.sess(), fold_span)
&& msrv.meets(msrvs::ITERATOR_TRY_FOLD)
+ && is_trait_method(cx, expr, sym::Iterator)
&& let init_ty = cx.typeck_results().expr_ty(init)
&& let Some(try_trait) = cx.tcx.lang_items().try_trait()
&& implements_trait(cx, init_ty, try_trait, &[])
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
index e0f8cb1b9..cc6eeaa86 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
use clippy_utils::{is_diag_trait_item, peel_blocks};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -16,57 +15,55 @@ use rustc_span::{sym, Span};
use super::MAP_CLONE;
pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>, msrv: &Msrv) {
- if_chain! {
- if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id);
- if cx.tcx.impl_of_method(method_id)
- .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id).instantiate_identity(), sym::Option))
- || is_diag_trait_item(cx, method_id, sym::Iterator);
- if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind;
- then {
- let closure_body = cx.tcx.hir().body(body);
- let closure_expr = peel_blocks(closure_body.value);
- match closure_body.params[0].pat.kind {
- hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
- hir::BindingAnnotation::NONE, .., name, None
- ) = inner.kind {
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+ && (cx.tcx.impl_of_method(method_id).map_or(false, |id| {
+ is_type_diagnostic_item(cx, cx.tcx.type_of(id).instantiate_identity(), sym::Option)
+ }) || is_diag_trait_item(cx, method_id, sym::Iterator))
+ && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind
+ {
+ let closure_body = cx.tcx.hir().body(body);
+ let closure_expr = peel_blocks(closure_body.value);
+ match closure_body.params[0].pat.kind {
+ hir::PatKind::Ref(inner, hir::Mutability::Not) => {
+ if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) = inner.kind {
if ident_eq(name, closure_expr) {
lint_explicit_closure(cx, e.span, recv.span, true, msrv);
}
- },
- hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => {
- match closure_expr.kind {
- hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
- if ident_eq(name, inner) {
- if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
- lint_explicit_closure(cx, e.span, recv.span, true, msrv);
- }
+ }
+ },
+ hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => {
+ match closure_expr.kind {
+ hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
+ if ident_eq(name, inner) {
+ if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
+ lint_explicit_closure(cx, e.span, recv.span, true, msrv);
}
- },
- hir::ExprKind::MethodCall(method, obj, [], _) => if_chain! {
- if ident_eq(name, obj) && method.ident.name == sym::clone;
- if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id);
- if let Some(trait_id) = cx.tcx.trait_of_item(fn_id);
- if cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id);
- // no autoderefs
- if !cx.typeck_results().expr_adjustments(obj).iter()
- .any(|a| matches!(a.kind, Adjust::Deref(Some(..))));
- then {
- let obj_ty = cx.typeck_results().expr_ty(obj);
- if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
- if matches!(mutability, Mutability::Not) {
- let copy = is_copy(cx, *ty);
- lint_explicit_closure(cx, e.span, recv.span, copy, msrv);
- }
- } else {
- lint_needless_cloning(cx, e.span, recv.span);
+ }
+ },
+ hir::ExprKind::MethodCall(method, obj, [], _) => {
+ if ident_eq(name, obj) && method.ident.name == sym::clone
+ && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id)
+ && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+ && cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id)
+ // no autoderefs
+ && !cx.typeck_results().expr_adjustments(obj).iter()
+ .any(|a| matches!(a.kind, Adjust::Deref(Some(..))))
+ {
+ let obj_ty = cx.typeck_results().expr_ty(obj);
+ if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
+ if matches!(mutability, Mutability::Not) {
+ let copy = is_copy(cx, *ty);
+ lint_explicit_closure(cx, e.span, recv.span, copy, msrv);
}
+ } else {
+ lint_needless_cloning(cx, e.span, recv.span);
}
- },
- _ => {},
- }
- },
- _ => {},
- }
+ }
+ },
+ _ => {},
+ }
+ },
+ _ => {},
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs b/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs
index 01cdd02e6..e944eac91 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -13,26 +12,24 @@ use super::MAP_COLLECT_RESULT_UNIT;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr<'_>, map_fn: &hir::Expr<'_>) {
// return of collect `Result<(),_>`
let collect_ret_ty = cx.typeck_results().expr_ty(expr);
- if_chain! {
- if is_type_diagnostic_item(cx, collect_ret_ty, sym::Result);
- if let ty::Adt(_, args) = collect_ret_ty.kind();
- if let Some(result_t) = args.types().next();
- if result_t.is_unit();
- // get parts for snippet
- then {
- span_lint_and_sugg(
- cx,
- MAP_COLLECT_RESULT_UNIT,
- expr.span,
- "`.map().collect()` can be replaced with `.try_for_each()`",
- "try",
- format!(
- "{}.try_for_each({})",
- snippet(cx, iter.span, ".."),
- snippet(cx, map_fn.span, "..")
- ),
- Applicability::MachineApplicable,
- );
- }
+ if is_type_diagnostic_item(cx, collect_ret_ty, sym::Result)
+ && let ty::Adt(_, args) = collect_ret_ty.kind()
+ && let Some(result_t) = args.types().next()
+ && result_t.is_unit()
+ // get parts for snippet
+ {
+ span_lint_and_sugg(
+ cx,
+ MAP_COLLECT_RESULT_UNIT,
+ expr.span,
+ "`.map().collect()` can be replaced with `.try_for_each()`",
+ "try",
+ format!(
+ "{}.try_for_each({})",
+ snippet(cx, iter.span, ".."),
+ snippet(cx, map_fn.span, "..")
+ ),
+ Applicability::MachineApplicable,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
index e74a76455..26ef0d10f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
@@ -63,7 +63,7 @@ fn is_map_to_option(cx: &LateContext<'_>, map_arg: &Expr<'_>) -> bool {
ty::Closure(_, args) => args.as_closure().sig(),
_ => map_closure_ty.fn_sig(cx.tcx),
};
- let map_closure_return_ty = cx.tcx.erase_late_bound_regions(map_closure_sig.output());
+ let map_closure_return_ty = cx.tcx.instantiate_bound_regions_with_erased(map_closure_sig.output());
is_type_diagnostic_item(cx, map_closure_return_ty, sym::Option)
},
_ => false,
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
index bcfd0de8e..6da9a87f5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
@@ -18,22 +18,20 @@ pub(super) fn check(
) {
let caller_ty = cx.typeck_results().expr_ty(caller);
- if_chain! {
- if is_trait_method(cx, expr, sym::Iterator)
- || is_type_diagnostic_item(cx, caller_ty, sym::Result)
- || is_type_diagnostic_item(cx, caller_ty, sym::Option);
- if is_expr_untyped_identity_function(cx, map_arg);
- if let Some(sugg_span) = expr.span.trim_start(caller.span);
- then {
- span_lint_and_sugg(
- cx,
- MAP_IDENTITY,
- sugg_span,
- "unnecessary map of the identity function",
- &format!("remove the call to `{name}`"),
- String::new(),
- Applicability::MachineApplicable,
- )
- }
+ if (is_trait_method(cx, expr, sym::Iterator)
+ || is_type_diagnostic_item(cx, caller_ty, sym::Result)
+ || is_type_diagnostic_item(cx, caller_ty, sym::Option))
+ && is_expr_untyped_identity_function(cx, map_arg)
+ && let Some(sugg_span) = expr.span.trim_start(caller.span)
+ {
+ span_lint_and_sugg(
+ cx,
+ MAP_IDENTITY,
+ sugg_span,
+ "unnecessary map of the identity function",
+ &format!("remove the call to `{name}`"),
+ String::new(),
+ Applicability::MachineApplicable,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
index cb81b3919..52ea584a2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
@@ -44,11 +44,9 @@ pub(super) fn check<'tcx>(
// lint message
let msg = if is_option {
- "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling \
- `map_or_else(<g>, <f>)` instead"
+ "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value"
} else {
- "called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling \
- `.map_or_else(<g>, <f>)` instead"
+ "called `map(<f>).unwrap_or_else(<g>)` on a `Result` value"
};
// get snippets for args to map() and unwrap_or_else()
let map_snippet = snippet(cx, map_arg.span, "..");
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index a71a136eb..b4f60ffad 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -49,6 +49,7 @@ mod iter_skip_next;
mod iter_skip_zero;
mod iter_with_drain;
mod iterator_step_by_zero;
+mod join_absolute_paths;
mod manual_next_back;
mod manual_ok_or;
mod manual_saturating_arithmetic;
@@ -69,6 +70,7 @@ mod obfuscated_if_else;
mod ok_expect;
mod open_options;
mod option_as_ref_deref;
+mod option_map_or_err_ok;
mod option_map_or_none;
mod option_map_unwrap_or;
mod or_fun_call;
@@ -80,6 +82,7 @@ mod read_line_without_trim;
mod readonly_write_lock;
mod redundant_as_str;
mod repeat_once;
+mod result_map_or_else_none;
mod search_is_some;
mod seek_from_current;
mod seek_to_start_instead_of_rewind;
@@ -123,7 +126,6 @@ use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty};
-use if_chain::if_chain;
pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
@@ -131,7 +133,7 @@ use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, TraitRef, Ty};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{sym, Span};
declare_clippy_lint! {
@@ -3610,7 +3612,7 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
- /// Checks for usage of `as_str()` on a `String`` chained with a method available on the `String` itself.
+ /// Checks for usage of `as_str()` on a `String` chained with a method available on the `String` itself.
///
/// ### Why is this bad?
/// The `as_str()` conversion is pointless and can be removed for simplicity and cleanliness.
@@ -3619,14 +3621,16 @@ declare_clippy_lint! {
/// ```no_run
/// # #![allow(unused)]
/// let owned_string = "This is a string".to_owned();
- /// owned_string.as_str().as_bytes();
+ /// owned_string.as_str().as_bytes()
+ /// # ;
/// ```
///
/// Use instead:
/// ```no_run
/// # #![allow(unused)]
/// let owned_string = "This is a string".to_owned();
- /// owned_string.as_bytes();
+ /// owned_string.as_bytes()
+ /// # ;
/// ```
#[clippy::version = "1.74.0"]
pub REDUNDANT_AS_STR,
@@ -3683,6 +3687,71 @@ declare_clippy_lint! {
"calling the `try_from` and `try_into` trait methods when `From`/`Into` is implemented"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for calls to `Path::join` that start with a path separator (`\\` or `/`).
+ ///
+ /// ### Why is this bad?
+ /// If the argument to `Path::join` starts with a separator, it will overwrite
+ /// the original path. If this is intentional, prefer using `Path::new` instead.
+ ///
+ /// Note the behavior is platform dependent. A leading `\\` will be accepted
+ /// on unix systems as part of the file name
+ ///
+ /// See [`Path::join`](https://doc.rust-lang.org/std/path/struct.Path.html#method.join)
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::path::{Path, PathBuf};
+ /// let path = Path::new("/bin");
+ /// let joined_path = path.join("/sh");
+ /// assert_eq!(joined_path, PathBuf::from("/sh"));
+ /// ```
+ ///
+ /// Use instead;
+ /// ```rust
+ /// # use std::path::{Path, PathBuf};
+ /// let path = Path::new("/bin");
+ ///
+ /// // If this was unintentional, remove the leading separator
+ /// let joined_path = path.join("sh");
+ /// assert_eq!(joined_path, PathBuf::from("/bin/sh"));
+ ///
+ /// // If this was intentional, create a new path instead
+ /// let new = Path::new("/sh");
+ /// assert_eq!(new, PathBuf::from("/sh"));
+ /// ```
+ #[clippy::version = "1.76.0"]
+ pub JOIN_ABSOLUTE_PATHS,
+ suspicious,
+ "calls to `Path::join` which will overwrite the original path"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usage of `_.map_or(Err(_), Ok)`.
+ ///
+ /// ### Why is this bad?
+ /// Readability, this can be written more concisely as
+ /// `_.ok_or(_)`.
+ ///
+ /// ### Example
+ /// ```no_run
+ /// # let opt = Some(1);
+ /// opt.map_or(Err("error"), Ok);
+ /// ```
+ ///
+ /// Use instead:
+ /// ```no_run
+ /// # let opt = Some(1);
+ /// opt.ok_or("error");
+ /// ```
+ #[clippy::version = "1.76.0"]
+ pub OPTION_MAP_OR_ERR_OK,
+ style,
+ "using `Option.map_or(Err(_), Ok)`, which is more succinctly expressed as `Option.ok_or(_)`"
+}
+
pub struct Methods {
avoid_breaking_exported_api: bool,
msrv: Msrv,
@@ -3698,8 +3767,10 @@ impl Methods {
msrv: Msrv,
allow_expect_in_tests: bool,
allow_unwrap_in_tests: bool,
- allowed_dotfiles: FxHashSet<String>,
+ mut allowed_dotfiles: FxHashSet<String>,
) -> Self {
+ allowed_dotfiles.extend(DEFAULT_ALLOWED_DOTFILES.iter().map(ToString::to_string));
+
Self {
avoid_breaking_exported_api,
msrv,
@@ -3830,10 +3901,12 @@ impl_lint_pass!(Methods => [
REDUNDANT_AS_STR,
WAKER_CLONE_WAKE,
UNNECESSARY_FALLIBLE_CONVERSIONS,
+ JOIN_ABSOLUTE_PATHS,
+ OPTION_MAP_OR_ERR_OK,
]);
/// Extracts a method call name, args, and `Span` of the method name.
-fn method_call<'tcx>(
+pub fn method_call<'tcx>(
recv: &'tcx hir::Expr<'tcx>,
) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> {
if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind {
@@ -3896,7 +3969,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind {
let method_sig = cx.tcx.fn_sig(impl_item.owner_id).instantiate_identity();
- let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
+ let method_sig = cx.tcx.instantiate_bound_regions_with_erased(method_sig);
let first_arg_ty_opt = method_sig.inputs().iter().next().copied();
// if this impl block implements a trait, lint in trait definition instead
if !implements_trait && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
@@ -3977,44 +4050,41 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
return;
}
- if_chain! {
- if let TraitItemKind::Fn(ref sig, _) = item.kind;
- if sig.decl.implicit_self.has_implicit_self();
- if let Some(first_arg_hir_ty) = sig.decl.inputs.first();
- if let Some(&first_arg_ty) = cx.tcx.fn_sig(item.owner_id)
+ if let TraitItemKind::Fn(ref sig, _) = item.kind
+ && sig.decl.implicit_self.has_implicit_self()
+ && let Some(first_arg_hir_ty) = sig.decl.inputs.first()
+ && let Some(&first_arg_ty) = cx
+ .tcx
+ .fn_sig(item.owner_id)
.instantiate_identity()
.inputs()
.skip_binder()
- .first();
- then {
- let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty();
- wrong_self_convention::check(
- cx,
- item.ident.name.as_str(),
- self_ty,
- first_arg_ty,
- first_arg_hir_ty.span,
- false,
- true,
- );
- }
- }
-
- if_chain! {
- if item.ident.name == sym::new;
- if let TraitItemKind::Fn(_, _) = item.kind;
- let ret_ty = return_ty(cx, item.owner_id);
+ .first()
+ {
let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty();
- if !ret_ty.contains(self_ty);
+ wrong_self_convention::check(
+ cx,
+ item.ident.name.as_str(),
+ self_ty,
+ first_arg_ty,
+ first_arg_hir_ty.span,
+ false,
+ true,
+ );
+ }
- then {
- span_lint(
- cx,
- NEW_RET_NO_SELF,
- item.span,
- "methods called `new` usually return `Self`",
- );
- }
+ if item.ident.name == sym::new
+ && let TraitItemKind::Fn(_, _) = item.kind
+ && let ret_ty = return_ty(cx, item.owner_id)
+ && let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty()
+ && !ret_ty.contains(self_ty)
+ {
+ span_lint(
+ cx,
+ NEW_RET_NO_SELF,
+ item.span,
+ "methods called `new` usually return `Self`",
+ );
}
}
@@ -4235,6 +4305,8 @@ impl Methods {
("join", [join_arg]) => {
if let Some(("collect", _, _, span, _)) = method_call(recv) {
unnecessary_join::check(cx, expr, recv, join_arg, span);
+ } else {
+ join_absolute_paths::check(cx, recv, join_arg, expr.span);
}
},
("last", []) => {
@@ -4257,7 +4329,7 @@ impl Methods {
map_clone::check(cx, expr, recv, m_arg, &self.msrv);
match method_call(recv) {
Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => {
- iter_kv_map::check(cx, map_name, expr, recv2, m_arg);
+ iter_kv_map::check(cx, map_name, expr, recv2, m_arg, &self.msrv);
},
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
cx,
@@ -4290,6 +4362,10 @@ impl Methods {
("map_or", [def, map]) => {
option_map_or_none::check(cx, expr, recv, def, map);
manual_ok_or::check(cx, expr, recv, def, map);
+ option_map_or_err_ok::check(cx, expr, recv, def, map);
+ },
+ ("map_or_else", [def, map]) => {
+ result_map_or_else_none::check(cx, expr, recv, def, map);
},
("next", []) => {
if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
index 2855e23bf..1a0fce287 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::expr_custom_deref_adjustment;
use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, Mutability};
use rustc_lint::LateContext;
@@ -11,22 +10,20 @@ use rustc_span::{sym, Span};
use super::MUT_MUTEX_LOCK;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) {
- if_chain! {
- if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut));
- if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind();
- if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id);
- if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Mutex);
- then {
- span_lint_and_sugg(
- cx,
- MUT_MUTEX_LOCK,
- name_span,
- "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference",
- "change this to",
- "get_mut".to_owned(),
- Applicability::MaybeIncorrect,
- );
- }
+ if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut))
+ && let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind()
+ && let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Mutex)
+ {
+ span_lint_and_sugg(
+ cx,
+ MUT_MUTEX_LOCK,
+ name_span,
+ "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference",
+ "change this to",
+ "get_mut".to_owned(),
+ Applicability::MaybeIncorrect,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 2ef71be32..293b4981c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -225,7 +225,10 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -
&& let sig = cx.tcx.fn_sig(id).instantiate_identity()
&& sig.skip_binder().output().is_bool()
&& let [_, search_ty] = *sig.skip_binder().inputs()
- && let ty::Ref(_, search_ty, Mutability::Not) = *cx.tcx.erase_late_bound_regions(sig.rebind(search_ty)).kind()
+ && let ty::Ref(_, search_ty, Mutability::Not) = *cx
+ .tcx
+ .instantiate_bound_regions_with_erased(sig.rebind(search_ty))
+ .kind()
&& let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
&& let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_name_and_kind(
cx.tcx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs b/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs
index 01655e860..81df32bde 100644
--- a/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::is_type_lang_item;
use clippy_utils::SpanlessEq;
-use if_chain::if_chain;
use rustc_ast::LitKind;
use rustc_hir::{ExprKind, LangItem};
use rustc_lint::LateContext;
@@ -19,17 +18,13 @@ pub(super) fn check<'tcx>(
return;
}
- if_chain! {
- if let ExprKind::Lit(spanned) = &arg1.kind;
- if let Some(param1) = lit_string_value(&spanned.node);
-
- if let ExprKind::Lit(spanned) = &arg2.kind;
- if let LitKind::Str(param2, _) = &spanned.node;
- if param1 == param2.as_str();
-
- then {
- span_lint(cx, NO_EFFECT_REPLACE, expr.span, "replacing text with itself");
- }
+ if let ExprKind::Lit(spanned) = &arg1.kind
+ && let Some(param1) = lit_string_value(&spanned.node)
+ && let ExprKind::Lit(spanned) = &arg2.kind
+ && let LitKind::Str(param2, _) = &spanned.node
+ && param1 == param2.as_str()
+ {
+ span_lint(cx, NO_EFFECT_REPLACE, expr.span, "replacing text with itself");
}
if SpanlessEq::new(cx).eq_expr(arg1, arg2) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs b/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
index f2ef42933..e10bc0216 100644
--- a/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item};
-use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
@@ -10,23 +9,20 @@ use super::OK_EXPECT;
/// lint use of `ok().expect()` for `Result`s
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
- if_chain! {
+ if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
// lint if the caller of `ok()` is a `Result`
- if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
- let result_type = cx.typeck_results().expr_ty(recv);
- if let Some(error_type) = get_error_type(cx, result_type);
- if has_debug_impl(cx, error_type);
-
- then {
- span_lint_and_help(
- cx,
- OK_EXPECT,
- expr.span,
- "called `ok().expect()` on a `Result` value",
- None,
- "you can call `expect()` directly on the `Result`",
- );
- }
+ && let result_type = cx.typeck_results().expr_ty(recv)
+ && let Some(error_type) = get_error_type(cx, result_type)
+ && has_debug_impl(cx, error_type)
+ {
+ span_lint_and_help(
+ cx,
+ OK_EXPECT,
+ expr.span,
+ "called `ok().expect()` on a `Result` value",
+ None,
+ "you can call `expect()` directly on the `Result`",
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index 7b81d4571..756dbe62d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{match_def_path, path_to_local_id, paths, peel_blocks};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -58,34 +57,30 @@ pub(super) fn check(
match &closure_expr.kind {
hir::ExprKind::MethodCall(_, receiver, [], _) => {
- if_chain! {
- if path_to_local_id(receiver, closure_body.params[0].pat.hir_id);
- let adj = cx
+ if path_to_local_id(receiver, closure_body.params[0].pat.hir_id)
+ && let adj = cx
.typeck_results()
.expr_adjustments(receiver)
.iter()
.map(|x| &x.kind)
- .collect::<Box<[_]>>();
- if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
- then {
- let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
- cx.tcx.is_diagnostic_item(sym::deref_method, method_did)
- || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did)
- || deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
- } else {
- false
- }
+ .collect::<Box<[_]>>()
+ && let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj
+ {
+ let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
+ cx.tcx.is_diagnostic_item(sym::deref_method, method_did)
+ || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did)
+ || deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
+ } else {
+ false
}
},
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, inner) if same_mutability(m) => {
- if_chain! {
- if let hir::ExprKind::Unary(hir::UnOp::Deref, inner1) = inner.kind;
- if let hir::ExprKind::Unary(hir::UnOp::Deref, inner2) = inner1.kind;
- then {
- path_to_local_id(inner2, closure_body.params[0].pat.hir_id)
- } else {
- false
- }
+ if let hir::ExprKind::Unary(hir::UnOp::Deref, inner1) = inner.kind
+ && let hir::ExprKind::Unary(hir::UnOp::Deref, inner2) = inner1.kind
+ {
+ path_to_local_id(inner2, closure_body.params[0].pat.hir_id)
+ } else {
+ false
}
},
_ => false,
@@ -104,10 +99,7 @@ pub(super) fn check(
let hint = format!("{}.{method_hint}()", snippet(cx, as_ref_recv.span, ".."));
let suggestion = format!("try using {method_hint} instead");
- let msg = format!(
- "called `{current_method}` on an Option value. This can be done more directly \
- by calling `{hint}` instead"
- );
+ let msg = format!("called `{current_method}` on an `Option` value");
span_lint_and_sugg(
cx,
OPTION_AS_REF_DEREF,
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_err_ok.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_err_ok.rs
new file mode 100644
index 000000000..91e39d5a1
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_err_ok.rs
@@ -0,0 +1,41 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_res_lang_ctor, path_res};
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::{ResultErr, ResultOk};
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
+
+use super::OPTION_MAP_OR_ERR_OK;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'tcx>,
+ recv: &'tcx Expr<'_>,
+ or_expr: &'tcx Expr<'_>,
+ map_expr: &'tcx Expr<'_>,
+) {
+ // We check that it's called on an `Option` type.
+ if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option)
+ // We check that first we pass an `Err`.
+ && let ExprKind::Call(call, &[arg]) = or_expr.kind
+ && is_res_lang_ctor(cx, path_res(cx, call), ResultErr)
+ // And finally we check that it is mapped as `Ok`.
+ && is_res_lang_ctor(cx, path_res(cx, map_expr), ResultOk)
+ {
+ let msg = "called `map_or(Err(_), Ok)` on an `Option` value";
+ let self_snippet = snippet(cx, recv.span, "..");
+ let err_snippet = snippet(cx, arg.span, "..");
+ span_lint_and_sugg(
+ cx,
+ OPTION_MAP_OR_ERR_OK,
+ expr.span,
+ msg,
+ "try using `ok_or` instead",
+ format!("{self_snippet}.ok_or({err_snippet})"),
+ Applicability::MachineApplicable,
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
index cb6a23068..ff4d8cc9e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
@@ -58,32 +58,28 @@ pub(super) fn check<'tcx>(
if is_option {
let self_snippet = snippet(cx, recv.span, "..");
- if_chain! {
- if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = map_arg.kind;
- let arg_snippet = snippet(cx, fn_decl_span, "..");
- let body = cx.tcx.hir().body(body);
- if let Some((func, [arg_char])) = reduce_unit_expression(body.value);
- if let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id));
- if Some(id) == cx.tcx.lang_items().option_some_variant();
- then {
- let func_snippet = snippet(cx, arg_char.span, "..");
- let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
- `map(..)` instead";
- return span_lint_and_sugg(
- cx,
- OPTION_MAP_OR_NONE,
- expr.span,
- msg,
- "try using `map` instead",
- format!("{self_snippet}.map({arg_snippet} {func_snippet})"),
- Applicability::MachineApplicable,
- );
- }
+ if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = map_arg.kind
+ && let arg_snippet = snippet(cx, fn_decl_span, "..")
+ && let body = cx.tcx.hir().body(body)
+ && let Some((func, [arg_char])) = reduce_unit_expression(body.value)
+ && let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id))
+ && Some(id) == cx.tcx.lang_items().option_some_variant()
+ {
+ let func_snippet = snippet(cx, arg_char.span, "..");
+ let msg = "called `map_or(None, ..)` on an `Option` value";
+ return span_lint_and_sugg(
+ cx,
+ OPTION_MAP_OR_NONE,
+ expr.span,
+ msg,
+ "try using `map` instead",
+ format!("{self_snippet}.map({arg_snippet} {func_snippet})"),
+ Applicability::MachineApplicable,
+ );
}
let func_snippet = snippet(cx, map_arg.span, "..");
- let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
- `and_then(..)` instead";
+ let msg = "called `map_or(None, ..)` on an `Option` value";
span_lint_and_sugg(
cx,
OPTION_MAP_OR_NONE,
@@ -94,8 +90,7 @@ pub(super) fn check<'tcx>(
Applicability::MachineApplicable,
);
} else if f_arg_is_some {
- let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \
- `ok()` instead";
+ let msg = "called `map_or(None, Some)` on a `Result` value";
let self_snippet = snippet(cx, recv.span, "..");
span_lint_and_sugg(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
index c78f8b71c..63e64a5b3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::intravisit::{walk_path, Visitor};
-use rustc_hir::{self, ExprKind, HirId, Node, PatKind, Path, QPath};
+use rustc_hir::{ExprKind, HirId, Node, PatKind, Path, QPath};
use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter;
use rustc_span::{sym, Span};
@@ -97,10 +97,7 @@ pub(super) fn check<'tcx>(
} else {
"map_or(<a>, <f>)"
};
- let msg = &format!(
- "called `map(<f>).unwrap_or({arg})` on an `Option` value. \
- This can be done more directly by calling `{suggest}` instead"
- );
+ let msg = &format!("called `map(<f>).unwrap_or({arg})` on an `Option` value");
span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| {
let map_arg_span = map_arg.span;
@@ -138,7 +135,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> {
fn visit_path(&mut self, path: &Path<'tcx>, _: HirId) {
if let Res::Local(local_id) = path.res
- && let Some(Node::Pat(pat)) = self.cx.tcx.hir().find(local_id)
+ && let Some(Node::Pat(pat)) = self.cx.tcx.opt_hir_node(local_id)
&& let PatKind::Binding(_, local_id, ..) = pat.kind
{
self.identifiers.insert(local_id);
@@ -169,7 +166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ReferenceVisitor<'a, 'tcx> {
&& let ExprKind::Path(ref path) = expr.kind
&& let QPath::Resolved(_, path) = path
&& let Res::Local(local_id) = path.res
- && let Some(Node::Pat(pat)) = self.cx.tcx.hir().find(local_id)
+ && let Some(Node::Pat(pat)) = self.cx.tcx.opt_hir_node(local_id)
&& let PatKind::Binding(_, local_id, ..) = pat.kind
&& self.identifiers.contains(&local_id)
{
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index b89c15146..e38c66f67 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -3,12 +3,11 @@ use clippy_utils::eager_or_lazy::switch_to_lazy_eval;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item};
use clippy_utils::{contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_span::Span;
use rustc_span::symbol::{self, sym, Symbol};
+use rustc_span::Span;
use {rustc_ast as ast, rustc_hir as hir};
use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT};
@@ -131,54 +130,47 @@ pub(super) fn check<'tcx>(
(sym::Result, true, &["or", "unwrap_or"], "else"),
];
- if_chain! {
- if KNOW_TYPES.iter().any(|k| k.2.contains(&name));
-
- if switch_to_lazy_eval(cx, arg);
- if !contains_return(arg);
-
- let self_ty = cx.typeck_results().expr_ty(self_expr);
-
- if let Some(&(_, fn_has_arguments, poss, suffix)) =
- KNOW_TYPES.iter().find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0));
-
- if poss.contains(&name);
-
- then {
- let ctxt = span.ctxt();
- let mut app = Applicability::HasPlaceholders;
- let sugg = {
- let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) {
- (false, Some(fun_span)) => (fun_span, false),
- _ => (arg.span, true),
- };
-
- let snip = snippet_with_context(cx, snippet_span, ctxt, "..", &mut app).0;
- let snip = if use_lambda {
- let l_arg = if fn_has_arguments { "_" } else { "" };
- format!("|{l_arg}| {snip}")
- } else {
- snip.into_owned()
- };
-
- if let Some(f) = second_arg {
- let f = snippet_with_context(cx, f.span, ctxt, "..", &mut app).0;
- format!("{snip}, {f}")
- } else {
- snip
- }
+ if KNOW_TYPES.iter().any(|k| k.2.contains(&name))
+ && switch_to_lazy_eval(cx, arg)
+ && !contains_return(arg)
+ && let self_ty = cx.typeck_results().expr_ty(self_expr)
+ && let Some(&(_, fn_has_arguments, poss, suffix)) =
+ KNOW_TYPES.iter().find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0))
+ && poss.contains(&name)
+ {
+ let ctxt = span.ctxt();
+ let mut app = Applicability::HasPlaceholders;
+ let sugg = {
+ let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) {
+ (false, Some(fun_span)) => (fun_span, false),
+ _ => (arg.span, true),
+ };
+
+ let snip = snippet_with_context(cx, snippet_span, ctxt, "..", &mut app).0;
+ let snip = if use_lambda {
+ let l_arg = if fn_has_arguments { "_" } else { "" };
+ format!("|{l_arg}| {snip}")
+ } else {
+ snip.into_owned()
};
- let span_replace_word = method_span.with_hi(span.hi());
- span_lint_and_sugg(
- cx,
- OR_FUN_CALL,
- span_replace_word,
- &format!("use of `{name}` followed by a function call"),
- "try",
- format!("{name}_{suffix}({sugg})"),
- app,
- );
- }
+
+ if let Some(f) = second_arg {
+ let f = snippet_with_context(cx, f.span, ctxt, "..", &mut app).0;
+ format!("{snip}, {f}")
+ } else {
+ snip
+ }
+ };
+ let span_replace_word = method_span.with_hi(span.hi());
+ span_lint_and_sugg(
+ cx,
+ OR_FUN_CALL,
+ span_replace_word,
+ &format!("use of `{name}` followed by a function call"),
+ "try",
+ format!("{name}_{suffix}({sugg})"),
+ app,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
index 1c07d2a3a..04a27cc98 100644
--- a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
@@ -11,27 +10,25 @@ use std::path::{Component, Path};
use super::PATH_BUF_PUSH_OVERWRITE;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
- if_chain! {
- if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::PathBuf);
- if let ExprKind::Lit(lit) = arg.kind;
- if let LitKind::Str(ref path_lit, _) = lit.node;
- if let pushed_path = Path::new(path_lit.as_str());
- if let Some(pushed_path_lit) = pushed_path.to_str();
- if pushed_path.has_root();
- if let Some(root) = pushed_path.components().next();
- if root == Component::RootDir;
- then {
- span_lint_and_sugg(
- cx,
- PATH_BUF_PUSH_OVERWRITE,
- lit.span,
- "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition",
- "try",
- format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')),
- Applicability::MachineApplicable,
- );
- }
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::PathBuf)
+ && let ExprKind::Lit(lit) = arg.kind
+ && let LitKind::Str(ref path_lit, _) = lit.node
+ && let pushed_path = Path::new(path_lit.as_str())
+ && let Some(pushed_path_lit) = pushed_path.to_str()
+ && pushed_path.has_root()
+ && let Some(root) = pushed_path.components().next()
+ && root == Component::RootDir
+ {
+ span_lint_and_sugg(
+ cx,
+ PATH_BUF_PUSH_OVERWRITE,
+ lit.span,
+ "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition",
+ "try",
+ format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')),
+ Applicability::MachineApplicable,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
index f253d8de9..1148628b0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet;
use clippy_utils::{higher, is_integer_const, is_trait_method, SpanlessEq};
-use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::LateContext;
use rustc_span::sym;
@@ -9,25 +8,26 @@ use rustc_span::sym;
use super::RANGE_ZIP_WITH_LEN;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, zip_arg: &'tcx Expr<'_>) {
- if_chain! {
- if is_trait_method(cx, expr, sym::Iterator);
+ if is_trait_method(cx, expr, sym::Iterator)
// range expression in `.zip()` call: `0..x.len()`
- if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
- if is_integer_const(cx, start, 0);
+ && let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg)
+ && is_integer_const(cx, start, 0)
// `.len()` call
- if let ExprKind::MethodCall(len_path, len_recv, [], _) = end.kind;
- if len_path.ident.name == sym::len;
+ && let ExprKind::MethodCall(len_path, len_recv, [], _) = end.kind
+ && len_path.ident.name == sym::len
// `.iter()` and `.len()` called on same `Path`
- if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind;
- if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_recv.kind;
- if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments);
- then {
- span_lint(cx,
- RANGE_ZIP_WITH_LEN,
- expr.span,
- &format!("it is more idiomatic to use `{}.iter().enumerate()`",
- snippet(cx, recv.span, "_"))
- );
- }
+ && let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind
+ && let ExprKind::Path(QPath::Resolved(_, len_path)) = len_recv.kind
+ && SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments)
+ {
+ span_lint(
+ cx,
+ RANGE_ZIP_WITH_LEN,
+ expr.span,
+ &format!(
+ "it is more idiomatic to use `{}.iter().enumerate()`",
+ snippet(cx, recv.span, "_")
+ ),
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs b/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs
new file mode 100644
index 000000000..bc16a1128
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs
@@ -0,0 +1,42 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks};
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::LangItem::{OptionNone, OptionSome};
+use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
+
+use super::RESULT_MAP_OR_INTO_OPTION;
+
+/// lint use of `_.map_or_else(|_| None, Some)` for `Result`s
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx hir::Expr<'_>,
+ recv: &'tcx hir::Expr<'_>,
+ def_arg: &'tcx hir::Expr<'_>,
+ map_arg: &'tcx hir::Expr<'_>,
+) {
+ // lint if the caller of `map_or_else()` is a `Result`
+ if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
+ // We check that it is mapped as `Some`.
+ && is_res_lang_ctor(cx, path_res(cx, map_arg), OptionSome)
+ && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = def_arg.kind
+ && let body = cx.tcx.hir().body(body)
+ // And finally we check that we return a `None` in the "else case".
+ && is_res_lang_ctor(cx, path_res(cx, peel_blocks(body.value)), OptionNone)
+ {
+ let msg = "called `map_or_else(|_| None, Some)` on a `Result` value";
+ let self_snippet = snippet(cx, recv.span, "..");
+ span_lint_and_sugg(
+ cx,
+ RESULT_MAP_OR_INTO_OPTION,
+ expr.span,
+ msg,
+ "try using `ok` instead",
+ format!("{self_snippet}.ok()"),
+ Applicability::MachineApplicable,
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
index 05a9a06c8..6339011c9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
@@ -3,13 +3,12 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::deref_closure_args;
use clippy_utils::ty::is_type_lang_item;
use clippy_utils::{is_trait_method, strip_pat_refs};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::PatKind;
use rustc_lint::LateContext;
-use rustc_span::Span;
use rustc_span::symbol::sym;
+use rustc_span::Span;
use super::SEARCH_IS_SOME;
@@ -35,29 +34,27 @@ pub(super) fn check<'tcx>(
// suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
// suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
let mut applicability = Applicability::MachineApplicable;
- let any_search_snippet = if_chain! {
- if search_method == "find";
- if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind;
- let closure_body = cx.tcx.hir().body(body);
- if let Some(closure_arg) = closure_body.params.first();
- then {
- if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
- Some(search_snippet.replacen('&', "", 1))
- } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind {
- // `find()` provides a reference to the item, but `any` does not,
- // so we should fix item usages for suggestion
- if let Some(closure_sugg) = deref_closure_args(cx, search_arg) {
- applicability = closure_sugg.applicability;
- Some(closure_sugg.suggestion)
- } else {
- Some(search_snippet.to_string())
- }
+ let any_search_snippet = if search_method == "find"
+ && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind
+ && let closure_body = cx.tcx.hir().body(body)
+ && let Some(closure_arg) = closure_body.params.first()
+ {
+ if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
+ Some(search_snippet.replacen('&', "", 1))
+ } else if let PatKind::Binding(..) = strip_pat_refs(closure_arg.pat).kind {
+ // `find()` provides a reference to the item, but `any` does not,
+ // so we should fix item usages for suggestion
+ if let Some(closure_sugg) = deref_closure_args(cx, search_arg) {
+ applicability = closure_sugg.applicability;
+ Some(closure_sugg.suggestion)
} else {
- None
+ Some(search_snippet.to_string())
}
} else {
None
}
+ } else {
+ None
};
// add note if not multi-line
if is_some {
@@ -110,41 +107,37 @@ pub(super) fn check<'tcx>(
self_ty.is_str()
}
};
- if_chain! {
- if is_string_or_str_slice(search_recv);
- if is_string_or_str_slice(search_arg);
- then {
- let msg = format!("called `{option_check_method}()` after calling `find()` on a string");
- match option_check_method {
- "is_some" => {
- let mut applicability = Applicability::MachineApplicable;
- let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability);
- span_lint_and_sugg(
- cx,
- SEARCH_IS_SOME,
- method_span.with_hi(expr.span.hi()),
- &msg,
- "use `contains()` instead",
- format!("contains({find_arg})"),
- applicability,
- );
- },
- "is_none" => {
- let string = snippet(cx, search_recv.span, "..");
- let mut applicability = Applicability::MachineApplicable;
- let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability);
- span_lint_and_sugg(
- cx,
- SEARCH_IS_SOME,
- expr.span,
- &msg,
- "use `!_.contains()` instead",
- format!("!{string}.contains({find_arg})"),
- applicability,
- );
- },
- _ => (),
- }
+ if is_string_or_str_slice(search_recv) && is_string_or_str_slice(search_arg) {
+ let msg = format!("called `{option_check_method}()` after calling `find()` on a string");
+ match option_check_method {
+ "is_some" => {
+ let mut applicability = Applicability::MachineApplicable;
+ let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability);
+ span_lint_and_sugg(
+ cx,
+ SEARCH_IS_SOME,
+ method_span.with_hi(expr.span.hi()),
+ &msg,
+ "use `contains()` instead",
+ format!("contains({find_arg})"),
+ applicability,
+ );
+ },
+ "is_none" => {
+ let string = snippet(cx, search_recv.span, "..");
+ let mut applicability = Applicability::MachineApplicable;
+ let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability);
+ span_lint_and_sugg(
+ cx,
+ SEARCH_IS_SOME,
+ expr.span,
+ &msg,
+ "use `!_.contains()` instead",
+ format!("!{string}.contains({find_arg})"),
+ applicability,
+ );
+ },
+ _ => (),
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
index 4d704ec39..3983f0c0c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
@@ -1,6 +1,5 @@
use super::utils::get_hint_if_single_char_arg;
use clippy_utils::diagnostics::span_lint_and_sugg;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -45,24 +44,23 @@ pub(super) fn check(
args: &[hir::Expr<'_>],
) {
for &(method, pos) in &PATTERN_METHODS {
- if_chain! {
- if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind();
- if ty.is_str();
- if method_name.as_str() == method && args.len() > pos;
- let arg = &args[pos];
- let mut applicability = Applicability::MachineApplicable;
- if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability);
- then {
- span_lint_and_sugg(
- cx,
- SINGLE_CHAR_PATTERN,
- arg.span,
- "single-character string constant used as pattern",
- "try using a `char` instead",
- hint,
- applicability,
- );
- }
+ if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind()
+ && ty.is_str()
+ && method_name.as_str() == method
+ && args.len() > pos
+ && let arg = &args[pos]
+ && let mut applicability = Applicability::MachineApplicable
+ && let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability)
+ {
+ span_lint_and_sugg(
+ cx,
+ SINGLE_CHAR_PATTERN,
+ arg.span,
+ "single-character string constant used as pattern",
+ "try using a `char` instead",
+ hint,
+ applicability,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 9da61bca5..0e7ad8fc9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -6,7 +6,6 @@ use clippy_utils::usage::local_used_after_expr;
use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths};
use core::ops::ControlFlow;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{
BindingAnnotation, Expr, ExprKind, HirId, LangItem, Local, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind,
@@ -286,41 +285,35 @@ fn parse_iter_usage<'tcx>(
match (name.ident.as_str(), args) {
("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span),
("next_tuple", []) => {
- return if_chain! {
- if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE);
- if let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind();
- if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did());
- if let ty::Tuple(subs) = subs.type_at(0).kind();
- if subs.len() == 2;
- then {
- Some(IterUsage {
- kind: IterUsageKind::NextTuple,
- span: e.span,
- unwrap_kind: None
- })
- } else {
- None
- }
+ return if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE)
+ && let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind()
+ && cx.tcx.is_diagnostic_item(sym::Option, adt_def.did())
+ && let ty::Tuple(subs) = subs.type_at(0).kind()
+ && subs.len() == 2
+ {
+ Some(IterUsage {
+ kind: IterUsageKind::NextTuple,
+ span: e.span,
+ unwrap_kind: None,
+ })
+ } else {
+ None
};
},
("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
if let Some(Constant::Int(idx)) = constant(cx, cx.typeck_results(), idx_expr) {
let span = if name.ident.as_str() == "nth" {
e.span
+ } else if let Some((_, Node::Expr(next_expr))) = iter.next()
+ && let ExprKind::MethodCall(next_name, _, [], _) = next_expr.kind
+ && next_name.ident.name == sym::next
+ && next_expr.span.ctxt() == ctxt
+ && let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id)
+ && cx.tcx.trait_of_item(next_id) == Some(iter_id)
+ {
+ next_expr.span
} else {
- if_chain! {
- if let Some((_, Node::Expr(next_expr))) = iter.next();
- if let ExprKind::MethodCall(next_name, _, [], _) = next_expr.kind;
- if next_name.ident.name == sym::next;
- if next_expr.span.ctxt() == ctxt;
- if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id);
- if cx.tcx.trait_of_item(next_id) == Some(iter_id);
- then {
- next_expr.span
- } else {
- return None;
- }
- }
+ return None;
};
(IterUsageKind::Nth(idx), span)
} else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
index 0dc7fe2a2..ed49233ac 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::usage::mutated_variables;
use clippy_utils::{expr_or_init, is_trait_method};
-use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::sym;
@@ -9,26 +8,24 @@ use rustc_span::sym;
use super::SUSPICIOUS_MAP;
pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) {
- if_chain! {
- if is_trait_method(cx, count_recv, sym::Iterator);
- if let hir::ExprKind::Closure(closure) = expr_or_init(cx, map_arg).kind;
- let closure_body = cx.tcx.hir().body(closure.body);
- if !cx.typeck_results().expr_ty(closure_body.value).is_unit();
- then {
- if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) {
- // A variable is used mutably inside of the closure. Suppress the lint.
- if !map_mutated_vars.is_empty() {
- return;
- }
+ if is_trait_method(cx, count_recv, sym::Iterator)
+ && let hir::ExprKind::Closure(closure) = expr_or_init(cx, map_arg).kind
+ && let closure_body = cx.tcx.hir().body(closure.body)
+ && !cx.typeck_results().expr_ty(closure_body.value).is_unit()
+ {
+ if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) {
+ // A variable is used mutably inside of the closure. Suppress the lint.
+ if !map_mutated_vars.is_empty() {
+ return;
}
- span_lint_and_help(
- cx,
- SUSPICIOUS_MAP,
- expr.span,
- "this call to `map()` won't have an effect on the call to `count()`",
- None,
- "make sure you did not confuse `map` with `filter`, `for_each` or `inspect`",
- );
}
+ span_lint_and_help(
+ cx,
+ SUSPICIOUS_MAP,
+ expr.span,
+ "this call to `map()` won't have an effect on the call to `count()`",
+ None,
+ "make sure you did not confuse `map` with `filter`, `for_each` or `inspect`",
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
index 3cb2719e4..c45212581 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_note;
-use if_chain::if_chain;
use rustc_ast::LitKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
@@ -8,41 +7,36 @@ use rustc_span::source_map::Spanned;
use super::SUSPICIOUS_SPLITN;
pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) {
- if_chain! {
- if count <= 1;
- if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if let Some(impl_id) = cx.tcx.impl_of_method(call_id);
- if cx.tcx.impl_trait_ref(impl_id).is_none();
- let self_ty = cx.tcx.type_of(impl_id).instantiate_identity();
- if self_ty.is_slice() || self_ty.is_str();
- then {
- // Ignore empty slice and string literals when used with a literal count.
- if matches!(self_arg.kind, ExprKind::Array([]))
- || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty())
- {
- return;
- }
+ if count <= 1
+ && let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_method(call_id)
+ && cx.tcx.impl_trait_ref(impl_id).is_none()
+ && let self_ty = cx.tcx.type_of(impl_id).instantiate_identity()
+ && (self_ty.is_slice() || self_ty.is_str())
+ {
+ // Ignore empty slice and string literals when used with a literal count.
+ if matches!(self_arg.kind, ExprKind::Array([]))
+ || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty())
+ {
+ return;
+ }
- let (msg, note_msg) = if count == 0 {
- (format!("`{method_name}` called with `0` splits"),
- "the resulting iterator will always return `None`")
- } else {
- (format!("`{method_name}` called with `1` split"),
+ let (msg, note_msg) = if count == 0 {
+ (
+ format!("`{method_name}` called with `0` splits"),
+ "the resulting iterator will always return `None`",
+ )
+ } else {
+ (
+ format!("`{method_name}` called with `1` split"),
if self_ty.is_slice() {
"the resulting iterator will always return the entire slice followed by `None`"
} else {
"the resulting iterator will always return the entire string followed by `None`"
- })
- };
+ },
+ )
+ };
- span_lint_and_note(
- cx,
- SUSPICIOUS_SPLITN,
- expr.span,
- &msg,
- None,
- note_msg,
- );
- }
+ span_lint_and_note(cx, SUSPICIOUS_SPLITN, expr.span, &msg, None, note_msg);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
index 9eb8d6e6e..60864902a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_diag_trait_item;
use clippy_utils::source::snippet_with_context;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -12,40 +11,37 @@ use rustc_span::sym;
use super::SUSPICIOUS_TO_OWNED;
pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -> bool {
- if_chain! {
- if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if is_diag_trait_item(cx, method_def_id, sym::ToOwned);
- let input_type = cx.typeck_results().expr_ty(expr);
- if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind();
- if cx.tcx.is_diagnostic_item(sym::Cow, adt.did());
-
- then {
- let mut app = Applicability::MaybeIncorrect;
- let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
- span_lint_and_then(
- cx,
- SUSPICIOUS_TO_OWNED,
- expr.span,
- &with_forced_trimmed_paths!(format!(
- "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"
- )),
- |diag| {
- diag.span_suggestion(
- expr.span,
- "depending on intent, either make the Cow an Owned variant",
- format!("{recv_snip}.into_owned()"),
- app
- );
- diag.span_suggestion(
- expr.span,
- "or clone the Cow itself",
- format!("{recv_snip}.clone()"),
- app
- );
- }
- );
- return true;
- }
+ if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && is_diag_trait_item(cx, method_def_id, sym::ToOwned)
+ && let input_type = cx.typeck_results().expr_ty(expr)
+ && let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind()
+ && cx.tcx.is_diagnostic_item(sym::Cow, adt.did())
+ {
+ let mut app = Applicability::MaybeIncorrect;
+ let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
+ span_lint_and_then(
+ cx,
+ SUSPICIOUS_TO_OWNED,
+ expr.span,
+ &with_forced_trimmed_paths!(format!(
+ "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"
+ )),
+ |diag| {
+ diag.span_suggestion(
+ expr.span,
+ "depending on intent, either make the Cow an Owned variant",
+ format!("{recv_snip}.into_owned()"),
+ app,
+ );
+ diag.span_suggestion(
+ expr.span,
+ "or clone the Cow itself",
+ format!("{recv_snip}.clone()"),
+ app,
+ );
+ },
+ );
+ return true;
}
false
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs b/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
index bc9c518db..1ee655d61 100644
--- a/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_path_diagnostic_item;
use clippy_utils::ty::is_uninit_value_valid_for_ty;
-use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::sym;
@@ -10,18 +9,16 @@ use super::UNINIT_ASSUMED_INIT;
/// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter)
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
- if_chain! {
- if let hir::ExprKind::Call(callee, args) = recv.kind;
- if args.is_empty();
- if is_path_diagnostic_item(cx, callee, sym::maybe_uninit_uninit);
- if !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr));
- then {
- span_lint(
- cx,
- UNINIT_ASSUMED_INIT,
- expr.span,
- "this call for this type may be undefined behavior"
- );
- }
+ if let hir::ExprKind::Call(callee, args) = recv.kind
+ && args.is_empty()
+ && is_path_diagnostic_item(cx, callee, sym::maybe_uninit_uninit)
+ && !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr))
+ {
+ span_lint(
+ cx,
+ UNINIT_ASSUMED_INIT,
+ expr.span,
+ "this call for this type may be undefined behavior",
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs
index bb32b1bb7..89cf20c14 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs
@@ -1,10 +1,11 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::get_parent_expr;
use clippy_utils::ty::implements_trait;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty;
+use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_span::{sym, Span};
use super::UNNECESSARY_FALLIBLE_CONVERSIONS;
@@ -42,6 +43,7 @@ fn check<'tcx>(
// (else there would be conflicting impls, even with #![feature(spec)]), so we don't even need to check
// what `<T as TryFrom<U>>::Error` is: it's always `Infallible`
&& implements_trait(cx, self_ty, from_into_trait, &[other_ty])
+ && let Some(other_ty) = other_ty.as_type()
{
let parent_unwrap_call = get_parent_expr(cx, expr).and_then(|parent| {
if let ExprKind::MethodCall(path, .., span) = parent.kind
@@ -52,8 +54,7 @@ fn check<'tcx>(
None
}
});
-
- let (sugg, span, applicability) = match kind {
+ let (source_ty, target_ty, sugg, span, applicability) = match kind {
FunctionKind::TryIntoMethod if let Some(unwrap_span) = parent_unwrap_call => {
// Extend the span to include the unwrap/expect call:
// `foo.try_into().expect("..")`
@@ -63,24 +64,41 @@ fn check<'tcx>(
// so that can be machine-applicable
(
+ self_ty,
+ other_ty,
"into()",
primary_span.with_hi(unwrap_span.hi()),
Applicability::MachineApplicable,
)
},
- FunctionKind::TryFromFunction => ("From::from", primary_span, Applicability::Unspecified),
- FunctionKind::TryIntoFunction => ("Into::into", primary_span, Applicability::Unspecified),
- FunctionKind::TryIntoMethod => ("into", primary_span, Applicability::Unspecified),
+ FunctionKind::TryFromFunction => (
+ other_ty,
+ self_ty,
+ "From::from",
+ primary_span,
+ Applicability::Unspecified,
+ ),
+ FunctionKind::TryIntoFunction => (
+ self_ty,
+ other_ty,
+ "Into::into",
+ primary_span,
+ Applicability::Unspecified,
+ ),
+ FunctionKind::TryIntoMethod => (self_ty, other_ty, "into", primary_span, Applicability::Unspecified),
};
- span_lint_and_sugg(
+ span_lint_and_then(
cx,
UNNECESSARY_FALLIBLE_CONVERSIONS,
span,
"use of a fallible conversion when an infallible one could be used",
- "use",
- sugg.into(),
- applicability,
+ |diag| {
+ with_forced_trimmed_paths!({
+ diag.note(format!("converting `{source_ty}` to `{target_ty}` cannot fail"));
+ });
+ diag.span_suggestion(span, "use", sugg, applicability);
+ },
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index 6d51c4ab0..ebbdde48b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, strip_pat_refs};
-use if_chain::if_chain;
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -60,57 +59,51 @@ fn check_fold_with_op(
op: hir::BinOpKind,
replacement: Replacement,
) {
- if_chain! {
+ if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind
// Extract the body of the closure passed to fold
- if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind;
- let closure_body = cx.tcx.hir().body(body);
- let closure_expr = peel_blocks(closure_body.value);
+ && let closure_body = cx.tcx.hir().body(body)
+ && let closure_expr = peel_blocks(closure_body.value)
// Check if the closure body is of the form `acc <op> some_expr(x)`
- if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind;
- if bin_op.node == op;
+ && let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind
+ && bin_op.node == op
// Extract the names of the two arguments to the closure
- if let [param_a, param_b] = closure_body.params;
- if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind;
- if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind;
+ && let [param_a, param_b] = closure_body.params
+ && let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind
+ && let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind
- if path_to_local_id(left_expr, first_arg_id);
- if replacement.has_args || path_to_local_id(right_expr, second_arg_id);
-
- then {
- let mut applicability = Applicability::MachineApplicable;
-
- let turbofish = if replacement.has_generic_return {
- format!("::<{}>", cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs())
- } else {
- String::new()
- };
-
- let sugg = if replacement.has_args {
- format!(
- "{method}{turbofish}(|{second_arg_ident}| {r})",
- method = replacement.method_name,
- r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability),
- )
- } else {
- format!(
- "{method}{turbofish}()",
- method = replacement.method_name,
- )
- };
-
- span_lint_and_sugg(
- cx,
- UNNECESSARY_FOLD,
- fold_span.with_hi(expr.span.hi()),
- // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f)
- "this `.fold` can be written more succinctly using another method",
- "try",
- sugg,
- applicability,
- );
- }
+ && path_to_local_id(left_expr, first_arg_id)
+ && (replacement.has_args || path_to_local_id(right_expr, second_arg_id))
+ {
+ let mut applicability = Applicability::MachineApplicable;
+
+ let turbofish = if replacement.has_generic_return {
+ format!("::<{}>", cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs())
+ } else {
+ String::new()
+ };
+
+ let sugg = if replacement.has_args {
+ format!(
+ "{method}{turbofish}(|{second_arg_ident}| {r})",
+ method = replacement.method_name,
+ r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability),
+ )
+ } else {
+ format!("{method}{turbofish}()", method = replacement.method_name,)
+ };
+
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_FOLD,
+ fold_span.with_hi(expr.span.hi()),
+ // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f)
+ "this `.fold` can be written more succinctly using another method",
+ "try",
+ sugg,
+ applicability,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
index 0c72c13a3..36497d59a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -13,15 +13,13 @@ use rustc_span::{sym, Symbol};
use super::UNNECESSARY_TO_OWNED;
pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
- if_chain! {
- if let Some(parent) = get_parent_expr(cx, expr);
- if let Some(callee_def_id) = fn_def_id(cx, parent);
- if is_into_iter(cx, callee_def_id);
- then {
- check_for_loop_iter(cx, parent, method_name, receiver, false)
- } else {
- false
- }
+ if let Some(parent) = get_parent_expr(cx, expr)
+ && let Some(callee_def_id) = fn_def_id(cx, parent)
+ && is_into_iter(cx, callee_def_id)
+ {
+ check_for_loop_iter(cx, parent, method_name, receiver, false)
+ } else {
+ false
}
}
@@ -36,65 +34,58 @@ pub fn check_for_loop_iter(
receiver: &Expr<'_>,
cloned_before_iter: bool,
) -> bool {
- if_chain! {
- if let Some(grandparent) = get_parent_expr(cx, expr).and_then(|parent| get_parent_expr(cx, parent));
- if let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent);
- let (clone_or_copy_needed, addr_of_exprs) = clone_or_copy_needed(cx, pat, body);
- if !clone_or_copy_needed;
- if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
- then {
- let snippet = if_chain! {
- if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind;
- if maybe_iter_method_name.ident.name == sym::iter;
-
- if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
- let receiver_ty = cx.typeck_results().expr_ty(receiver);
- if implements_trait(cx, receiver_ty, iterator_trait_id, &[]);
- if let Some(iter_item_ty) = get_iterator_item_ty(cx, receiver_ty);
-
- if let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator);
- let collection_ty = cx.typeck_results().expr_ty(collection);
- if implements_trait(cx, collection_ty, into_iterator_trait_id, &[]);
- if let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item");
-
- if iter_item_ty == into_iter_item_ty;
- if let Some(collection_snippet) = snippet_opt(cx, collection.span);
- then {
- collection_snippet
+ if let Some(grandparent) = get_parent_expr(cx, expr).and_then(|parent| get_parent_expr(cx, parent))
+ && let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent)
+ && let (clone_or_copy_needed, addr_of_exprs) = clone_or_copy_needed(cx, pat, body)
+ && !clone_or_copy_needed
+ && let Some(receiver_snippet) = snippet_opt(cx, receiver.span)
+ {
+ let snippet = if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind
+ && maybe_iter_method_name.ident.name == sym::iter
+ && let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
+ && let receiver_ty = cx.typeck_results().expr_ty(receiver)
+ && implements_trait(cx, receiver_ty, iterator_trait_id, &[])
+ && let Some(iter_item_ty) = get_iterator_item_ty(cx, receiver_ty)
+ && let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
+ && let collection_ty = cx.typeck_results().expr_ty(collection)
+ && implements_trait(cx, collection_ty, into_iterator_trait_id, &[])
+ && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item")
+ && iter_item_ty == into_iter_item_ty
+ && let Some(collection_snippet) = snippet_opt(cx, collection.span)
+ {
+ collection_snippet
+ } else {
+ receiver_snippet
+ };
+ span_lint_and_then(
+ cx,
+ UNNECESSARY_TO_OWNED,
+ expr.span,
+ &format!("unnecessary use of `{method_name}`"),
+ |diag| {
+ // If `check_into_iter_call_arg` called `check_for_loop_iter` because a call to
+ // a `to_owned`-like function was removed, then the next suggestion may be
+ // incorrect. This is because the iterator that results from the call's removal
+ // could hold a reference to a resource that is used mutably. See
+ // https://github.com/rust-lang/rust-clippy/issues/8148.
+ let applicability = if cloned_before_iter {
+ Applicability::MaybeIncorrect
} else {
- receiver_snippet
- }
- };
- span_lint_and_then(
- cx,
- UNNECESSARY_TO_OWNED,
- expr.span,
- &format!("unnecessary use of `{method_name}`"),
- |diag| {
- // If `check_into_iter_call_arg` called `check_for_loop_iter` because a call to
- // a `to_owned`-like function was removed, then the next suggestion may be
- // incorrect. This is because the iterator that results from the call's removal
- // could hold a reference to a resource that is used mutably. See
- // https://github.com/rust-lang/rust-clippy/issues/8148.
- let applicability = if cloned_before_iter {
- Applicability::MaybeIncorrect
- } else {
- Applicability::MachineApplicable
- };
- diag.span_suggestion(expr.span, "use", snippet, applicability);
- for addr_of_expr in addr_of_exprs {
- match addr_of_expr.kind {
- ExprKind::AddrOf(_, _, referent) => {
- let span = addr_of_expr.span.with_hi(referent.span.lo());
- diag.span_suggestion(span, "remove this `&`", "", applicability);
- }
- _ => unreachable!(),
- }
+ Applicability::MachineApplicable
+ };
+ diag.span_suggestion(expr.span, "use", snippet, applicability);
+ for addr_of_expr in addr_of_exprs {
+ match addr_of_expr.kind {
+ ExprKind::AddrOf(_, _, referent) => {
+ let span = addr_of_expr.span.with_hi(referent.span.lo());
+ diag.span_suggestion(span, "remove this `&`", "", applicability);
+ },
+ _ => unreachable!(),
}
}
- );
- return true;
- }
+ },
+ );
+ return true;
}
false
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs
index d0c62fb56..e2b389e96 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs
@@ -18,25 +18,23 @@ pub(super) fn check<'tcx>(
) {
let applicability = Applicability::MachineApplicable;
let collect_output_adjusted_type = cx.typeck_results().expr_ty_adjusted(join_self_arg);
- if_chain! {
+ if let Ref(_, ref_type, _) = collect_output_adjusted_type.kind()
// the turbofish for collect is ::<Vec<String>>
- if let Ref(_, ref_type, _) = collect_output_adjusted_type.kind();
- if let Slice(slice) = ref_type.kind();
- if is_type_lang_item(cx, *slice, LangItem::String);
+ && let Slice(slice) = ref_type.kind()
+ && is_type_lang_item(cx, *slice, LangItem::String)
// the argument for join is ""
- if let ExprKind::Lit(spanned) = &join_arg.kind;
- if let LitKind::Str(symbol, _) = spanned.node;
- if symbol.is_empty();
- then {
- span_lint_and_sugg(
- cx,
- UNNECESSARY_JOIN,
- span.with_hi(expr.span.hi()),
- r#"called `.collect::<Vec<String>>().join("")` on an iterator"#,
- "try using",
- "collect::<String>()".to_owned(),
- applicability,
- );
- }
+ && let ExprKind::Lit(spanned) = &join_arg.kind
+ && let LitKind::Str(symbol, _) = spanned.node
+ && symbol.is_empty()
+ {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_JOIN,
+ span.with_hi(expr.span.hi()),
+ r#"called `.collect::<Vec<String>>().join("")` on an iterator"#,
+ "try using",
+ "collect::<String>()".to_owned(),
+ applicability,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
index e62a65a27..696e5e74d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_trait_method;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::implements_trait;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
use rustc_lint::LateContext;
@@ -115,55 +114,72 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident
}
fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) -> Option<LintTrigger> {
- if_chain! {
- if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- if cx.tcx.type_of(impl_id).instantiate_identity().is_slice();
- if let ExprKind::Closure(&Closure { body, .. }) = arg.kind;
- if let closure_body = cx.tcx.hir().body(body);
- if let &[
- Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
- Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
- ] = &closure_body.params;
- if let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind;
- if method_path.ident.name == sym::cmp;
- if is_trait_method(cx, closure_body.value, sym::Ord);
- then {
- let (closure_body, closure_arg, reverse) = if mirrored_exprs(
- left_expr,
- left_ident,
- right_expr,
- right_ident
- ) {
- (Sugg::hir(cx, left_expr, "..").to_string(), left_ident.name.to_string(), false)
- } else if mirrored_exprs(left_expr, right_ident, right_expr, left_ident) {
- (Sugg::hir(cx, left_expr, "..").to_string(), right_ident.name.to_string(), true)
- } else {
- return None;
- };
- let vec_name = Sugg::hir(cx, recv, "..").to_string();
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && cx.tcx.type_of(impl_id).instantiate_identity().is_slice()
+ && let ExprKind::Closure(&Closure { body, .. }) = arg.kind
+ && let closure_body = cx.tcx.hir().body(body)
+ && let &[
+ Param {
+ pat:
+ Pat {
+ kind: PatKind::Binding(_, _, left_ident, _),
+ ..
+ },
+ ..
+ },
+ Param {
+ pat:
+ Pat {
+ kind: PatKind::Binding(_, _, right_ident, _),
+ ..
+ },
+ ..
+ },
+ ] = &closure_body.params
+ && let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind
+ && method_path.ident.name == sym::cmp
+ && is_trait_method(cx, closure_body.value, sym::Ord)
+ {
+ let (closure_body, closure_arg, reverse) = if mirrored_exprs(left_expr, left_ident, right_expr, right_ident) {
+ (
+ Sugg::hir(cx, left_expr, "..").to_string(),
+ left_ident.name.to_string(),
+ false,
+ )
+ } else if mirrored_exprs(left_expr, right_ident, right_expr, left_ident) {
+ (
+ Sugg::hir(cx, left_expr, "..").to_string(),
+ right_ident.name.to_string(),
+ true,
+ )
+ } else {
+ return None;
+ };
+ let vec_name = Sugg::hir(cx, recv, "..").to_string();
- if_chain! {
- if let ExprKind::Path(QPath::Resolved(_, Path {
- segments: [PathSegment { ident: left_name, .. }], ..
- })) = &left_expr.kind;
- if left_name == left_ident;
- if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| {
- implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])
- });
- then {
- return Some(LintTrigger::Sort(SortDetection { vec_name }));
- }
- }
+ if let ExprKind::Path(QPath::Resolved(
+ _,
+ Path {
+ segments: [PathSegment { ident: left_name, .. }],
+ ..
+ },
+ )) = &left_expr.kind
+ && left_name == left_ident
+ && cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| {
+ implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])
+ })
+ {
+ return Some(LintTrigger::Sort(SortDetection { vec_name }));
+ }
- if !expr_borrows(cx, left_expr) {
- return Some(LintTrigger::SortByKey(SortByKeyDetection {
- vec_name,
- closure_arg,
- closure_body,
- reverse,
- }));
- }
+ if !expr_borrows(cx, left_expr) {
+ return Some(LintTrigger::SortByKey(SortByKeyDetection {
+ vec_name,
+ closure_arg,
+ closure_body,
+ reverse,
+ }));
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 7a50feff6..c4775b6bd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -31,25 +31,23 @@ pub fn check<'tcx>(
args: &'tcx [Expr<'_>],
msrv: &Msrv,
) {
- if_chain! {
- if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if args.is_empty();
- then {
- if is_cloned_or_copied(cx, method_name, method_def_id) {
- unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
- } else if is_to_owned_like(cx, expr, method_name, method_def_id) {
- // At this point, we know the call is of a `to_owned`-like function. The functions
- // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary
- // based on its context, that is, whether it is a referent in an `AddrOf` expression, an
- // argument in a `into_iter` call, or an argument in the call of some other function.
- if check_addr_of_expr(cx, expr, method_name, method_def_id, receiver) {
- return;
- }
- if check_into_iter_call_arg(cx, expr, method_name, receiver, msrv) {
- return;
- }
- check_other_call_arg(cx, expr, method_name, receiver);
+ if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && args.is_empty()
+ {
+ if is_cloned_or_copied(cx, method_name, method_def_id) {
+ unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
+ } else if is_to_owned_like(cx, expr, method_name, method_def_id) {
+ // At this point, we know the call is of a `to_owned`-like function. The functions
+ // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary
+ // based on its context, that is, whether it is a referent in an `AddrOf` expression, an
+ // argument in a `into_iter` call, or an argument in the call of some other function.
+ if check_addr_of_expr(cx, expr, method_name, method_def_id, receiver) {
+ return;
}
+ if check_into_iter_call_arg(cx, expr, method_name, receiver, msrv) {
+ return;
+ }
+ check_other_call_arg(cx, expr, method_name, receiver);
}
}
}
@@ -64,11 +62,10 @@ fn check_addr_of_expr(
method_def_id: DefId,
receiver: &Expr<'_>,
) -> bool {
- if_chain! {
- 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
+ if let Some(parent) = get_parent_expr(cx, expr)
+ && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = parent.kind
+ && let adjustments = cx.typeck_results().expr_adjustments(parent).iter().collect::<Vec<_>>()
+ && let
// For matching uses of `Cow::from`
[
Adjustment {
@@ -109,10 +106,10 @@ fn check_addr_of_expr(
kind: Adjust::Borrow(_),
target: target_ty,
},
- ] = adjustments[..];
- let receiver_ty = cx.typeck_results().expr_ty(receiver);
- let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty);
- let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty);
+ ] = adjustments[..]
+ && let receiver_ty = cx.typeck_results().expr_ty(receiver)
+ && 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
@@ -122,77 +119,72 @@ fn check_addr_of_expr(
// 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
+ && (*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 {
- if receiver_ty == target_ty && n_target_refs >= n_receiver_refs {
+ || is_cow_into_owned(cx, method_name, method_def_id))
+ && let Some(receiver_snippet) = snippet_opt(cx, receiver.span)
+ {
+ if receiver_ty == target_ty && n_target_refs >= n_receiver_refs {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_TO_OWNED,
+ parent.span,
+ &format!("unnecessary use of `{method_name}`"),
+ "use",
+ format!(
+ "{:&>width$}{receiver_snippet}",
+ "",
+ width = n_target_refs - n_receiver_refs
+ ),
+ Applicability::MachineApplicable,
+ );
+ return true;
+ }
+ if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
+ && implements_trait(cx, receiver_ty, deref_trait_id, &[])
+ && cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty)
+ // Make sure that it's actually calling the right `.to_string()`, (#10033)
+ // *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow)
+ // but that's ok for Cow::into_owned specifically)
+ && (cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() == target_ty
+ || is_cow_into_owned(cx, method_name, method_def_id))
+ {
+ if n_receiver_refs > 0 {
span_lint_and_sugg(
cx,
UNNECESSARY_TO_OWNED,
parent.span,
&format!("unnecessary use of `{method_name}`"),
"use",
- format!(
- "{:&>width$}{receiver_snippet}",
- "",
- width = n_target_refs - n_receiver_refs
- ),
+ receiver_snippet,
+ Applicability::MachineApplicable,
+ );
+ } else {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_TO_OWNED,
+ expr.span.with_lo(receiver.span.hi()),
+ &format!("unnecessary use of `{method_name}`"),
+ "remove this",
+ String::new(),
Applicability::MachineApplicable,
);
- return true;
- }
- if_chain! {
- if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
- if implements_trait(cx, receiver_ty, deref_trait_id, &[]);
- if cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty);
- // Make sure that it's actually calling the right `.to_string()`, (#10033)
- // *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow)
- // but that's ok for Cow::into_owned specifically)
- if cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() == target_ty
- || is_cow_into_owned(cx, method_name, method_def_id);
- then {
- if n_receiver_refs > 0 {
- span_lint_and_sugg(
- cx,
- UNNECESSARY_TO_OWNED,
- parent.span,
- &format!("unnecessary use of `{method_name}`"),
- "use",
- receiver_snippet,
- Applicability::MachineApplicable,
- );
- } else {
- span_lint_and_sugg(
- cx,
- UNNECESSARY_TO_OWNED,
- expr.span.with_lo(receiver.span.hi()),
- &format!("unnecessary use of `{method_name}`"),
- "remove this",
- String::new(),
- Applicability::MachineApplicable,
- );
- }
- return true;
- }
- }
- if_chain! {
- if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef);
- if implements_trait(cx, receiver_ty, as_ref_trait_id, &[GenericArg::from(target_ty)]);
- then {
- span_lint_and_sugg(
- cx,
- UNNECESSARY_TO_OWNED,
- parent.span,
- &format!("unnecessary use of `{method_name}`"),
- "use",
- format!("{receiver_snippet}.as_ref()"),
- Applicability::MachineApplicable,
- );
- return true;
- }
}
+ return true;
+ }
+ if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
+ && implements_trait(cx, receiver_ty, as_ref_trait_id, &[GenericArg::from(target_ty)])
+ {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_TO_OWNED,
+ parent.span,
+ &format!("unnecessary use of `{method_name}`"),
+ "use",
+ format!("{receiver_snippet}.as_ref()"),
+ Applicability::MachineApplicable,
+ );
+ return true;
}
}
false
@@ -207,38 +199,36 @@ fn check_into_iter_call_arg(
receiver: &Expr<'_>,
msrv: &Msrv,
) -> bool {
- if_chain! {
- if let Some(parent) = get_parent_expr(cx, expr);
- if let Some(callee_def_id) = fn_def_id(cx, parent);
- if is_into_iter(cx, callee_def_id);
- if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
- let parent_ty = cx.typeck_results().expr_ty(parent);
- if implements_trait(cx, parent_ty, iterator_trait_id, &[]);
- if let Some(item_ty) = get_iterator_item_ty(cx, parent_ty);
- if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
- then {
- 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) && msrv.meets(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.
- span_lint_and_sugg(
- cx,
- UNNECESSARY_TO_OWNED,
- parent.span,
- &format!("unnecessary use of `{method_name}`"),
- "use",
- format!("{receiver_snippet}.iter().{cloned_or_copied}()"),
- Applicability::MaybeIncorrect,
- );
+ if let Some(parent) = get_parent_expr(cx, expr)
+ && let Some(callee_def_id) = fn_def_id(cx, parent)
+ && is_into_iter(cx, callee_def_id)
+ && let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
+ && let parent_ty = cx.typeck_results().expr_ty(parent)
+ && implements_trait(cx, parent_ty, iterator_trait_id, &[])
+ && let Some(item_ty) = get_iterator_item_ty(cx, parent_ty)
+ && let Some(receiver_snippet) = snippet_opt(cx, receiver.span)
+ {
+ 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) && msrv.meets(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.
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_TO_OWNED,
+ parent.span,
+ &format!("unnecessary use of `{method_name}`"),
+ "use",
+ format!("{receiver_snippet}.iter().{cloned_or_copied}()"),
+ Applicability::MaybeIncorrect,
+ );
+ return true;
}
false
}
@@ -251,26 +241,25 @@ fn check_other_call_arg<'tcx>(
method_name: Symbol,
receiver: &'tcx Expr<'tcx>,
) -> bool {
- if_chain! {
- if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
- if let Some((callee_def_id, _, recv, call_args)) = get_callee_generic_args_and_args(cx, maybe_call);
- let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder();
- if let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id);
- if let Some(input) = fn_sig.inputs().get(i);
- let (input, n_refs) = peel_mid_ty_refs(*input);
- if let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input);
- if let Some(sized_def_id) = cx.tcx.lang_items().sized_trait();
- if let [trait_predicate] = trait_predicates
+ if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr)
+ && let Some((callee_def_id, _, recv, call_args)) = get_callee_generic_args_and_args(cx, maybe_call)
+ && let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder()
+ && let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id)
+ && let Some(input) = fn_sig.inputs().get(i)
+ && let (input, n_refs) = peel_mid_ty_refs(*input)
+ && let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input)
+ && let Some(sized_def_id) = cx.tcx.lang_items().sized_trait()
+ && let [trait_predicate] = trait_predicates
.iter()
.filter(|trait_predicate| trait_predicate.def_id() != sized_def_id)
- .collect::<Vec<_>>()[..];
- if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
- if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef);
- if trait_predicate.def_id() == deref_trait_id || trait_predicate.def_id() == as_ref_trait_id;
- let receiver_ty = cx.typeck_results().expr_ty(receiver);
+ .collect::<Vec<_>>()[..]
+ && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
+ && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
+ && (trait_predicate.def_id() == deref_trait_id || trait_predicate.def_id() == as_ref_trait_id)
+ && let receiver_ty = cx.typeck_results().expr_ty(receiver)
// We can't add an `&` when the trait is `Deref` because `Target = &T` won't match
// `Target = T`.
- if let Some((n_refs, receiver_ty)) = if n_refs > 0 || is_copy(cx, receiver_ty) {
+ && let Some((n_refs, receiver_ty)) = if n_refs > 0 || is_copy(cx, receiver_ty) {
Some((n_refs, receiver_ty))
} else if trait_predicate.def_id() != deref_trait_id {
Some((1, Ty::new_ref(cx.tcx,
@@ -282,21 +271,20 @@ fn check_other_call_arg<'tcx>(
)))
} else {
None
- };
- if can_change_type(cx, maybe_arg, receiver_ty);
- if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
- then {
- span_lint_and_sugg(
- cx,
- UNNECESSARY_TO_OWNED,
- maybe_arg.span,
- &format!("unnecessary use of `{method_name}`"),
- "use",
- format!("{:&>n_refs$}{receiver_snippet}", ""),
- Applicability::MachineApplicable,
- );
- return true;
}
+ && can_change_type(cx, maybe_arg, receiver_ty)
+ && let Some(receiver_snippet) = snippet_opt(cx, receiver.span)
+ {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_TO_OWNED,
+ maybe_arg.span,
+ &format!("unnecessary use of `{method_name}`"),
+ "use",
+ format!("{:&>n_refs$}{receiver_snippet}", ""),
+ Applicability::MachineApplicable,
+ );
+ return true;
}
false
}
@@ -328,22 +316,18 @@ fn get_callee_generic_args_and_args<'tcx>(
Option<&'tcx Expr<'tcx>>,
&'tcx [Expr<'tcx>],
)> {
- if_chain! {
- if let ExprKind::Call(callee, args) = expr.kind;
- let callee_ty = cx.typeck_results().expr_ty(callee);
- if let ty::FnDef(callee_def_id, _) = callee_ty.kind();
- then {
- let generic_args = cx.typeck_results().node_args(callee.hir_id);
- return Some((*callee_def_id, generic_args, None, args));
- }
+ if let ExprKind::Call(callee, args) = expr.kind
+ && let callee_ty = cx.typeck_results().expr_ty(callee)
+ && let ty::FnDef(callee_def_id, _) = callee_ty.kind()
+ {
+ let generic_args = cx.typeck_results().node_args(callee.hir_id);
+ return Some((*callee_def_id, generic_args, None, args));
}
- if_chain! {
- if let ExprKind::MethodCall(_, recv, args, _) = expr.kind;
- if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- then {
- let generic_args = cx.typeck_results().node_args(expr.hir_id);
- return Some((method_def_id, generic_args, Some(recv), args));
- }
+ if let ExprKind::MethodCall(_, recv, args, _) = expr.kind
+ && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ {
+ let generic_args = cx.typeck_results().node_args(expr.hir_id);
+ return Some((method_def_id, generic_args, Some(recv), args));
}
None
}
@@ -458,7 +442,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
return false;
}
- let output_ty = cx.tcx.erase_late_bound_regions(fn_sig.output());
+ let output_ty = cx.tcx.instantiate_bound_regions_with_erased(fn_sig.output());
if output_ty.contains(param_ty) {
if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions(
new_subst,
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index b5f810edd..84ee64e88 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::walk_ptrs_ty_depth;
use clippy_utils::{get_parent_expr, is_trait_method};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -22,13 +21,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
// allow the `as_ref` or `as_mut` if it is followed by another method call
- if_chain! {
- if let Some(parent) = get_parent_expr(cx, expr);
- if let hir::ExprKind::MethodCall(segment, ..) = parent.kind;
- if segment.ident.span != expr.span;
- then {
- return;
- }
+ if let Some(parent) = get_parent_expr(cx, expr)
+ && let hir::ExprKind::MethodCall(segment, ..) = parent.kind
+ && segment.ident.span != expr.span
+ {
+ return;
}
let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index 9f1f73e60..9ad4250a1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -1,7 +1,6 @@
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{get_parent_expr, path_to_local_id, usage};
-use if_chain::if_chain;
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -55,32 +54,33 @@ pub(super) fn get_hint_if_single_char_arg(
arg: &hir::Expr<'_>,
applicability: &mut Applicability,
) -> Option<String> {
- if_chain! {
- if let hir::ExprKind::Lit(lit) = &arg.kind;
- if let ast::LitKind::Str(r, style) = lit.node;
- let string = r.as_str();
- if string.chars().count() == 1;
- then {
- let snip = snippet_with_applicability(cx, arg.span, string, applicability);
- let ch = if let ast::StrStyle::Raw(nhash) = style {
- let nhash = nhash as usize;
- // for raw string: r##"a"##
- &snip[(nhash + 2)..(snip.len() - 1 - nhash)]
- } else {
- // for regular string: "a"
- &snip[1..(snip.len() - 1)]
- };
+ if let hir::ExprKind::Lit(lit) = &arg.kind
+ && let ast::LitKind::Str(r, style) = lit.node
+ && let string = r.as_str()
+ && string.chars().count() == 1
+ {
+ let snip = snippet_with_applicability(cx, arg.span, string, applicability);
+ let ch = if let ast::StrStyle::Raw(nhash) = style {
+ let nhash = nhash as usize;
+ // for raw string: r##"a"##
+ &snip[(nhash + 2)..(snip.len() - 1 - nhash)]
+ } else {
+ // for regular string: "a"
+ &snip[1..(snip.len() - 1)]
+ };
- let hint = format!("'{}'", match ch {
- "'" => "\\'" ,
+ let hint = format!(
+ "'{}'",
+ match ch {
+ "'" => "\\'",
r"\" => "\\\\",
_ => ch,
- });
+ }
+ );
- Some(hint)
- } else {
- None
- }
+ Some(hint)
+ } else {
+ None
}
}
@@ -140,15 +140,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
return;
},
ExprKind::MethodCall(.., args, _) => {
- if_chain! {
- if args.iter().all(|arg| !self.is_binding(arg));
- if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id);
- let method_ty = self.cx.tcx.type_of(method_def_id).instantiate_identity();
- let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder();
- if matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Not));
- then {
- return;
- }
+ if args.iter().all(|arg| !self.is_binding(arg))
+ && let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id)
+ && let method_ty = self.cx.tcx.type_of(method_def_id).instantiate_identity()
+ && let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder()
+ && matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Not))
+ {
+ return;
}
},
_ => {},
diff --git a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
index 730727186..9e87fb45a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
@@ -17,29 +16,32 @@ pub(super) fn check<'tcx>(
default_arg: &'tcx Expr<'_>,
name_span: Span,
) {
- if_chain! {
- if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Vec);
- if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = count_arg.kind;
- if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = default_arg.kind;
- then {
- let method_call_span = expr.span.with_lo(name_span.lo());
- span_lint_and_then(
- cx,
- VEC_RESIZE_TO_ZERO,
- expr.span,
- "emptying a vector with `resize`",
- |db| {
- db.help("the arguments may be inverted...");
- db.span_suggestion(
- method_call_span,
- "...or you can empty the vector with",
- "clear()".to_string(),
- Applicability::MaybeIncorrect,
- );
- },
- );
- }
+ if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+ && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Vec)
+ && let ExprKind::Lit(Spanned {
+ node: LitKind::Int(0, _),
+ ..
+ }) = count_arg.kind
+ && let ExprKind::Lit(Spanned {
+ node: LitKind::Int(..), ..
+ }) = default_arg.kind
+ {
+ let method_call_span = expr.span.with_lo(name_span.lo());
+ span_lint_and_then(
+ cx,
+ VEC_RESIZE_TO_ZERO,
+ expr.span,
+ "emptying a vector with `resize`",
+ |db| {
+ db.help("the arguments may be inverted...");
+ db.span_suggestion(
+ method_call_span,
+ "...or you can empty the vector with",
+ "clear()".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs b/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs
index e9f268da6..0b829d99a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs
@@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint;
-use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty;
@@ -7,12 +6,10 @@ use rustc_middle::ty;
use super::ZST_OFFSET;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
- if_chain! {
- if let ty::RawPtr(ty::TypeAndMut { ty, .. }) = cx.typeck_results().expr_ty(recv).kind();
- if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(*ty));
- if layout.is_zst();
- then {
- span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value");
- }
+ if let ty::RawPtr(ty::TypeAndMut { ty, .. }) = cx.typeck_results().expr_ty(recv).kind()
+ && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(*ty))
+ && layout.is_zst()
+ {
+ span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value");
}
}
diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
index 4ad12e899..34b8e0dbe 100644
--- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
@@ -6,7 +6,7 @@ use rustc_hir::intravisit::{walk_item, Visitor};
use rustc_hir::{GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::Span;
use std::borrow::Cow;
@@ -91,7 +91,7 @@ impl Visitor<'_> for IdentVisitor<'_, '_> {
let node = if hir_id.local_id == ItemLocalId::from_u32(0) {
// In this case, we can just use `find`, `Owner`'s `node` field is private anyway so we can't
// reimplement it even if we wanted to
- cx.tcx.hir().find(hir_id)
+ cx.tcx.opt_hir_node(hir_id)
} else {
let Some(owner) = cx.tcx.hir_owner_nodes(hir_id.owner).as_owner() else {
return;
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index e0904f17b..fca626fa5 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_trait_method;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
use std::cmp::Ordering;
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index f4af5f37b..b9784a585 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -5,7 +5,6 @@ use clippy_utils::{
any_parent_is_automatically_derived, fulfill_or_allowed, get_parent_expr, is_lint_allowed, iter_input_pats,
last_path_segment, SpanlessEq,
};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::intravisit::FnKind;
@@ -14,7 +13,7 @@ use rustc_hir::{
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
@@ -143,73 +142,64 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
}
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
- if_chain! {
- if !in_external_macro(cx.tcx.sess, stmt.span);
- if let StmtKind::Local(local) = stmt.kind;
- if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind;
- if let Some(init) = local.init;
+ if !in_external_macro(cx.tcx.sess, stmt.span)
+ && let StmtKind::Local(local) = stmt.kind
+ && let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind
+ && let Some(init) = local.init
// Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
- if is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id);
- then {
- let ctxt = local.span.ctxt();
- let mut app = Applicability::MachineApplicable;
- let sugg_init = Sugg::hir_with_context(cx, init, ctxt, "..", &mut app);
- let (mutopt, initref) = if mutabl == Mutability::Mut {
- ("mut ", sugg_init.mut_addr())
- } else {
- ("", sugg_init.addr())
- };
- let tyopt = if let Some(ty) = local.ty {
- let ty_snip = snippet_with_context(cx, ty.span, ctxt, "_", &mut app).0;
- format!(": &{mutopt}{ty_snip}")
- } else {
- String::new()
- };
- span_lint_hir_and_then(
- cx,
- TOPLEVEL_REF_ARG,
- init.hir_id,
- local.pat.span,
- "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead",
- |diag| {
- diag.span_suggestion(
- stmt.span,
- "try",
- format!(
- "let {name}{tyopt} = {initref};",
- name=snippet(cx, name.span, ".."),
- ),
- app,
- );
- }
- );
- }
+ && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id)
+ {
+ let ctxt = local.span.ctxt();
+ let mut app = Applicability::MachineApplicable;
+ let sugg_init = Sugg::hir_with_context(cx, init, ctxt, "..", &mut app);
+ let (mutopt, initref) = if mutabl == Mutability::Mut {
+ ("mut ", sugg_init.mut_addr())
+ } else {
+ ("", sugg_init.addr())
+ };
+ let tyopt = if let Some(ty) = local.ty {
+ let ty_snip = snippet_with_context(cx, ty.span, ctxt, "_", &mut app).0;
+ format!(": &{mutopt}{ty_snip}")
+ } else {
+ String::new()
+ };
+ span_lint_hir_and_then(
+ cx,
+ TOPLEVEL_REF_ARG,
+ init.hir_id,
+ local.pat.span,
+ "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead",
+ |diag| {
+ diag.span_suggestion(
+ stmt.span,
+ "try",
+ format!("let {name}{tyopt} = {initref};", name = snippet(cx, name.span, ".."),),
+ app,
+ );
+ },
+ );
};
- if_chain! {
- if let StmtKind::Semi(expr) = stmt.kind;
- if let ExprKind::Binary(ref binop, a, b) = expr.kind;
- if binop.node == BinOpKind::And || binop.node == BinOpKind::Or;
- if let Some(sugg) = Sugg::hir_opt(cx, a);
- then {
- span_lint_hir_and_then(
- cx,
- SHORT_CIRCUIT_STATEMENT,
- expr.hir_id,
- stmt.span,
- "boolean short circuit operator in statement may be clearer using an explicit test",
- |diag| {
- let sugg = if binop.node == BinOpKind::Or { !sugg } else { sugg };
- diag.span_suggestion(
- stmt.span,
- "replace it with",
- format!(
- "if {sugg} {{ {}; }}",
- &snippet(cx, b.span, ".."),
- ),
- Applicability::MachineApplicable, // snippet
- );
- });
- }
+ if let StmtKind::Semi(expr) = stmt.kind
+ && let ExprKind::Binary(ref binop, a, b) = expr.kind
+ && (binop.node == BinOpKind::And || binop.node == BinOpKind::Or)
+ && let Some(sugg) = Sugg::hir_opt(cx, a)
+ {
+ span_lint_hir_and_then(
+ cx,
+ SHORT_CIRCUIT_STATEMENT,
+ expr.hir_id,
+ stmt.span,
+ "boolean short circuit operator in statement may be clearer using an explicit test",
+ |diag| {
+ let sugg = if binop.node == BinOpKind::Or { !sugg } else { sugg };
+ diag.span_suggestion(
+ stmt.span,
+ "replace it with",
+ format!("if {sugg} {{ {}; }}", &snippet(cx, b.span, ".."),),
+ Applicability::MachineApplicable, // snippet
+ );
+ },
+ );
};
}
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
index df0dd9e4e..abe5b00e8 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -16,7 +16,7 @@ use rustc_ast::visit::FnKind;
use rustc_data_structures::fx::FxHashMap;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
index 0d79ece08..0739b49fe 100644
--- a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
+++ b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
@@ -4,7 +4,7 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::{GenericArg, Item, ItemKind, QPath, Ty, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::GenericParamDefKind;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -49,59 +49,59 @@ declare_lint_pass!(TypeParamMismatch => [MISMATCHING_TYPE_PARAM_ORDER]);
impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
- if_chain! {
- if !item.span.from_expansion();
- if let ItemKind::Impl(imp) = &item.kind;
- if let TyKind::Path(QPath::Resolved(_, path)) = &imp.self_ty.kind;
- if let Some(segment) = path.segments.iter().next();
- if let Some(generic_args) = segment.args;
- if !generic_args.args.is_empty();
- then {
- // get the name and span of the generic parameters in the Impl
- let mut impl_params = Vec::new();
- for p in generic_args.args {
- match p {
- GenericArg::Type(Ty {kind: TyKind::Path(QPath::Resolved(_, path)), ..}) =>
- impl_params.push((path.segments[0].ident.to_string(), path.span)),
- GenericArg::Type(_) => return,
- _ => (),
- };
- }
-
- // find the type that the Impl is for
- // only lint on struct/enum/union for now
- let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, defid) = path.res else {
- return
+ if !item.span.from_expansion()
+ && let ItemKind::Impl(imp) = &item.kind
+ && let TyKind::Path(QPath::Resolved(_, path)) = &imp.self_ty.kind
+ && let Some(segment) = path.segments.iter().next()
+ && let Some(generic_args) = segment.args
+ && !generic_args.args.is_empty()
+ {
+ // get the name and span of the generic parameters in the Impl
+ let mut impl_params = Vec::new();
+ for p in generic_args.args {
+ match p {
+ GenericArg::Type(Ty {
+ kind: TyKind::Path(QPath::Resolved(_, path)),
+ ..
+ }) => impl_params.push((path.segments[0].ident.to_string(), path.span)),
+ GenericArg::Type(_) => return,
+ _ => (),
};
+ }
+
+ // find the type that the Impl is for
+ // only lint on struct/enum/union for now
+ let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, defid) = path.res else {
+ return;
+ };
- // get the names of the generic parameters in the type
- let type_params = &cx.tcx.generics_of(defid).params;
- let type_param_names: Vec<_> = type_params.iter()
- .filter_map(|p|
- match p.kind {
- GenericParamDefKind::Type {..} => Some(p.name.to_string()),
- _ => None,
- }
- ).collect();
- // hashmap of name -> index for mismatch_param_name
- let type_param_names_hashmap: FxHashMap<&String, usize> =
- type_param_names.iter().enumerate().map(|(i, param)| (param, i)).collect();
+ // get the names of the generic parameters in the type
+ let type_params = &cx.tcx.generics_of(defid).params;
+ let type_param_names: Vec<_> = type_params
+ .iter()
+ .filter_map(|p| match p.kind {
+ GenericParamDefKind::Type { .. } => Some(p.name.to_string()),
+ _ => None,
+ })
+ .collect();
+ // hashmap of name -> index for mismatch_param_name
+ let type_param_names_hashmap: FxHashMap<&String, usize> = type_param_names
+ .iter()
+ .enumerate()
+ .map(|(i, param)| (param, i))
+ .collect();
- let type_name = segment.ident;
- for (i, (impl_param_name, impl_param_span)) in impl_params.iter().enumerate() {
- if mismatch_param_name(i, impl_param_name, &type_param_names_hashmap) {
- let msg = format!("`{type_name}` has a similarly named generic type parameter `{impl_param_name}` in its declaration, but in a different order");
- let help = format!("try `{}`, or a name that does not conflict with `{type_name}`'s generic params",
- type_param_names[i]);
- span_lint_and_help(
- cx,
- MISMATCHING_TYPE_PARAM_ORDER,
- *impl_param_span,
- &msg,
- None,
- &help
- );
- }
+ let type_name = segment.ident;
+ for (i, (impl_param_name, impl_param_span)) in impl_params.iter().enumerate() {
+ if mismatch_param_name(i, impl_param_name, &type_param_names_hashmap) {
+ let msg = format!(
+ "`{type_name}` has a similarly named generic type parameter `{impl_param_name}` in its declaration, but in a different order"
+ );
+ let help = format!(
+ "try `{}`, or a name that does not conflict with `{type_name}`'s generic params",
+ type_param_names[i]
+ );
+ span_lint_and_help(cx, MISMATCHING_TYPE_PARAM_ORDER, *impl_param_span, &msg, None, &help);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
index 4e00215c5..04df7b7a7 100644
--- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
@@ -3,7 +3,7 @@ use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_cal
use clippy_utils::{is_in_cfg_test, is_in_test_function};
use rustc_hir::Expr;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
index dccf72d3c..0f18e9434 100644
--- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
@@ -9,9 +9,9 @@ use clippy_utils::{eq_expr_value, hash_expr, higher};
use rustc_ast::{LitKind, RangeLimits};
use rustc_data_structures::unhash::UnhashMap;
use rustc_errors::{Applicability, Diagnostic};
-use rustc_hir::{BinOp, Block, Expr, ExprKind, UnOp};
+use rustc_hir::{BinOp, Block, Body, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::{sym, Span};
@@ -52,12 +52,12 @@ declare_clippy_lint! {
/// Use instead:
/// ```no_run
/// fn sum(v: &[u8]) -> u8 {
- /// assert!(v.len() > 4);
+ /// assert!(v.len() > 3);
/// // no bounds checks
/// v[0] + v[1] + v[2] + v[3]
/// }
/// ```
- #[clippy::version = "1.70.0"]
+ #[clippy::version = "1.74.0"]
pub MISSING_ASSERTS_FOR_INDEXING,
restriction,
"indexing into a slice multiple times without an `assert`"
@@ -87,11 +87,14 @@ enum LengthComparison {
LengthLessThanOrEqualInt,
/// `5 <= v.len()`
IntLessThanOrEqualLength,
+ /// `5 == v.len()`
+ /// `v.len() == 5`
+ LengthEqualInt,
}
/// Extracts parts out of a length comparison expression.
///
-/// E.g. for `v.len() > 5` this returns `Some((LengthComparison::IntLessThanLength, 5, `v.len()`))`
+/// E.g. for `v.len() > 5` this returns `Some((LengthComparison::IntLessThanLength, 5, v.len()))`
fn len_comparison<'hir>(
bin_op: BinOp,
left: &'hir Expr<'hir>,
@@ -114,6 +117,8 @@ fn len_comparison<'hir>(
(Rel::Lt, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanInt, *right as usize, left)),
(Rel::Le, int_lit_pat!(left), _) => Some((LengthComparison::IntLessThanOrEqualLength, *left as usize, right)),
(Rel::Le, _, int_lit_pat!(right)) => Some((LengthComparison::LengthLessThanOrEqualInt, *right as usize, left)),
+ (Rel::Eq, int_lit_pat!(left), _) => Some((LengthComparison::LengthEqualInt, *left as usize, right)),
+ (Rel::Eq, _, int_lit_pat!(right)) => Some((LengthComparison::LengthEqualInt, *right as usize, left)),
_ => None,
}
}
@@ -316,11 +321,11 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>
continue;
};
- match entry {
+ match *entry {
IndexEntry::AssertWithIndex {
highest_index,
asserted_len,
- indexes,
+ ref indexes,
comparison,
assert_span,
slice,
@@ -343,6 +348,12 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>
"assert!({}.len() > {highest_index})",
snippet(cx, slice.span, "..")
)),
+ // `highest_index` here is rather a length, so we need to add 1 to it
+ LengthComparison::LengthEqualInt if asserted_len < highest_index + 1 => Some(format!(
+ "assert!({}.len() == {})",
+ snippet(cx, slice.span, ".."),
+ highest_index + 1
+ )),
_ => None,
};
@@ -354,7 +365,7 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>
indexes,
|diag| {
diag.span_suggestion(
- *assert_span,
+ assert_span,
"provide the highest index that is indexed with",
sugg,
Applicability::MachineApplicable,
@@ -364,7 +375,7 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>
}
},
IndexEntry::IndexWithoutAssert {
- indexes,
+ ref indexes,
highest_index,
slice,
} if indexes.len() > 1 => {
@@ -390,10 +401,10 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>
}
impl LateLintPass<'_> for MissingAssertsForIndexing {
- fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) {
+ fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
let mut map = UnhashMap::default();
- for_each_expr(block, |expr| {
+ for_each_expr(body.value, |expr| {
check_index(cx, expr, &mut map);
check_assert(cx, expr, &mut map);
ControlFlow::<!, ()>::Continue(())
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index 97522cbe6..acaa6be30 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -9,7 +9,7 @@ use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, Constness, FnDecl, GenericParamKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
@@ -131,13 +131,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
FnKind::Closure => return,
}
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
+ let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
// Const fns are not allowed as methods in a trait.
{
let parent = cx.tcx.hir().get_parent_item(hir_id).def_id;
if parent != CRATE_DEF_ID {
- if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent) {
+ if let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(parent) {
if let hir::ItemKind::Trait(..) = &item.kind {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 973caa72b..bf4af7946 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -8,13 +8,12 @@
use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_from_proc_macro;
-use if_chain::if_chain;
use rustc_ast::ast::{self, MetaItem, MetaItemKind};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::Visibility;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::{sym, Span};
@@ -63,16 +62,14 @@ impl MissingDoc {
}
fn has_include(meta: Option<MetaItem>) -> bool {
- if_chain! {
- if let Some(meta) = meta;
- if let MetaItemKind::List(list) = meta.kind;
- if let Some(meta) = list.first();
- if let Some(name) = meta.ident();
- then {
- name.name == sym::include
- } else {
- false
- }
+ if let Some(meta) = meta
+ && let MetaItemKind::List(list) = meta.kind
+ && let Some(meta) = list.first()
+ && let Some(name) = meta.ident()
+ {
+ name.name == sym::include
+ } else {
+ false
}
}
diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
index 16ff98a59..c1f6c71a6 100644
--- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
@@ -7,7 +7,7 @@ use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::{Item, ItemKind, UseKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::Symbol;
declare_clippy_lint! {
@@ -72,13 +72,12 @@ impl LateLintPass<'_> for ImportRename {
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
if let ItemKind::Use(path, UseKind::Single) = &item.kind {
for &res in &path.res {
- if_chain! {
- if let Res::Def(_, id) = res;
- if let Some(name) = self.renames.get(&id);
+ if let Res::Def(_, id) = res
+ && let Some(name) = self.renames.get(&id)
// Remove semicolon since it is not present for nested imports
- let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';');
- if let Some(snip) = snippet_opt(cx, span_without_semi);
- if let Some(import) = match snip.split_once(" as ") {
+ && let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';')
+ && let Some(snip) = snippet_opt(cx, span_without_semi)
+ && let Some(import) = match snip.split_once(" as ") {
None => Some(snip.as_str()),
Some((import, rename)) => {
if rename.trim() == name.as_str() {
@@ -87,20 +86,17 @@ impl LateLintPass<'_> for ImportRename {
Some(import.trim())
}
},
- };
- then {
- span_lint_and_sugg(
- cx,
- MISSING_ENFORCED_IMPORT_RENAMES,
- span_without_semi,
- "this import should be renamed",
- "try",
- format!(
- "{import} as {name}",
- ),
- Applicability::MachineApplicable,
- );
}
+ {
+ span_lint_and_sugg(
+ cx,
+ MISSING_ENFORCED_IMPORT_RENAMES,
+ span_without_semi,
+ "this import should be renamed",
+ "try",
+ format!("{import} as {name}",),
+ Applicability::MachineApplicable,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
index 95f9df4e4..88b331dde 100644
--- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
@@ -12,7 +12,7 @@ use rustc_hir::{
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{Ty, TypeckResults};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, Span, Symbol};
declare_clippy_lint! {
@@ -220,7 +220,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug {
&& let self_ty = cx.tcx.type_of(self_path_did).skip_binder().peel_refs()
&& let Some(self_adt) = self_ty.ty_adt_def()
&& let Some(self_def_id) = self_adt.did().as_local()
- && let Some(Node::Item(self_item)) = cx.tcx.hir().find_by_def_id(self_def_id)
+ && let Some(Node::Item(self_item)) = cx.tcx.opt_hir_node_by_def_id(self_def_id)
// NB: can't call cx.typeck_results() as we are not in a body
&& let typeck_results = cx.tcx.typeck_body(*body_id)
&& should_lint(cx, typeck_results, block)
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index b815da79b..7393b39c8 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -1,8 +1,8 @@
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast;
use rustc_hir as hir;
-use rustc_lint::{self, LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, Span};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
index ad5f45a32..6bbf18d52 100644
--- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -5,7 +5,7 @@ use rustc_hir::def_id::DefIdMap;
use rustc_hir::{Impl, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::AssocItem;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index 215161b04..3ff40081c 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id};
-use if_chain::if_chain;
use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -80,11 +79,13 @@ declare_lint_pass!(EvalOrderDependence => [MIXED_READ_WRITE_IN_EXPRESSION, DIVER
impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// Find a write to a local variable.
- let var = if_chain! {
- if let ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) = expr.kind;
- if let Some(var) = path_to_local(lhs);
- if expr.span.desugaring_kind().is_none();
- then { var } else { return; }
+ let var = if let ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) = expr.kind
+ && let Some(var) = path_to_local(lhs)
+ && expr.span.desugaring_kind().is_none()
+ {
+ var
+ } else {
+ return;
};
let mut visitor = ReadVisitor {
cx,
@@ -164,7 +165,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
match typ.kind() {
ty::FnDef(..) | ty::FnPtr(_) => {
let sig = typ.fn_sig(self.cx.tcx);
- if self.cx.tcx.erase_late_bound_regions(sig).output().kind() == &ty::Never {
+ if self.cx.tcx.instantiate_bound_regions_with_erased(sig).output().kind() == &ty::Never {
self.report_diverging_sub_expr(e);
}
},
@@ -212,7 +213,9 @@ fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
if parent_id == cur_id {
break;
}
- let Some(parent_node) = map.find(parent_id) else { break };
+ let Some(parent_node) = vis.cx.tcx.opt_hir_node(parent_id) else {
+ break;
+ };
let stop_early = match parent_node {
Node::Expr(expr) => check_expr(vis, expr),
diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs
index efdc7560e..0226b31dd 100644
--- a/src/tools/clippy/clippy_lints/src/module_style.rs
+++ b/src/tools/clippy/clippy_lints/src/module_style.rs
@@ -1,7 +1,8 @@
+use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::{FileName, SourceFile, Span, SyntaxContext};
use std::ffi::OsStr;
@@ -124,11 +125,13 @@ impl EarlyLintPass for ModStyle {
correct.pop();
correct.push(folder);
correct.push("mod.rs");
- cx.struct_span_lint(
+ span_lint_and_help(
+ cx,
SELF_NAMED_MODULE_FILES,
Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
- format!("`mod.rs` files are required, found `{}`", path.display()),
- |lint| lint.help(format!("move `{}` to `{}`", path.display(), correct.display(),)),
+ &format!("`mod.rs` files are required, found `{}`", path.display()),
+ None,
+ &format!("move `{}` to `{}`", path.display(), correct.display(),),
);
}
}
@@ -153,17 +156,22 @@ fn process_paths_for_mod_files<'a>(
}
/// Checks every path for the presence of `mod.rs` files and emits the lint if found.
+/// We should not emit a lint for test modules in the presence of `mod.rs`.
+/// Using `mod.rs` in integration tests is a [common pattern](https://doc.rust-lang.org/book/ch11-03-test-organization.html#submodules-in-integration-test)
+/// for code-sharing between tests.
fn check_self_named_mod_exists(cx: &EarlyContext<'_>, path: &Path, file: &SourceFile) {
- if path.ends_with("mod.rs") {
+ if path.ends_with("mod.rs") && !path.starts_with("tests") {
let mut mod_file = path.to_path_buf();
mod_file.pop();
mod_file.set_extension("rs");
- cx.struct_span_lint(
+ span_lint_and_help(
+ cx,
MOD_MODULE_FILES,
Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
- format!("`mod.rs` files are not allowed, found `{}`", path.display()),
- |lint| lint.help(format!("move `{}` to `{}`", path.display(), mod_file.display())),
+ &format!("`mod.rs` files are not allowed, found `{}`", path.display()),
+ None,
+ &format!("move `{}` to `{}`", path.display(), mod_file.display()),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/multi_assignments.rs b/src/tools/clippy/clippy_lints/src/multi_assignments.rs
index b42dce7a1..9a6b1dfc5 100644
--- a/src/tools/clippy/clippy_lints/src/multi_assignments.rs
+++ b/src/tools/clippy/clippy_lints/src/multi_assignments.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index d4f8008ae..049f44f32 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -8,7 +8,7 @@ use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{DesugaringKind, Span};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index ebfd53f1e..04d2ced6a 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -6,10 +6,10 @@ use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::query::Key;
use rustc_middle::ty::{Adt, Ty};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId;
-use rustc_span::Span;
use rustc_span::symbol::sym;
+use rustc_span::Span;
use std::iter;
declare_clippy_lint! {
@@ -143,7 +143,11 @@ impl MutableKeyType {
for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) {
self.check_ty_(cx, hir_ty.span, *ty);
}
- self.check_ty_(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output()));
+ self.check_ty_(
+ cx,
+ decl.output.span(),
+ cx.tcx.instantiate_bound_regions_with_erased(fn_sig.output()),
+ );
}
// We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased
diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs
index 6989504a4..72a2cca1e 100644
--- a/src/tools/clippy/clippy_lints/src/mut_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs
@@ -5,7 +5,7 @@ use rustc_hir::intravisit;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index 4f8e24422..f905a4e5b 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use std::iter;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
index dea432fdb..96cd81ecd 100644
--- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
+++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
@@ -5,7 +5,7 @@ use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
index 9d8c06cd0..a23e12f7a 100644
--- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
+++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
@@ -7,7 +7,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
use rustc_hir::Expr;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
index 97e8f1c03..2ab83f733 100644
--- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -1,9 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use if_chain::if_chain;
use rustc_ast::ast::{BindingAnnotation, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::kw;
use rustc_span::Span;
@@ -66,48 +65,46 @@ enum Mode {
}
fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mode: &Mode, mutbl: Mutability) {
- if_chain! {
- if let [segment] = &path.segments[..];
- if segment.ident.name == kw::SelfUpper;
- then {
- // In case we have a named lifetime, we check if the name comes from expansion.
- // If it does, at this point we know the rest of the parameter was written by the user,
- // so let them decide what the name of the lifetime should be.
- // See #6089 for more details.
- let mut applicability = Applicability::MachineApplicable;
- let self_param = match (binding_mode, mutbl) {
- (Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(),
- (Mode::Ref(Some(lifetime)), Mutability::Mut) => {
- if lifetime.ident.span.from_expansion() {
- applicability = Applicability::HasPlaceholders;
- "&'_ mut self".to_string()
- } else {
- format!("&{} mut self", &lifetime.ident.name)
- }
- },
- (Mode::Ref(None), Mutability::Not) => "&self".to_string(),
- (Mode::Ref(Some(lifetime)), Mutability::Not) => {
- if lifetime.ident.span.from_expansion() {
- applicability = Applicability::HasPlaceholders;
- "&'_ self".to_string()
- } else {
- format!("&{} self", &lifetime.ident.name)
- }
- },
- (Mode::Value, Mutability::Mut) => "mut self".to_string(),
- (Mode::Value, Mutability::Not) => "self".to_string(),
- };
+ if let [segment] = &path.segments[..]
+ && segment.ident.name == kw::SelfUpper
+ {
+ // In case we have a named lifetime, we check if the name comes from expansion.
+ // If it does, at this point we know the rest of the parameter was written by the user,
+ // so let them decide what the name of the lifetime should be.
+ // See #6089 for more details.
+ let mut applicability = Applicability::MachineApplicable;
+ let self_param = match (binding_mode, mutbl) {
+ (Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(),
+ (Mode::Ref(Some(lifetime)), Mutability::Mut) => {
+ if lifetime.ident.span.from_expansion() {
+ applicability = Applicability::HasPlaceholders;
+ "&'_ mut self".to_string()
+ } else {
+ format!("&{} mut self", &lifetime.ident.name)
+ }
+ },
+ (Mode::Ref(None), Mutability::Not) => "&self".to_string(),
+ (Mode::Ref(Some(lifetime)), Mutability::Not) => {
+ if lifetime.ident.span.from_expansion() {
+ applicability = Applicability::HasPlaceholders;
+ "&'_ self".to_string()
+ } else {
+ format!("&{} self", &lifetime.ident.name)
+ }
+ },
+ (Mode::Value, Mutability::Mut) => "mut self".to_string(),
+ (Mode::Value, Mutability::Not) => "self".to_string(),
+ };
- span_lint_and_sugg(
- cx,
- NEEDLESS_ARBITRARY_SELF_TYPE,
- span,
- "the type of the `self` parameter does not need to be arbitrary",
- "consider to change this parameter to",
- self_param,
- applicability,
- )
- }
+ span_lint_and_sugg(
+ cx,
+ NEEDLESS_ARBITRARY_SELF_TYPE,
+ span,
+ "the type of the `self` parameter does not need to be arbitrary",
+ "consider to change this parameter to",
+ self_param,
+ applicability,
+ );
}
}
@@ -125,12 +122,10 @@ impl EarlyLintPass for NeedlessArbitrarySelfType {
}
},
TyKind::Ref(lifetime, mut_ty) => {
- if_chain! {
- if let TyKind::Path(None, path) = &mut_ty.ty.kind;
- if let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind;
- then {
- check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl);
- }
+ if let TyKind::Path(None, path) = &mut_ty.ty.kind
+ && let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind
+ {
+ check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl);
}
},
_ => {},
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index 02c177c92..218ca5e80 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -13,7 +13,7 @@ use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::Span;
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
index fdb91f0dc..4710a6944 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use rustc_errors::Applicability;
use rustc_hir::{BindingAnnotation, Mutability, Node, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index dcfb109a4..a32bca3d0 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -2,7 +2,7 @@ use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap};
use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::is_copy;
+use clippy_utils::ty::{implements_trait, is_copy};
use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
@@ -15,7 +15,7 @@ use rustc_middle::mir::{Rvalue, StatementKind};
use rustc_middle::ty::{
self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, List, ParamTy, ProjectionPredicate, Ty,
};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::sym;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{Obligation, ObligationCause};
@@ -50,7 +50,7 @@ declare_clippy_lint! {
/// let x = "foo";
/// f(x);
/// ```
- #[clippy::version = "pre 1.29.0"]
+ #[clippy::version = "1.74.0"]
pub NEEDLESS_BORROWS_FOR_GENERIC_ARGS,
style,
"taking a reference that is going to be automatically dereferenced"
@@ -169,6 +169,7 @@ fn needless_borrow_count<'tcx>(
) -> usize {
let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
+ let drop_trait_def_id = cx.tcx.lang_items().drop_trait();
let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder();
let predicates = cx.tcx.param_env(fn_id).caller_bounds();
@@ -223,7 +224,14 @@ fn needless_borrow_count<'tcx>(
// elements are modified each time `check_referent` is called.
let mut args_with_referent_ty = callee_args.to_vec();
- let mut check_reference_and_referent = |reference, referent| {
+ let mut check_reference_and_referent = |reference: &Expr<'tcx>, referent: &Expr<'tcx>| {
+ if let ExprKind::Field(base, _) = &referent.kind {
+ let base_ty = cx.typeck_results().expr_ty(base);
+ if drop_trait_def_id.map_or(false, |id| implements_trait(cx, base_ty, id, &[])) {
+ return false;
+ }
+ }
+
let referent_ty = cx.typeck_results().expr_ty(referent);
if !is_copy(cx, referent_ty)
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index cb2738947..4b9ab50e4 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -37,7 +37,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::{indent_of, snippet, snippet_block};
use rustc_ast::ast;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
@@ -362,21 +362,19 @@ fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &Lin
}
fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
- if_chain! {
- if let ast::ExprKind::Loop(loop_block, ..) = &expr.kind;
- if let Some(last_stmt) = loop_block.stmts.last();
- if let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind;
- if let ast::ExprKind::Continue(_) = inner_expr.kind;
- then {
- span_lint_and_help(
- cx,
- NEEDLESS_CONTINUE,
- last_stmt.span,
- MSG_REDUNDANT_CONTINUE_EXPRESSION,
- None,
- DROP_CONTINUE_EXPRESSION_MSG,
- );
- }
+ if let ast::ExprKind::Loop(loop_block, ..) = &expr.kind
+ && let Some(last_stmt) = loop_block.stmts.last()
+ && let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind
+ && let ast::ExprKind::Continue(_) = inner_expr.kind
+ {
+ span_lint_and_help(
+ cx,
+ NEEDLESS_CONTINUE,
+ last_stmt.span,
+ MSG_REDUNDANT_CONTINUE_EXPRESSION,
+ None,
+ DROP_CONTINUE_EXPRESSION_MSG,
+ );
}
with_loop_block(expr, |loop_block, label| {
for (i, stmt) in loop_block.stmts.iter().enumerate() {
diff --git a/src/tools/clippy/clippy_lints/src/needless_else.rs b/src/tools/clippy/clippy_lints/src/needless_else.rs
index d881c13f8..b6aad69d1 100644
--- a/src/tools/clippy/clippy_lints/src/needless_else.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_else.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_opt, trim_span};
use rustc_ast::ast::{Expr, ExprKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index c71996131..84a07df1b 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -2,11 +2,9 @@ use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{Closure, Expr, ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, Span, Symbol};
-use if_chain::if_chain;
-
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_trait_method;
use clippy_utils::source::snippet_with_applicability;
@@ -51,65 +49,63 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
return;
};
- if_chain! {
+ if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind
// Check the method name is `for_each`.
- if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind;
- if method_name.ident.name == Symbol::intern("for_each");
+ && method_name.ident.name == Symbol::intern("for_each")
// Check `for_each` is an associated function of `Iterator`.
- if is_trait_method(cx, expr, sym::Iterator);
+ && is_trait_method(cx, expr, sym::Iterator)
// Checks the receiver of `for_each` is also a method call.
- if let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind;
+ && let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind
// Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or
// `v.foo().iter().for_each()` must be skipped.
- if matches!(
+ && matches!(
iter_recv.kind,
ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Path(..)
- );
+ )
// Checks the type of the `iter` method receiver is NOT a user defined type.
- if has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some();
+ && has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some()
// Skip the lint if the body is not block because this is simpler than `for` loop.
// e.g. `v.iter().for_each(f)` is simpler and clearer than using `for` loop.
- if let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind;
- let body = cx.tcx.hir().body(body);
- if let ExprKind::Block(..) = body.value.kind;
- then {
- let mut ret_collector = RetCollector::default();
- ret_collector.visit_expr(body.value);
-
- // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`.
- if ret_collector.ret_in_loop {
- return;
- }
-
- let (mut applicability, ret_suggs) = if ret_collector.spans.is_empty() {
- (Applicability::MachineApplicable, None)
- } else {
- (
- Applicability::MaybeIncorrect,
- Some(
- ret_collector
- .spans
- .into_iter()
- .map(|span| (span, "continue".to_string()))
- .collect(),
- ),
- )
- };
+ && let ExprKind::Closure(&Closure { body, .. }) = for_each_arg.kind
+ && let body = cx.tcx.hir().body(body)
+ && let ExprKind::Block(..) = body.value.kind
+ {
+ let mut ret_collector = RetCollector::default();
+ ret_collector.visit_expr(body.value);
+
+ // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`.
+ if ret_collector.ret_in_loop {
+ return;
+ }
- let sugg = format!(
- "for {} in {} {}",
- snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability),
- snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability),
- snippet_with_applicability(cx, body.value.span, "..", &mut applicability),
- );
+ let (mut applicability, ret_suggs) = if ret_collector.spans.is_empty() {
+ (Applicability::MachineApplicable, None)
+ } else {
+ (
+ Applicability::MaybeIncorrect,
+ Some(
+ ret_collector
+ .spans
+ .into_iter()
+ .map(|span| (span, "continue".to_string()))
+ .collect(),
+ ),
+ )
+ };
+
+ let sugg = format!(
+ "for {} in {} {}",
+ snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability),
+ snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability),
+ snippet_with_applicability(cx, body.value.span, "..", &mut applicability),
+ );
- span_lint_and_then(cx, NEEDLESS_FOR_EACH, stmt.span, "needless use of `for_each`", |diag| {
- diag.span_suggestion(stmt.span, "try", sugg, applicability);
- if let Some(ret_suggs) = ret_suggs {
- diag.multipart_suggestion("...and replace `return` with `continue`", ret_suggs, applicability);
- }
- })
- }
+ span_lint_and_then(cx, NEEDLESS_FOR_EACH, stmt.span, "needless use of `for_each`", |diag| {
+ diag.span_suggestion(stmt.span, "try", sugg, applicability);
+ if let Some(ret_suggs) = ret_suggs {
+ diag.multipart_suggestion("...and replace `return` with `continue`", ret_suggs, applicability);
+ }
+ });
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_if.rs b/src/tools/clippy/clippy_lints/src/needless_if.rs
index 23aabc548..51bee4b51 100644
--- a/src/tools/clippy/clippy_lints/src/needless_if.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_if.rs
@@ -6,7 +6,7 @@ use rustc_errors::Applicability;
use rustc_hir::{ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
index c8888c744..3e63c0a1d 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -10,7 +10,7 @@ use rustc_hir::{
StmtKind,
};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
@@ -128,21 +128,18 @@ impl LocalAssign {
let assign = match expr.kind {
ExprKind::Block(Block { expr: Some(expr), .. }, _) => Self::from_expr(expr, expr.span),
ExprKind::Block(block, _) => {
- if_chain! {
- if let Some((last, other_stmts)) = block.stmts.split_last();
- if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = last.kind;
+ if let Some((last, other_stmts)) = block.stmts.split_last()
+ && let StmtKind::Expr(expr) | StmtKind::Semi(expr) = last.kind
- let assign = Self::from_expr(expr, last.span)?;
+ && let assign = Self::from_expr(expr, last.span)?
// avoid visiting if not needed
- if assign.lhs_id == binding_id;
- if other_stmts.iter().all(|stmt| !contains_assign_expr(cx, stmt));
-
- then {
- Some(assign)
- } else {
- None
- }
+ && assign.lhs_id == binding_id
+ && other_stmts.iter().all(|stmt| !contains_assign_expr(cx, stmt))
+ {
+ Some(assign)
+ } else {
+ None
}
},
ExprKind::Assign(..) => Self::from_expr(expr, expr.span),
@@ -368,22 +365,20 @@ fn check<'tcx>(
impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit {
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
let mut parents = cx.tcx.hir().parent_iter(local.hir_id);
- if_chain! {
- if let Local {
- init: None,
- pat: &Pat {
+ if let Local {
+ init: None,
+ pat:
+ &Pat {
kind: PatKind::Binding(BindingAnnotation::NONE, binding_id, _, None),
..
},
- source: LocalSource::Normal,
- ..
- } = local;
- if let Some((_, Node::Stmt(local_stmt))) = parents.next();
- if let Some((_, Node::Block(block))) = parents.next();
-
- then {
- check(cx, local, local_stmt, block, binding_id);
- }
+ source: LocalSource::Normal,
+ ..
+ } = local
+ && let Some((_, Node::Stmt(local_stmt))) = parents.next()
+ && let Some((_, Node::Block(block))) = parents.next()
+ {
+ check(cx, local, local_stmt, block, binding_id);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
index 7bbf1fb4c..8a6210637 100644
--- a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
@@ -7,7 +7,7 @@ use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -53,21 +53,23 @@ fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) {
// don't check floating point literals on the start expression of a range
return;
}
- if_chain! {
- if let ExprKind::Lit(literal) = e.kind;
+ if let ExprKind::Lit(literal) = e.kind
// the indicator that parenthesis surround the literal is that the span of the expression and the literal differ
- if (literal.span.data().hi - literal.span.data().lo) != (e.span.data().hi - e.span.data().lo);
+ && (literal.span.data().hi - literal.span.data().lo) != (e.span.data().hi - e.span.data().lo)
// inspect the source code of the expression for parenthesis
- if snippet_enclosed_in_parenthesis(&snippet(cx, e.span, ""));
- then {
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_then(cx, NEEDLESS_PARENS_ON_RANGE_LITERALS, e.span,
- "needless parenthesis on range literals can be removed",
- |diag| {
- let suggestion = snippet_with_applicability(cx, literal.span, "_", &mut applicability);
- diag.span_suggestion(e.span, "try", suggestion, applicability);
- });
- }
+ && snippet_enclosed_in_parenthesis(&snippet(cx, e.span, ""))
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_then(
+ cx,
+ NEEDLESS_PARENS_ON_RANGE_LITERALS,
+ e.span,
+ "needless parenthesis on range literals can be removed",
+ |diag| {
+ let suggestion = snippet_with_applicability(cx, literal.span, "_", &mut applicability);
+ diag.span_suggestion(e.span, "try", suggestion, applicability);
+ },
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index d610ba520..64ef709e2 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -17,7 +17,7 @@ use rustc_middle::hir::map::associated_body;
use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::{self, Ty, TyCtxt, UpvarId, UpvarPath};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::kw;
use rustc_span::Span;
@@ -113,8 +113,9 @@ fn check_closures<'tcx>(
}
ctx.prev_bind = None;
ctx.prev_move_to_closure.clear();
- if let Some(body) = hir
- .find_by_def_id(closure)
+ if let Some(body) = cx
+ .tcx
+ .opt_hir_node_by_def_id(closure)
.and_then(associated_body)
.map(|(_, body_id)| hir.body(body_id))
{
@@ -137,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
return;
}
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
+ let hir_id = cx.tcx.local_def_id_to_hir_id(fn_def_id);
let is_async = match kind {
FnKind::ItemFn(.., header) => {
if header.is_unsafe() {
@@ -256,7 +257,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
span_lint_hir_and_then(
cx,
NEEDLESS_PASS_BY_REF_MUT,
- cx.tcx.hir().local_def_id_to_hir_id(*fn_def_id),
+ cx.tcx.local_def_id_to_hir_id(*fn_def_id),
sp,
"this argument is a mutable reference, but not used mutably",
|diag| {
@@ -412,7 +413,7 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
],
),
..
- }) = self.tcx.hir().get(cmt.hir_id)
+ }) = self.tcx.hir_node(cmt.hir_id)
{
self.async_closures.insert(*def_id);
}
@@ -521,7 +522,7 @@ impl<'tcx> Visitor<'tcx> for FnNeedsMutVisitor<'_, 'tcx> {
let Self { cx, used_fn_def_ids } = self;
// #11182; do not lint if mutability is required elsewhere
- if let Node::Expr(expr) = cx.tcx.hir().get(hir_id)
+ if let Node::Expr(expr) = cx.tcx.hir_node(hir_id)
&& let Some(parent) = get_parent_node(cx.tcx, expr.hir_id)
&& let ty::FnDef(def_id, _) = cx
.tcx
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 8fa461ac1..2c5c3dcaa 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -5,7 +5,6 @@ use clippy_utils::source::{snippet, snippet_opt};
use clippy_utils::ty::{
implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item,
};
-use if_chain::if_chain;
use rustc_ast::ast::Attribute;
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir::intravisit::FnKind;
@@ -18,7 +17,7 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::kw;
use rustc_span::{sym, Span};
@@ -87,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
return;
}
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
+ let hir_id = cx.tcx.local_def_id_to_hir_id(fn_def_id);
match kind {
FnKind::ItemFn(.., header) => {
@@ -177,118 +176,120 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
)
};
- if_chain! {
- if !is_self(arg);
- if !ty.is_mutable_ptr();
- if !is_copy(cx, ty);
- if ty.is_sized(cx.tcx, cx.param_env);
- if !allowed_traits.iter().any(|&t| implements_trait_with_env_from_iter(
- cx.tcx,
- cx.param_env,
- ty,
- t,
- [Option::<ty::GenericArg<'tcx>>::None],
- ));
- if !implements_borrow_trait;
- if !all_borrowable_trait;
-
- if let PatKind::Binding(BindingAnnotation(_, Mutability::Not), canonical_id, ..) = arg.pat.kind;
- if !moved_vars.contains(&canonical_id);
- then {
- // Dereference suggestion
- let sugg = |diag: &mut Diagnostic| {
- if let ty::Adt(def, ..) = ty.kind() {
- if let Some(span) = cx.tcx.hir().span_if_local(def.did()) {
- if type_allowed_to_implement_copy(
- cx.tcx,
- cx.param_env,
- ty,
- traits::ObligationCause::dummy_with_span(span),
- ).is_ok() {
- diag.span_help(span, "consider marking this type as `Copy`");
- }
+ if !is_self(arg)
+ && !ty.is_mutable_ptr()
+ && !is_copy(cx, ty)
+ && ty.is_sized(cx.tcx, cx.param_env)
+ && !allowed_traits.iter().any(|&t| {
+ implements_trait_with_env_from_iter(
+ cx.tcx,
+ cx.param_env,
+ ty,
+ t,
+ None,
+ [Option::<ty::GenericArg<'tcx>>::None],
+ )
+ })
+ && !implements_borrow_trait
+ && !all_borrowable_trait
+ && let PatKind::Binding(BindingAnnotation(_, Mutability::Not), canonical_id, ..) = arg.pat.kind
+ && !moved_vars.contains(&canonical_id)
+ {
+ // Dereference suggestion
+ let sugg = |diag: &mut Diagnostic| {
+ if let ty::Adt(def, ..) = ty.kind() {
+ if let Some(span) = cx.tcx.hir().span_if_local(def.did()) {
+ if type_allowed_to_implement_copy(
+ cx.tcx,
+ cx.param_env,
+ ty,
+ traits::ObligationCause::dummy_with_span(span),
+ )
+ .is_ok()
+ {
+ diag.span_help(span, "consider marking this type as `Copy`");
}
}
+ }
- if_chain! {
- if is_type_diagnostic_item(cx, ty, sym::Vec);
- if let Some(clone_spans) =
- get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]);
- if let TyKind::Path(QPath::Resolved(_, path)) = input.kind;
- if let Some(elem_ty) = path.segments.iter()
- .find(|seg| seg.ident.name == sym::Vec)
- .and_then(|ps| ps.args.as_ref())
- .map(|params| params.args.iter().find_map(|arg| match arg {
- GenericArg::Type(ty) => Some(ty),
- _ => None,
- }).unwrap());
- then {
- let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_"));
- diag.span_suggestion(
- input.span,
- "consider changing the type to",
- slice_ty,
- Applicability::Unspecified,
- );
-
- for (span, suggestion) in clone_spans {
- diag.span_suggestion(
- span,
- snippet_opt(cx, span)
- .map_or(
- "change the call to".into(),
- |x| format!("change `{x}` to"),
- ),
- suggestion,
- Applicability::Unspecified,
- );
- }
-
- // cannot be destructured, no need for `*` suggestion
- return;
- }
+ if is_type_diagnostic_item(cx, ty, sym::Vec)
+ && let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")])
+ && let TyKind::Path(QPath::Resolved(_, path)) = input.kind
+ && let Some(elem_ty) = path
+ .segments
+ .iter()
+ .find(|seg| seg.ident.name == sym::Vec)
+ .and_then(|ps| ps.args.as_ref())
+ .map(|params| {
+ params
+ .args
+ .iter()
+ .find_map(|arg| match arg {
+ GenericArg::Type(ty) => Some(ty),
+ _ => None,
+ })
+ .unwrap()
+ })
+ {
+ let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_"));
+ diag.span_suggestion(
+ input.span,
+ "consider changing the type to",
+ slice_ty,
+ Applicability::Unspecified,
+ );
+
+ for (span, suggestion) in clone_spans {
+ diag.span_suggestion(
+ span,
+ snippet_opt(cx, span)
+ .map_or("change the call to".into(), |x| format!("change `{x}` to")),
+ suggestion,
+ Applicability::Unspecified,
+ );
}
- if is_type_lang_item(cx, ty, LangItem::String) {
- if let Some(clone_spans) =
- get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) {
+ // cannot be destructured, no need for `*` suggestion
+ return;
+ }
+
+ if is_type_lang_item(cx, ty, LangItem::String) {
+ if let Some(clone_spans) =
+ get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")])
+ {
+ diag.span_suggestion(
+ input.span,
+ "consider changing the type to",
+ "&str",
+ Applicability::Unspecified,
+ );
+
+ for (span, suggestion) in clone_spans {
diag.span_suggestion(
- input.span,
- "consider changing the type to",
- "&str",
+ span,
+ snippet_opt(cx, span)
+ .map_or("change the call to".into(), |x| format!("change `{x}` to")),
+ suggestion,
Applicability::Unspecified,
);
-
- for (span, suggestion) in clone_spans {
- diag.span_suggestion(
- span,
- snippet_opt(cx, span)
- .map_or(
- "change the call to".into(),
- |x| format!("change `{x}` to")
- ),
- suggestion,
- Applicability::Unspecified,
- );
- }
-
- return;
}
+
+ return;
}
+ }
- let spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))];
+ let spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))];
- multispan_sugg(diag, "consider taking a reference instead", spans);
- };
+ multispan_sugg(diag, "consider taking a reference instead", spans);
+ };
- span_lint_and_then(
- cx,
- NEEDLESS_PASS_BY_VALUE,
- input.span,
- "this argument is passed by value, but not consumed in the function body",
- sugg,
- );
- }
+ span_lint_and_then(
+ cx,
+ NEEDLESS_PASS_BY_VALUE,
+ input.span,
+ "this argument is passed by value, but not consumed in the function body",
+ sugg,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index 074c9fef1..a4d3aaf0d 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -1,12 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::path_res;
use clippy_utils::source::snippet;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, Expr, ExprKind, LangItem, MatchSource, QPath};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -111,34 +110,32 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
}
fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
- if_chain! {
- if let ExprKind::Call(path, [arg]) = expr.kind;
- if let Res::Def(DefKind::Ctor(..), ctor_id) = path_res(cx, path);
- if let Some(variant_id) = cx.tcx.opt_parent(ctor_id);
- let sugg_remove = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) {
+ if let ExprKind::Call(path, [arg]) = expr.kind
+ && let Res::Def(DefKind::Ctor(..), ctor_id) = path_res(cx, path)
+ && let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
+ && let sugg_remove = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) {
"Some()"
} else if cx.tcx.lang_items().result_ok_variant() == Some(variant_id) {
"Ok()"
} else {
return;
- };
- if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar(_)) = &arg.kind;
- if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind;
- if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind;
- if expr.span.eq_ctxt(inner_expr.span);
- let expr_ty = cx.typeck_results().expr_ty(expr);
- let inner_ty = cx.typeck_results().expr_ty(inner_expr);
- if expr_ty == inner_ty;
- then {
- span_lint_and_sugg(
- cx,
- NEEDLESS_QUESTION_MARK,
- expr.span,
- "question mark operator is useless here",
- &format!("try removing question mark and `{sugg_remove}`"),
- format!("{}", snippet(cx, inner_expr.span, r#""...""#)),
- Applicability::MachineApplicable,
- );
}
+ && let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar(_)) = &arg.kind
+ && let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind
+ && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind
+ && expr.span.eq_ctxt(inner_expr.span)
+ && let expr_ty = cx.typeck_results().expr_ty(expr)
+ && let inner_ty = cx.typeck_results().expr_ty(inner_expr)
+ && expr_ty == inner_ty
+ {
+ span_lint_and_sugg(
+ cx,
+ NEEDLESS_QUESTION_MARK,
+ expr.span,
+ "question mark operator is useless here",
+ &format!("try removing question mark and `{sugg_remove}`"),
+ format!("{}", snippet(cx, inner_expr.span, r#""...""#)),
+ Applicability::MachineApplicable,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_update.rs b/src/tools/clippy/clippy_lints/src/needless_update.rs
index f8888d368..6a2893cef 100644
--- a/src/tools/clippy/clippy_lints/src/needless_update.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_update.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
index 56c67406d..f7621822b 100644
--- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::implements_trait;
-use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -46,42 +45,39 @@ declare_lint_pass!(NoNegCompOpForPartialOrd => [NEG_CMP_OP_ON_PARTIAL_ORD]);
impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if_chain! {
- if !in_external_macro(cx.sess(), expr.span);
- if let ExprKind::Unary(UnOp::Not, inner) = expr.kind;
- if let ExprKind::Binary(ref op, left, _) = inner.kind;
- if let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node;
+ if !in_external_macro(cx.sess(), expr.span)
+ && let ExprKind::Unary(UnOp::Not, inner) = expr.kind
+ && let ExprKind::Binary(ref op, left, _) = inner.kind
+ && let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node
+ {
+ let ty = cx.typeck_results().expr_ty(left);
- then {
- let ty = cx.typeck_results().expr_ty(left);
-
- let implements_ord = {
- if let Some(id) = cx.tcx.get_diagnostic_item(sym::Ord) {
- implements_trait(cx, ty, id, &[])
- } else {
- return;
- }
- };
-
- let implements_partial_ord = {
- if let Some(id) = cx.tcx.lang_items().partial_ord_trait() {
- implements_trait(cx, ty, id, &[ty.into()])
- } else {
- return;
- }
- };
+ let implements_ord = {
+ if let Some(id) = cx.tcx.get_diagnostic_item(sym::Ord) {
+ implements_trait(cx, ty, id, &[])
+ } else {
+ return;
+ }
+ };
- if implements_partial_ord && !implements_ord {
- span_lint(
- cx,
- NEG_CMP_OP_ON_PARTIAL_ORD,
- expr.span,
- "the use of negated comparison operators on partially ordered \
- types produces code that is hard to read and refactor, please \
- consider using the `partial_cmp` method instead, to make it \
- clear that the two values could be incomparable",
- );
+ let implements_partial_ord = {
+ if let Some(id) = cx.tcx.lang_items().partial_ord_trait() {
+ implements_trait(cx, ty, id, &[ty.into()])
+ } else {
+ return;
}
+ };
+
+ if implements_partial_ord && !implements_ord {
+ span_lint(
+ cx,
+ NEG_CMP_OP_ON_PARTIAL_ORD,
+ expr.span,
+ "the use of negated comparison operators on partially ordered \
+ types produces code that is hard to read and refactor, please \
+ consider using the `partial_cmp` method instead, to make it \
+ clear that the two values could be incomparable",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index 8b69f94cb..f84d9fadb 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -2,12 +2,11 @@ use clippy_utils::consts::{self, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context;
use clippy_utils::sugg::has_enclosing_paren;
-use if_chain::if_chain;
use rustc_ast::util::parser::PREC_PREFIX;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
@@ -53,28 +52,25 @@ impl<'tcx> LateLintPass<'tcx> for NegMultiply {
}
fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
- if_chain! {
- if let ExprKind::Lit(l) = lit.kind;
- if consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1);
- if cx.typeck_results().expr_ty(exp).is_integral();
-
- then {
- let mut applicability = Applicability::MachineApplicable;
- let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability);
- let suggestion = if !from_macro && exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) {
- format!("-({snip})")
- } else {
- format!("-{snip}")
- };
- span_lint_and_sugg(
- cx,
- NEG_MULTIPLY,
- span,
- "this multiplication by -1 can be written more succinctly",
- "consider using",
- suggestion,
- applicability,
- );
- }
+ if let ExprKind::Lit(l) = lit.kind
+ && consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1)
+ && cx.typeck_results().expr_ty(exp).is_integral()
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability);
+ let suggestion = if !from_macro && exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) {
+ format!("-({snip})")
+ } else {
+ format!("-{snip}")
+ };
+ span_lint_and_sugg(
+ cx,
+ NEG_MULTIPLY,
+ span,
+ "this multiplication by -1 can be written more succinctly",
+ "consider using",
+ suggestion,
+ applicability,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index f7f9dccfb..9de6ad421 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -2,13 +2,12 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::return_ty;
use clippy_utils::source::snippet;
use clippy_utils::sugg::DiagnosticExt;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::HirIdSet;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -93,73 +92,69 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
// an impl of `Default`
return;
}
- if_chain! {
- if sig.decl.inputs.is_empty();
- if name == sym::new;
- if cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id);
- let self_def_id = cx.tcx.hir().get_parent_item(id.into());
- let self_ty = cx.tcx.type_of(self_def_id).instantiate_identity();
- if self_ty == return_ty(cx, id);
- if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
- then {
- if self.impling_types.is_none() {
- let mut impls = HirIdSet::default();
- cx.tcx.for_each_impl(default_trait_id, |d| {
- let ty = cx.tcx.type_of(d).instantiate_identity();
- if let Some(ty_def) = ty.ty_adt_def() {
- if let Some(local_def_id) = ty_def.did().as_local() {
- impls.insert(cx.tcx.hir().local_def_id_to_hir_id(local_def_id));
- }
+ if sig.decl.inputs.is_empty()
+ && name == sym::new
+ && cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id)
+ && let self_def_id = cx.tcx.hir().get_parent_item(id.into())
+ && let self_ty = cx.tcx.type_of(self_def_id).instantiate_identity()
+ && self_ty == return_ty(cx, id)
+ && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default)
+ {
+ if self.impling_types.is_none() {
+ let mut impls = HirIdSet::default();
+ cx.tcx.for_each_impl(default_trait_id, |d| {
+ let ty = cx.tcx.type_of(d).instantiate_identity();
+ if let Some(ty_def) = ty.ty_adt_def() {
+ if let Some(local_def_id) = ty_def.did().as_local() {
+ impls.insert(cx.tcx.local_def_id_to_hir_id(local_def_id));
}
- });
- self.impling_types = Some(impls);
- }
-
- // Check if a Default implementation exists for the Self type, regardless of
- // generics
- if_chain! {
- if let Some(ref impling_types) = self.impling_types;
- let self_def = cx.tcx.type_of(self_def_id).instantiate_identity();
- if let Some(self_def) = self_def.ty_adt_def();
- if let Some(self_local_did) = self_def.did().as_local();
- let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
- if impling_types.contains(&self_id);
- then {
- return;
}
- }
+ });
+ self.impling_types = Some(impls);
+ }
- let generics_sugg = snippet(cx, generics.span, "");
- let where_clause_sugg = if generics.has_where_clause_predicates {
- format!("\n{}\n", snippet(cx, generics.where_clause_span, ""))
- } else {
- String::new()
- };
- let self_ty_fmt = self_ty.to_string();
- let self_type_snip = snippet(cx, impl_self_ty.span, &self_ty_fmt);
- span_lint_hir_and_then(
- cx,
- NEW_WITHOUT_DEFAULT,
- id.into(),
- impl_item.span,
- &format!(
- "you should consider adding a `Default` implementation for `{self_type_snip}`"
- ),
- |diag| {
- diag.suggest_prepend_item(
- cx,
- item.span,
- "try adding this",
- &create_new_without_default_suggest_msg(
- &self_type_snip,
- &generics_sugg,
- &where_clause_sugg
- ),
- Applicability::MachineApplicable,
- );
- },
- );
+ // Check if a Default implementation exists for the Self type, regardless of
+ // generics
+ if let Some(ref impling_types) = self.impling_types
+ && let self_def = cx.tcx.type_of(self_def_id).instantiate_identity()
+ && let Some(self_def) = self_def.ty_adt_def()
+ && let Some(self_local_did) = self_def.did().as_local()
+ && let self_id = cx.tcx.local_def_id_to_hir_id(self_local_did)
+ && impling_types.contains(&self_id)
+ {
+ return;
}
+
+ let generics_sugg = snippet(cx, generics.span, "");
+ let where_clause_sugg = if generics.has_where_clause_predicates {
+ format!("\n{}\n", snippet(cx, generics.where_clause_span, ""))
+ } else {
+ String::new()
+ };
+ let self_ty_fmt = self_ty.to_string();
+ let self_type_snip = snippet(cx, impl_self_ty.span, &self_ty_fmt);
+ span_lint_hir_and_then(
+ cx,
+ NEW_WITHOUT_DEFAULT,
+ id.into(),
+ impl_item.span,
+ &format!(
+ "you should consider adding a `Default` implementation for `{self_type_snip}`"
+ ),
+ |diag| {
+ diag.suggest_prepend_item(
+ cx,
+ item.span,
+ "try adding this",
+ &create_new_without_default_suggest_msg(
+ &self_type_snip,
+ &generics_sugg,
+ &where_clause_sugg,
+ ),
+ Applicability::MachineApplicable,
+ );
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 3a28e511f..5978da831 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -10,7 +10,7 @@ use rustc_hir::{
use rustc_infer::infer::TyCtxtInferExt as _;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use std::ops::Deref;
declare_clippy_lint! {
@@ -87,6 +87,17 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect {
fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
if let StmtKind::Semi(expr) = stmt.kind {
+ // move `expr.span.from_expansion()` ahead
+ if expr.span.from_expansion() {
+ return false;
+ }
+ let expr = peel_blocks(expr);
+
+ if is_operator_overridden(cx, expr) {
+ // Return `true`, to prevent `check_unnecessary_operation` from
+ // linting on this statement as well.
+ return true;
+ }
if has_no_effect(cx, expr) {
span_lint_hir_and_then(
cx,
@@ -132,34 +143,47 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
return true;
}
} else if let StmtKind::Local(local) = stmt.kind {
- if_chain! {
- if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id);
- if let Some(init) = local.init;
- if local.els.is_none();
- if !local.pat.span.from_expansion();
- if has_no_effect(cx, init);
- if let PatKind::Binding(_, _, ident, _) = local.pat.kind;
- if ident.name.to_ident_string().starts_with('_');
- then {
- span_lint_hir(
- cx,
- NO_EFFECT_UNDERSCORE_BINDING,
- init.hir_id,
- stmt.span,
- "binding to `_` prefixed variable with no side-effect"
- );
- return true;
- }
+ if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id)
+ && let Some(init) = local.init
+ && local.els.is_none()
+ && !local.pat.span.from_expansion()
+ && has_no_effect(cx, init)
+ && let PatKind::Binding(_, _, ident, _) = local.pat.kind
+ && ident.name.to_ident_string().starts_with('_')
+ {
+ span_lint_hir(
+ cx,
+ NO_EFFECT_UNDERSCORE_BINDING,
+ init.hir_id,
+ stmt.span,
+ "binding to `_` prefixed variable with no side-effect",
+ );
+ return true;
}
}
false
}
-fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- if expr.span.from_expansion() {
- return false;
+fn is_operator_overridden(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ // It's very hard or impossable to check whether overridden operator have side-effect this lint.
+ // So, this function assume user-defined operator is overridden with an side-effect.
+ // The definition of user-defined structure here is ADT-type,
+ // Althrough this will weaken the ability of this lint, less error lint-fix happen.
+ match expr.kind {
+ ExprKind::Binary(..) | ExprKind::Unary(..) => {
+ // No need to check type of `lhs` and `rhs`
+ // because if the operator is overridden, at least one operand is ADT type
+
+ // reference: rust/compiler/rustc_middle/src/ty/typeck_results.rs: `is_method_call`.
+ // use this function to check whether operator is overridden in `ExprKind::{Binary, Unary}`.
+ cx.typeck_results().is_method_call(expr)
+ },
+ _ => false,
}
- match peel_blocks(expr).kind {
+}
+
+fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ match expr.kind {
ExprKind::Lit(..) | ExprKind::Closure { .. } => true,
ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)),
ExprKind::Index(a, b, _) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b),
@@ -199,63 +223,60 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
}
fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
- if_chain! {
- if let StmtKind::Semi(expr) = stmt.kind;
- let ctxt = stmt.span.ctxt();
- if expr.span.ctxt() == ctxt;
- if let Some(reduced) = reduce_expression(cx, expr);
- if !in_external_macro(cx.sess(), stmt.span);
- if reduced.iter().all(|e| e.span.ctxt() == ctxt);
- then {
- if let ExprKind::Index(..) = &expr.kind {
- let snippet = if let (Some(arr), Some(func)) =
- (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span))
- {
+ if let StmtKind::Semi(expr) = stmt.kind
+ && let ctxt = stmt.span.ctxt()
+ && expr.span.ctxt() == ctxt
+ && let Some(reduced) = reduce_expression(cx, expr)
+ && !in_external_macro(cx.sess(), stmt.span)
+ && reduced.iter().all(|e| e.span.ctxt() == ctxt)
+ {
+ if let ExprKind::Index(..) = &expr.kind {
+ let snippet =
+ if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) {
format!("assert!({}.len() > {});", &arr, &func)
} else {
return;
};
- span_lint_hir_and_then(
- cx,
- UNNECESSARY_OPERATION,
- expr.hir_id,
- stmt.span,
- "unnecessary operation",
- |diag| {
- diag.span_suggestion(
- stmt.span,
- "statement can be written as",
- snippet,
- Applicability::MaybeIncorrect,
- );
- },
- );
- } else {
- let mut snippet = String::new();
- for e in reduced {
- if let Some(snip) = snippet_opt(cx, e.span) {
- snippet.push_str(&snip);
- snippet.push(';');
- } else {
- return;
- }
+ span_lint_hir_and_then(
+ cx,
+ UNNECESSARY_OPERATION,
+ expr.hir_id,
+ stmt.span,
+ "unnecessary operation",
+ |diag| {
+ diag.span_suggestion(
+ stmt.span,
+ "statement can be written as",
+ snippet,
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
+ } else {
+ let mut snippet = String::new();
+ for e in reduced {
+ if let Some(snip) = snippet_opt(cx, e.span) {
+ snippet.push_str(&snip);
+ snippet.push(';');
+ } else {
+ return;
}
- span_lint_hir_and_then(
- cx,
- UNNECESSARY_OPERATION,
- expr.hir_id,
- stmt.span,
- "unnecessary operation",
- |diag| {
- diag.span_suggestion(
- stmt.span,
- "statement can be reduced to",
- snippet,
- Applicability::MachineApplicable,
- );
- },
- );
}
+ span_lint_hir_and_then(
+ cx,
+ UNNECESSARY_OPERATION,
+ expr.hir_id,
+ stmt.span,
+ "unnecessary operation",
+ |diag| {
+ diag.span_suggestion(
+ stmt.span,
+ "statement can be reduced to",
+ snippet,
+ Applicability::MachineApplicable,
+ );
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
index 04d750148..8d5a523fd 100644
--- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
+++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability;
use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{BytePos, Pos};
use rustc_target::spec::abi::Abi;
diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
index 9689f63a0..63050080a 100644
--- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
@@ -6,7 +6,7 @@ use rustc_hir::def_id::LocalDefId;
use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::EarlyBinder;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
use rustc_span::symbol::kw;
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 54cec066b..4013cb345 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -7,7 +7,6 @@ use std::ptr;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::macro_backtrace;
use clippy_utils::{def_path_def_ids, in_constant};
-use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
@@ -19,7 +18,7 @@ use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId};
use rustc_middle::query::Key;
use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{sym, InnerSpan, Span};
use rustc_target::abi::VariantIdx;
@@ -386,15 +385,14 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
of_trait: Some(of_trait_ref),
..
}) => {
- if_chain! {
+ if let Some(of_trait_def_id) = of_trait_ref.trait_def_id()
// Lint a trait impl item only when the definition is a generic type,
// assuming an assoc const is not meant to be an interior mutable type.
- if let Some(of_trait_def_id) = of_trait_ref.trait_def_id();
- if let Some(of_assoc_item) = cx
+ && let Some(of_assoc_item) = cx
.tcx
.associated_item(impl_item.owner_id)
- .trait_item_def_id;
- if cx
+ .trait_item_def_id
+ && cx
.tcx
.layout_of(cx.tcx.param_env(of_trait_def_id).and(
// Normalize assoc types because ones originated from generic params
@@ -405,23 +403,17 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
cx.tcx.type_of(of_assoc_item).instantiate_identity(),
),
))
- .is_err();
+ .is_err()
// If there were a function like `has_frozen_variant` described above,
// we should use here as a frozen variant is a potential to be frozen
// similar to unknown layouts.
// e.g. `layout_of(...).is_err() || has_frozen_variant(...);`
- let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity();
- let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
- if !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized);
- if self.is_value_unfrozen_poly(cx, *body_id, normalized);
- then {
- lint(
- cx,
- Source::Assoc {
- item: impl_item.span,
- },
- );
- }
+ && let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity()
+ && let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty)
+ && !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized)
+ && self.is_value_unfrozen_poly(cx, *body_id, normalized)
+ {
+ lint(cx, Source::Assoc { item: impl_item.span });
}
},
ItemKind::Impl(Impl { of_trait: None, .. }) => {
@@ -462,7 +454,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
if parent_id == cur_expr.hir_id {
break;
}
- if let Some(Node::Expr(parent_expr)) = cx.tcx.hir().find(parent_id) {
+ if let Some(Node::Expr(parent_expr)) = cx.tcx.opt_hir_node(parent_id) {
match &parent_expr.kind {
ExprKind::AddrOf(..) => {
// `&e` => `e` must be referenced.
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index 61622034d..ba9230dab 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -5,9 +5,9 @@ use rustc_ast::ast::{
use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{sym, Span};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::{sym, Span};
use std::cmp::Ordering;
declare_clippy_lint! {
@@ -341,7 +341,9 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> {
self.apply(|this| {
SimilarNamesNameVisitor(this).visit_pat(&arm.pat);
- this.apply(|this| walk_expr(this, &arm.body));
+ if let Some(body) = &arm.body {
+ this.apply(|this| walk_expr(this, body));
+ }
});
self.check_single_char_names();
diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
index e94e45899..49e9e2c00 100644
--- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
use clippy_utils::{match_def_path, paths};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -44,38 +43,36 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
match &expr.kind {
ExprKind::MethodCall(path, func, [param], _) => {
- if_chain! {
- if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def();
- if (path.ident.name == sym!(mode)
- && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::FsOpenOptions | sym::DirBuilder)))
+ if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def()
+ && ((path.ident.name == sym!(mode)
+ && matches!(
+ cx.tcx.get_diagnostic_name(adt.did()),
+ Some(sym::FsOpenOptions | sym::DirBuilder)
+ ))
|| (path.ident.name == sym!(set_mode)
- && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did()));
- if let ExprKind::Lit(_) = param.kind;
- if param.span.eq_ctxt(expr.span);
+ && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())))
+ && let ExprKind::Lit(_) = param.kind
+ && param.span.eq_ctxt(expr.span)
+ {
+ let Some(snip) = snippet_opt(cx, param.span) else {
+ return;
+ };
- then {
- let Some(snip) = snippet_opt(cx, param.span) else {
- return
- };
-
- if !snip.starts_with("0o") {
- show_error(cx, param);
- }
+ if !snip.starts_with("0o") {
+ show_error(cx, param);
}
}
},
ExprKind::Call(func, [param]) => {
- if_chain! {
- if let ExprKind::Path(ref path) = func.kind;
- if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
- if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE);
- if let ExprKind::Lit(_) = param.kind;
- if param.span.eq_ctxt(expr.span);
- if let Some(snip) = snippet_opt(cx, param.span);
- if !snip.starts_with("0o");
- then {
- show_error(cx, param);
- }
+ if let ExprKind::Path(ref path) = func.kind
+ && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
+ && match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE)
+ && let ExprKind::Lit(_) = param.kind
+ && param.span.eq_ctxt(expr.span)
+ && let Some(snip) = snippet_opt(cx, param.span)
+ && !snip.starts_with("0o")
+ {
+ show_error(cx, param);
}
},
_ => {},
diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
index 62ef48c8a..793a3a954 100644
--- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -8,7 +8,7 @@ use rustc_hir::{FieldDef, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, GenericArgKind, Ty};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -81,73 +81,73 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
// We start from `Send` impl instead of `check_field_def()` because
// single `AdtDef` may have multiple `Send` impls due to generic
// parameters, and the lint is much easier to implement in this way.
- if_chain! {
- if !in_external_macro(cx.tcx.sess, item.span);
- if let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send);
- if let ItemKind::Impl(hir_impl) = &item.kind;
- if let Some(trait_ref) = &hir_impl.of_trait;
- if let Some(trait_id) = trait_ref.trait_def_id();
- if send_trait == trait_id;
- if hir_impl.polarity == ImplPolarity::Positive;
- if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
- if let self_ty = ty_trait_ref.instantiate_identity().self_ty();
- if let ty::Adt(adt_def, impl_trait_args) = self_ty.kind();
- then {
- let mut non_send_fields = Vec::new();
-
- let hir_map = cx.tcx.hir();
- for variant in adt_def.variants() {
- for field in &variant.fields {
- if_chain! {
- if let Some(field_hir_id) = field
- .did
- .as_local()
- .map(|local_def_id| hir_map.local_def_id_to_hir_id(local_def_id));
- if !is_lint_allowed(cx, NON_SEND_FIELDS_IN_SEND_TY, field_hir_id);
- if let field_ty = field.ty(cx.tcx, impl_trait_args);
- if !ty_allowed_in_send(cx, field_ty, send_trait);
- if let Node::Field(field_def) = hir_map.get(field_hir_id);
- then {
- non_send_fields.push(NonSendField {
- def: field_def,
- ty: field_ty,
- generic_params: collect_generic_params(field_ty),
- })
- }
- }
+ if !in_external_macro(cx.tcx.sess, item.span)
+ && let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send)
+ && let ItemKind::Impl(hir_impl) = &item.kind
+ && let Some(trait_ref) = &hir_impl.of_trait
+ && let Some(trait_id) = trait_ref.trait_def_id()
+ && send_trait == trait_id
+ && hir_impl.polarity == ImplPolarity::Positive
+ && let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+ && let self_ty = ty_trait_ref.instantiate_identity().self_ty()
+ && let ty::Adt(adt_def, impl_trait_args) = self_ty.kind()
+ {
+ let mut non_send_fields = Vec::new();
+
+ for variant in adt_def.variants() {
+ for field in &variant.fields {
+ if let Some(field_hir_id) = field
+ .did
+ .as_local()
+ .map(|local_def_id| cx.tcx.local_def_id_to_hir_id(local_def_id))
+ && !is_lint_allowed(cx, NON_SEND_FIELDS_IN_SEND_TY, field_hir_id)
+ && let field_ty = field.ty(cx.tcx, impl_trait_args)
+ && !ty_allowed_in_send(cx, field_ty, send_trait)
+ && let Node::Field(field_def) = cx.tcx.hir_node(field_hir_id)
+ {
+ non_send_fields.push(NonSendField {
+ def: field_def,
+ ty: field_ty,
+ generic_params: collect_generic_params(field_ty),
+ });
}
}
+ }
- if !non_send_fields.is_empty() {
- span_lint_and_then(
- cx,
- NON_SEND_FIELDS_IN_SEND_TY,
- item.span,
- &format!(
- "some fields in `{}` are not safe to be sent to another thread",
- snippet(cx, hir_impl.self_ty.span, "Unknown")
- ),
- |diag| {
- for field in non_send_fields {
- diag.span_note(
- field.def.span,
- format!("it is not safe to send field `{}` to another thread", field.def.ident.name),
- );
-
- match field.generic_params.len() {
- 0 => diag.help("use a thread-safe type that implements `Send`"),
- 1 if is_ty_param(field.ty) => diag.help(format!("add `{}: Send` bound in `Send` impl", field.ty)),
- _ => diag.help(format!(
- "add bounds on type parameter{} `{}` that satisfy `{}: Send`",
- if field.generic_params.len() > 1 { "s" } else { "" },
- field.generic_params_string(),
- snippet(cx, field.def.ty.span, "Unknown"),
- )),
- };
- }
- },
- );
- }
+ if !non_send_fields.is_empty() {
+ span_lint_and_then(
+ cx,
+ NON_SEND_FIELDS_IN_SEND_TY,
+ item.span,
+ &format!(
+ "some fields in `{}` are not safe to be sent to another thread",
+ snippet(cx, hir_impl.self_ty.span, "Unknown")
+ ),
+ |diag| {
+ for field in non_send_fields {
+ diag.span_note(
+ field.def.span,
+ format!(
+ "it is not safe to send field `{}` to another thread",
+ field.def.ident.name
+ ),
+ );
+
+ match field.generic_params.len() {
+ 0 => diag.help("use a thread-safe type that implements `Send`"),
+ 1 if is_ty_param(field.ty) => {
+ diag.help(format!("add `{}: Send` bound in `Send` impl", field.ty))
+ },
+ _ => diag.help(format!(
+ "add bounds on type parameter{} `{}` that satisfy `{}: Send`",
+ if field.generic_params.len() > 1 { "s" } else { "" },
+ field.generic_params_string(),
+ snippet(cx, field.def.ty.span, "Unknown"),
+ )),
+ };
+ }
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
index 11c3a5417..1c6069e9c 100644
--- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
+++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
@@ -1,13 +1,12 @@
use clippy_config::types::MacroMatcher;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt;
-use if_chain::if_chain;
use rustc_ast::ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::Span;
@@ -34,17 +33,17 @@ declare_clippy_lint! {
}
/// The (callsite span, (open brace, close brace), source snippet)
-type MacroInfo<'a> = (Span, &'a (String, String), String);
+type MacroInfo = (Span, (char, char), String);
-#[derive(Clone, Debug, Default)]
+#[derive(Debug)]
pub struct MacroBraces {
- macro_braces: FxHashMap<String, (String, String)>,
+ macro_braces: FxHashMap<String, (char, char)>,
done: FxHashSet<Span>,
}
impl MacroBraces {
- pub fn new(conf: &FxHashSet<MacroMatcher>) -> Self {
- let macro_braces = macro_braces(conf.clone());
+ pub fn new(conf: &[MacroMatcher]) -> Self {
+ let macro_braces = macro_braces(conf);
Self {
macro_braces,
done: FxHashSet::default(),
@@ -84,7 +83,7 @@ impl EarlyLintPass for MacroBraces {
}
}
-fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a MacroBraces) -> Option<MacroInfo<'a>> {
+fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBraces) -> Option<MacroInfo> {
let unnested_or_local = || {
!span.ctxt().outer_expn_data().call_site.from_expansion()
|| span
@@ -93,28 +92,26 @@ fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a Mac
.map_or(false, |e| e.macro_def_id.map_or(false, DefId::is_local))
};
let span_call_site = span.ctxt().outer_expn_data().call_site;
- if_chain! {
- if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind;
- let name = mac_name.as_str();
- if let Some(braces) = mac_braces.macro_braces.get(name);
- if let Some(snip) = snippet_opt(cx, span_call_site);
+ if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind
+ && let name = mac_name.as_str()
+ && let Some(&braces) = mac_braces.macro_braces.get(name)
+ && let Some(snip) = snippet_opt(cx, span_call_site)
// we must check only invocation sites
// https://github.com/rust-lang/rust-clippy/issues/7422
- if snip.starts_with(&format!("{name}!"));
- if unnested_or_local();
+ && snip.starts_with(&format!("{name}!"))
+ && unnested_or_local()
// make formatting consistent
- let c = snip.replace(' ', "");
- if !c.starts_with(&format!("{name}!{}", braces.0));
- if !mac_braces.done.contains(&span_call_site);
- then {
- Some((span_call_site, braces, snip))
- } else {
- None
- }
+ && let c = snip.replace(' ', "")
+ && !c.starts_with(&format!("{name}!{}", braces.0))
+ && !mac_braces.done.contains(&span_call_site)
+ {
+ Some((span_call_site, braces, snip))
+ } else {
+ None
}
}
-fn emit_help(cx: &EarlyContext<'_>, snip: &str, braces: &(String, String), span: Span) {
+fn emit_help(cx: &EarlyContext<'_>, snip: &str, (open, close): (char, char), span: Span) {
if let Some((macro_name, macro_args_str)) = snip.split_once('!') {
let mut macro_args = macro_args_str.trim().to_string();
// now remove the wrong braces
@@ -126,67 +123,31 @@ fn emit_help(cx: &EarlyContext<'_>, snip: &str, braces: &(String, String), span:
span,
&format!("use of irregular braces for `{macro_name}!` macro"),
"consider writing",
- format!("{macro_name}!{}{macro_args}{}", braces.0, braces.1),
+ format!("{macro_name}!{open}{macro_args}{close}"),
Applicability::MachineApplicable,
);
}
}
-fn macro_braces(conf: FxHashSet<MacroMatcher>) -> FxHashMap<String, (String, String)> {
- let mut braces = vec![
- macro_matcher!(
- name: "print",
- braces: ("(", ")"),
- ),
- macro_matcher!(
- name: "println",
- braces: ("(", ")"),
- ),
- macro_matcher!(
- name: "eprint",
- braces: ("(", ")"),
- ),
- macro_matcher!(
- name: "eprintln",
- braces: ("(", ")"),
- ),
- macro_matcher!(
- name: "write",
- braces: ("(", ")"),
- ),
- macro_matcher!(
- name: "writeln",
- braces: ("(", ")"),
- ),
- macro_matcher!(
- name: "format",
- braces: ("(", ")"),
- ),
- macro_matcher!(
- name: "format_args",
- braces: ("(", ")"),
- ),
- macro_matcher!(
- name: "vec",
- braces: ("[", "]"),
- ),
- macro_matcher!(
- name: "matches",
- braces: ("(", ")"),
- ),
- ]
- .into_iter()
- .collect::<FxHashMap<_, _>>();
+fn macro_braces(conf: &[MacroMatcher]) -> FxHashMap<String, (char, char)> {
+ let mut braces = FxHashMap::from_iter(
+ [
+ ("print", ('(', ')')),
+ ("println", ('(', ')')),
+ ("eprint", ('(', ')')),
+ ("eprintln", ('(', ')')),
+ ("write", ('(', ')')),
+ ("writeln", ('(', ')')),
+ ("format", ('(', ')')),
+ ("format_args", ('(', ')')),
+ ("vec", ('[', ']')),
+ ("matches", ('(', ')')),
+ ]
+ .map(|(k, v)| (k.to_string(), v)),
+ );
// We want users items to override any existing items
for it in conf {
- braces.insert(it.name, it.braces);
+ braces.insert(it.name.clone(), it.braces);
}
braces
}
-
-macro_rules! macro_matcher {
- (name: $name:expr, braces: ($open:expr, $close:expr) $(,)?) => {
- ($name.to_owned(), ($open.to_owned(), $close.to_owned()))
- };
-}
-pub(crate) use macro_matcher;
diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
index 0faf4ce3d..8822dfeed 100644
--- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs
+++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
@@ -4,7 +4,7 @@ use rustc_ast::token::{Lit, LitKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
use std::fmt::Write;
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index ef7b36764..d621051ef 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -8,7 +8,7 @@ use rustc_hir::hir_id::HirIdMap;
use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, ConstKind, EarlyBinder, GenericArgKind, GenericArgsRef};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::{kw, Ident};
use rustc_span::Span;
use std::iter;
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index 4c6462b77..c081dec9b 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -7,9 +7,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
use rustc_session::impl_lint_pass;
-use rustc_span::{Span, Symbol};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
+use rustc_span::{Span, Symbol};
use {rustc_ast as ast, rustc_hir as hir};
const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[["f32", "f32"], ["f64", "f64"], ["std::string::String", "str"]];
diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
index c4572a09d..2f85130fb 100644
--- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
@@ -4,7 +4,6 @@ use clippy_utils::ty::implements_trait;
use clippy_utils::visitors::for_each_expr;
use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method};
use core::ops::ControlFlow;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
@@ -25,43 +24,40 @@ pub(super) fn check<'tcx>(
let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| {
let ty = cx.typeck_results().expr_ty(assignee);
let rty = cx.typeck_results().expr_ty(rhs);
- if_chain! {
- if let Some((_, lang_item)) = binop_traits(op.node);
- if let Some(trait_id) = cx.tcx.lang_items().get(lang_item);
- let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id).def_id;
- if trait_ref_of_method(cx, parent_fn)
- .map_or(true, |t| t.path.res.def_id() != trait_id);
- if implements_trait(cx, ty, trait_id, &[rty.into()]);
- then {
- // Primitive types execute assign-ops right-to-left. Every other type is left-to-right.
- if !(ty.is_primitive() && rty.is_primitive()) {
- // TODO: This will have false negatives as it doesn't check if the borrows are
- // actually live at the end of their respective expressions.
- let mut_borrows = mut_borrows_in_expr(cx, assignee);
- let imm_borrows = imm_borrows_in_expr(cx, rhs);
- if mut_borrows.iter().any(|id| imm_borrows.contains(id)) {
- return;
- }
+ if let Some((_, lang_item)) = binop_traits(op.node)
+ && let Some(trait_id) = cx.tcx.lang_items().get(lang_item)
+ && let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id).def_id
+ && trait_ref_of_method(cx, parent_fn).map_or(true, |t| t.path.res.def_id() != trait_id)
+ && implements_trait(cx, ty, trait_id, &[rty.into()])
+ {
+ // Primitive types execute assign-ops right-to-left. Every other type is left-to-right.
+ if !(ty.is_primitive() && rty.is_primitive()) {
+ // TODO: This will have false negatives as it doesn't check if the borrows are
+ // actually live at the end of their respective expressions.
+ let mut_borrows = mut_borrows_in_expr(cx, assignee);
+ let imm_borrows = imm_borrows_in_expr(cx, rhs);
+ if mut_borrows.iter().any(|id| imm_borrows.contains(id)) {
+ return;
}
- span_lint_and_then(
- cx,
- ASSIGN_OP_PATTERN,
- expr.span,
- "manual implementation of an assign operation",
- |diag| {
- if let (Some(snip_a), Some(snip_r)) =
- (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span))
- {
- diag.span_suggestion(
- expr.span,
- "replace it with",
- format!("{snip_a} {}= {snip_r}", op.node.as_str()),
- Applicability::MachineApplicable,
- );
- }
- },
- );
}
+ span_lint_and_then(
+ cx,
+ ASSIGN_OP_PATTERN,
+ expr.span,
+ "manual implementation of an assign operation",
+ |diag| {
+ if let (Some(snip_a), Some(snip_r)) =
+ (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span))
+ {
+ diag.span_suggestion(
+ expr.span,
+ "replace it with",
+ format!("{snip_a} {}= {snip_r}", op.node.as_str()),
+ Applicability::MachineApplicable,
+ );
+ }
+ },
+ );
}
};
diff --git a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
index ec2bb8699..e278cf983 100644
--- a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
@@ -3,13 +3,12 @@
use std::cmp::Ordering;
use clippy_utils::consts::{constant, Constant};
-use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::{Ty, TypeckResults};
-use rustc_span::Span;
use rustc_span::source_map::Spanned;
+use rustc_span::Span;
use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::source::snippet;
@@ -24,19 +23,17 @@ fn comparison_to_const<'tcx>(
typeck: &TypeckResults<'tcx>,
expr: &'tcx Expr<'tcx>,
) -> Option<(CmpOp, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Constant<'tcx>, Ty<'tcx>)> {
- if_chain! {
- if let ExprKind::Binary(operator, left, right) = expr.kind;
- if let Ok(cmp_op) = CmpOp::try_from(operator.node);
- then {
- match (constant(cx, typeck, left), constant(cx, typeck, right)) {
- (Some(_), Some(_)) => None,
- (_, Some(con)) => Some((cmp_op, left, right, con, typeck.expr_ty(right))),
- (Some(con), _) => Some((cmp_op.reverse(), right, left, con, typeck.expr_ty(left))),
- _ => None,
- }
- } else {
- None
+ if let ExprKind::Binary(operator, left, right) = expr.kind
+ && let Ok(cmp_op) = CmpOp::try_from(operator.node)
+ {
+ match (constant(cx, typeck, left), constant(cx, typeck, right)) {
+ (Some(_), Some(_)) => None,
+ (_, Some(con)) => Some((cmp_op, left, right, con, typeck.expr_ty(right))),
+ (Some(con), _) => Some((cmp_op.reverse(), right, left, con, typeck.expr_ty(left))),
+ _ => None,
}
+ } else {
+ None
}
}
@@ -47,87 +44,89 @@ pub(super) fn check<'tcx>(
right_cond: &'tcx Expr<'tcx>,
span: Span,
) {
- if_chain! {
+ if and_op.node == BinOpKind::And
// Ensure that the binary operator is &&
- if and_op.node == BinOpKind::And;
// Check that both operands to '&&' are themselves a binary operation
// The `comparison_to_const` step also checks this, so this step is just an optimization
- if let ExprKind::Binary(_, _, _) = left_cond.kind;
- if let ExprKind::Binary(_, _, _) = right_cond.kind;
+ && let ExprKind::Binary(_, _, _) = left_cond.kind
+ && let ExprKind::Binary(_, _, _) = right_cond.kind
- let typeck = cx.typeck_results();
+ && let typeck = cx.typeck_results()
// Check that both operands to '&&' compare a non-literal to a literal
- if let Some((left_cmp_op, left_expr, left_const_expr, left_const, left_type)) =
- comparison_to_const(cx, typeck, left_cond);
- if let Some((right_cmp_op, right_expr, right_const_expr, right_const, right_type)) =
- comparison_to_const(cx, typeck, right_cond);
+ && let Some((left_cmp_op, left_expr, left_const_expr, left_const, left_type)) =
+ comparison_to_const(cx, typeck, left_cond)
+ && let Some((right_cmp_op, right_expr, right_const_expr, right_const, right_type)) =
+ comparison_to_const(cx, typeck, right_cond)
- if left_type == right_type;
+ && left_type == right_type
// Check that the same expression is compared in both comparisons
- if SpanlessEq::new(cx).eq_expr(left_expr, right_expr);
+ && SpanlessEq::new(cx).eq_expr(left_expr, right_expr)
- if !left_expr.can_have_side_effects();
+ && !left_expr.can_have_side_effects()
// Compare the two constant expressions
- if let Some(ordering) = Constant::partial_cmp(cx.tcx(), left_type, &left_const, &right_const);
+ && let Some(ordering) = Constant::partial_cmp(cx.tcx(), left_type, &left_const, &right_const)
// Rule out the `x >= 42 && x <= 42` corner case immediately
// Mostly to simplify the implementation, but it is also covered by `clippy::double_comparisons`
- if !matches!(
+ && !matches!(
(&left_cmp_op, &right_cmp_op, ordering),
(CmpOp::Le | CmpOp::Ge, CmpOp::Le | CmpOp::Ge, Ordering::Equal)
- );
-
- then {
- if left_cmp_op.direction() == right_cmp_op.direction() {
- let lhs_str = snippet(cx, left_cond.span, "<lhs>");
- let rhs_str = snippet(cx, right_cond.span, "<rhs>");
- // We already know that either side of `&&` has no effect,
- // but emit a different error message depending on which side it is
- if left_side_is_useless(left_cmp_op, ordering) {
- span_lint_and_note(
- cx,
- REDUNDANT_COMPARISONS,
- span,
- "left-hand side of `&&` operator has no effect",
- Some(left_cond.span.until(right_cond.span)),
- &format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"),
- );
- } else {
- span_lint_and_note(
- cx,
- REDUNDANT_COMPARISONS,
- span,
- "right-hand side of `&&` operator has no effect",
- Some(and_op.span.to(right_cond.span)),
- &format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"),
- );
- }
- // We could autofix this error but choose not to,
- // because code triggering this lint probably not behaving correctly in the first place
- }
- else if !comparison_is_possible(left_cmp_op.direction(), ordering) {
- let expr_str = snippet(cx, left_expr.span, "..");
- let lhs_str = snippet(cx, left_const_expr.span, "<lhs>");
- let rhs_str = snippet(cx, right_const_expr.span, "<rhs>");
- let note = match ordering {
- Ordering::Less => format!("since `{lhs_str}` < `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"),
- Ordering::Equal => format!("`{expr_str}` cannot simultaneously be greater than and less than `{lhs_str}`"),
- Ordering::Greater => format!("since `{lhs_str}` > `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"),
- };
+ )
+ {
+ if left_cmp_op.direction() == right_cmp_op.direction() {
+ let lhs_str = snippet(cx, left_cond.span, "<lhs>");
+ let rhs_str = snippet(cx, right_cond.span, "<rhs>");
+ // We already know that either side of `&&` has no effect,
+ // but emit a different error message depending on which side it is
+ if left_side_is_useless(left_cmp_op, ordering) {
span_lint_and_note(
cx,
- IMPOSSIBLE_COMPARISONS,
+ REDUNDANT_COMPARISONS,
span,
- "boolean expression will never evaluate to 'true'",
- None,
- &note,
+ "left-hand side of `&&` operator has no effect",
+ Some(left_cond.span.until(right_cond.span)),
+ &format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"),
);
+ } else {
+ span_lint_and_note(
+ cx,
+ REDUNDANT_COMPARISONS,
+ span,
+ "right-hand side of `&&` operator has no effect",
+ Some(and_op.span.to(right_cond.span)),
+ &format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"),
+ );
+ }
+ // We could autofix this error but choose not to,
+ // because code triggering this lint probably not behaving correctly in the first place
+ } else if !comparison_is_possible(left_cmp_op.direction(), ordering) {
+ let expr_str = snippet(cx, left_expr.span, "..");
+ let lhs_str = snippet(cx, left_const_expr.span, "<lhs>");
+ let rhs_str = snippet(cx, right_const_expr.span, "<rhs>");
+ let note = match ordering {
+ Ordering::Less => format!(
+ "since `{lhs_str}` < `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"
+ ),
+ Ordering::Equal => {
+ format!("`{expr_str}` cannot simultaneously be greater than and less than `{lhs_str}`")
+ },
+ Ordering::Greater => format!(
+ "since `{lhs_str}` > `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"
+ ),
};
- }
+ span_lint_and_note(
+ cx,
+ IMPOSSIBLE_COMPARISONS,
+ span,
+ "boolean expression will never evaluate to 'true'",
+ None,
+ &note,
+ );
+ };
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
index fd3502ad8..01dd418c3 100644
--- a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
@@ -36,7 +36,7 @@ pub(crate) fn check<'tcx>(
left: &'tcx Expr<'_>,
right: &'tcx Expr<'_>,
) {
- if is_useless_with_eq_exprs(op.into()) && eq_expr_value(cx, left, right) && !is_in_test_function(cx.tcx, e.hir_id) {
+ if is_useless_with_eq_exprs(op) && eq_expr_value(cx, left, right) && !is_in_test_function(cx.tcx, e.hir_id) {
span_lint_and_then(
cx,
EQ_OP,
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
index bce6bdcaf..0561739d1 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
@@ -2,7 +2,6 @@ use clippy_utils::consts::{constant_with_source, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::get_item_name;
use clippy_utils::sugg::Sugg;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::LateContext;
@@ -105,14 +104,12 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
return is_signum(cx, child_expr);
}
- if_chain! {
- if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind;
- if sym!(signum) == method_name.ident.name;
- // Check that the receiver of the signum() is a float (expressions[0] is the receiver of
- // the method call)
- then {
- return is_float(cx, self_arg);
- }
+ if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind
+ && sym!(signum) == method_name.ident.name
+ // Check that the receiver of the signum() is a float (expressions[0] is the receiver of
+ // the method call)
+ {
+ return is_float(cx, self_arg);
}
false
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs
index a0a8b6aab..cace85a24 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{match_def_path, paths, sugg};
-use if_chain::if_chain;
use rustc_ast::util::parser::AssocOp;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
@@ -24,48 +23,43 @@ pub(crate) fn check<'tcx>(
_ => return,
};
- if_chain! {
+ if let ExprKind::Binary(
// left hand side is a subtraction
- if let ExprKind::Binary(
Spanned {
node: BinOpKind::Sub,
..
},
val_l,
val_r,
- ) = lhs.kind;
+ ) = lhs.kind
// right hand side matches either f32::EPSILON or f64::EPSILON
- if let ExprKind::Path(ref epsilon_path) = rhs.kind;
- if let Res::Def(DefKind::AssocConst, def_id) = cx.qpath_res(epsilon_path, rhs.hir_id);
- if match_def_path(cx, def_id, &paths::F32_EPSILON) || match_def_path(cx, def_id, &paths::F64_EPSILON);
+ && let ExprKind::Path(ref epsilon_path) = rhs.kind
+ && let Res::Def(DefKind::AssocConst, def_id) = cx.qpath_res(epsilon_path, rhs.hir_id)
+ && (match_def_path(cx, def_id, &paths::F32_EPSILON) || match_def_path(cx, def_id, &paths::F64_EPSILON))
// values of the subtractions on the left hand side are of the type float
- let t_val_l = cx.typeck_results().expr_ty(val_l);
- let t_val_r = cx.typeck_results().expr_ty(val_r);
- if let ty::Float(_) = t_val_l.kind();
- if let ty::Float(_) = t_val_r.kind();
-
- then {
- let sug_l = sugg::Sugg::hir(cx, val_l, "..");
- let sug_r = sugg::Sugg::hir(cx, val_r, "..");
- // format the suggestion
- let suggestion = format!("{}.abs()", sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par());
- // spans the lint
- span_lint_and_then(
- cx,
- FLOAT_EQUALITY_WITHOUT_ABS,
- expr.span,
- "float equality check without `.abs()`",
- | diag | {
- diag.span_suggestion(
- lhs.span,
- "add `.abs()`",
- suggestion,
- Applicability::MaybeIncorrect,
- );
- }
- );
- }
+ && let t_val_l = cx.typeck_results().expr_ty(val_l)
+ && let t_val_r = cx.typeck_results().expr_ty(val_r)
+ && let ty::Float(_) = t_val_l.kind()
+ && let ty::Float(_) = t_val_r.kind()
+ {
+ let sug_l = sugg::Sugg::hir(cx, val_l, "..");
+ let sug_r = sugg::Sugg::hir(cx, val_r, "..");
+ // format the suggestion
+ let suggestion = format!(
+ "{}.abs()",
+ sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par()
+ );
+ // spans the lint
+ span_lint_and_then(
+ cx,
+ FLOAT_EQUALITY_WITHOUT_ABS,
+ expr.span,
+ "float equality check without `.abs()`",
+ |diag| {
+ diag.span_suggestion(lhs.span, "add `.abs()`", suggestion, Applicability::MaybeIncorrect);
+ },
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs b/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs
index 5eabb349e..fecc5a857 100644
--- a/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs
@@ -46,7 +46,7 @@ fn lint_misrefactored_assign_op(
if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) {
let a = &sugg::Sugg::hir(cx, assignee, "..");
let r = &sugg::Sugg::hir(cx, rhs, "..");
- let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r));
+ let long = format!("{snip_a} = {}", sugg::make_binop(op, a, r));
diag.span_suggestion(
expr.span,
format!(
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index ee79ea276..4c09c4eea 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -25,7 +25,7 @@ pub(crate) mod arithmetic_side_effects;
use rustc_hir::{Body, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
index a2c3a4d8b..cb3916484 100644
--- a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
@@ -1,7 +1,6 @@
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sext;
-use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
@@ -19,15 +18,12 @@ pub(super) fn check<'tcx>(
if op == BinOpKind::Rem {
let lhs_operand = analyze_operand(lhs, cx, e);
let rhs_operand = analyze_operand(rhs, cx, e);
- if_chain! {
- if let Some(lhs_operand) = lhs_operand;
- if let Some(rhs_operand) = rhs_operand;
- then {
- check_const_operands(cx, e, &lhs_operand, &rhs_operand);
- }
- else {
- check_non_const_operands(cx, e, lhs);
- }
+ if let Some(lhs_operand) = lhs_operand
+ && let Some(rhs_operand) = rhs_operand
+ {
+ check_const_operands(cx, e, &lhs_operand, &rhs_operand);
+ } else {
+ check_non_const_operands(cx, e, lhs);
}
};
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
index 932dd470f..7d8aa3f56 100644
--- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
use clippy_utils::get_enclosing_block;
use clippy_utils::source::snippet;
use clippy_utils::ty::{implements_trait, is_copy};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
@@ -180,41 +179,33 @@ fn in_impl<'tcx>(
e: &'tcx Expr<'_>,
bin_op: DefId,
) -> Option<(&'tcx rustc_hir::Ty<'tcx>, &'tcx rustc_hir::Ty<'tcx>)> {
- if_chain! {
- if let Some(block) = get_enclosing_block(cx, e.hir_id);
- if let Some(impl_def_id) = cx.tcx.impl_of_method(block.hir_id.owner.to_def_id());
- let item = cx.tcx.hir().expect_item(impl_def_id.expect_local());
- if let ItemKind::Impl(item) = &item.kind;
- if let Some(of_trait) = &item.of_trait;
- if let Some(seg) = of_trait.path.segments.last();
- if let Res::Def(_, trait_id) = seg.res;
- if trait_id == bin_op;
- if let Some(generic_args) = seg.args;
- if let Some(GenericArg::Type(other_ty)) = generic_args.args.last();
-
- then {
- Some((item.self_ty, other_ty))
- }
- else {
- None
- }
+ if let Some(block) = get_enclosing_block(cx, e.hir_id)
+ && let Some(impl_def_id) = cx.tcx.impl_of_method(block.hir_id.owner.to_def_id())
+ && let item = cx.tcx.hir().expect_item(impl_def_id.expect_local())
+ && let ItemKind::Impl(item) = &item.kind
+ && let Some(of_trait) = &item.of_trait
+ && let Some(seg) = of_trait.path.segments.last()
+ && let Res::Def(_, trait_id) = seg.res
+ && trait_id == bin_op
+ && let Some(generic_args) = seg.args
+ && let Some(GenericArg::Type(other_ty)) = generic_args.args.last()
+ {
+ Some((item.self_ty, other_ty))
+ } else {
+ None
}
}
fn are_equal(cx: &LateContext<'_>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool {
- if_chain! {
- if let ty::Adt(adt_def, _) = middle_ty.kind();
- if let Some(local_did) = adt_def.did().as_local();
- let item = cx.tcx.hir().expect_item(local_did);
- let middle_ty_id = item.owner_id.to_def_id();
- if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
- if let Res::Def(_, hir_ty_id) = path.res;
-
- then {
- hir_ty_id == middle_ty_id
- }
- else {
- false
- }
+ if let ty::Adt(adt_def, _) = middle_ty.kind()
+ && let Some(local_did) = adt_def.did().as_local()
+ && let item = cx.tcx.hir().expect_item(local_did)
+ && let middle_ty_id = item.owner_id.to_def_id()
+ && let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind
+ && let Res::Def(_, hir_ty_id) = path.res
+ {
+ hir_ty_id == middle_ty_id
+ } else {
+ false
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs
index 1229c202f..9db2e2463 100644
--- a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
@@ -22,22 +21,20 @@ pub(super) fn check<'tcx>(
_ => (left, right),
};
- if_chain! {
- if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left);
- if let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right);
- if let Some(left_snip) = snippet_opt(cx, left_var.span);
- if let Some(right_snip) = snippet_opt(cx, right_var.span);
- then {
- span_lint_and_sugg(
- cx,
- PTR_EQ,
- expr.span,
- LINT_MSG,
- "try",
- format!("std::ptr::eq({left_snip}, {right_snip})"),
- Applicability::MachineApplicable,
- );
- }
+ if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left)
+ && let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right)
+ && let Some(left_snip) = snippet_opt(cx, left_var.span)
+ && let Some(right_snip) = snippet_opt(cx, right_var.span)
+ {
+ span_lint_and_sugg(
+ cx,
+ PTR_EQ,
+ expr.span,
+ LINT_MSG,
+ "try",
+ format!("std::ptr::eq({left_snip}, {right_snip})"),
+ Applicability::MachineApplicable,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
index 7792efe6a..4bfb26209 100644
--- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_direct_expn_of;
use rustc_ast::ast::{Expr, ExprKind, MethodCall};
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, Span};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index d7cbbe13a..89e4e3c74 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -4,13 +4,12 @@ use clippy_utils::{
can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_res_lang_ctor, peel_blocks,
peel_hir_expr_while, CaptureKind,
};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::SyntaxContext;
declare_clippy_lint! {
@@ -122,73 +121,97 @@ fn try_get_option_occurrence<'tcx>(
_ => expr,
};
let (inner_pat, is_result) = try_get_inner_pat_and_is_result(cx, pat)?;
- if_chain! {
- if let PatKind::Binding(bind_annotation, _, id, None) = inner_pat.kind;
- if let Some(some_captures) = can_move_expr_to_closure(cx, if_then);
- if let Some(none_captures) = can_move_expr_to_closure(cx, if_else);
- if some_captures
+ if let PatKind::Binding(bind_annotation, _, id, None) = inner_pat.kind
+ && let Some(some_captures) = can_move_expr_to_closure(cx, if_then)
+ && let Some(none_captures) = can_move_expr_to_closure(cx, if_else)
+ && some_captures
.iter()
.filter_map(|(id, &c)| none_captures.get(id).map(|&c2| (c, c2)))
- .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref());
- then {
- let capture_mut = if bind_annotation == BindingAnnotation::MUT { "mut " } else { "" };
- let some_body = peel_blocks(if_then);
- let none_body = peel_blocks(if_else);
- let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" };
- let capture_name = id.name.to_ident_string();
- let (as_ref, as_mut) = match &expr.kind {
- ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
- ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true),
- _ if let Some(mutb) = cx.typeck_results().expr_ty(expr).ref_mutability() => {
- (mutb == Mutability::Not, mutb == Mutability::Mut)
- }
- _ => (bind_annotation == BindingAnnotation::REF, bind_annotation == BindingAnnotation::REF_MUT),
- };
+ .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref())
+ {
+ let capture_mut = if bind_annotation == BindingAnnotation::MUT {
+ "mut "
+ } else {
+ ""
+ };
+ let some_body = peel_blocks(if_then);
+ let none_body = peel_blocks(if_else);
+ let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) {
+ "map_or"
+ } else {
+ "map_or_else"
+ };
+ let capture_name = id.name.to_ident_string();
+ let (as_ref, as_mut) = match &expr.kind {
+ ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
+ ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true),
+ _ if let Some(mutb) = cx.typeck_results().expr_ty(expr).ref_mutability() => {
+ (mutb == Mutability::Not, mutb == Mutability::Mut)
+ },
+ _ => (
+ bind_annotation == BindingAnnotation::REF,
+ bind_annotation == BindingAnnotation::REF_MUT,
+ ),
+ };
- // Check if captures the closure will need conflict with borrows made in the scrutinee.
- // TODO: check all the references made in the scrutinee expression. This will require interacting
- // with the borrow checker. Currently only `<local>[.<field>]*` is checked for.
- if as_ref || as_mut {
- let e = peel_hir_expr_while(cond_expr, |e| match e.kind {
- ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e),
- _ => None,
- });
- if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(local_id), .. })) = e.kind {
- match some_captures.get(local_id)
- .or_else(|| (method_sugg == "map_or_else").then_some(()).and_then(|()| none_captures.get(local_id)))
- {
- Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None,
- Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None,
- Some(CaptureKind::Ref(Mutability::Not)) | None => (),
- }
+ // Check if captures the closure will need conflict with borrows made in the scrutinee.
+ // TODO: check all the references made in the scrutinee expression. This will require interacting
+ // with the borrow checker. Currently only `<local>[.<field>]*` is checked for.
+ if as_ref || as_mut {
+ let e = peel_hir_expr_while(cond_expr, |e| match e.kind {
+ ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e),
+ _ => None,
+ });
+ if let ExprKind::Path(QPath::Resolved(
+ None,
+ Path {
+ res: Res::Local(local_id),
+ ..
+ },
+ )) = e.kind
+ {
+ match some_captures.get(local_id).or_else(|| {
+ (method_sugg == "map_or_else")
+ .then_some(())
+ .and_then(|()| none_captures.get(local_id))
+ }) {
+ Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None,
+ Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None,
+ Some(CaptureKind::Ref(Mutability::Not)) | None => (),
}
}
+ }
- let mut app = Applicability::Unspecified;
+ let mut app = Applicability::Unspecified;
- let (none_body, is_argless_call) = match none_body.kind {
- ExprKind::Call(call_expr, []) if !none_body.span.from_expansion() => (call_expr, true),
- _ => (none_body, false),
- };
+ let (none_body, is_argless_call) = match none_body.kind {
+ ExprKind::Call(call_expr, []) if !none_body.span.from_expansion() => (call_expr, true),
+ _ => (none_body, false),
+ };
- return Some(OptionOccurrence {
- option: format_option_in_sugg(
- Sugg::hir_with_context(cx, cond_expr, ctxt, "..", &mut app),
- as_ref,
- as_mut,
- ),
- method_sugg: method_sugg.to_string(),
- some_expr: format!(
- "|{capture_mut}{capture_name}| {}",
- Sugg::hir_with_context(cx, some_body, ctxt, "..", &mut app),
- ),
- none_expr: format!(
- "{}{}",
- if method_sugg == "map_or" || is_argless_call { "" } else if is_result { "|_| " } else { "|| "},
- Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app),
- ),
- });
- }
+ return Some(OptionOccurrence {
+ option: format_option_in_sugg(
+ Sugg::hir_with_context(cx, cond_expr, ctxt, "..", &mut app),
+ as_ref,
+ as_mut,
+ ),
+ method_sugg: method_sugg.to_string(),
+ some_expr: format!(
+ "|{capture_mut}{capture_name}| {}",
+ Sugg::hir_with_context(cx, some_body, ctxt, "..", &mut app),
+ ),
+ none_expr: format!(
+ "{}{}",
+ if method_sugg == "map_or" || is_argless_call {
+ ""
+ } else if is_result {
+ "|_| "
+ } else {
+ "|| "
+ },
+ Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app),
+ ),
+ });
}
None
@@ -216,21 +239,24 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
if_then,
if_else: Some(if_else),
}) = higher::IfLet::hir(cx, expr)
+ && !cx.typeck_results().expr_ty(expr).is_unit()
+ && !is_else_clause(cx.tcx, expr)
{
- if !is_else_clause(cx.tcx, expr) {
- return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, let_expr, if_then, if_else);
- }
+ try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, let_expr, if_then, if_else)
+ } else {
+ None
}
- None
}
fn detect_option_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionOccurrence> {
- if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind {
- if let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) {
- return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, ex, if_then, if_else);
- }
+ if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind
+ && !cx.typeck_results().expr_ty(expr).is_unit()
+ && let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms)
+ {
+ try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, ex, if_then, if_else)
+ } else {
+ None
}
- None
}
fn try_convert_match<'tcx>(
diff --git a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
index 38cd5043a..de7898793 100644
--- a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
+++ b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
@@ -1,9 +1,8 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::SpanlessEq;
-use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -34,41 +33,37 @@ impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional {
// a + b < a, a > a + b, a < a - b, a - b > a
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let eq = |l, r| SpanlessEq::new(cx).eq_path_segment(l, r);
- if_chain! {
- if let ExprKind::Binary(ref op, first, second) = expr.kind;
- if let ExprKind::Binary(ref op2, ident1, ident2) = first.kind;
- if let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind;
- if let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind;
- if let ExprKind::Path(QPath::Resolved(_, path3)) = second.kind;
- if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]);
- if cx.typeck_results().expr_ty(ident1).is_integral();
- if cx.typeck_results().expr_ty(ident2).is_integral();
- then {
- if op.node == BinOpKind::Lt && op2.node == BinOpKind::Add {
- span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG);
- }
- if op.node == BinOpKind::Gt && op2.node == BinOpKind::Sub {
- span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG);
- }
+ if let ExprKind::Binary(ref op, first, second) = expr.kind
+ && let ExprKind::Binary(ref op2, ident1, ident2) = first.kind
+ && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind
+ && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind
+ && let ExprKind::Path(QPath::Resolved(_, path3)) = second.kind
+ && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]))
+ && cx.typeck_results().expr_ty(ident1).is_integral()
+ && cx.typeck_results().expr_ty(ident2).is_integral()
+ {
+ if op.node == BinOpKind::Lt && op2.node == BinOpKind::Add {
+ span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG);
+ }
+ if op.node == BinOpKind::Gt && op2.node == BinOpKind::Sub {
+ span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG);
}
}
- if_chain! {
- if let ExprKind::Binary(ref op, first, second) = expr.kind;
- if let ExprKind::Binary(ref op2, ident1, ident2) = second.kind;
- if let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind;
- if let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind;
- if let ExprKind::Path(QPath::Resolved(_, path3)) = first.kind;
- if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]);
- if cx.typeck_results().expr_ty(ident1).is_integral();
- if cx.typeck_results().expr_ty(ident2).is_integral();
- then {
- if op.node == BinOpKind::Gt && op2.node == BinOpKind::Add {
- span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG);
- }
- if op.node == BinOpKind::Lt && op2.node == BinOpKind::Sub {
- span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG);
- }
+ if let ExprKind::Binary(ref op, first, second) = expr.kind
+ && let ExprKind::Binary(ref op2, ident1, ident2) = second.kind
+ && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind
+ && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind
+ && let ExprKind::Path(QPath::Resolved(_, path3)) = first.kind
+ && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]))
+ && cx.typeck_results().expr_ty(ident1).is_integral()
+ && cx.typeck_results().expr_ty(ident2).is_integral()
+ {
+ if op.node == BinOpKind::Gt && op2.node == BinOpKind::Add {
+ span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG);
+ }
+ if op.node == BinOpKind::Lt && op2.node == BinOpKind::Sub {
+ span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
index 6a760f9fe..f821a4efe 100644
--- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
@@ -7,7 +7,7 @@ use core::ops::ControlFlow;
use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span};
@@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn {
if matches!(fn_kind, FnKind::Closure) {
return;
}
- let owner = cx.tcx.hir().local_def_id_to_hir_id(def_id).expect_owner();
+ let owner = cx.tcx.local_def_id_to_hir_id(def_id).expect_owner();
if is_type_diagnostic_item(cx, return_ty(cx, owner), sym::Result) {
lint_impl_body(cx, span, body);
}
diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
index f4f1f6ddb..ef51a9a9a 100644
--- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint;
use clippy_utils::macros::{is_panic, root_macro_call_first_node};
use rustc_hir::Expr;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
index 99ba55b6b..ffa403e27 100644
--- a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
+++ b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{Item, ItemKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
index 68d3d00ac..18e6aad9c 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
@@ -1,8 +1,7 @@
use clippy_utils::diagnostics::span_lint_hir;
-use if_chain::if_chain;
use rustc_hir::{Impl, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -34,22 +33,24 @@ declare_lint_pass!(PartialEqNeImpl => [PARTIALEQ_NE_IMPL]);
impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
- if_chain! {
- if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind;
- if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
- if let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
- if trait_ref.path.res.def_id() == eq_trait;
- then {
- for impl_item in *impl_items {
- if impl_item.ident.name == sym::ne {
- span_lint_hir(
- cx,
- PARTIALEQ_NE_IMPL,
- impl_item.id.hir_id(),
- impl_item.span,
- "re-implementing `PartialEq::ne` is unnecessary",
- );
- }
+ if let ItemKind::Impl(Impl {
+ of_trait: Some(ref trait_ref),
+ items: impl_items,
+ ..
+ }) = item.kind
+ && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived)
+ && let Some(eq_trait) = cx.tcx.lang_items().eq_trait()
+ && trait_ref.path.res.def_id() == eq_trait
+ {
+ for impl_item in *impl_items {
+ if impl_item.ident.name == sym::ne {
+ span_lint_hir(
+ cx,
+ PARTIALEQ_NE_IMPL,
+ impl_item.id.hir_id(),
+ impl_item.span,
+ "re-implementing `PartialEq::ne` is unnecessary",
+ );
}
}
};
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
index 11e9a2bc3..6d4216970 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
@@ -4,7 +4,7 @@ use clippy_utils::{is_res_lang_ctor, path_res, peel_hir_expr_refs, peel_ref_oper
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 4d7a055da..57d37067e 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -5,7 +5,6 @@ use clippy_utils::source::snippet;
use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy};
use clippy_utils::{is_self, is_self_ty};
use core::ops::ControlFlow;
-use if_chain::if_chain;
use rustc_ast::attr;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@@ -16,11 +15,10 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::adjustment::{Adjust, PointerCoercion};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, RegionKind};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span};
use rustc_target::spec::abi::Abi;
-use rustc_target::spec::Target;
declare_clippy_lint! {
/// ### What it does
@@ -117,10 +115,10 @@ impl<'tcx> PassByRefOrValue {
ref_min_size: Option<u64>,
value_max_size: u64,
avoid_breaking_exported_api: bool,
- target: &Target,
+ pointer_width: u32,
) -> Self {
let ref_min_size = ref_min_size.unwrap_or_else(|| {
- let bit_width = u64::from(target.pointer_width);
+ let bit_width = u64::from(pointer_width);
// 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);
@@ -168,18 +166,18 @@ impl<'tcx> PassByRefOrValue {
match *ty.skip_binder().kind() {
ty::Ref(lt, ty, Mutability::Not) => {
match lt.kind() {
- RegionKind::ReLateBound(index, region)
+ RegionKind::ReBound(index, region)
if index.as_u32() == 0 && output_regions.contains(&region) =>
{
continue;
},
// Early bound regions on functions are either from the containing item, are bounded by another
// lifetime, or are used as a bound for a type or lifetime.
- RegionKind::ReEarlyBound(..) => continue,
+ RegionKind::ReEarlyParam(..) => continue,
_ => (),
}
- let ty = cx.tcx.erase_late_bound_regions(fn_sig.rebind(ty));
+ let ty = cx.tcx.instantiate_bound_regions_with_erased(fn_sig.rebind(ty));
if is_copy(cx, ty)
&& let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes())
&& size <= self.ref_min_size
@@ -227,24 +225,25 @@ impl<'tcx> PassByRefOrValue {
_ => continue,
}
}
- let ty = cx.tcx.erase_late_bound_regions(ty);
+ let ty = cx.tcx.instantiate_bound_regions_with_erased(ty);
- if_chain! {
- if is_copy(cx, ty);
- if !is_self_ty(input);
- if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
- if size > self.value_max_size;
- then {
- span_lint_and_sugg(
- cx,
- LARGE_TYPES_PASSED_BY_VALUE,
- input.span,
- &format!("this argument ({size} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", self.value_max_size),
- "consider passing by reference instead",
- format!("&{}", snippet(cx, input.span, "_")),
- Applicability::MaybeIncorrect,
- );
- }
+ if is_copy(cx, ty)
+ && !is_self_ty(input)
+ && let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes())
+ && size > self.value_max_size
+ {
+ span_lint_and_sugg(
+ cx,
+ LARGE_TYPES_PASSED_BY_VALUE,
+ input.span,
+ &format!(
+ "this argument ({size} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)",
+ self.value_max_size
+ ),
+ "consider passing by reference instead",
+ format!("&{}", snippet(cx, input.span, "_")),
+ Applicability::MaybeIncorrect,
+ );
}
},
@@ -280,7 +279,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
return;
}
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
+ let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
match kind {
FnKind::ItemFn(.., header) => {
if header.abi != Abi::Rust {
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
index dcd1e7af0..60ced9c12 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -3,7 +3,7 @@ use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, Let, LocalSource, Muta
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
diff --git a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
index b98005d59..704acdc10 100644
--- a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
+++ b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
use rustc_ast::ast::LitKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs
index 057b7e306..ff83725da 100644
--- a/src/tools/clippy/clippy_lints/src/precedence.rs
+++ b/src/tools/clippy/clippy_lints/src/precedence.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
-use if_chain::if_chain;
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, MethodCall, UnOp};
use rustc_ast::token;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
const ALLOWED_ODD_FUNCTIONS: [&str; 14] = [
@@ -79,7 +78,7 @@ impl EarlyLintPass for Precedence {
let sugg = format!(
"({}) {} ({})",
snippet_with_applicability(cx, left.span, "..", &mut applicability),
- op.to_string(),
+ op.as_str(),
snippet_with_applicability(cx, right.span, "..", &mut applicability)
);
span_sugg(expr, sugg, applicability);
@@ -88,7 +87,7 @@ impl EarlyLintPass for Precedence {
let sugg = format!(
"({}) {} {}",
snippet_with_applicability(cx, left.span, "..", &mut applicability),
- op.to_string(),
+ op.as_str(),
snippet_with_applicability(cx, right.span, "..", &mut applicability)
);
span_sugg(expr, sugg, applicability);
@@ -97,7 +96,7 @@ impl EarlyLintPass for Precedence {
let sugg = format!(
"{} {} ({})",
snippet_with_applicability(cx, left.span, "..", &mut applicability),
- op.to_string(),
+ op.as_str(),
snippet_with_applicability(cx, right.span, "..", &mut applicability)
);
span_sugg(expr, sugg, applicability);
@@ -118,25 +117,23 @@ impl EarlyLintPass for Precedence {
arg = receiver;
}
- if_chain! {
- if !all_odd;
- if let ExprKind::Lit(lit) = &arg.kind;
- if let token::LitKind::Integer | token::LitKind::Float = &lit.kind;
- then {
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- PRECEDENCE,
- expr.span,
- "unary minus has lower precedence than method call",
- "consider adding parentheses to clarify your intent",
- format!(
- "-({})",
- snippet_with_applicability(cx, operand.span, "..", &mut applicability)
- ),
- applicability,
- );
- }
+ if !all_odd
+ && let ExprKind::Lit(lit) = &arg.kind
+ && let token::LitKind::Integer | token::LitKind::Float = &lit.kind
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ PRECEDENCE,
+ expr.span,
+ "unary minus has lower precedence than method call",
+ "consider adding parentheses to clarify your intent",
+ format!(
+ "-({})",
+ snippet_with_applicability(cx, operand.span, "..", &mut applicability)
+ ),
+ applicability,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 83863b92c..2587b3881 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -20,14 +20,16 @@ use rustc_infer::traits::{Obligation, ObligationCause};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{sym, Span};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::Symbol;
+use rustc_span::{sym, Span};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use std::{fmt, iter};
+use crate::vec::is_allowed_vec_method;
+
declare_clippy_lint! {
/// ### What it does
/// This lint checks for function arguments of type `&String`, `&Vec`,
@@ -465,9 +467,9 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
.walk()
.filter_map(|arg| {
arg.as_region().and_then(|lifetime| match lifetime.kind() {
- ty::ReEarlyBound(r) => Some(r.def_id),
- ty::ReLateBound(_, r) => r.kind.get_id(),
- ty::ReFree(r) => r.bound_region.get_id(),
+ ty::ReEarlyParam(r) => Some(r.def_id),
+ ty::ReBound(_, r) => r.kind.get_id(),
+ ty::ReLateParam(r) => r.bound_region.get_id(),
ty::ReStatic
| ty::ReVar(_)
| ty::RePlaceholder(_)
@@ -660,7 +662,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
},
// If the types match check for methods which exist on both types. e.g. `Vec::len` and
// `slice::len`
- ty::Adt(def, _) if def.did() == args.ty_did => {
+ ty::Adt(def, _) if def.did() == args.ty_did && !is_allowed_vec_method(self.cx, e) => {
set_skip_flag();
},
_ => (),
@@ -712,23 +714,25 @@ fn matches_preds<'tcx>(
preds: &'tcx [ty::PolyExistentialPredicate<'tcx>],
) -> bool {
let infcx = cx.tcx.infer_ctxt().build();
- preds.iter().all(|&p| match cx.tcx.erase_late_bound_regions(p) {
- ExistentialPredicate::Trait(p) => infcx
- .type_implements_trait(p.def_id, [ty.into()].into_iter().chain(p.args.iter()), cx.param_env)
- .must_apply_modulo_regions(),
- ExistentialPredicate::Projection(p) => infcx.predicate_must_hold_modulo_regions(&Obligation::new(
- cx.tcx,
- ObligationCause::dummy(),
- cx.param_env,
- cx.tcx
- .mk_predicate(Binder::dummy(PredicateKind::Clause(ClauseKind::Projection(
- p.with_self_ty(cx.tcx, ty),
- )))),
- )),
- ExistentialPredicate::AutoTrait(p) => infcx
- .type_implements_trait(p, [ty], cx.param_env)
- .must_apply_modulo_regions(),
- })
+ preds
+ .iter()
+ .all(|&p| match cx.tcx.instantiate_bound_regions_with_erased(p) {
+ ExistentialPredicate::Trait(p) => infcx
+ .type_implements_trait(p.def_id, [ty.into()].into_iter().chain(p.args.iter()), cx.param_env)
+ .must_apply_modulo_regions(),
+ ExistentialPredicate::Projection(p) => infcx.predicate_must_hold_modulo_regions(&Obligation::new(
+ cx.tcx,
+ ObligationCause::dummy(),
+ cx.param_env,
+ cx.tcx
+ .mk_predicate(Binder::dummy(PredicateKind::Clause(ClauseKind::Projection(
+ p.with_self_ty(cx.tcx, ty),
+ )))),
+ )),
+ ExistentialPredicate::AutoTrait(p) => infcx
+ .type_implements_trait(p, [ty], cx.param_env)
+ .must_apply_modulo_regions(),
+ })
}
fn get_ref_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
index 66d869bc4..ff8ec2ad5 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet_opt;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
use std::fmt;
diff --git a/src/tools/clippy/clippy_lints/src/pub_use.rs b/src/tools/clippy/clippy_lints/src/pub_use.rs
index 316a72988..c0e999e76 100644
--- a/src/tools/clippy/clippy_lints/src/pub_use.rs
+++ b/src/tools/clippy/clippy_lints/src/pub_use.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index b133635e8..fc5835408 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -10,7 +10,6 @@ use clippy_utils::{
is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks,
peel_blocks_with_stmt,
};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
@@ -19,7 +18,7 @@ use rustc_hir::{
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::sym;
use rustc_span::symbol::Symbol;
@@ -179,17 +178,15 @@ fn expr_return_none_or_err(
_ => false,
},
ExprKind::Call(call_expr, args_expr) => {
- if_chain! {
- if smbl == sym::Result;
- if let ExprKind::Path(QPath::Resolved(_, path)) = &call_expr.kind;
- if let Some(segment) = path.segments.first();
- if let Some(err_sym) = err_sym;
- if let Some(arg) = args_expr.first();
- if let ExprKind::Path(QPath::Resolved(_, arg_path)) = &arg.kind;
- if let Some(PathSegment { ident, .. }) = arg_path.segments.first();
- then {
- return segment.ident.name == sym::Err && err_sym == ident.name;
- }
+ if smbl == sym::Result
+ && let ExprKind::Path(QPath::Resolved(_, path)) = &call_expr.kind
+ && let Some(segment) = path.segments.first()
+ && let Some(err_sym) = err_sym
+ && let Some(arg) = args_expr.first()
+ && let ExprKind::Path(QPath::Resolved(_, arg_path)) = &arg.kind
+ && let Some(PathSegment { ident, .. }) = arg_path.segments.first()
+ {
+ return segment.ident.name == sym::Err && err_sym == ident.name;
}
false
},
@@ -218,81 +215,85 @@ impl QuestionMark {
///
/// If it matches, it will suggest to use the question mark operator instead
fn check_is_none_or_err_and_early_return<'tcx>(&self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
- if_chain! {
- if !self.inside_try_block();
- if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
- if !is_else_clause(cx.tcx, expr);
- if let ExprKind::MethodCall(segment, caller, ..) = &cond.kind;
- let caller_ty = cx.typeck_results().expr_ty(caller);
- let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else);
- if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block);
- then {
- let mut applicability = Applicability::MachineApplicable;
- let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability);
- let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) &&
- !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..));
- let sugg = if let Some(else_inner) = r#else {
- if eq_expr_value(cx, caller, peel_blocks(else_inner)) {
- format!("Some({receiver_str}?)")
- } else {
- return;
- }
+ if !self.inside_try_block()
+ && let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr)
+ && !is_else_clause(cx.tcx, expr)
+ && let ExprKind::MethodCall(segment, caller, ..) = &cond.kind
+ && let caller_ty = cx.typeck_results().expr_ty(caller)
+ && let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else)
+ && (is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block))
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability);
+ let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env)
+ && !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..));
+ let sugg = if let Some(else_inner) = r#else {
+ if eq_expr_value(cx, caller, peel_blocks(else_inner)) {
+ format!("Some({receiver_str}?)")
} else {
- format!("{receiver_str}{}?;", if by_ref { ".as_ref()" } else { "" })
- };
+ return;
+ }
+ } else {
+ format!("{receiver_str}{}?;", if by_ref { ".as_ref()" } else { "" })
+ };
- span_lint_and_sugg(
- cx,
- QUESTION_MARK,
- expr.span,
- "this block may be rewritten with the `?` operator",
- "replace it with",
- sugg,
- applicability,
- );
- }
+ span_lint_and_sugg(
+ cx,
+ QUESTION_MARK,
+ expr.span,
+ "this block may be rewritten with the `?` operator",
+ "replace it with",
+ sugg,
+ applicability,
+ );
}
}
fn check_if_let_some_or_err_and_early_return<'tcx>(&self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
- if_chain! {
- if !self.inside_try_block();
- if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr);
- if !is_else_clause(cx.tcx, expr);
- if let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind;
- if ddpos.as_opt_usize().is_none();
- if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind;
- let caller_ty = cx.typeck_results().expr_ty(let_expr);
- let if_block = IfBlockType::IfLet(
+ if !self.inside_try_block()
+ && let Some(higher::IfLet {
+ let_pat,
+ let_expr,
+ if_then,
+ if_else,
+ }) = higher::IfLet::hir(cx, expr)
+ && !is_else_clause(cx.tcx, expr)
+ && let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind
+ && ddpos.as_opt_usize().is_none()
+ && let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind
+ && let caller_ty = cx.typeck_results().expr_ty(let_expr)
+ && let if_block = IfBlockType::IfLet(
cx.qpath_res(path1, let_pat.hir_id),
caller_ty,
ident.name,
let_expr,
if_then,
- if_else
+ if_else,
+ )
+ && ((is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id))
+ || is_early_return(sym::Result, cx, &if_block))
+ && if_else
+ .map(|e| eq_expr_value(cx, let_expr, peel_blocks(e)))
+ .filter(|e| *e)
+ .is_none()
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
+ let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_)));
+ let sugg = format!(
+ "{receiver_str}{}?{}",
+ if by_ref == ByRef::Yes { ".as_ref()" } else { "" },
+ if requires_semi { ";" } else { "" }
+ );
+ span_lint_and_sugg(
+ cx,
+ QUESTION_MARK,
+ expr.span,
+ "this block may be rewritten with the `?` operator",
+ "replace it with",
+ sugg,
+ applicability,
);
- if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id))
- || is_early_return(sym::Result, cx, &if_block);
- if if_else.map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))).filter(|e| *e).is_none();
- then {
- let mut applicability = Applicability::MachineApplicable;
- let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
- let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_)));
- let sugg = format!(
- "{receiver_str}{}?{}",
- if by_ref == ByRef::Yes { ".as_ref()" } else { "" },
- if requires_semi { ";" } else { "" }
- );
- span_lint_and_sugg(
- cx,
- QUESTION_MARK,
- expr.span,
- "this block may be rewritten with the `?` operator",
- "replace it with",
- sugg,
- applicability,
- );
- }
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/question_mark_used.rs b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
index d0de33e3c..ddfc53083 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark_used.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::macros::span_is_local;
use rustc_hir::{Expr, ExprKind, MatchSource};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 1b3081abc..6b54258dd 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -4,15 +4,14 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::{get_parent_expr, higher, in_constant, is_integer_const, path_to_local};
-use if_chain::if_chain;
use rustc_ast::ast::RangeLimits;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, HirId};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::Span;
+use rustc_session::impl_lint_pass;
use rustc_span::source_map::Spanned;
+use rustc_span::Span;
use std::cmp::Ordering;
declare_clippy_lint! {
@@ -283,16 +282,14 @@ fn check_possible_range_contains(
// If the LHS is the same operator, we have to recurse to get the "real" RHS, since they have
// the same operator precedence
- if_chain! {
- if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind;
- if op == lhs_op.node;
- let new_span = Span::new(new_lhs.span.lo(), right.span.hi(), expr.span.ctxt(), expr.span.parent());
- if let Some(snip) = &snippet_opt(cx, new_span);
+ if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind
+ && op == lhs_op.node
+ && let new_span = Span::new(new_lhs.span.lo(), right.span.hi(), expr.span.ctxt(), expr.span.parent())
+ && let Some(snip) = &snippet_opt(cx, new_span)
// Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong
- if snip.matches('(').count() == snip.matches(')').count();
- then {
- check_possible_range_contains(cx, op, new_lhs, right, expr, new_span);
- }
+ && snip.matches('(').count() == snip.matches(')').count()
+ {
+ check_possible_range_contains(cx, op, new_lhs, right, expr, new_span);
}
}
@@ -349,71 +346,66 @@ fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) ->
// exclusive range plus one: `x..(y+1)`
fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
- if_chain! {
- if expr.span.can_be_used_for_suggestions();
- if let Some(higher::Range {
+ if expr.span.can_be_used_for_suggestions()
+ && let Some(higher::Range {
start,
end: Some(end),
- limits: RangeLimits::HalfOpen
- }) = higher::Range::hir(expr);
- if let Some(y) = y_plus_one(cx, end);
- then {
- let span = expr.span;
- span_lint_and_then(
- cx,
- RANGE_PLUS_ONE,
- span,
- "an inclusive range would be more readable",
- |diag| {
- let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string());
- let end = Sugg::hir(cx, y, "y").maybe_par();
- if let Some(is_wrapped) = &snippet_opt(cx, span) {
- if is_wrapped.starts_with('(') && is_wrapped.ends_with(')') {
- diag.span_suggestion(
- span,
- "use",
- format!("({start}..={end})"),
- Applicability::MaybeIncorrect,
- );
- } else {
- diag.span_suggestion(
- span,
- "use",
- format!("{start}..={end}"),
- Applicability::MachineApplicable, // snippet
- );
- }
+ limits: RangeLimits::HalfOpen,
+ }) = higher::Range::hir(expr)
+ && let Some(y) = y_plus_one(cx, end)
+ {
+ let span = expr.span;
+ span_lint_and_then(
+ cx,
+ RANGE_PLUS_ONE,
+ span,
+ "an inclusive range would be more readable",
+ |diag| {
+ let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string());
+ let end = Sugg::hir(cx, y, "y").maybe_par();
+ if let Some(is_wrapped) = &snippet_opt(cx, span) {
+ if is_wrapped.starts_with('(') && is_wrapped.ends_with(')') {
+ diag.span_suggestion(span, "use", format!("({start}..={end})"), Applicability::MaybeIncorrect);
+ } else {
+ diag.span_suggestion(
+ span,
+ "use",
+ format!("{start}..={end}"),
+ Applicability::MachineApplicable, // snippet
+ );
}
- },
- );
- }
+ }
+ },
+ );
}
}
// inclusive range minus one: `x..=(y-1)`
fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
- if_chain! {
- if expr.span.can_be_used_for_suggestions();
- if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::Range::hir(expr);
- if let Some(y) = y_minus_one(cx, end);
- then {
- span_lint_and_then(
- cx,
- RANGE_MINUS_ONE,
- expr.span,
- "an exclusive range would be more readable",
- |diag| {
- let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string());
- let end = Sugg::hir(cx, y, "y").maybe_par();
- diag.span_suggestion(
- expr.span,
- "use",
- format!("{start}..{end}"),
- Applicability::MachineApplicable, // snippet
- );
- },
- );
- }
+ if expr.span.can_be_used_for_suggestions()
+ && let Some(higher::Range {
+ start,
+ end: Some(end),
+ limits: RangeLimits::Closed,
+ }) = higher::Range::hir(expr)
+ && let Some(y) = y_minus_one(cx, end)
+ {
+ span_lint_and_then(
+ cx,
+ RANGE_MINUS_ONE,
+ expr.span,
+ "an exclusive range would be more readable",
+ |diag| {
+ let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string());
+ let end = Sugg::hir(cx, y, "y").maybe_par();
+ diag.span_suggestion(
+ expr.span,
+ "use",
+ format!("{start}..{end}"),
+ Applicability::MachineApplicable, // snippet
+ );
+ },
+ );
}
}
@@ -447,52 +439,54 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
}
}
- if_chain! {
- if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::Range::hir(expr);
- let ty = cx.typeck_results().expr_ty(start);
- if let ty::Int(_) | ty::Uint(_) = ty.kind();
- if let Some(start_idx) = constant(cx, cx.typeck_results(), start);
- if let Some(end_idx) = constant(cx, cx.typeck_results(), end);
- if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx);
- if is_empty_range(limits, ordering);
- then {
- if inside_indexing_expr(cx, expr) {
- // Avoid linting `N..N` as it has proven to be useful, see #5689 and #5628 ...
- if ordering != Ordering::Equal {
- span_lint(
- cx,
- REVERSED_EMPTY_RANGES,
- expr.span,
- "this range is reversed and using it to index a slice will panic at run-time",
- );
- }
- // ... except in for loop arguments for backwards compatibility with `reverse_range_loop`
- } else if ordering != Ordering::Equal || is_for_loop_arg(cx, expr) {
- span_lint_and_then(
+ if let Some(higher::Range {
+ start: Some(start),
+ end: Some(end),
+ limits,
+ }) = higher::Range::hir(expr)
+ && let ty = cx.typeck_results().expr_ty(start)
+ && let ty::Int(_) | ty::Uint(_) = ty.kind()
+ && let Some(start_idx) = constant(cx, cx.typeck_results(), start)
+ && let Some(end_idx) = constant(cx, cx.typeck_results(), end)
+ && let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx)
+ && is_empty_range(limits, ordering)
+ {
+ if inside_indexing_expr(cx, expr) {
+ // Avoid linting `N..N` as it has proven to be useful, see #5689 and #5628 ...
+ if ordering != Ordering::Equal {
+ span_lint(
cx,
REVERSED_EMPTY_RANGES,
expr.span,
- "this range is empty so it will yield no values",
- |diag| {
- if ordering != Ordering::Equal {
- let start_snippet = snippet(cx, start.span, "_");
- let end_snippet = snippet(cx, end.span, "_");
- let dots = match limits {
- RangeLimits::HalfOpen => "..",
- RangeLimits::Closed => "..="
- };
-
- diag.span_suggestion(
- expr.span,
- "consider using the following if you are attempting to iterate over this \
- range in reverse",
- format!("({end_snippet}{dots}{start_snippet}).rev()"),
- Applicability::MaybeIncorrect,
- );
- }
- },
+ "this range is reversed and using it to index a slice will panic at run-time",
);
}
+ // ... except in for loop arguments for backwards compatibility with `reverse_range_loop`
+ } else if ordering != Ordering::Equal || is_for_loop_arg(cx, expr) {
+ span_lint_and_then(
+ cx,
+ REVERSED_EMPTY_RANGES,
+ expr.span,
+ "this range is empty so it will yield no values",
+ |diag| {
+ if ordering != Ordering::Equal {
+ let start_snippet = snippet(cx, start.span, "_");
+ let end_snippet = snippet(cx, end.span, "_");
+ let dots = match limits {
+ RangeLimits::HalfOpen => "..",
+ RangeLimits::Closed => "..=",
+ };
+
+ diag.span_suggestion(
+ expr.span,
+ "consider using the following if you are attempting to iterate over this \
+ range in reverse",
+ format!("({end_snippet}{dots}{start_snippet}).rev()"),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/raw_strings.rs b/src/tools/clippy/clippy_lints/src/raw_strings.rs
index 391c77dbf..ac29d2730 100644
--- a/src/tools/clippy/clippy_lints/src/raw_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/raw_strings.rs
@@ -8,7 +8,7 @@ use rustc_ast::token::LitKind;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{BytePos, Pos, Span};
declare_clippy_lint! {
@@ -56,7 +56,7 @@ declare_clippy_lint! {
impl_lint_pass!(RawStrings => [NEEDLESS_RAW_STRINGS, NEEDLESS_RAW_STRING_HASHES]);
pub struct RawStrings {
- pub needless_raw_string_hashes_allow_one: bool,
+ pub allow_one_hash_in_raw_strings: bool,
}
impl EarlyLintPass for RawStrings {
diff --git a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
index 59ce289e7..d0b45b595 100644
--- a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
+++ b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
@@ -7,7 +7,7 @@ use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, Span, Symbol};
declare_clippy_lint! {
@@ -118,26 +118,24 @@ fn emit_lint(cx: &LateContext<'_>, symbol: Symbol, lint_span: Span, elem: &Expr<
/// Checks whether the given `expr` is a call to `Arc::new`, `Rc::new`, or evaluates to a `Weak`
fn ref_init(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(Symbol, Span)> {
- 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();
-
- then {
- if last_path_segment(func_path).ident.name == sym::new
- && let Some(symbol) = cx
- .tcx
- .get_diagnostic_name(def_id)
- .filter(|symbol| symbol == &sym::Arc || symbol == &sym::Rc) {
- return Some((symbol, func.span));
- }
+ if let ExprKind::Call(func, _args) = expr.kind
+ && let ExprKind::Path(ref func_path @ QPath::TypeRelative(ty, _)) = func.kind
+ && let TyKind::Path(ref ty_path) = ty.kind
+ && 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
+ && let Some(symbol) = cx
+ .tcx
+ .get_diagnostic_name(def_id)
+ .filter(|symbol| symbol == &sym::Arc || symbol == &sym::Rc)
+ {
+ return Some((symbol, func.span));
+ }
- if let ty::Adt(adt, _) = *cx.typeck_results().expr_ty(expr).kind()
- && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::RcWeak | sym::ArcWeak))
- {
- return Some((Symbol::intern("Weak"), func.span));
- }
+ if let ty::Adt(adt, _) = *cx.typeck_results().expr_ty(expr).kind()
+ && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::RcWeak | sym::ArcWeak))
+ {
+ return Some((Symbol::intern("Weak"), func.span));
}
}
diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
index b27d4cc6e..62f3c09aa 100644
--- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
@@ -7,7 +7,7 @@ use hir::{Expr, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
index 90297ca8b..19d9d64b3 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
@@ -9,7 +9,7 @@ use rustc_hir::{Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSo
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::UpvarCapture;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index 8daf085a4..c62c351e7 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -3,14 +3,13 @@ use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth};
use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{def_id, Body, FnDecl, LangItem};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir;
use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, BytePos, Span};
@@ -145,18 +144,16 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
let pred_terminator = mir[ps[0]].terminator();
// receiver of the `deref()` call
- let (pred_arg, deref_clone_ret) = if_chain! {
- if let Some((pred_fn_def_id, pred_arg, pred_arg_ty, res)) =
- is_call_with_ref_arg(cx, mir, &pred_terminator.kind);
- if res == cloned;
- if cx.tcx.is_diagnostic_item(sym::deref_method, pred_fn_def_id);
- if is_type_diagnostic_item(cx, pred_arg_ty, sym::PathBuf)
- || is_type_diagnostic_item(cx, pred_arg_ty, sym::OsString);
- then {
- (pred_arg, res)
- } else {
- continue;
- }
+ let (pred_arg, deref_clone_ret) = if let Some((pred_fn_def_id, pred_arg, pred_arg_ty, res)) =
+ is_call_with_ref_arg(cx, mir, &pred_terminator.kind)
+ && res == cloned
+ && cx.tcx.is_diagnostic_item(sym::deref_method, pred_fn_def_id)
+ && (is_type_diagnostic_item(cx, pred_arg_ty, sym::PathBuf)
+ || is_type_diagnostic_item(cx, pred_arg_ty, sym::OsString))
+ {
+ (pred_arg, res)
+ } else {
+ continue;
};
let (local, cannot_move_out) =
@@ -211,45 +208,37 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
.assert_crate_local()
.lint_root;
- if_chain! {
- if let Some(snip) = snippet_opt(cx, span);
- if let Some(dot) = snip.rfind('.');
- then {
- let sugg_span = span.with_lo(
- span.lo() + BytePos(u32::try_from(dot).unwrap())
- );
- let mut app = Applicability::MaybeIncorrect;
-
- let call_snip = &snip[dot + 1..];
- // Machine applicable when `call_snip` looks like `foobar()`
- if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) {
- if call_snip.as_bytes().iter().all(|b| b.is_ascii_alphabetic() || *b == b'_') {
- app = Applicability::MachineApplicable;
- }
+ if let Some(snip) = snippet_opt(cx, span)
+ && let Some(dot) = snip.rfind('.')
+ {
+ let sugg_span = span.with_lo(span.lo() + BytePos(u32::try_from(dot).unwrap()));
+ let mut app = Applicability::MaybeIncorrect;
+
+ let call_snip = &snip[dot + 1..];
+ // Machine applicable when `call_snip` looks like `foobar()`
+ if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) {
+ if call_snip
+ .as_bytes()
+ .iter()
+ .all(|b| b.is_ascii_alphabetic() || *b == b'_')
+ {
+ app = Applicability::MachineApplicable;
}
+ }
- span_lint_hir_and_then(cx, REDUNDANT_CLONE, node, sugg_span, "redundant clone", |diag| {
- diag.span_suggestion(
- sugg_span,
- "remove this",
- "",
- app,
+ span_lint_hir_and_then(cx, REDUNDANT_CLONE, node, sugg_span, "redundant clone", |diag| {
+ diag.span_suggestion(sugg_span, "remove this", "", app);
+ if clone_usage.cloned_used {
+ diag.span_note(span, "cloned value is neither consumed nor mutated");
+ } else {
+ diag.span_note(
+ span.with_hi(span.lo() + BytePos(u32::try_from(dot).unwrap())),
+ "this value is dropped without further use",
);
- if clone_usage.cloned_used {
- diag.span_note(
- span,
- "cloned value is neither consumed nor mutated",
- );
- } else {
- diag.span_note(
- span.with_hi(span.lo() + BytePos(u32::try_from(dot).unwrap())),
- "this value is dropped without further use",
- );
- }
- });
- } else {
- span_lint_hir(cx, REDUNDANT_CLONE, node, span, "redundant clone");
- }
+ }
+ });
+ } else {
+ span_lint_hir(cx, REDUNDANT_CLONE, node, span, "redundant clone");
}
}
}
@@ -261,18 +250,21 @@ fn is_call_with_ref_arg<'tcx>(
mir: &'tcx mir::Body<'tcx>,
kind: &'tcx mir::TerminatorKind<'tcx>,
) -> Option<(def_id::DefId, mir::Local, Ty<'tcx>, mir::Local)> {
- if_chain! {
- if let mir::TerminatorKind::Call { func, args, destination, .. } = kind;
- if args.len() == 1;
- if let mir::Operand::Move(mir::Place { local, .. }) = &args[0];
- if let ty::FnDef(def_id, _) = *func.ty(mir, cx.tcx).kind();
- if let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(mir, cx.tcx));
- if !is_copy(cx, inner_ty);
- then {
- Some((def_id, *local, inner_ty, destination.as_local()?))
- } else {
- None
- }
+ if let mir::TerminatorKind::Call {
+ func,
+ args,
+ destination,
+ ..
+ } = kind
+ && args.len() == 1
+ && let mir::Operand::Move(mir::Place { local, .. }) = &args[0]
+ && let ty::FnDef(def_id, _) = *func.ty(mir, cx.tcx).kind()
+ && let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(mir, cx.tcx))
+ && !is_copy(cx, inner_ty)
+ {
+ Some((def_id, *local, inner_ty, destination.as_local()?))
+ } else {
+ None
}
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index e679fab53..8bac2e40e 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -2,16 +2,15 @@ use crate::rustc_lint::LintContext;
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::get_parent_expr;
use clippy_utils::sugg::Sugg;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
-use rustc_hir::intravisit as hir_visit;
use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
+use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -61,11 +60,14 @@ impl<'tcx> Visitor<'tcx> for ReturnVisitor {
}
}
-/// Checks if the body is owned by an async closure
-fn is_async_closure(body: &hir::Body<'_>) -> bool {
- if let hir::ExprKind::Closure(closure) = body.value.kind
- && let [resume_ty] = closure.fn_decl.inputs
- && let hir::TyKind::Path(hir::QPath::LangItem(hir::LangItem::ResumeTy, ..)) = resume_ty.kind
+/// Checks if the body is owned by an async closure.
+/// Returns true for `async || whatever_expression`, but false for `|| async { whatever_expression
+/// }`.
+fn is_async_closure(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool {
+ if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind
+ && let desugared_inner_closure_body = cx.tcx.hir().body(innermost_closure_generated_by_desugar.body)
+ // checks whether it is `async || whatever_expression`
+ && let Some(CoroutineKind::Async(CoroutineSource::Closure)) = desugared_inner_closure_body.coroutine_kind
{
true
} else {
@@ -101,7 +103,7 @@ fn find_innermost_closure<'tcx>(
data = Some((
body.value,
closure.fn_decl,
- if is_async_closure(body) {
+ if is_async_closure(cx, body) {
ty::Asyncness::Yes
} else {
ty::Asyncness::No
@@ -141,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
}
if let hir::ExprKind::Call(recv, _) = expr.kind
- // don't lint if the receiver is a call, too.
+ // don't lint if the receiver is a call, too.
// we do this in order to prevent linting multiple times; consider:
// `(|| || 1)()()`
// ^^ we only want to lint for this call (but we walk up the calls to consider both calls).
@@ -174,12 +176,18 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
hint = hint.asyncify();
}
- diag.span_suggestion(
- full_expr.span,
- "try doing something like",
- hint.maybe_par(),
- applicability,
- );
+ let is_in_fn_call_arg =
+ clippy_utils::get_parent_node(cx.tcx, expr.hir_id).is_some_and(|x| match x {
+ Node::Expr(expr) => matches!(expr.kind, hir::ExprKind::Call(_, _)),
+ _ => false,
+ });
+
+ // avoid clippy::double_parens
+ if !is_in_fn_call_arg {
+ hint = hint.maybe_par();
+ };
+
+ diag.span_suggestion(full_expr.span, "try doing something like", hint, applicability);
}
},
);
@@ -201,14 +209,12 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
type NestedFilter = nested_filter::OnlyBodies;
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
- if_chain! {
- if let hir::ExprKind::Call(closure, _) = expr.kind;
- if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind;
- if self.path.segments[0].ident == path.segments[0].ident;
- if self.path.res == path.res;
- then {
- self.count += 1;
- }
+ if let hir::ExprKind::Call(closure, _) = expr.kind
+ && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind
+ && self.path.segments[0].ident == path.segments[0].ident
+ && self.path.res == path.res
+ {
+ self.count += 1;
}
hir_visit::walk_expr(self, expr);
}
@@ -223,25 +229,23 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
}
for w in block.stmts.windows(2) {
- if_chain! {
- if let hir::StmtKind::Local(local) = w[0].kind;
- if let Option::Some(t) = local.init;
- if let hir::ExprKind::Closure { .. } = t.kind;
- if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind;
- if let hir::StmtKind::Semi(second) = w[1].kind;
- if let hir::ExprKind::Assign(_, call, _) = second.kind;
- if let hir::ExprKind::Call(closure, _) = call.kind;
- if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind;
- if ident == path.segments[0].ident;
- if count_closure_usage(cx, block, path) == 1;
- then {
- span_lint(
- cx,
- REDUNDANT_CLOSURE_CALL,
- second.span,
- "closure called just once immediately after it was declared",
- );
- }
+ if let hir::StmtKind::Local(local) = w[0].kind
+ && let Option::Some(t) = local.init
+ && let hir::ExprKind::Closure { .. } = t.kind
+ && let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind
+ && let hir::StmtKind::Semi(second) = w[1].kind
+ && let hir::ExprKind::Assign(_, call, _) = second.kind
+ && let hir::ExprKind::Call(closure, _) = call.kind
+ && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind
+ && ident == path.segments[0].ident
+ && count_closure_usage(cx, block, path) == 1
+ {
+ span_lint(
+ cx,
+ REDUNDANT_CLOSURE_CALL,
+ second.span,
+ "closure called just once immediately after it was declared",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs
index 221aa317e..001686c84 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_else.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs
@@ -3,7 +3,7 @@ use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind};
use rustc_ast::visit::{walk_expr, Visitor};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -105,7 +105,9 @@ impl<'ast> Visitor<'ast> for BreakVisitor {
fn visit_expr(&mut self, expr: &'ast Expr) {
self.is_break = match expr.kind {
ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) => true,
- ExprKind::Match(_, ref arms) => arms.iter().all(|arm| self.check_expr(&arm.body)),
+ ExprKind::Match(_, ref arms) => arms.iter().all(|arm|
+ arm.body.is_none() || arm.body.as_deref().is_some_and(|body| self.check_expr(body))
+ ),
ExprKind::If(_, ref then, Some(ref els)) => self.check_block(then) && self.check_expr(els),
ExprKind::If(_, _, None)
// ignore loops for simplicity
diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
index b8e606df7..fb000cd71 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
@@ -4,7 +4,7 @@ use rustc_ast::ast::{Expr, ExprKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
index 6bc0d0618..2c511ee0b 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -6,7 +6,7 @@ use rustc_hir::def::Res;
use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::Ident;
use rustc_span::DesugaringKind;
@@ -46,40 +46,38 @@ declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]);
impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
- if_chain! {
- if !local.span.is_desugaring(DesugaringKind::Async);
+ if !local.span.is_desugaring(DesugaringKind::Async)
// the pattern is a single by-value binding
- if let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind;
+ && let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind
// the binding is not type-ascribed
- if local.ty.is_none();
+ && local.ty.is_none()
// the expression is a resolved path
- if let Some(expr) = local.init;
- if let ExprKind::Path(qpath @ QPath::Resolved(None, path)) = expr.kind;
+ && let Some(expr) = local.init
+ && let ExprKind::Path(qpath @ QPath::Resolved(None, path)) = expr.kind
// the path is a single segment equal to the local's name
- if let [last_segment] = path.segments;
- if last_segment.ident == ident;
+ && let [last_segment] = path.segments
+ && last_segment.ident == ident
// resolve the path to its defining binding pattern
- if let Res::Local(binding_id) = cx.qpath_res(&qpath, expr.hir_id);
- if let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id);
+ && let Res::Local(binding_id) = cx.qpath_res(&qpath, expr.hir_id)
+ && let Node::Pat(binding_pat) = cx.tcx.hir_node(binding_id)
// the previous binding has the same mutability
- if find_binding(binding_pat, ident).is_some_and(|bind| bind.1 == mutability);
+ && find_binding(binding_pat, ident).is_some_and(|bind| bind.1 == mutability)
// the local does not change the effect of assignments to the binding. see #11290
- if !affects_assignments(cx, mutability, binding_id, local.hir_id);
+ && !affects_assignments(cx, mutability, binding_id, local.hir_id)
// the local does not affect the code's drop behavior
- if !needs_ordered_drop(cx, cx.typeck_results().expr_ty(expr));
+ && !needs_ordered_drop(cx, cx.typeck_results().expr_ty(expr))
// the local is user-controlled
- if !in_external_macro(cx.sess(), local.span);
- if !is_from_proc_macro(cx, expr);
- then {
- span_lint_and_help(
- cx,
- REDUNDANT_LOCALS,
- local.span,
- &format!("redundant redefinition of a binding `{ident}`"),
- Some(binding_pat.span),
- &format!("`{ident}` is initially defined here"),
- );
- }
+ && !in_external_macro(cx.sess(), local.span)
+ && !is_from_proc_macro(cx, expr)
+ {
+ span_lint_and_help(
+ cx,
+ REDUNDANT_LOCALS,
+ local.span,
+ &format!("redundant redefinition of a binding `{ident}`"),
+ Some(binding_pat.span),
+ &format!("`{ident}` is initially defined here"),
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index 03673eb27..0e43e4a7e 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -4,7 +4,7 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::hygiene::MacroKind;
@@ -45,28 +45,27 @@ impl_lint_pass!(RedundantPubCrate => [REDUNDANT_PUB_CRATE]);
impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
- if_chain! {
- if cx.tcx.visibility(item.owner_id.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id());
- if !cx.effective_visibilities.is_exported(item.owner_id.def_id) && self.is_exported.last() == Some(&false);
- if is_not_macro_export(item);
- then {
- let span = item.span.with_hi(item.ident.span.hi());
- let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id());
- span_lint_and_then(
- cx,
- REDUNDANT_PUB_CRATE,
- span,
- &format!("pub(crate) {descr} inside private module"),
- |diag| {
- diag.span_suggestion(
- item.vis_span,
- "consider using",
- "pub".to_string(),
- Applicability::MachineApplicable,
- );
- },
- );
- }
+ if cx.tcx.visibility(item.owner_id.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
+ && !cx.effective_visibilities.is_exported(item.owner_id.def_id)
+ && self.is_exported.last() == Some(&false)
+ && is_not_macro_export(item)
+ {
+ let span = item.span.with_hi(item.ident.span.hi());
+ let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id());
+ span_lint_and_then(
+ cx,
+ REDUNDANT_PUB_CRATE,
+ span,
+ &format!("pub(crate) {descr} inside private module"),
+ |diag| {
+ diag.span_suggestion(
+ item.vis_span,
+ "consider using",
+ "pub".to_string(),
+ Applicability::MachineApplicable,
+ );
+ },
+ );
}
if let ItemKind::Mod { .. } = item.kind {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 7adbd6791..c99b657c2 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -2,14 +2,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::get_parent_expr;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::{is_type_lang_item, peel_mid_ty_refs};
-use if_chain::if_chain;
use rustc_ast::util::parser::PREC_PREFIX;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
use rustc_lint::{LateContext, LateLintPass, Lint};
use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::{GenericArg, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -78,92 +77,83 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
}
let ctxt = expr.span.ctxt();
- if_chain! {
- if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind;
- if addressee.span.ctxt() == ctxt;
- if let ExprKind::Index(indexed, range, _) = addressee.kind;
- if is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull);
- then {
- let (expr_ty, expr_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(expr));
- let (indexed_ty, indexed_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(indexed));
- let parent_expr = get_parent_expr(cx, expr);
- let needs_parens_for_prefix = parent_expr.map_or(false, |parent| {
- parent.precedence().order() > PREC_PREFIX
- });
- let mut app = Applicability::MachineApplicable;
+ if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind
+ && addressee.span.ctxt() == ctxt
+ && let ExprKind::Index(indexed, range, _) = addressee.kind
+ && is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull)
+ {
+ let (expr_ty, expr_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(expr));
+ let (indexed_ty, indexed_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(indexed));
+ let parent_expr = get_parent_expr(cx, expr);
+ let needs_parens_for_prefix = parent_expr.map_or(false, |parent| parent.precedence().order() > PREC_PREFIX);
+ let mut app = Applicability::MachineApplicable;
- let ((lint, msg), help, sugg) = if expr_ty == indexed_ty {
- if expr_ref_count > indexed_ref_count {
- // Indexing takes self by reference and can't return a reference to that
- // reference as it's a local variable. The only way this could happen is if
- // `self` contains a reference to the `Self` type. If this occurs then the
- // lint no longer applies as it's essentially a field access, which is not
- // redundant.
- return;
- }
- let deref_count = indexed_ref_count - expr_ref_count;
+ let ((lint, msg), help, sugg) = if expr_ty == indexed_ty {
+ if expr_ref_count > indexed_ref_count {
+ // Indexing takes self by reference and can't return a reference to that
+ // reference as it's a local variable. The only way this could happen is if
+ // `self` contains a reference to the `Self` type. If this occurs then the
+ // lint no longer applies as it's essentially a field access, which is not
+ // redundant.
+ return;
+ }
+ let deref_count = indexed_ref_count - expr_ref_count;
- let (lint, reborrow_str, help_str) = if mutability == Mutability::Mut {
- // The slice was used to reborrow the mutable reference.
- (DEREF_BY_SLICING_LINT, "&mut *", "reborrow the original value instead")
- } else if matches!(
- parent_expr,
- Some(Expr {
- kind: ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _),
- ..
- })
- ) || cx.typeck_results().expr_adjustments(expr).first().map_or(false, |a| {
- matches!(a.kind, Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })))
- }) {
- // The slice was used to make a temporary reference.
- (DEREF_BY_SLICING_LINT, "&*", "reborrow the original value instead")
- } else if deref_count != 0 {
- (DEREF_BY_SLICING_LINT, "", "dereference the original value instead")
- } else {
- (REDUNDANT_SLICING_LINT, "", "use the original value instead")
- };
+ let (lint, reborrow_str, help_str) = if mutability == Mutability::Mut {
+ // The slice was used to reborrow the mutable reference.
+ (DEREF_BY_SLICING_LINT, "&mut *", "reborrow the original value instead")
+ } else if matches!(
+ parent_expr,
+ Some(Expr {
+ kind: ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _),
+ ..
+ })
+ ) || cx.typeck_results().expr_adjustments(expr).first().map_or(false, |a| {
+ matches!(
+ a.kind,
+ Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. }))
+ )
+ }) {
+ // The slice was used to make a temporary reference.
+ (DEREF_BY_SLICING_LINT, "&*", "reborrow the original value instead")
+ } else if deref_count != 0 {
+ (DEREF_BY_SLICING_LINT, "", "dereference the original value instead")
+ } else {
+ (REDUNDANT_SLICING_LINT, "", "use the original value instead")
+ };
- let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
- let sugg = if (deref_count != 0 || !reborrow_str.is_empty()) && needs_parens_for_prefix {
- format!("({reborrow_str}{}{snip})", "*".repeat(deref_count))
- } else {
- format!("{reborrow_str}{}{snip}", "*".repeat(deref_count))
- };
+ let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
+ let sugg = if (deref_count != 0 || !reborrow_str.is_empty()) && needs_parens_for_prefix {
+ format!("({reborrow_str}{}{snip})", "*".repeat(deref_count))
+ } else {
+ format!("{reborrow_str}{}{snip}", "*".repeat(deref_count))
+ };
- (lint, help_str, sugg)
- } else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
- if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
- cx.param_env,
- Ty::new_projection(cx.tcx,target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])),
- ) {
- if deref_ty == expr_ty {
- let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
- let sugg = if needs_parens_for_prefix {
- format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count))
- } else {
- format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count))
- };
- (DEREF_BY_SLICING_LINT, "dereference the original value instead", sugg)
+ (lint, help_str, sugg)
+ } else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
+ if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
+ cx.param_env,
+ Ty::new_projection(cx.tcx, target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])),
+ ) {
+ if deref_ty == expr_ty {
+ let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
+ let sugg = if needs_parens_for_prefix {
+ format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count))
} else {
- return;
- }
+ format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count))
+ };
+ (DEREF_BY_SLICING_LINT, "dereference the original value instead", sugg)
} else {
return;
}
} else {
return;
- };
+ }
+ } else {
+ return;
+ };
- span_lint_and_sugg(
- cx,
- lint,
- expr.span,
- msg,
- help,
- sugg,
- app,
- );
- }
+ span_lint_and_sugg(cx, lint, expr.span, msg, help, sugg, app);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
index a70b831a8..07b604f23 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet;
use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::kw;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
index f6af9cac3..07fcb69af 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
@@ -5,7 +5,7 @@ use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
index c984a8286..19ce08bde 100644
--- a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::last_path_segment;
use clippy_utils::source::snippet;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{GenericArg, GenericArgsParentheses, Mutability, Ty, TyKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
declare_clippy_lint! {
@@ -38,34 +37,30 @@ declare_lint_pass!(RefOptionRef => [REF_OPTION_REF]);
impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
- if_chain! {
- if let TyKind::Ref(_, ref mut_ty) = ty.kind;
- if mut_ty.mutbl == Mutability::Not;
- if let TyKind::Path(ref qpath) = &mut_ty.ty.kind;
- let last = last_path_segment(qpath);
- if let Some(def_id) = last.res.opt_def_id();
-
- if cx.tcx.is_diagnostic_item(sym::Option, def_id);
- if let Some(params) = last_path_segment(qpath).args ;
- if params.parenthesized == GenericArgsParentheses::No;
- if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg {
+ if let TyKind::Ref(_, ref mut_ty) = ty.kind
+ && mut_ty.mutbl == Mutability::Not
+ && let TyKind::Path(ref qpath) = &mut_ty.ty.kind
+ && let last = last_path_segment(qpath)
+ && let Some(def_id) = last.res.opt_def_id()
+ && cx.tcx.is_diagnostic_item(sym::Option, def_id)
+ && let Some(params) = last_path_segment(qpath).args
+ && params.parenthesized == GenericArgsParentheses::No
+ && let Some(inner_ty) = params.args.iter().find_map(|arg| match arg {
GenericArg::Type(inner_ty) => Some(inner_ty),
_ => None,
- });
- if let TyKind::Ref(_, ref inner_mut_ty) = inner_ty.kind;
- if inner_mut_ty.mutbl == Mutability::Not;
-
- then {
- span_lint_and_sugg(
- cx,
- REF_OPTION_REF,
- ty.span,
- "since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`",
- "try",
- format!("Option<{}>", &snippet(cx, inner_ty.span, "..")),
- Applicability::MaybeIncorrect,
- );
- }
+ })
+ && let TyKind::Ref(_, ref inner_mut_ty) = inner_ty.kind
+ && inner_mut_ty.mutbl == Mutability::Not
+ {
+ span_lint_and_sugg(
+ cx,
+ REF_OPTION_REF,
+ ty.span,
+ "since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`",
+ "try",
+ format!("Option<{}>", &snippet(cx, inner_ty.span, "..")),
+ Applicability::MaybeIncorrect,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/ref_patterns.rs b/src/tools/clippy/clippy_lints/src/ref_patterns.rs
index 8b3dabde9..a4be78b31 100644
--- a/src/tools/clippy/clippy_lints/src/ref_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/ref_patterns.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{BindingAnnotation, Pat, PatKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs
index 12da29f11..16086ba66 100644
--- a/src/tools/clippy/clippy_lints/src/reference.rs
+++ b/src/tools/clippy/clippy_lints/src/reference.rs
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
-use if_chain::if_chain;
use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::BytePos;
declare_clippy_lint! {
@@ -47,58 +46,62 @@ fn without_parens(mut e: &Expr) -> &Expr {
impl EarlyLintPass for DerefAddrOf {
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
- if_chain! {
- if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind;
- if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind;
- if deref_target.span.eq_ctxt(e.span);
- if !addrof_target.span.from_expansion();
- then {
- let mut applicability = Applicability::MachineApplicable;
- let sugg = if e.span.from_expansion() {
- if let Some(macro_source) = snippet_opt(cx, e.span) {
- // Remove leading whitespace from the given span
- // e.g: ` $visitor` turns into `$visitor`
- let trim_leading_whitespaces = |span| {
- snippet_opt(cx, span).and_then(|snip| {
+ if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind
+ && let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind
+ && deref_target.span.eq_ctxt(e.span)
+ && !addrof_target.span.from_expansion()
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let sugg = if e.span.from_expansion() {
+ if let Some(macro_source) = snippet_opt(cx, e.span) {
+ // Remove leading whitespace from the given span
+ // e.g: ` $visitor` turns into `$visitor`
+ let trim_leading_whitespaces = |span| {
+ snippet_opt(cx, span)
+ .and_then(|snip| {
#[expect(clippy::cast_possible_truncation)]
- snip.find(|c: char| !c.is_whitespace()).map(|pos| {
- span.lo() + BytePos(pos as u32)
- })
- }).map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace))
- };
-
- let mut generate_snippet = |pattern: &str| {
- #[expect(clippy::cast_possible_truncation)]
- macro_source.rfind(pattern).map(|pattern_pos| {
- let rpos = pattern_pos + pattern.len();
- let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32));
- let span = trim_leading_whitespaces(span_after_ref);
- snippet_with_applicability(cx, span, "_", &mut applicability)
+ snip.find(|c: char| !c.is_whitespace())
+ .map(|pos| span.lo() + BytePos(pos as u32))
})
- };
+ .map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace))
+ };
+
+ let mut generate_snippet = |pattern: &str| {
+ #[expect(clippy::cast_possible_truncation)]
+ macro_source.rfind(pattern).map(|pattern_pos| {
+ let rpos = pattern_pos + pattern.len();
+ let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32));
+ let span = trim_leading_whitespaces(span_after_ref);
+ snippet_with_applicability(cx, span, "_", &mut applicability)
+ })
+ };
- if *mutability == Mutability::Mut {
- generate_snippet("mut")
- } else {
- generate_snippet("&")
- }
+ if *mutability == Mutability::Mut {
+ generate_snippet("mut")
} else {
- Some(snippet_with_applicability(cx, e.span, "_", &mut applicability))
+ generate_snippet("&")
}
} else {
- Some(snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability))
- };
- if let Some(sugg) = sugg {
- span_lint_and_sugg(
- cx,
- DEREF_ADDROF,
- e.span,
- "immediately dereferencing a reference",
- "try",
- sugg.to_string(),
- applicability,
- );
+ Some(snippet_with_applicability(cx, e.span, "_", &mut applicability))
}
+ } else {
+ Some(snippet_with_applicability(
+ cx,
+ addrof_target.span,
+ "_",
+ &mut applicability,
+ ))
+ };
+ if let Some(sugg) = sugg {
+ span_lint_and_sugg(
+ cx,
+ DEREF_ADDROF,
+ e.span,
+ "immediately dereferencing a reference",
+ "try",
+ sugg.to_string(),
+ applicability,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index cb78eec9e..687bad35a 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -8,7 +8,7 @@ use rustc_ast::ast::{LitKind, StrStyle};
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{BorrowKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{BytePos, Span};
declare_clippy_lint! {
@@ -191,13 +191,11 @@ fn is_trivial_regex(s: &regex_syntax::hir::Hir) -> Option<&'static str> {
}
fn check_set<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
- if_chain! {
- if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind;
- if let ExprKind::Array(exprs) = expr.kind;
- then {
- for expr in exprs {
- check_regex(cx, expr, utf8);
- }
+ if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind
+ && let ExprKind::Array(exprs) = expr.kind
+ {
+ for expr in exprs {
+ check_regex(cx, expr, utf8);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index 613f1ecc6..85979903b 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -4,8 +4,9 @@
pub static RENAMED_LINTS: &[(&str, &str)] = &[
("clippy::almost_complete_letter_range", "clippy::almost_complete_range"),
("clippy::blacklisted_name", "clippy::disallowed_names"),
- ("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"),
- ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"),
+ ("clippy::block_in_if_condition_expr", "clippy::blocks_in_conditions"),
+ ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_conditions"),
+ ("clippy::blocks_in_if_conditions", "clippy::blocks_in_conditions"),
("clippy::box_vec", "clippy::box_collection"),
("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"),
("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),
@@ -58,4 +59,5 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
("clippy::undropped_manually_drops", "undropped_manually_drops"),
("clippy::unknown_clippy_lints", "unknown_lints"),
("clippy::unused_label", "unused_labels"),
+ ("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"),
];
diff --git a/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
new file mode 100644
index 000000000..5a4933a3f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/repeat_vec_with_capacity.rs
@@ -0,0 +1,114 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::higher::VecArgs;
+use clippy_utils::macros::root_macro_call;
+use clippy_utils::source::snippet;
+use clippy_utils::{expr_or_init, fn_def_id, match_def_path, paths};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::{sym, Span};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Looks for patterns such as `vec![Vec::with_capacity(x); n]` or `iter::repeat(Vec::with_capacity(x))`.
+ ///
+ /// ### Why is this bad?
+ /// These constructs work by cloning the element, but cloning a `Vec<_>` does not
+ /// respect the old vector's capacity and effectively discards it.
+ ///
+ /// This makes `iter::repeat(Vec::with_capacity(x))` especially suspicious because the user most certainly
+ /// expected that the yielded `Vec<_>` will have the requested capacity, otherwise one can simply write
+ /// `iter::repeat(Vec::new())` instead and it will have the same effect.
+ ///
+ /// Similarly for `vec![x; n]`, the element `x` is cloned to fill the vec.
+ /// Unlike `iter::repeat` however, the vec repeat macro does not have to clone the value `n` times
+ /// but just `n - 1` times, because it can reuse the passed value for the last slot.
+ /// That means that the last `Vec<_>` gets the requested capacity but all other ones do not.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::iter;
+ ///
+ /// let _: Vec<Vec<u8>> = vec![Vec::with_capacity(42); 123];
+ /// let _: Vec<Vec<u8>> = iter::repeat(Vec::with_capacity(42)).take(123).collect();
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # use std::iter;
+ ///
+ /// let _: Vec<Vec<u8>> = iter::repeat_with(|| Vec::with_capacity(42)).take(123).collect();
+ /// // ^^^ this closure executes 123 times
+ /// // and the vecs will have the expected capacity
+ /// ```
+ #[clippy::version = "1.74.0"]
+ pub REPEAT_VEC_WITH_CAPACITY,
+ suspicious,
+ "repeating a `Vec::with_capacity` expression which does not retain capacity"
+}
+
+declare_lint_pass!(RepeatVecWithCapacity => [REPEAT_VEC_WITH_CAPACITY]);
+
+fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, sugg_msg: &'static str, sugg: String) {
+ span_lint_and_then(
+ cx,
+ REPEAT_VEC_WITH_CAPACITY,
+ span,
+ &format!("repeating `Vec::with_capacity` using `{kind}`, which does not retain capacity"),
+ |diag| {
+ diag.note(note);
+ diag.span_suggestion_verbose(span, sugg_msg, sugg, Applicability::MaybeIncorrect);
+ },
+ );
+}
+
+/// Checks `vec![Vec::with_capacity(x); n]`
+fn check_vec_macro(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if let Some(mac_call) = root_macro_call(expr.span)
+ && cx.tcx.is_diagnostic_item(sym::vec_macro, mac_call.def_id)
+ && let Some(VecArgs::Repeat(repeat_expr, len_expr)) = VecArgs::hir(cx, expr)
+ && fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY))
+ && !len_expr.span.from_expansion()
+ && let Some(Constant::Int(2..)) = constant(cx, cx.typeck_results(), expr_or_init(cx, len_expr))
+ {
+ emit_lint(
+ cx,
+ expr.span.source_callsite(),
+ "vec![x; n]",
+ "only the last `Vec` will have the capacity",
+ "if you intended to initialize multiple `Vec`s with an initial capacity, try",
+ format!(
+ "(0..{}).map(|_| {}).collect::<Vec<_>>()",
+ snippet(cx, len_expr.span, ""),
+ snippet(cx, repeat_expr.span, "..")
+ ),
+ );
+ }
+}
+
+/// Checks `iter::repeat(Vec::with_capacity(x))`
+fn check_repeat_fn(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if !expr.span.from_expansion()
+ && fn_def_id(cx, expr).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::iter_repeat, did))
+ && let ExprKind::Call(_, [repeat_expr]) = expr.kind
+ && fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY))
+ && !repeat_expr.span.from_expansion()
+ {
+ emit_lint(
+ cx,
+ expr.span,
+ "iter::repeat",
+ "none of the yielded `Vec`s will have the requested capacity",
+ "if you intended to create an iterator that yields `Vec`s with an initial capacity, try",
+ format!("std::iter::repeat_with(|| {})", snippet(cx, repeat_expr.span, "..")),
+ );
+ }
+}
+
+impl LateLintPass<'_> for RepeatVecWithCapacity {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ check_vec_macro(cx, expr);
+ check_repeat_fn(cx, expr);
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
index 1975946c6..ca7a0c7c8 100644
--- a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
@@ -7,7 +7,7 @@ use rustc_hir::def::Res;
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
@@ -26,7 +26,7 @@ declare_clippy_lint! {
/// ```no_run
/// let mut v: Vec<usize> = Vec::with_capacity(10);
/// ```
- #[clippy::version = "1.73.0"]
+ #[clippy::version = "1.74.0"]
pub RESERVE_AFTER_INITIALIZATION,
complexity,
"`reserve` called immediately after `Vec` creation"
diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
index 245029a06..5962e8be9 100644
--- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
@@ -6,7 +6,7 @@ use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, Span};
declare_clippy_lint! {
@@ -69,35 +69,32 @@ declare_clippy_lint! {
declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]);
fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, owner_id: OwnerId) {
- if_chain! {
+ if !in_external_macro(cx.sess(), span)
// If it comes from an external macro, better ignore it.
- if !in_external_macro(cx.sess(), span);
- if decl.implicit_self.has_implicit_self();
+ && decl.implicit_self.has_implicit_self()
// We only show this warning for public exported methods.
- if cx.effective_visibilities.is_exported(fn_def);
+ && cx.effective_visibilities.is_exported(fn_def)
// We don't want to emit this lint if the `#[must_use]` attribute is already there.
- if !cx.tcx.hir().attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use));
- if cx.tcx.visibility(fn_def.to_def_id()).is_public();
- let ret_ty = return_ty(cx, owner_id);
- let self_arg = nth_arg(cx, owner_id, 0);
+ && !cx.tcx.hir().attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use))
+ && cx.tcx.visibility(fn_def.to_def_id()).is_public()
+ && let ret_ty = return_ty(cx, owner_id)
+ && let self_arg = nth_arg(cx, owner_id, 0)
// If `Self` has the same type as the returned type, then we want to warn.
//
// For this check, we don't want to remove the reference on the returned type because if
// there is one, we shouldn't emit a warning!
- if self_arg.peel_refs() == ret_ty;
+ && self_arg.peel_refs() == ret_ty
// If `Self` is already marked as `#[must_use]`, no need for the attribute here.
- if !is_must_use_ty(cx, ret_ty);
-
- then {
- span_lint_and_help(
- cx,
- RETURN_SELF_NOT_MUST_USE,
- span,
- "missing `#[must_use]` attribute on a method returning `Self`",
- None,
- "consider adding the `#[must_use]` attribute to the method or directly to the `Self` type"
- );
- }
+ && !is_must_use_ty(cx, ret_ty)
+ {
+ span_lint_and_help(
+ cx,
+ RETURN_SELF_NOT_MUST_USE,
+ span,
+ "missing `#[must_use]` attribute on a method returning `Self`",
+ None,
+ "consider adding the `#[must_use]` attribute to the method or directly to the `Self` type",
+ );
}
}
@@ -111,18 +108,15 @@ impl<'tcx> LateLintPass<'tcx> for ReturnSelfNotMustUse {
span: Span,
fn_def: LocalDefId,
) {
- if_chain! {
+ if matches!(kind, FnKind::Method(_, _))
// We are only interested in methods, not in functions or associated functions.
- if matches!(kind, FnKind::Method(_, _));
- if let Some(impl_def) = cx.tcx.impl_of_method(fn_def.to_def_id());
+ && let Some(impl_def) = cx.tcx.impl_of_method(fn_def.to_def_id())
// We don't want this method to be te implementation of a trait because the
// `#[must_use]` should be put on the trait definition directly.
- if cx.tcx.trait_id_of_impl(impl_def).is_none();
-
- then {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def);
- check_method(cx, decl, fn_def, span, hir_id.expect_owner());
- }
+ && cx.tcx.trait_id_of_impl(impl_def).is_none()
+ {
+ let hir_id = cx.tcx.local_def_id_to_hir_id(fn_def);
+ check_method(cx, decl, fn_def, span, hir_id.expect_owner());
}
}
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index f2a3dc509..2293b53b4 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -2,18 +2,19 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lin
use clippy_utils::source::{snippet_opt, snippet_with_context};
use clippy_utils::sugg::has_enclosing_paren;
use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
-use clippy_utils::{fn_def_id, is_from_proc_macro, path_to_local_id, span_find_starting_semi};
+use clippy_utils::{fn_def_id, is_from_proc_macro, is_inside_let_else, path_to_local_id, span_find_starting_semi};
use core::ops::ControlFlow;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
- Block, Body, Expr, ExprKind, FnDecl, ItemKind, LangItem, MatchSource, OwnerNode, PatKind, QPath, Stmt, StmtKind,
+ Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt,
+ StmtKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::{self, GenericArgKind, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::{BytePos, Pos, Span};
use std::borrow::Cow;
@@ -159,6 +160,22 @@ impl<'tcx> ToString for RetReplacement<'tcx> {
declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN, NEEDLESS_RETURN_WITH_QUESTION_MARK]);
+/// Checks if a return statement is "needed" in the middle of a block, or if it can be removed. This
+/// is the case when the enclosing block expression is coerced to some other type, which only works
+/// because of the never-ness of `return` expressions
+fn stmt_needs_never_type(cx: &LateContext<'_>, stmt_hir_id: HirId) -> bool {
+ cx.tcx
+ .hir()
+ .parent_iter(stmt_hir_id)
+ .find_map(|(_, node)| if let Node::Expr(expr) = node { Some(expr) } else { None })
+ .is_some_and(|e| {
+ cx.typeck_results()
+ .expr_adjustments(e)
+ .iter()
+ .any(|adjust| adjust.target != cx.tcx.types.unit && matches!(adjust.kind, Adjust::NeverToAny))
+ })
+}
+
impl<'tcx> LateLintPass<'tcx> for Return {
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
if !in_external_macro(cx.sess(), stmt.span)
@@ -170,9 +187,11 @@ impl<'tcx> LateLintPass<'tcx> for Return {
&& let ItemKind::Fn(_, _, body) = item.kind
&& let block = cx.tcx.hir().body(body).value
&& let ExprKind::Block(block, _) = block.kind
+ && !is_inside_let_else(cx.tcx, expr)
&& let [.., final_stmt] = block.stmts
&& final_stmt.hir_id != stmt.hir_id
&& !is_from_proc_macro(cx, expr)
+ && !stmt_needs_never_type(cx, stmt.hir_id)
{
span_lint_and_sugg(
cx,
@@ -188,50 +207,45 @@ impl<'tcx> LateLintPass<'tcx> for Return {
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
// we need both a let-binding stmt and an expr
- if_chain! {
- if let Some(retexpr) = block.expr;
- if let Some(stmt) = block.stmts.iter().last();
- if let StmtKind::Local(local) = &stmt.kind;
- if local.ty.is_none();
- if cx.tcx.hir().attrs(local.hir_id).is_empty();
- if let Some(initexpr) = &local.init;
- if let PatKind::Binding(_, local_id, _, _) = local.pat.kind;
- if path_to_local_id(retexpr, local_id);
- if !last_statement_borrows(cx, initexpr);
- if !in_external_macro(cx.sess(), initexpr.span);
- if !in_external_macro(cx.sess(), retexpr.span);
- if !local.span.from_expansion();
- then {
- span_lint_hir_and_then(
- cx,
- LET_AND_RETURN,
- retexpr.hir_id,
- retexpr.span,
- "returning the result of a `let` binding from a block",
- |err| {
- err.span_label(local.span, "unnecessary `let` binding");
+ if let Some(retexpr) = block.expr
+ && let Some(stmt) = block.stmts.iter().last()
+ && let StmtKind::Local(local) = &stmt.kind
+ && local.ty.is_none()
+ && cx.tcx.hir().attrs(local.hir_id).is_empty()
+ && let Some(initexpr) = &local.init
+ && let PatKind::Binding(_, local_id, _, _) = local.pat.kind
+ && path_to_local_id(retexpr, local_id)
+ && !last_statement_borrows(cx, initexpr)
+ && !in_external_macro(cx.sess(), initexpr.span)
+ && !in_external_macro(cx.sess(), retexpr.span)
+ && !local.span.from_expansion()
+ {
+ span_lint_hir_and_then(
+ cx,
+ LET_AND_RETURN,
+ retexpr.hir_id,
+ retexpr.span,
+ "returning the result of a `let` binding from a block",
+ |err| {
+ err.span_label(local.span, "unnecessary `let` binding");
- if let Some(mut snippet) = snippet_opt(cx, initexpr.span) {
- if !cx.typeck_results().expr_adjustments(retexpr).is_empty() {
- if !has_enclosing_paren(&snippet) {
- snippet = format!("({snippet})");
- }
- snippet.push_str(" as _");
+ if let Some(mut snippet) = snippet_opt(cx, initexpr.span) {
+ if !cx.typeck_results().expr_adjustments(retexpr).is_empty() {
+ if !has_enclosing_paren(&snippet) {
+ snippet = format!("({snippet})");
}
- err.multipart_suggestion(
- "return the expression directly",
- vec![
- (local.span, String::new()),
- (retexpr.span, snippet),
- ],
- Applicability::MachineApplicable,
- );
- } else {
- err.span_help(initexpr.span, "this expression can be directly returned");
+ snippet.push_str(" as _");
}
- },
- );
- }
+ err.multipart_suggestion(
+ "return the expression directly",
+ vec![(local.span, String::new()), (retexpr.span, snippet)],
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.span_help(initexpr.span, "this expression can be directly returned");
+ }
+ },
+ );
}
}
@@ -314,7 +328,7 @@ fn check_final_expr<'tcx>(
let replacement = if let Some(inner_expr) = inner {
// if desugar of `do yeet`, don't lint
if let ExprKind::Call(path_expr, _) = inner_expr.kind
- && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind
+ && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, ..)) = path_expr.kind
{
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index fd1f3d390..7a351dab2 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -4,7 +4,7 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::AssocKind;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::Symbol;
use rustc_span::Span;
use std::collections::{BTreeMap, BTreeSet};
@@ -55,11 +55,11 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl { .. })
&& let item = cx.tcx.hir().item(id)
&& let ItemKind::Impl(Impl {
- items,
- of_trait,
- self_ty,
- ..
- }) = &item.kind
+ items,
+ of_trait,
+ self_ty,
+ ..
+ }) = &item.kind
&& let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind
{
if !map.contains_key(res) {
@@ -75,11 +75,11 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
match of_trait {
Some(trait_ref) => {
- let mut methods_in_trait: BTreeSet<Symbol> = if_chain! {
+ let mut methods_in_trait: BTreeSet<Symbol> =
if let Some(Node::TraitRef(TraitRef { path, .. })) =
- cx.tcx.hir().find(trait_ref.hir_ref_id);
- if let Res::Def(DefKind::Trait, did) = path.res;
- then{
+ cx.tcx.opt_hir_node(trait_ref.hir_ref_id)
+ && let Res::Def(DefKind::Trait, did) = path.res
+ {
// FIXME: if
// `rustc_middle::ty::assoc::AssocItems::items` is public,
// we can iterate its keys instead of `in_definition_order`,
@@ -87,15 +87,12 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
cx.tcx
.associated_items(did)
.in_definition_order()
- .filter(|assoc_item| {
- matches!(assoc_item.kind, AssocKind::Fn)
- })
+ .filter(|assoc_item| matches!(assoc_item.kind, AssocKind::Fn))
.map(|assoc_item| assoc_item.name)
.collect()
- }else{
+ } else {
BTreeSet::new()
- }
- };
+ };
let mut check_trait_method = |method_name: Symbol, trait_method_span: Span| {
if let Some((impl_span, hir_id)) = existing_name.impl_methods.get(&method_name) {
diff --git a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
index b92014f68..98f3235af 100644
--- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
+++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
@@ -3,7 +3,7 @@ use clippy_utils::return_ty;
use clippy_utils::ty::contains_adt_constructor;
use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -70,22 +70,20 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
return;
}
- if_chain! {
- if let Some(self_def) = self_ty.ty_adt_def();
- if let Some(self_local_did) = self_def.did().as_local();
- let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
- if let Some(Node::Item(x)) = cx.tcx.hir().find(self_id);
- let type_name = x.ident.name.as_str().to_lowercase();
- if impl_item.ident.name.as_str() == type_name || impl_item.ident.name.as_str().replace('_', "") == type_name;
-
- then {
- span_lint(
- cx,
- SELF_NAMED_CONSTRUCTORS,
- impl_item.span,
- &format!("constructor `{}` has the same name as the type", impl_item.ident.name),
- );
- }
+ if let Some(self_def) = self_ty.ty_adt_def()
+ && let Some(self_local_did) = self_def.did().as_local()
+ && let self_id = cx.tcx.local_def_id_to_hir_id(self_local_did)
+ && let Some(Node::Item(x)) = cx.tcx.opt_hir_node(self_id)
+ && let type_name = x.ident.name.as_str().to_lowercase()
+ && (impl_item.ident.name.as_str() == type_name
+ || impl_item.ident.name.as_str().replace('_', "") == type_name)
+ {
+ span_lint(
+ cx,
+ SELF_NAMED_CONSTRUCTORS,
+ impl_item.span,
+ &format!("constructor `{}` has the same name as the type", impl_item.ident.name),
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index b0601bba4..0b3adfb7a 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and
use rustc_errors::Applicability;
use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
index ccf8b9977..2cd3e57f8 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
@@ -1,11 +1,10 @@
use crate::rustc_lint::LintContext;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Block, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -38,30 +37,29 @@ declare_lint_pass!(SemicolonIfNothingReturned => [SEMICOLON_IF_NOTHING_RETURNED]
impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned {
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
- if_chain! {
- if !block.span.from_expansion();
- if let Some(expr) = block.expr;
- let t_expr = cx.typeck_results().expr_ty(expr);
- if t_expr.is_unit();
- let mut app = Applicability::MachineApplicable;
- if let snippet = snippet_with_context(cx, expr.span, block.span.ctxt(), "}", &mut app).0;
- if !snippet.ends_with('}') && !snippet.ends_with(';');
- if cx.sess().source_map().is_multiline(block.span);
- then {
- // filter out the desugared `for` loop
- if let ExprKind::DropTemps(..) = &expr.kind {
- return;
- }
- span_lint_and_sugg(
- cx,
- SEMICOLON_IF_NOTHING_RETURNED,
- expr.span.source_callsite(),
- "consider adding a `;` to the last statement for consistent formatting",
- "add a `;` here",
- format!("{snippet};"),
- app,
- );
+ if !block.span.from_expansion()
+ && let Some(expr) = block.expr
+ && let t_expr = cx.typeck_results().expr_ty(expr)
+ && t_expr.is_unit()
+ && let mut app = Applicability::MachineApplicable
+ && let snippet = snippet_with_context(cx, expr.span, block.span.ctxt(), "}", &mut app).0
+ && !snippet.ends_with('}')
+ && !snippet.ends_with(';')
+ && cx.sess().source_map().is_multiline(block.span)
+ {
+ // filter out the desugared `for` loop
+ if let ExprKind::DropTemps(..) = &expr.kind {
+ return;
}
+ span_lint_and_sugg(
+ cx,
+ SEMICOLON_IF_NOTHING_RETURNED,
+ expr.span.source_callsite(),
+ "consider adding a `;` to the last statement for consistent formatting",
+ "add a `;` here",
+ format!("{snippet};"),
+ app,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs
index fc1c2af92..90834d784 100644
--- a/src/tools/clippy/clippy_lints/src/serde_api.rs
+++ b/src/tools/clippy/clippy_lints/src/serde_api.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint;
use clippy_utils::{get_trait_def_id, paths};
use rustc_hir::{Impl, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 41c10b34a..c74364d89 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -7,7 +7,7 @@ use rustc_hir::def_id::LocalDefId;
use rustc_hir::hir_id::ItemLocalId;
use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{Span, Symbol};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
index 57bcee1a8..6c99ccda7 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -8,7 +8,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{self as hir};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::Ident;
use rustc_span::{sym, Span, DUMMY_SP};
use std::borrow::Cow;
diff --git a/src/tools/clippy/clippy_lints/src/single_call_fn.rs b/src/tools/clippy/clippy_lints/src/single_call_fn.rs
index 0492df68d..8e181c3cc 100644
--- a/src/tools/clippy/clippy_lints/src/single_call_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/single_call_fn.rs
@@ -7,7 +7,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
index 74ee8ce2d..42f1564db 100644
--- a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
+++ b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{GenericParam, GenericParamKind};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
index 9c21d70c8..18fbbdb40 100644
--- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
@@ -5,7 +5,7 @@ use rustc_ast::visit::{walk_expr, Visitor};
use rustc_ast::{Crate, Expr, ExprKind, Item, ItemKind, MacroDef, ModKind, Ty, TyKind, UseTreeKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::edition::Edition;
use rustc_span::symbol::kw;
use rustc_span::{Span, Symbol};
diff --git a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
index 099743d22..95b4a11a7 100644
--- a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
+++ b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
@@ -8,7 +8,7 @@ use rustc_ast::{LitIntType, LitKind, UintTy};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem, QPath};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use std::fmt::{self, Display, Formatter};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
index b940cac60..756e47cbd 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
@@ -2,11 +2,10 @@
//! expecting a count of T
use clippy_utils::diagnostics::span_lint_and_help;
-use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty, TypeAndMut};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -39,16 +38,17 @@ declare_lint_pass!(SizeOfInElementCount => [SIZE_OF_IN_ELEMENT_COUNT]);
fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool) -> Option<Ty<'tcx>> {
match expr.kind {
ExprKind::Call(count_func, _func_args) => {
- if_chain! {
- if !inverted;
- if let ExprKind::Path(ref count_func_qpath) = count_func.kind;
- if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
- if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::mem_size_of | sym::mem_size_of_val));
- then {
- cx.typeck_results().node_args(count_func.hir_id).types().next()
- } else {
- None
- }
+ if !inverted
+ && let ExprKind::Path(ref count_func_qpath) = count_func.kind
+ && let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id()
+ && matches!(
+ cx.tcx.get_diagnostic_name(def_id),
+ Some(sym::mem_size_of | sym::mem_size_of_val)
+ )
+ {
+ cx.typeck_results().node_args(count_func.hir_id).types().next()
+ } else {
+ None
}
},
ExprKind::Binary(op, left, right) if BinOpKind::Mul == op.node => {
@@ -80,13 +80,12 @@ fn get_pointee_ty_and_count_expr<'tcx>(
"wrapping_offset",
];
- if_chain! {
+ if let ExprKind::Call(func, [.., count]) = expr.kind
// Find calls to ptr::{copy, copy_nonoverlapping}
// and ptr::{swap_nonoverlapping, write_bytes},
- if let ExprKind::Call(func, [.., count]) = expr.kind;
- if let ExprKind::Path(ref func_qpath) = func.kind;
- if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
- if matches!(cx.tcx.get_diagnostic_name(def_id), Some(
+ && let ExprKind::Path(ref func_qpath) = func.kind
+ && let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id()
+ && matches!(cx.tcx.get_diagnostic_name(def_id), Some(
sym::ptr_copy
| sym::ptr_copy_nonoverlapping
| sym::ptr_slice_from_raw_parts
@@ -95,26 +94,23 @@ fn get_pointee_ty_and_count_expr<'tcx>(
| sym::ptr_write_bytes
| sym::slice_from_raw_parts
| sym::slice_from_raw_parts_mut
- ));
+ ))
// Get the pointee type
- if let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).types().next();
- then {
- return Some((pointee_ty, count));
- }
+ && let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).types().next()
+ {
+ return Some((pointee_ty, count));
};
- if_chain! {
+ if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind
// Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods
- if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind;
- let method_ident = method_path.ident.as_str();
- if METHODS.iter().any(|m| *m == method_ident);
+ && let method_ident = method_path.ident.as_str()
+ && METHODS.iter().any(|m| *m == method_ident)
// Get the pointee type
- if let ty::RawPtr(TypeAndMut { ty: pointee_ty, .. }) =
- cx.typeck_results().expr_ty(ptr_self).kind();
- then {
- return Some((*pointee_ty, count));
- }
+ && let ty::RawPtr(TypeAndMut { ty: pointee_ty, .. }) =
+ cx.typeck_results().expr_ty(ptr_self).kind()
+ {
+ return Some((*pointee_ty, count));
};
None
}
@@ -127,25 +123,16 @@ impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount {
const LINT_MSG: &str = "found a count of bytes \
instead of a count of elements of `T`";
- if_chain! {
+ if let Some((pointee_ty, count_expr)) = get_pointee_ty_and_count_expr(cx, expr)
// Find calls to functions with an element count parameter and get
// the pointee type and count parameter expression
- if let Some((pointee_ty, count_expr)) = get_pointee_ty_and_count_expr(cx, expr);
// Find a size_of call in the count parameter expression and
// check that it's the same type
- if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count_expr, false);
- if pointee_ty == ty_used_for_size_of;
- then {
- span_lint_and_help(
- cx,
- SIZE_OF_IN_ELEMENT_COUNT,
- count_expr.span,
- LINT_MSG,
- None,
- HELP_MSG
- );
- }
+ && let Some(ty_used_for_size_of) = get_size_of_ty(cx, count_expr, false)
+ && pointee_ty == ty_used_for_size_of
+ {
+ span_lint_and_help(cx, SIZE_OF_IN_ELEMENT_COUNT, count_expr.span, LINT_MSG, None, HELP_MSG);
};
}
}
diff --git a/src/tools/clippy/clippy_lints/src/size_of_ref.rs b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
index 7de029b7b..14ca7a3f0 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
@@ -3,7 +3,7 @@ use clippy_utils::path_def_id;
use clippy_utils::ty::peel_mid_ty_refs;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 2244eab96..c4a5e48e8 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -5,12 +5,11 @@ use clippy_utils::{
get_enclosing_block, is_expr_path_def_path, is_integer_literal, is_path_diagnostic_item, path_to_local,
path_to_local_id, paths, SpanlessEq,
};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor};
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
declare_clippy_lint! {
@@ -103,41 +102,35 @@ enum InitializationType<'tcx> {
impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// Matches initialization on reassignments. For example: `vec = Vec::with_capacity(100)`
- if_chain! {
- if let ExprKind::Assign(left, right, _) = expr.kind;
- if let Some(local_id) = path_to_local(left);
- if let Some(size_expr) = Self::as_vec_initializer(cx, right);
-
- then {
- let vi = VecAllocation {
- local_id,
- allocation_expr: right,
- size_expr,
- };
-
- Self::search_initialization(cx, vi, expr.hir_id);
- }
+ if let ExprKind::Assign(left, right, _) = expr.kind
+ && let Some(local_id) = path_to_local(left)
+ && let Some(size_expr) = Self::as_vec_initializer(cx, right)
+ {
+ let vi = VecAllocation {
+ local_id,
+ allocation_expr: right,
+ size_expr,
+ };
+
+ Self::search_initialization(cx, vi, expr.hir_id);
}
}
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
// Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)`
// or `Vec::new()`
- if_chain! {
- if let StmtKind::Local(local) = stmt.kind;
- if let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind;
- if let Some(init) = local.init;
- if let Some(size_expr) = Self::as_vec_initializer(cx, init);
-
- then {
- let vi = VecAllocation {
- local_id,
- allocation_expr: init,
- size_expr,
- };
-
- Self::search_initialization(cx, vi, stmt.hir_id);
- }
+ if let StmtKind::Local(local) = stmt.kind
+ && let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind
+ && let Some(init) = local.init
+ && let Some(size_expr) = Self::as_vec_initializer(cx, init)
+ {
+ let vi = VecAllocation {
+ local_id,
+ allocation_expr: init,
+ size_expr,
+ };
+
+ Self::search_initialization(cx, vi, stmt.hir_id);
}
}
}
@@ -242,16 +235,13 @@ struct VectorInitializationVisitor<'a, 'tcx> {
impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
/// Checks if the given expression is extending a vector with `repeat(0).take(..)`
fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) {
- if_chain! {
- if self.initialization_found;
- if let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind;
- if path_to_local_id(self_arg, self.vec_alloc.local_id);
- if path.ident.name == sym!(extend);
- if self.is_repeat_take(extend_arg);
-
- then {
- self.slow_expression = Some(InitializationType::Extend(expr));
- }
+ if self.initialization_found
+ && let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind
+ && path_to_local_id(self_arg, self.vec_alloc.local_id)
+ && path.ident.name == sym!(extend)
+ && self.is_repeat_take(extend_arg)
+ {
+ self.slow_expression = Some(InitializationType::Extend(expr));
}
}
@@ -281,21 +271,19 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
/// Returns `true` if give expression is `repeat(0).take(...)`
fn is_repeat_take(&mut self, expr: &'tcx Expr<'tcx>) -> bool {
- if_chain! {
- if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind;
- if take_path.ident.name == sym!(take);
+ if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind
+ && take_path.ident.name == sym!(take)
// Check that take is applied to `repeat(0)`
- if self.is_repeat_zero(recv);
- then {
- if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
- // Check that len expression is equals to `with_capacity` expression
- return SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
- || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity")
- }
-
- self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);
- return true;
+ && self.is_repeat_zero(recv)
+ {
+ if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
+ // Check that len expression is equals to `with_capacity` expression
+ return SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
+ || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity");
}
+
+ self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);
+ return true;
}
false
@@ -303,15 +291,13 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
/// Returns `true` if given expression is `repeat(0)`
fn is_repeat_zero(&self, expr: &Expr<'_>) -> bool {
- if_chain! {
- if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind;
- if is_path_diagnostic_item(self.cx, fn_expr, sym::iter_repeat);
- if is_integer_literal(repeat_arg, 0);
- then {
- true
- } else {
- false
- }
+ if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind
+ && is_path_diagnostic_item(self.cx, fn_expr, sym::iter_repeat)
+ && is_integer_literal(repeat_arg, 0)
+ {
+ true
+ } else {
+ false
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
index d07a44770..38fd54a0f 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::{HirId, Path, PathSegment};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::kw;
use rustc_span::{sym, Span};
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index a44adc938..13ae1ff52 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -5,14 +5,13 @@ use clippy_utils::{
get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, is_path_diagnostic_item, method_calls,
peel_blocks, SpanlessEq,
};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::sym;
@@ -251,128 +250,115 @@ const MAX_LENGTH_BYTE_STRING_LIT: usize = 32;
declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS_BYTES]);
impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
- #[expect(clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
use rustc_ast::LitKind;
- if_chain! {
+ if let ExprKind::Call(fun, args) = e.kind
// Find std::str::converts::from_utf8
- if let ExprKind::Call(fun, args) = e.kind;
- if is_path_diagnostic_item(cx, fun, sym::str_from_utf8);
+ && is_path_diagnostic_item(cx, fun, sym::str_from_utf8)
// Find string::as_bytes
- if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args[0].kind;
- if let ExprKind::Index(left, right, _) = args.kind;
- let (method_names, expressions, _) = method_calls(left, 1);
- if method_names.len() == 1;
- if expressions.len() == 1;
- if expressions[0].1.is_empty();
- if method_names[0] == sym!(as_bytes);
+ && let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args[0].kind
+ && let ExprKind::Index(left, right, _) = args.kind
+ && let (method_names, expressions, _) = method_calls(left, 1)
+ && method_names.len() == 1
+ && expressions.len() == 1
+ && expressions[0].1.is_empty()
+ && method_names[0] == sym!(as_bytes)
// Check for slicer
- if let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), _, _) = right.kind;
+ && let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), _, _) = right.kind
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let string_expression = &expressions[0].0;
- then {
- let mut applicability = Applicability::MachineApplicable;
- let string_expression = &expressions[0].0;
+ let snippet_app = snippet_with_applicability(cx, string_expression.span, "..", &mut applicability);
- let snippet_app = snippet_with_applicability(
- cx,
- string_expression.span, "..",
- &mut applicability,
- );
+ span_lint_and_sugg(
+ cx,
+ STRING_FROM_UTF8_AS_BYTES,
+ e.span,
+ "calling a slice of `as_bytes()` with `from_utf8` should be not necessary",
+ "try",
+ format!("Some(&{snippet_app}[{}])", snippet(cx, right.span, "..")),
+ applicability,
+ );
+ }
+ if !in_external_macro(cx.sess(), e.span)
+ && let ExprKind::MethodCall(path, receiver, ..) = &e.kind
+ && path.ident.name == sym!(as_bytes)
+ && let ExprKind::Lit(lit) = &receiver.kind
+ && let LitKind::Str(lit_content, _) = &lit.node
+ {
+ let callsite = snippet(cx, receiver.span.source_callsite(), r#""foo""#);
+ let mut applicability = Applicability::MachineApplicable;
+ if callsite.starts_with("include_str!") {
span_lint_and_sugg(
cx,
- STRING_FROM_UTF8_AS_BYTES,
+ STRING_LIT_AS_BYTES,
e.span,
- "calling a slice of `as_bytes()` with `from_utf8` should be not necessary",
- "try",
- format!("Some(&{snippet_app}[{}])", snippet(cx, right.span, "..")),
- applicability
- )
- }
- }
-
- if_chain! {
- if !in_external_macro(cx.sess(), e.span);
- if let ExprKind::MethodCall(path, receiver, ..) = &e.kind;
- if path.ident.name == sym!(as_bytes);
- if let ExprKind::Lit(lit) = &receiver.kind;
- if let LitKind::Str(lit_content, _) = &lit.node;
- then {
- let callsite = snippet(cx, receiver.span.source_callsite(), r#""foo""#);
- let mut applicability = Applicability::MachineApplicable;
- if callsite.starts_with("include_str!") {
+ "calling `as_bytes()` on `include_str!(..)`",
+ "consider using `include_bytes!(..)` instead",
+ snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability).replacen(
+ "include_str",
+ "include_bytes",
+ 1,
+ ),
+ applicability,
+ );
+ } else if lit_content.as_str().is_ascii()
+ && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
+ && !receiver.span.from_expansion()
+ {
+ if let Some((parent, id)) = get_expr_use_or_unification_node(cx.tcx, e)
+ && let Node::Expr(parent) = parent
+ && let ExprKind::Match(scrutinee, ..) = parent.kind
+ && scrutinee.hir_id == id
+ {
+ // Don't lint. Byte strings produce `&[u8; N]` whereas `as_bytes()` produces
+ // `&[u8]`. This change would prevent matching with different sized slices.
+ } else if !callsite.starts_with("env!") {
span_lint_and_sugg(
cx,
STRING_LIT_AS_BYTES,
e.span,
- "calling `as_bytes()` on `include_str!(..)`",
- "consider using `include_bytes!(..)` instead",
- snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability).replacen(
- "include_str",
- "include_bytes",
- 1,
+ "calling `as_bytes()` on a string literal",
+ "consider using a byte string literal instead",
+ format!(
+ "b{}",
+ snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
),
applicability,
);
- } else if lit_content.as_str().is_ascii()
- && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
- && !receiver.span.from_expansion()
- {
- if let Some((parent, id)) = get_expr_use_or_unification_node(cx.tcx, e)
- && let Node::Expr(parent) = parent
- && let ExprKind::Match(scrutinee, ..) = parent.kind
- && scrutinee.hir_id == id
- {
- // Don't lint. Byte strings produce `&[u8; N]` whereas `as_bytes()` produces
- // `&[u8]`. This change would prevent matching with different sized slices.
- } else if !callsite.starts_with("env!") {
- span_lint_and_sugg(
- cx,
- STRING_LIT_AS_BYTES,
- e.span,
- "calling `as_bytes()` on a string literal",
- "consider using a byte string literal instead",
- format!(
- "b{}",
- snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
- ),
- applicability,
- );
- }
}
}
}
- if_chain! {
- if let ExprKind::MethodCall(path, recv, [], _) = &e.kind;
- if path.ident.name == sym!(into_bytes);
- if let ExprKind::MethodCall(path, recv, [], _) = &recv.kind;
- if matches!(path.ident.name.as_str(), "to_owned" | "to_string");
- if let ExprKind::Lit(lit) = &recv.kind;
- if let LitKind::Str(lit_content, _) = &lit.node;
-
- if lit_content.as_str().is_ascii();
- if lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT;
- if !recv.span.from_expansion();
- then {
- let mut applicability = Applicability::MachineApplicable;
+ if let ExprKind::MethodCall(path, recv, [], _) = &e.kind
+ && path.ident.name == sym!(into_bytes)
+ && let ExprKind::MethodCall(path, recv, [], _) = &recv.kind
+ && matches!(path.ident.name.as_str(), "to_owned" | "to_string")
+ && let ExprKind::Lit(lit) = &recv.kind
+ && let LitKind::Str(lit_content, _) = &lit.node
+ && lit_content.as_str().is_ascii()
+ && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
+ && !recv.span.from_expansion()
+ {
+ let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- STRING_LIT_AS_BYTES,
- e.span,
- "calling `into_bytes()` on a string literal",
- "consider using a byte string literal instead",
- format!(
- "b{}.to_vec()",
- snippet_with_applicability(cx, recv.span, r#""..""#, &mut applicability)
- ),
- applicability,
- );
- }
+ span_lint_and_sugg(
+ cx,
+ STRING_LIT_AS_BYTES,
+ e.span,
+ "calling `into_bytes()` on a string literal",
+ "consider using a byte string literal instead",
+ format!(
+ "b{}.to_vec()",
+ snippet_with_applicability(cx, recv.span, r#""..""#, &mut applicability)
+ ),
+ applicability,
+ );
}
}
}
@@ -406,22 +392,20 @@ declare_lint_pass!(StrToString => [STR_TO_STRING]);
impl<'tcx> LateLintPass<'tcx> for StrToString {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
- if_chain! {
- if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
- if path.ident.name == sym::to_string;
- let ty = cx.typeck_results().expr_ty(self_arg);
- if let ty::Ref(_, ty, ..) = ty.kind();
- if ty.is_str();
- then {
- span_lint_and_help(
- cx,
- STR_TO_STRING,
- expr.span,
- "`to_string()` called on a `&str`",
- None,
- "consider using `.to_owned()`",
- );
- }
+ if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
+ && path.ident.name == sym::to_string
+ && let ty = cx.typeck_results().expr_ty(self_arg)
+ && let ty::Ref(_, ty, ..) = ty.kind()
+ && ty.is_str()
+ {
+ span_lint_and_help(
+ cx,
+ STR_TO_STRING,
+ expr.span,
+ "`to_string()` called on a `&str`",
+ None,
+ "consider using `.to_owned()`",
+ );
}
}
}
@@ -456,21 +440,19 @@ declare_lint_pass!(StringToString => [STRING_TO_STRING]);
impl<'tcx> LateLintPass<'tcx> for StringToString {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
- if_chain! {
- if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
- if path.ident.name == sym::to_string;
- let ty = cx.typeck_results().expr_ty(self_arg);
- if is_type_lang_item(cx, ty, LangItem::String);
- then {
- span_lint_and_help(
- cx,
- STRING_TO_STRING,
- expr.span,
- "`to_string()` called on a `String`",
- None,
- "consider using `.clone()`",
- );
- }
+ if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
+ && path.ident.name == sym::to_string
+ && let ty = cx.typeck_results().expr_ty(self_arg)
+ && is_type_lang_item(cx, ty, LangItem::String)
+ {
+ span_lint_and_help(
+ cx,
+ STRING_TO_STRING,
+ expr.span,
+ "`to_string()` called on a `String`",
+ None,
+ "consider using `.clone()`",
+ );
}
}
}
@@ -500,26 +482,24 @@ declare_lint_pass!(TrimSplitWhitespace => [TRIM_SPLIT_WHITESPACE]);
impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
let tyckres = cx.typeck_results();
- if_chain! {
- if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind;
- if path.ident.name == sym!(split_whitespace);
- if let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id);
- if cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id);
- if let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind;
- if let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str();
- if let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id);
- if is_one_of_trim_diagnostic_items(cx, trim_def_id);
- then {
- span_lint_and_sugg(
- cx,
- TRIM_SPLIT_WHITESPACE,
- trim_span.with_hi(split_ws_span.lo()),
- &format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"),
- &format!("remove `{trim_fn_name}()`"),
- String::new(),
- Applicability::MachineApplicable,
- );
- }
+ if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind
+ && path.ident.name == sym!(split_whitespace)
+ && let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id)
+ && cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id)
+ && let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind
+ && let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str()
+ && let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id)
+ && is_one_of_trim_diagnostic_items(cx, trim_def_id)
+ {
+ span_lint_and_sugg(
+ cx,
+ TRIM_SPLIT_WHITESPACE,
+ trim_span.with_hi(split_ws_span.lo()),
+ &format!("found call to `str::{trim_fn_name}` before `str::split_whitespace`"),
+ &format!("remove `{trim_fn_name}()`"),
+ String::new(),
+ Applicability::MachineApplicable,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
index b3db5e9a4..8cf4715ee 100644
--- a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
@@ -3,11 +3,10 @@ use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
use clippy_utils::visitors::is_expr_unsafe;
use clippy_utils::{get_parent_node, match_libc_symbol};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
declare_clippy_lint! {
@@ -41,48 +40,45 @@ declare_lint_pass!(StrlenOnCStrings => [STRLEN_ON_C_STRINGS]);
impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if_chain! {
- if !expr.span.from_expansion();
- if let ExprKind::Call(func, [recv]) = expr.kind;
- if let ExprKind::Path(path) = &func.kind;
- if let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id();
- if match_libc_symbol(cx, did, "strlen");
- if let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind;
- if !recv.span.from_expansion();
- if path.ident.name == sym::as_ptr;
- then {
- let ctxt = expr.span.ctxt();
- let span = match get_parent_node(cx.tcx, expr.hir_id) {
- Some(Node::Block(&Block {
- rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), span, ..
- }))
- if span.ctxt() == ctxt && !is_expr_unsafe(cx, self_arg) => {
- span
- }
- _ => expr.span,
- };
+ if !expr.span.from_expansion()
+ && let ExprKind::Call(func, [recv]) = expr.kind
+ && let ExprKind::Path(path) = &func.kind
+ && let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id()
+ && match_libc_symbol(cx, did, "strlen")
+ && let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind
+ && !recv.span.from_expansion()
+ && path.ident.name == sym::as_ptr
+ {
+ let ctxt = expr.span.ctxt();
+ let span = match get_parent_node(cx.tcx, expr.hir_id) {
+ Some(Node::Block(&Block {
+ rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
+ span,
+ ..
+ })) if span.ctxt() == ctxt && !is_expr_unsafe(cx, self_arg) => span,
+ _ => expr.span,
+ };
- let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
- let mut app = Applicability::MachineApplicable;
- let val_name = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0;
- let method_name = if is_type_diagnostic_item(cx, ty, sym::cstring_type) {
- "as_bytes"
- } else if is_type_lang_item(cx, ty, LangItem::CStr) {
- "to_bytes"
- } else {
- return;
- };
+ let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
+ let mut app = Applicability::MachineApplicable;
+ let val_name = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0;
+ let method_name = if is_type_diagnostic_item(cx, ty, sym::cstring_type) {
+ "as_bytes"
+ } else if is_type_lang_item(cx, ty, LangItem::CStr) {
+ "to_bytes"
+ } else {
+ return;
+ };
- span_lint_and_sugg(
- cx,
- STRLEN_ON_C_STRINGS,
- span,
- "using `libc::strlen` on a `CString` or `CStr` value",
- "try",
- format!("{val_name}.{method_name}().len()"),
- app,
- );
- }
+ span_lint_and_sugg(
+ cx,
+ STRLEN_ON_C_STRINGS,
+ span,
+ "using `libc::strlen` on a `CString` or `CStr` value",
+ "try",
+ format!("{val_name}.{method_name}().len()"),
+ app,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs
deleted file mode 100644
index 0abc199da..000000000
--- a/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
-use if_chain::if_chain;
-use rustc_ast::token::CommentKind;
-use rustc_ast::{AttrKind, AttrStyle, Attribute, Item};
-use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
-
-declare_clippy_lint! {
- /// ### What it does
- /// Detects the use of outer doc comments (`///`, `/**`) followed by a bang (`!`): `///!`
- ///
- /// ### Why is this bad?
- /// Triple-slash comments (known as "outer doc comments") apply to items that follow it.
- /// An outer doc comment followed by a bang (i.e. `///!`) has no specific meaning.
- ///
- /// The user most likely meant to write an inner doc comment (`//!`, `/*!`), which
- /// applies to the parent item (i.e. the item that the comment is contained in,
- /// usually a module or crate).
- ///
- /// ### Known problems
- /// Inner doc comments can only appear before items, so there are certain cases where the suggestion
- /// made by this lint is not valid code. For example:
- /// ```rs
- /// fn foo() {}
- /// ///!
- /// fn bar() {}
- /// ```
- /// This lint detects the doc comment and suggests changing it to `//!`, but an inner doc comment
- /// is not valid at that position.
- ///
- /// ### Example
- /// In this example, the doc comment is attached to the *function*, rather than the *module*.
- /// ```no_run
- /// pub mod util {
- /// ///! This module contains utility functions.
- ///
- /// pub fn dummy() {}
- /// }
- /// ```
- ///
- /// Use instead:
- /// ```no_run
- /// pub mod util {
- /// //! This module contains utility functions.
- ///
- /// pub fn dummy() {}
- /// }
- /// ```
- #[clippy::version = "1.70.0"]
- pub SUSPICIOUS_DOC_COMMENTS,
- suspicious,
- "suspicious usage of (outer) doc comments"
-}
-declare_lint_pass!(SuspiciousDocComments => [SUSPICIOUS_DOC_COMMENTS]);
-
-const WARNING: &str = "this is an outer doc comment and does not apply to the parent module or crate";
-const HELP: &str = "use an inner doc comment to document the parent module or crate";
-
-impl EarlyLintPass for SuspiciousDocComments {
- fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
- let replacements = collect_doc_comment_replacements(&item.attrs);
-
- if let Some(((lo_span, _), (hi_span, _))) = replacements.first().zip(replacements.last()) {
- let span = lo_span.to(*hi_span);
-
- span_lint_and_then(cx, SUSPICIOUS_DOC_COMMENTS, span, WARNING, |diag| {
- multispan_sugg_with_applicability(diag, HELP, Applicability::MaybeIncorrect, replacements);
- });
- }
- }
-}
-
-fn collect_doc_comment_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> {
- attrs
- .iter()
- .filter_map(|attr| {
- if_chain! {
- if let AttrKind::DocComment(com_kind, sym) = attr.kind;
- if let AttrStyle::Outer = attr.style;
- if let Some(com) = sym.as_str().strip_prefix('!');
- then {
- let sugg = match com_kind {
- CommentKind::Line => format!("//!{com}"),
- CommentKind::Block => format!("/*!{com}*/")
- };
- Some((attr.span, sugg))
- } else {
- None
- }
- }
- })
- .collect()
-}
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index bb8cde5b9..8b9d9bade 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -2,12 +2,11 @@ use clippy_utils::ast_utils::{eq_id, is_useless_with_eq_exprs, IdentIter};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use core::ops::{Add, AddAssign};
-use if_chain::if_chain;
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, StmtKind};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::Ident;
use rustc_span::Span;
@@ -155,34 +154,22 @@ fn check_binops(cx: &EarlyContext<'_>, binops: &[&BinaryOp<'_>]) {
match (no_difference_info, double_difference_info) {
(Some(i), None) => attempt_to_emit_no_difference_lint(cx, binops, i, expected_loc),
(None, Some((double_difference_index, ident_loc1, ident_loc2))) => {
- if_chain! {
- if one_ident_difference_count == binop_count - 1;
- if let Some(binop) = binops.get(double_difference_index);
- then {
- let changed_loc = if ident_loc1 == expected_loc {
- ident_loc2
- } else if ident_loc2 == expected_loc {
- ident_loc1
- } else {
- // This expression doesn't match the form we're
- // looking for.
- return;
- };
-
- if let Some(sugg) = ident_swap_sugg(
- cx,
- &paired_identifiers,
- binop,
- changed_loc,
- &mut applicability,
- ) {
- emit_suggestion(
- cx,
- binop.span,
- sugg,
- applicability,
- );
- }
+ if one_ident_difference_count == binop_count - 1
+ && let Some(binop) = binops.get(double_difference_index)
+ {
+ let changed_loc = if ident_loc1 == expected_loc {
+ ident_loc2
+ } else if ident_loc2 == expected_loc {
+ ident_loc1
+ } else {
+ // This expression doesn't match the form we're
+ // looking for.
+ return;
+ };
+
+ if let Some(sugg) = ident_swap_sugg(cx, &paired_identifiers, binop, changed_loc, &mut applicability)
+ {
+ emit_suggestion(cx, binop.span, sugg, applicability);
}
}
},
@@ -212,48 +199,32 @@ fn attempt_to_emit_no_difference_lint(
let old_right_ident = get_ident(binop.right, expected_loc);
for b in skip_index(binops.iter(), i) {
- if_chain! {
- if let (Some(old_ident), Some(new_ident)) =
- (old_left_ident, get_ident(b.left, expected_loc));
- if old_ident != new_ident;
- if let Some(sugg) = suggestion_with_swapped_ident(
+ if let (Some(old_ident), Some(new_ident)) = (old_left_ident, get_ident(b.left, expected_loc))
+ && old_ident != new_ident
+ && let Some(sugg) =
+ suggestion_with_swapped_ident(cx, binop.left, expected_loc, new_ident, &mut applicability)
+ {
+ emit_suggestion(
cx,
- binop.left,
- expected_loc,
- new_ident,
- &mut applicability,
+ binop.span,
+ replace_left_sugg(cx, binop, &sugg, &mut applicability),
+ applicability,
);
- then {
- emit_suggestion(
- cx,
- binop.span,
- replace_left_sugg(cx, binop, &sugg, &mut applicability),
- applicability,
- );
- return;
- }
+ return;
}
- if_chain! {
- if let (Some(old_ident), Some(new_ident)) =
- (old_right_ident, get_ident(b.right, expected_loc));
- if old_ident != new_ident;
- if let Some(sugg) = suggestion_with_swapped_ident(
+ if let (Some(old_ident), Some(new_ident)) = (old_right_ident, get_ident(b.right, expected_loc))
+ && old_ident != new_ident
+ && let Some(sugg) =
+ suggestion_with_swapped_ident(cx, binop.right, expected_loc, new_ident, &mut applicability)
+ {
+ emit_suggestion(
cx,
- binop.right,
- expected_loc,
- new_ident,
- &mut applicability,
+ binop.span,
+ replace_right_sugg(cx, binop, &sugg, &mut applicability),
+ applicability,
);
- then {
- emit_suggestion(
- cx,
- binop.span,
- replace_right_sugg(cx, binop, &sugg, &mut applicability),
- applicability,
- );
- return;
- }
+ return;
}
}
}
@@ -327,7 +298,7 @@ fn replace_left_sugg(
) -> String {
format!(
"{left_suggestion} {} {}",
- binop.op.to_string(),
+ binop.op.as_str(),
snippet_with_applicability(cx, binop.right.span, "..", applicability),
)
}
@@ -341,7 +312,7 @@ fn replace_right_sugg(
format!(
"{} {} {right_suggestion}",
snippet_with_applicability(cx, binop.left.span, "..", applicability),
- binop.op.to_string(),
+ binop.op.as_str(),
)
}
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
index 6271ea027..8eab3f587 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
@@ -2,10 +2,9 @@ use clippy_utils::diagnostics::span_lint;
use clippy_utils::visitors::for_each_expr;
use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TRAITS};
use core::ops::ControlFlow;
-use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -57,37 +56,39 @@ declare_lint_pass!(SuspiciousImpl => [SUSPICIOUS_ARITHMETIC_IMPL, SUSPICIOUS_OP_
impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if_chain! {
- if let hir::ExprKind::Binary(binop, _, _) | hir::ExprKind::AssignOp(binop, ..) = expr.kind;
- if let Some((binop_trait_lang, op_assign_trait_lang)) = binop_traits(binop.node);
- if let Some(binop_trait_id) = cx.tcx.lang_items().get(binop_trait_lang);
- if let Some(op_assign_trait_id) = cx.tcx.lang_items().get(op_assign_trait_lang);
+ if let hir::ExprKind::Binary(binop, _, _) | hir::ExprKind::AssignOp(binop, ..) = expr.kind
+ && let Some((binop_trait_lang, op_assign_trait_lang)) = binop_traits(binop.node)
+ && let Some(binop_trait_id) = cx.tcx.lang_items().get(binop_trait_lang)
+ && let Some(op_assign_trait_id) = cx.tcx.lang_items().get(op_assign_trait_lang)
// Check for more than one binary operation in the implemented function
// Linting when multiple operations are involved can result in false positives
- let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id;
- if let hir::Node::ImplItem(impl_item) = cx.tcx.hir().get_by_def_id(parent_fn);
- if let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind;
- let body = cx.tcx.hir().body(body_id);
- let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id;
- if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn);
- let trait_id = trait_ref.path.res.def_id();
- if ![binop_trait_id, op_assign_trait_id].contains(&trait_id);
- if let Some(&(_, lint)) = [
+ && let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id
+ && let hir::Node::ImplItem(impl_item) = cx.tcx.hir_node_by_def_id(parent_fn)
+ && let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind
+ && let body = cx.tcx.hir().body(body_id)
+ && let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id).def_id
+ && let Some(trait_ref) = trait_ref_of_method(cx, parent_fn)
+ && let trait_id = trait_ref.path.res.def_id()
+ && ![binop_trait_id, op_assign_trait_id].contains(&trait_id)
+ && let Some(&(_, lint)) = [
(&BINOP_TRAITS, SUSPICIOUS_ARITHMETIC_IMPL),
(&OP_ASSIGN_TRAITS, SUSPICIOUS_OP_ASSIGN_IMPL),
]
.iter()
- .find(|&(ts, _)| ts.iter().any(|&t| Some(trait_id) == cx.tcx.lang_items().get(t)));
- if count_binops(body.value) == 1;
- then {
- span_lint(
- cx,
- lint,
- binop.span,
- &format!("suspicious use of `{}` in `{}` impl", binop.node.as_str(), cx.tcx.item_name(trait_id)),
- );
- }
+ .find(|&(ts, _)| ts.iter().any(|&t| Some(trait_id) == cx.tcx.lang_items().get(t)))
+ && count_binops(body.value) == 1
+ {
+ span_lint(
+ cx,
+ lint,
+ binop.span,
+ &format!(
+ "suspicious use of `{}` in `{}` impl",
+ binop.node.as_str(),
+ cx.tcx.item_name(trait_id)
+ ),
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
index 4340c23f8..1cc27670f 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
@@ -6,7 +6,7 @@ use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 660e6835e..daa6fe871 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -3,13 +3,12 @@ use clippy_utils::source::snippet_with_context;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{can_mut_borrow_both, eq_expr_value, in_constant, std_or_core};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::Ident;
use rustc_span::{sym, Span, SyntaxContext};
@@ -149,36 +148,33 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
}
for [s1, s2, s3] in block.stmts.array_windows::<3>() {
- if_chain! {
+ if let StmtKind::Local(tmp) = s1.kind
// let t = foo();
- if let StmtKind::Local(tmp) = s1.kind;
- if let Some(tmp_init) = tmp.init;
- if let PatKind::Binding(.., ident, None) = tmp.pat.kind;
+ && let Some(tmp_init) = tmp.init
+ && let PatKind::Binding(.., ident, None) = tmp.pat.kind
// foo() = bar();
- if let StmtKind::Semi(first) = s2.kind;
- if let ExprKind::Assign(lhs1, rhs1, _) = first.kind;
+ && let StmtKind::Semi(first) = s2.kind
+ && let ExprKind::Assign(lhs1, rhs1, _) = first.kind
// bar() = t;
- if let StmtKind::Semi(second) = s3.kind;
- if let ExprKind::Assign(lhs2, rhs2, _) = second.kind;
- if let ExprKind::Path(QPath::Resolved(None, rhs2)) = rhs2.kind;
- if rhs2.segments.len() == 1;
+ && let StmtKind::Semi(second) = s3.kind
+ && let ExprKind::Assign(lhs2, rhs2, _) = second.kind
+ && let ExprKind::Path(QPath::Resolved(None, rhs2)) = rhs2.kind
+ && rhs2.segments.len() == 1
- if ident.name == rhs2.segments[0].ident.name;
- if eq_expr_value(cx, tmp_init, lhs1);
- if eq_expr_value(cx, rhs1, lhs2);
+ && ident.name == rhs2.segments[0].ident.name
+ && eq_expr_value(cx, tmp_init, lhs1)
+ && eq_expr_value(cx, rhs1, lhs2)
- let ctxt = s1.span.ctxt();
- if s2.span.ctxt() == ctxt;
- if s3.span.ctxt() == ctxt;
- if first.span.ctxt() == ctxt;
- if second.span.ctxt() == ctxt;
-
- then {
- let span = s1.span.to(s3.span);
- generate_swap_warning(cx, lhs1, lhs2, span, false);
- }
+ && let ctxt = s1.span.ctxt()
+ && s2.span.ctxt() == ctxt
+ && s3.span.ctxt() == ctxt
+ && first.span.ctxt() == ctxt
+ && second.span.ctxt() == ctxt
+ {
+ let span = s1.span.to(s3.span);
+ generate_swap_warning(cx, lhs1, lhs2, span, false);
}
}
}
@@ -261,20 +257,18 @@ fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr<
fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) {
for [s1, s2, s3] in block.stmts.array_windows::<3>() {
let ctxt = s1.span.ctxt();
- if_chain! {
- if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(s1, ctxt);
- if let Some((lhs1, rhs1)) = extract_sides_of_xor_assign(s2, ctxt);
- if let Some((lhs2, rhs2)) = extract_sides_of_xor_assign(s3, ctxt);
- if eq_expr_value(cx, lhs0, rhs1);
- if eq_expr_value(cx, lhs2, rhs1);
- if eq_expr_value(cx, lhs1, rhs0);
- if eq_expr_value(cx, lhs1, rhs2);
- if s2.span.ctxt() == ctxt;
- if s3.span.ctxt() == ctxt;
- then {
- let span = s1.span.to(s3.span);
- generate_swap_warning(cx, lhs0, rhs0, span, true);
- }
+ if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(s1, ctxt)
+ && let Some((lhs1, rhs1)) = extract_sides_of_xor_assign(s2, ctxt)
+ && let Some((lhs2, rhs2)) = extract_sides_of_xor_assign(s3, ctxt)
+ && eq_expr_value(cx, lhs0, rhs1)
+ && eq_expr_value(cx, lhs2, rhs1)
+ && eq_expr_value(cx, lhs1, rhs0)
+ && eq_expr_value(cx, lhs1, rhs2)
+ && s2.span.ctxt() == ctxt
+ && s3.span.ctxt() == ctxt
+ {
+ let span = s1.span.to(s3.span);
+ generate_swap_warning(cx, lhs0, rhs0, span, true);
};
}
}
diff --git a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
index 6a6c94425..20e9608a1 100644
--- a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, Span, SyntaxContext};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
index dcf1fac02..af9e13dba 100644
--- a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
+++ b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{BytePos, Span};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
index c717ccc35..8151dd8f2 100644
--- a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
+++ b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_adjusted;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs
index 0cfb1c125..da5575826 100644
--- a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs
+++ b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs
@@ -3,7 +3,7 @@ use clippy_utils::{is_in_cfg_test, is_in_test_function};
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, FnDecl};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
@@ -55,20 +55,18 @@ impl LateLintPass<'_> for TestsOutsideTestModule {
sp: Span,
_: LocalDefId,
) {
- if_chain! {
- if !matches!(kind, FnKind::Closure);
- if is_in_test_function(cx.tcx, body.id().hir_id);
- if !is_in_cfg_test(cx.tcx, body.id().hir_id);
- then {
- span_lint_and_note(
- cx,
- TESTS_OUTSIDE_TEST_MODULE,
- sp,
- "this function marked with #[test] is outside a #[cfg(test)] module",
- None,
- "move it to a testing module marked with #[cfg(test)]",
- );
- }
+ if !matches!(kind, FnKind::Closure)
+ && is_in_test_function(cx.tcx, body.id().hir_id)
+ && !is_in_cfg_test(cx.tcx, body.id().hir_id)
+ {
+ span_lint_and_note(
+ cx,
+ TESTS_OUTSIDE_TEST_MODULE,
+ sp,
+ "this function marked with #[test] is outside a #[cfg(test)] module",
+ None,
+ "move it to a testing module marked with #[cfg(test)]",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
index a171d225f..dafe9e388 100644
--- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
@@ -1,12 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::match_def_path;
use clippy_utils::source::snippet_with_applicability;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -38,59 +37,57 @@ declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]);
impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- if_chain! {
- if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind;
- if is_some_path.ident.name.as_str() == "is_some";
- then {
- let match_result = match &to_digit_expr.kind {
- hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => {
- if_chain! {
- if to_digits_path.ident.name.as_str() == "to_digit";
- let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg);
- if *char_arg_ty.kind() == ty::Char;
- then {
- Some((true, *char_arg, radix_arg))
- } else {
- None
- }
- }
+ if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind
+ && is_some_path.ident.name.as_str() == "is_some"
+ {
+ let match_result = match &to_digit_expr.kind {
+ hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => {
+ if to_digits_path.ident.name.as_str() == "to_digit"
+ && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg)
+ && *char_arg_ty.kind() == ty::Char
+ {
+ Some((true, *char_arg, radix_arg))
+ } else {
+ None
}
- hir::ExprKind::Call(to_digits_call, to_digit_args) => {
- if_chain! {
- if let [char_arg, radix_arg] = *to_digit_args;
- if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind;
- if let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id);
- if let Some(to_digits_def_id) = to_digits_call_res.opt_def_id();
- if match_def_path(cx, to_digits_def_id, &["core", "char", "methods", "<impl char>", "to_digit"]);
- then {
- Some((false, char_arg, radix_arg))
- } else {
- None
- }
- }
+ },
+ hir::ExprKind::Call(to_digits_call, to_digit_args) => {
+ if let [char_arg, radix_arg] = *to_digit_args
+ && let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind
+ && let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id)
+ && let Some(to_digits_def_id) = to_digits_call_res.opt_def_id()
+ && match_def_path(
+ cx,
+ to_digits_def_id,
+ &["core", "char", "methods", "<impl char>", "to_digit"],
+ )
+ {
+ Some((false, char_arg, radix_arg))
+ } else {
+ None
}
- _ => None
- };
+ },
+ _ => None,
+ };
- if let Some((is_method_call, char_arg, radix_arg)) = match_result {
- let mut applicability = Applicability::MachineApplicable;
- let char_arg_snip = snippet_with_applicability(cx, char_arg.span, "_", &mut applicability);
- let radix_snip = snippet_with_applicability(cx, radix_arg.span, "_", &mut applicability);
+ if let Some((is_method_call, char_arg, radix_arg)) = match_result {
+ let mut applicability = Applicability::MachineApplicable;
+ let char_arg_snip = snippet_with_applicability(cx, char_arg.span, "_", &mut applicability);
+ let radix_snip = snippet_with_applicability(cx, radix_arg.span, "_", &mut applicability);
- span_lint_and_sugg(
- cx,
- TO_DIGIT_IS_SOME,
- expr.span,
- "use of `.to_digit(..).is_some()`",
- "try",
- if is_method_call {
- format!("{char_arg_snip}.is_digit({radix_snip})")
- } else {
- format!("char::is_digit({char_arg_snip}, {radix_snip})")
- },
- applicability,
- );
- }
+ span_lint_and_sugg(
+ cx,
+ TO_DIGIT_IS_SOME,
+ expr.span,
+ "use of `.to_digit(..).is_some()`",
+ "try",
+ if is_method_call {
+ format!("{char_arg_snip}.is_digit({radix_snip})")
+ } else {
+ format!("char::is_digit({char_arg_snip}, {radix_snip})")
+ },
+ applicability,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
index 87181adc2..cbdf31c93 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -3,7 +3,7 @@ use clippy_utils::has_repr_attr;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Const;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -54,20 +54,18 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
}
fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
- if_chain! {
+ if let ItemKind::Struct(data, _) = &item.kind
// First check if last field is an array
- if let ItemKind::Struct(data, _) = &item.kind;
- if let Some(last_field) = data.fields().last();
- if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind;
+ && let Some(last_field) = data.fields().last()
+ && let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind
// Then check if that array is zero-sized
- let length = Const::from_anon_const(cx.tcx, length.def_id);
- let length = length.try_eval_target_usize(cx.tcx, cx.param_env);
- if let Some(length) = length;
- then {
- length == 0
- } else {
- false
- }
+ && let length = Const::from_anon_const(cx.tcx, length.def_id)
+ && let length = length.try_eval_target_usize(cx.tcx, cx.param_env)
+ && let Some(length) = length
+ {
+ length == 0
+ } else {
+ false
}
}
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index f065d215e..e4054393d 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -3,7 +3,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash};
use core::hash::{Hash, Hasher};
-use if_chain::if_chain;
use itertools::Itertools;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::unhash::UnhashMap;
@@ -14,7 +13,7 @@ use rustc_hir::{
TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate,
};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{BytePos, Span};
use std::collections::hash_map::Entry;
@@ -124,103 +123,100 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
let mut self_bounds_map = FxHashMap::default();
for predicate in item.generics.predicates {
- if_chain! {
- if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
- if bound_predicate.origin != PredicateOrigin::ImplTrait;
- if !bound_predicate.span.from_expansion();
- if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
- if let Some(PathSegment {
- res: Res::SelfTyParam { trait_: def_id }, ..
- }) = segments.first();
- if let Some(
- Node::Item(
- Item {
- kind: ItemKind::Trait(_, _, _, self_bounds, _),
- .. }
- )
- ) = cx.tcx.hir().get_if_local(*def_id);
- then {
- if self_bounds_map.is_empty() {
- for bound in *self_bounds {
- let Some((self_res, self_segments, _)) = get_trait_info_from_bound(bound) else { continue };
- self_bounds_map.insert(self_res, self_segments);
- }
+ if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate
+ && bound_predicate.origin != PredicateOrigin::ImplTrait
+ && !bound_predicate.span.from_expansion()
+ && let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind
+ && let Some(PathSegment {
+ res: Res::SelfTyParam { trait_: def_id },
+ ..
+ }) = segments.first()
+ && let Some(Node::Item(Item {
+ kind: ItemKind::Trait(_, _, _, self_bounds, _),
+ ..
+ })) = cx.tcx.hir().get_if_local(*def_id)
+ {
+ if self_bounds_map.is_empty() {
+ for bound in *self_bounds {
+ let Some((self_res, self_segments, _)) = get_trait_info_from_bound(bound) else {
+ continue;
+ };
+ self_bounds_map.insert(self_res, self_segments);
}
+ }
- bound_predicate
- .bounds
- .iter()
- .filter_map(get_trait_info_from_bound)
- .for_each(|(trait_item_res, trait_item_segments, span)| {
- if let Some(self_segments) = self_bounds_map.get(&trait_item_res) {
- if SpanlessEq::new(cx).eq_path_segments(self_segments, trait_item_segments) {
- span_lint_and_help(
- cx,
- TRAIT_DUPLICATION_IN_BOUNDS,
- span,
- "this trait bound is already specified in trait declaration",
- None,
- "consider removing this trait bound",
- );
- }
+ bound_predicate
+ .bounds
+ .iter()
+ .filter_map(get_trait_info_from_bound)
+ .for_each(|(trait_item_res, trait_item_segments, span)| {
+ if let Some(self_segments) = self_bounds_map.get(&trait_item_res) {
+ if SpanlessEq::new(cx).eq_path_segments(self_segments, trait_item_segments) {
+ span_lint_and_help(
+ cx,
+ TRAIT_DUPLICATION_IN_BOUNDS,
+ span,
+ "this trait bound is already specified in trait declaration",
+ None,
+ "consider removing this trait bound",
+ );
}
- });
- }
+ }
+ });
}
}
}
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
- if_chain! {
- if let TyKind::Ref(.., mut_ty) = &ty.kind;
- if let TyKind::TraitObject(bounds, ..) = mut_ty.ty.kind;
- if bounds.len() > 2;
- then {
-
- // Build up a hash of every trait we've seen
- // When we see a trait for the first time, add it to unique_traits
- // so we can later use it to build a string of all traits exactly once, without duplicates
+ if let TyKind::Ref(.., mut_ty) = &ty.kind
+ && let TyKind::TraitObject(bounds, ..) = mut_ty.ty.kind
+ && bounds.len() > 2
+ {
+ // Build up a hash of every trait we've seen
+ // When we see a trait for the first time, add it to unique_traits
+ // so we can later use it to build a string of all traits exactly once, without duplicates
- let mut seen_def_ids = FxHashSet::default();
- let mut unique_traits = Vec::new();
+ let mut seen_def_ids = FxHashSet::default();
+ let mut unique_traits = Vec::new();
- // Iterate the bounds and add them to our seen hash
- // If we haven't yet seen it, add it to the fixed traits
- for bound in bounds {
- let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; };
+ // Iterate the bounds and add them to our seen hash
+ // If we haven't yet seen it, add it to the fixed traits
+ for bound in bounds {
+ let Some(def_id) = bound.trait_ref.trait_def_id() else {
+ continue;
+ };
- let new_trait = seen_def_ids.insert(def_id);
+ let new_trait = seen_def_ids.insert(def_id);
- if new_trait {
- unique_traits.push(bound);
- }
+ if new_trait {
+ unique_traits.push(bound);
}
+ }
- // If the number of unique traits isn't the same as the number of traits in the bounds,
- // there must be 1 or more duplicates
- if bounds.len() != unique_traits.len() {
- let mut bounds_span = bounds[0].span;
-
- for bound in bounds.iter().skip(1) {
- bounds_span = bounds_span.to(bound.span);
- }
-
- let fixed_trait_snippet = unique_traits
- .iter()
- .filter_map(|b| snippet_opt(cx, b.span))
- .collect::<Vec<_>>()
- .join(" + ");
+ // If the number of unique traits isn't the same as the number of traits in the bounds,
+ // there must be 1 or more duplicates
+ if bounds.len() != unique_traits.len() {
+ let mut bounds_span = bounds[0].span;
- span_lint_and_sugg(
- cx,
- TRAIT_DUPLICATION_IN_BOUNDS,
- bounds_span,
- "this trait bound is already specified in trait declaration",
- "try",
- fixed_trait_snippet,
- Applicability::MaybeIncorrect,
- );
+ for bound in bounds.iter().skip(1) {
+ bounds_span = bounds_span.to(bound.span);
}
+
+ let fixed_trait_snippet = unique_traits
+ .iter()
+ .filter_map(|b| snippet_opt(cx, b.span))
+ .collect::<Vec<_>>()
+ .join(" + ");
+
+ span_lint_and_sugg(
+ cx,
+ TRAIT_DUPLICATION_IN_BOUNDS,
+ bounds_span,
+ "this trait bound is already specified in trait declaration",
+ "try",
+ fixed_trait_snippet,
+ Applicability::MaybeIncorrect,
+ );
}
}
}
@@ -267,36 +263,38 @@ impl TraitBounds {
let mut map: UnhashMap<SpanlessTy<'_, '_>, Vec<&GenericBound<'_>>> = UnhashMap::default();
let mut applicability = Applicability::MaybeIncorrect;
for bound in gen.predicates {
- if_chain! {
- if let WherePredicate::BoundPredicate(ref p) = bound;
- if p.origin != PredicateOrigin::ImplTrait;
- if p.bounds.len() as u64 <= self.max_trait_bounds;
- if !p.span.from_expansion();
- let bounds = p.bounds.iter().filter(|b| !self.cannot_combine_maybe_bound(cx, b)).collect::<Vec<_>>();
- if !bounds.is_empty();
- if let Some(ref v) = map.insert(SpanlessTy { ty: p.bounded_ty, cx }, bounds);
- if !is_from_proc_macro(cx, p.bounded_ty);
- then {
- let trait_bounds = v
- .iter()
- .copied()
- .chain(p.bounds.iter())
- .filter_map(get_trait_info_from_bound)
- .map(|(_, _, span)| snippet_with_applicability(cx, span, "..", &mut applicability))
- .join(" + ");
- let hint_string = format!(
- "consider combining the bounds: `{}: {trait_bounds}`",
- snippet(cx, p.bounded_ty.span, "_"),
- );
- span_lint_and_help(
- cx,
- TYPE_REPETITION_IN_BOUNDS,
- p.span,
- "this type has already been used as a bound predicate",
- None,
- &hint_string,
- );
- }
+ if let WherePredicate::BoundPredicate(ref p) = bound
+ && p.origin != PredicateOrigin::ImplTrait
+ && p.bounds.len() as u64 <= self.max_trait_bounds
+ && !p.span.from_expansion()
+ && let bounds = p
+ .bounds
+ .iter()
+ .filter(|b| !self.cannot_combine_maybe_bound(cx, b))
+ .collect::<Vec<_>>()
+ && !bounds.is_empty()
+ && let Some(ref v) = map.insert(SpanlessTy { ty: p.bounded_ty, cx }, bounds)
+ && !is_from_proc_macro(cx, p.bounded_ty)
+ {
+ let trait_bounds = v
+ .iter()
+ .copied()
+ .chain(p.bounds.iter())
+ .filter_map(get_trait_info_from_bound)
+ .map(|(_, _, span)| snippet_with_applicability(cx, span, "..", &mut applicability))
+ .join(" + ");
+ let hint_string = format!(
+ "consider combining the bounds: `{}: {trait_bounds}`",
+ snippet(cx, p.bounded_ty.span, "_"),
+ );
+ span_lint_and_help(
+ cx,
+ TYPE_REPETITION_IN_BOUNDS,
+ p.span,
+ "this type has already been used as a bound predicate",
+ None,
+ &hint_string,
+ );
}
}
}
@@ -318,15 +316,19 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
.predicates
.iter()
.filter_map(|pred| {
- if_chain! {
- if pred.in_where_clause();
- if let WherePredicate::BoundPredicate(bound_predicate) = pred;
- if let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind;
- then {
- return Some(
- rollup_traits(cx, bound_predicate.bounds, "these where clauses contain repeated elements")
- .into_iter().map(|(trait_ref, _)| (path.res, trait_ref)))
- }
+ if pred.in_where_clause()
+ && let WherePredicate::BoundPredicate(bound_predicate) = pred
+ && let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind
+ {
+ return Some(
+ rollup_traits(
+ cx,
+ bound_predicate.bounds,
+ "these where clauses contain repeated elements",
+ )
+ .into_iter()
+ .map(|(trait_ref, _)| (path.res, trait_ref)),
+ );
}
None
})
@@ -340,25 +342,23 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
// compare trait bounds keyed by generic name and comparable trait to collected where
// predicates eg. (T, Clone)
for predicate in gen.predicates.iter().filter(|pred| !pred.in_where_clause()) {
- if_chain! {
- if let WherePredicate::BoundPredicate(bound_predicate) = predicate;
- if bound_predicate.origin != PredicateOrigin::ImplTrait;
- if !bound_predicate.span.from_expansion();
- if let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind;
- then {
- let traits = rollup_traits(cx, bound_predicate.bounds, "these bounds contain repeated elements");
- for (trait_ref, span) in traits {
- let key = (path.res, trait_ref);
- if where_predicates.contains(&key) {
- span_lint_and_help(
- cx,
- TRAIT_DUPLICATION_IN_BOUNDS,
- span,
- "this trait bound is already specified in the where clause",
- None,
- "consider removing this trait bound",
- );
- }
+ if let WherePredicate::BoundPredicate(bound_predicate) = predicate
+ && bound_predicate.origin != PredicateOrigin::ImplTrait
+ && !bound_predicate.span.from_expansion()
+ && let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind
+ {
+ let traits = rollup_traits(cx, bound_predicate.bounds, "these bounds contain repeated elements");
+ for (trait_ref, span) in traits {
+ let key = (path.res, trait_ref);
+ if where_predicates.contains(&key) {
+ span_lint_and_help(
+ cx,
+ TRAIT_DUPLICATION_IN_BOUNDS,
+ span,
+ "this trait bound is already specified in the where clause",
+ None,
+ "consider removing this trait bound",
+ );
}
}
}
@@ -401,10 +401,10 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef {
.filter_map(|segment| {
// get trait bound type arguments
Some(segment.args?.args.iter().filter_map(|arg| {
- if_chain! {
- if let GenericArg::Type(ty) = arg;
- if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
- then { return Some(path.res) }
+ if let GenericArg::Type(ty) = arg
+ && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind
+ {
+ return Some(path.res);
}
None
}))
@@ -444,27 +444,24 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -
comparable_bounds[i] = (k, v);
}
- if_chain! {
- if repeated_res;
- if let [first_trait, .., last_trait] = bounds;
- then {
- let all_trait_span = first_trait.span().to(last_trait.span());
-
- let traits = comparable_bounds.iter()
- .filter_map(|&(_, span)| snippet_opt(cx, span))
- .collect::<Vec<_>>();
- let traits = traits.join(" + ");
-
- span_lint_and_sugg(
- cx,
- TRAIT_DUPLICATION_IN_BOUNDS,
- all_trait_span,
- msg,
- "try",
- traits,
- Applicability::MachineApplicable
- );
- }
+ if repeated_res && let [first_trait, .., last_trait] = bounds {
+ let all_trait_span = first_trait.span().to(last_trait.span());
+
+ let traits = comparable_bounds
+ .iter()
+ .filter_map(|&(_, span)| snippet_opt(cx, span))
+ .collect::<Vec<_>>();
+ let traits = traits.join(" + ");
+
+ span_lint_and_sugg(
+ cx,
+ TRAIT_DUPLICATION_IN_BOUNDS,
+ all_trait_span,
+ msg,
+ "try",
+ traits,
+ Applicability::MachineApplicable,
+ );
}
comparable_bounds
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index 6eec40cb5..95a92afea 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -19,10 +19,9 @@ mod wrong_transmute;
use clippy_config::msrvs::Msrv;
use clippy_utils::in_constant;
-use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::sym;
declare_clippy_lint! {
@@ -494,51 +493,47 @@ impl Transmute {
}
impl<'tcx> LateLintPass<'tcx> for Transmute {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
- if_chain! {
- if let ExprKind::Call(path_expr, [arg]) = e.kind;
- if let ExprKind::Path(QPath::Resolved(None, path)) = path_expr.kind;
- if let Some(def_id) = path.res.opt_def_id();
- if cx.tcx.is_diagnostic_item(sym::transmute, def_id);
- then {
- // Avoid suggesting non-const operations in const contexts:
- // - from/to bits (https://github.com/rust-lang/rust/issues/73736)
- // - dereferencing raw pointers (https://github.com/rust-lang/rust/issues/51911)
- // - char conversions (https://github.com/rust-lang/rust/issues/89259)
- let const_context = in_constant(cx, e.hir_id);
+ if let ExprKind::Call(path_expr, [arg]) = e.kind
+ && let ExprKind::Path(QPath::Resolved(None, path)) = path_expr.kind
+ && let Some(def_id) = path.res.opt_def_id()
+ && cx.tcx.is_diagnostic_item(sym::transmute, def_id)
+ {
+ // Avoid suggesting non-const operations in const contexts:
+ // - from/to bits (https://github.com/rust-lang/rust/issues/73736)
+ // - dereferencing raw pointers (https://github.com/rust-lang/rust/issues/51911)
+ // - char conversions (https://github.com/rust-lang/rust/issues/89259)
+ let const_context = in_constant(cx, e.hir_id);
- let (from_ty, from_ty_adjusted) = match cx.typeck_results().expr_adjustments(arg) {
- [] => (cx.typeck_results().expr_ty(arg), false),
- [.., a] => (a.target, true),
- };
- // Adjustments for `to_ty` happen after the call to `transmute`, so don't use them.
- let to_ty = cx.typeck_results().expr_ty(e);
+ let (from_ty, from_ty_adjusted) = match cx.typeck_results().expr_adjustments(arg) {
+ [] => (cx.typeck_results().expr_ty(arg), false),
+ [.., a] => (a.target, true),
+ };
+ // Adjustments for `to_ty` happen after the call to `transmute`, so don't use them.
+ let to_ty = cx.typeck_results().expr_ty(e);
- // If useless_transmute is triggered, the other lints can be skipped.
- if useless_transmute::check(cx, e, from_ty, to_ty, arg) {
- return;
- }
+ // If useless_transmute is triggered, the other lints can be skipped.
+ if useless_transmute::check(cx, e, from_ty, to_ty, arg) {
+ return;
+ }
- let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
- | crosspointer_transmute::check(cx, e, from_ty, to_ty)
- | transmuting_null::check(cx, e, arg, to_ty)
- | transmute_null_to_fn::check(cx, e, arg, to_ty)
- | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv)
- | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
- | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
- | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
- | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
- | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context)
- | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg)
- | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context)
- | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context)
- | (
- unsound_collection_transmute::check(cx, e, from_ty, to_ty)
- || transmute_undefined_repr::check(cx, e, from_ty, to_ty)
- );
+ let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
+ | crosspointer_transmute::check(cx, e, from_ty, to_ty)
+ | transmuting_null::check(cx, e, arg, to_ty)
+ | transmute_null_to_fn::check(cx, e, arg, to_ty)
+ | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, &self.msrv)
+ | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
+ | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
+ | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
+ | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
+ | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context)
+ | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg)
+ | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context)
+ | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context)
+ | (unsound_collection_transmute::check(cx, e, from_ty, to_ty)
+ || transmute_undefined_repr::check(cx, e, from_ty, to_ty));
- if !linted {
- transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg);
- }
+ if !linted {
+ transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
index 5ecba512b..aef520923 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
@@ -1,7 +1,6 @@
use super::TRANSMUTE_FLOAT_TO_INT;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg;
-use if_chain::if_chain;
use rustc_ast as ast;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, UnOp};
@@ -32,17 +31,15 @@ pub(super) fn check<'tcx>(
arg = inner_expr;
}
- if_chain! {
+ if let ExprKind::Lit(lit) = &arg.kind
// if the expression is a float literal and it is unsuffixed then
// add a suffix so the suggestion is valid and unambiguous
- if let ExprKind::Lit(lit) = &arg.kind;
- if let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node;
- then {
- let op = format!("{sugg}{}", float_ty.name_str()).into();
- match sugg {
- sugg::Sugg::MaybeParen(_) => sugg = sugg::Sugg::MaybeParen(op),
- _ => sugg = sugg::Sugg::NonParen(op)
- }
+ && let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node
+ {
+ let op = format!("{sugg}{}", float_ty.name_str()).into();
+ match sugg {
+ sugg::Sugg::MaybeParen(_) => sugg = sugg::Sugg::MaybeParen(op),
+ _ => sugg = sugg::Sugg::NonParen(op),
}
}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
index ea9ad9961..98e9ea2d7 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
@@ -2,7 +2,6 @@ use super::{TRANSMUTE_BYTES_TO_STR, TRANSMUTE_PTR_TO_PTR};
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::sugg;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, Mutability};
use rustc_lint::LateContext;
@@ -21,68 +20,59 @@ pub(super) fn check<'tcx>(
let mut triggered = false;
if let (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) = (&from_ty.kind(), &to_ty.kind()) {
- if_chain! {
- if let ty::Slice(slice_ty) = *ty_from.kind();
- if ty_to.is_str();
- if let ty::Uint(ty::UintTy::U8) = slice_ty.kind();
- if from_mutbl == to_mutbl;
- then {
- let postfix = if *from_mutbl == Mutability::Mut {
- "_mut"
- } else {
- ""
- };
+ if let ty::Slice(slice_ty) = *ty_from.kind()
+ && ty_to.is_str()
+ && let ty::Uint(ty::UintTy::U8) = slice_ty.kind()
+ && from_mutbl == to_mutbl
+ {
+ let postfix = if *from_mutbl == Mutability::Mut { "_mut" } else { "" };
- let snippet = snippet(cx, arg.span, "..");
+ let snippet = snippet(cx, arg.span, "..");
- span_lint_and_sugg(
- cx,
- TRANSMUTE_BYTES_TO_STR,
- e.span,
- &format!("transmute from a `{from_ty}` to a `{to_ty}`"),
- "consider using",
- if const_context {
- format!("std::str::from_utf8_unchecked{postfix}({snippet})")
- } else {
- format!("std::str::from_utf8{postfix}({snippet}).unwrap()")
- },
- Applicability::MaybeIncorrect,
- );
- triggered = true;
- } else {
- if (cx.tcx.erase_regions(from_ty) != cx.tcx.erase_regions(to_ty))
- && !const_context {
- span_lint_and_then(
- cx,
- TRANSMUTE_PTR_TO_PTR,
- e.span,
- "transmute from a reference to a reference",
- |diag| if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
- let ty_from_and_mut = ty::TypeAndMut {
- ty: *ty_from,
- mutbl: *from_mutbl
- };
- let ty_to_and_mut = ty::TypeAndMut { ty: *ty_to, mutbl: *to_mutbl };
- let sugg_paren = arg
- .as_ty(Ty::new_ptr(cx.tcx,ty_from_and_mut))
- .as_ty(Ty::new_ptr(cx.tcx,ty_to_and_mut));
- let sugg = if *to_mutbl == Mutability::Mut {
- sugg_paren.mut_addr_deref()
- } else {
- sugg_paren.addr_deref()
- };
- diag.span_suggestion(
- e.span,
- "try",
- sugg,
- Applicability::Unspecified,
- );
- },
- );
+ span_lint_and_sugg(
+ cx,
+ TRANSMUTE_BYTES_TO_STR,
+ e.span,
+ &format!("transmute from a `{from_ty}` to a `{to_ty}`"),
+ "consider using",
+ if const_context {
+ format!("std::str::from_utf8_unchecked{postfix}({snippet})")
+ } else {
+ format!("std::str::from_utf8{postfix}({snippet}).unwrap()")
+ },
+ Applicability::MaybeIncorrect,
+ );
+ triggered = true;
+ } else if (cx.tcx.erase_regions(from_ty) != cx.tcx.erase_regions(to_ty)) && !const_context {
+ span_lint_and_then(
+ cx,
+ TRANSMUTE_PTR_TO_PTR,
+ e.span,
+ "transmute from a reference to a reference",
+ |diag| {
+ if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
+ let ty_from_and_mut = ty::TypeAndMut {
+ ty: *ty_from,
+ mutbl: *from_mutbl,
+ };
+ let ty_to_and_mut = ty::TypeAndMut {
+ ty: *ty_to,
+ mutbl: *to_mutbl,
+ };
+ let sugg_paren = arg
+ .as_ty(Ty::new_ptr(cx.tcx, ty_from_and_mut))
+ .as_ty(Ty::new_ptr(cx.tcx, ty_to_and_mut));
+ let sugg = if *to_mutbl == Mutability::Mut {
+ sugg_paren.mut_addr_deref()
+ } else {
+ sugg_paren.addr_deref()
+ };
+ diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified);
+ }
+ },
+ );
- triggered = true;
- }
- }
+ triggered = true;
}
}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
index 7c2223ca3..a65bc0ce4 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -299,14 +299,12 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
}
fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
- if_chain! {
- if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty);
- if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
- then {
- layout.layout.size().bytes() == 0
- } else {
- false
- }
+ if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty)
+ && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty))
+ {
+ layout.layout.size().bytes() == 0
+ } else {
+ false
}
}
diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
index 642e39e82..e1cd82e18 100644
--- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
@@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use std::iter::once;
use std::ops::ControlFlow;
diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
index 306ca5724..801e88626 100644
--- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{
self as hir, GenericArg, GenericBounds, GenericParamKind, HirId, Lifetime, MutTy, Mutability, Node, QPath, TyKind,
@@ -15,66 +14,64 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
TyKind::Path(ref qpath) => {
let hir_id = mut_ty.ty.hir_id;
let def = cx.qpath_res(qpath, hir_id);
- if_chain! {
- if let Some(def_id) = def.opt_def_id();
- if Some(def_id) == cx.tcx.lang_items().owned_box();
- if let QPath::Resolved(None, path) = *qpath;
- if let [ref bx] = *path.segments;
- if let Some(params) = bx.args;
- if params.parenthesized == hir::GenericArgsParentheses::No;
- if let Some(inner) = params.args.iter().find_map(|arg| match arg {
+ if let Some(def_id) = def.opt_def_id()
+ && Some(def_id) == cx.tcx.lang_items().owned_box()
+ && let QPath::Resolved(None, path) = *qpath
+ && let [ref bx] = *path.segments
+ && let Some(params) = bx.args
+ && params.parenthesized == hir::GenericArgsParentheses::No
+ && let Some(inner) = params.args.iter().find_map(|arg| match arg {
GenericArg::Type(ty) => Some(ty),
_ => None,
- });
- then {
- if is_any_trait(cx, inner) {
- // Ignore `Box<Any>` types; see issue #1884 for details.
- return false;
- }
-
- let ltopt = if lt.is_anonymous() {
- String::new()
- } else {
- format!("{} ", lt.ident.as_str())
- };
+ })
+ {
+ if is_any_trait(cx, inner) {
+ // Ignore `Box<Any>` types; see issue #1884 for details.
+ return false;
+ }
- if mut_ty.mutbl == Mutability::Mut {
- // Ignore `&mut Box<T>` types; see issue #2907 for
- // details.
- return false;
- }
+ let ltopt = if lt.is_anonymous() {
+ String::new()
+ } else {
+ format!("{} ", lt.ident.as_str())
+ };
- // When trait objects or opaque types have lifetime or auto-trait bounds,
- // we need to add parentheses to avoid a syntax error due to its ambiguity.
- // Originally reported as the issue #3128.
- let inner_snippet = snippet(cx, inner.span, "..");
- let suggestion = match &inner.kind {
- TyKind::TraitObject(bounds, lt_bound, _) if bounds.len() > 1 || !lt_bound.is_elided() => {
- format!("&{ltopt}({})", &inner_snippet)
- },
- TyKind::Path(qpath)
- if get_bounds_if_impl_trait(cx, qpath, inner.hir_id)
- .map_or(false, |bounds| bounds.len() > 1) =>
- {
- format!("&{ltopt}({})", &inner_snippet)
- },
- _ => format!("&{ltopt}{}", &inner_snippet),
- };
- span_lint_and_sugg(
- cx,
- BORROWED_BOX,
- hir_ty.span,
- "you seem to be trying to use `&Box<T>`. Consider using just `&T`",
- "try",
- suggestion,
- // To make this `MachineApplicable`, at least one needs to check if it isn't a trait item
- // because the trait impls of it will break otherwise;
- // and there may be other cases that result in invalid code.
- // For example, type coercion doesn't work nicely.
- Applicability::Unspecified,
- );
- return true;
+ if mut_ty.mutbl == Mutability::Mut {
+ // Ignore `&mut Box<T>` types; see issue #2907 for
+ // details.
+ return false;
}
+
+ // When trait objects or opaque types have lifetime or auto-trait bounds,
+ // we need to add parentheses to avoid a syntax error due to its ambiguity.
+ // Originally reported as the issue #3128.
+ let inner_snippet = snippet(cx, inner.span, "..");
+ let suggestion = match &inner.kind {
+ TyKind::TraitObject(bounds, lt_bound, _) if bounds.len() > 1 || !lt_bound.is_elided() => {
+ format!("&{ltopt}({})", &inner_snippet)
+ },
+ TyKind::Path(qpath)
+ if get_bounds_if_impl_trait(cx, qpath, inner.hir_id)
+ .map_or(false, |bounds| bounds.len() > 1) =>
+ {
+ format!("&{ltopt}({})", &inner_snippet)
+ },
+ _ => format!("&{ltopt}{}", &inner_snippet),
+ };
+ span_lint_and_sugg(
+ cx,
+ BORROWED_BOX,
+ hir_ty.span,
+ "you seem to be trying to use `&Box<T>`. Consider using just `&T`",
+ "try",
+ suggestion,
+ // To make this `MachineApplicable`, at least one needs to check if it isn't a trait item
+ // because the trait impls of it will break otherwise;
+ // and there may be other cases that result in invalid code.
+ // For example, type coercion doesn't work nicely.
+ Applicability::Unspecified,
+ );
+ return true;
};
false
},
@@ -84,33 +81,29 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
// Returns true if given type is `Any` trait.
fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool {
- if_chain! {
- if let TyKind::TraitObject(traits, ..) = t.kind;
- if !traits.is_empty();
- if let Some(trait_did) = traits[0].trait_ref.trait_def_id();
+ if let TyKind::TraitObject(traits, ..) = t.kind
+ && !traits.is_empty()
+ && let Some(trait_did) = traits[0].trait_ref.trait_def_id()
// Only Send/Sync can be used as additional traits, so it is enough to
// check only the first trait.
- if cx.tcx.is_diagnostic_item(sym::Any, trait_did);
- then {
- return true;
- }
+ && cx.tcx.is_diagnostic_item(sym::Any, trait_did)
+ {
+ return true;
}
false
}
fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: HirId) -> Option<GenericBounds<'tcx>> {
- if_chain! {
- if let Some(did) = cx.qpath_res(qpath, id).opt_def_id();
- if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did);
- if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
- if synthetic;
- if let Some(generics) = cx.tcx.hir().get_generics(id.owner.def_id);
- if let Some(pred) = generics.bounds_for_param(did.expect_local()).next();
- then {
- Some(pred.bounds)
- } else {
- None
- }
+ if let Some(did) = cx.qpath_res(qpath, id).opt_def_id()
+ && let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did)
+ && let GenericParamKind::Type { synthetic, .. } = generic_param.kind
+ && synthetic
+ && let Some(generics) = cx.tcx.hir().get_generics(id.owner.def_id)
+ && let Some(pred) = generics.bounds_for_param(did.expect_local()).next()
+ {
+ Some(pred.bounds)
+ } else {
+ None
}
}
diff --git a/src/tools/clippy/clippy_lints/src/types/box_collection.rs b/src/tools/clippy/clippy_lints/src/types/box_collection.rs
index 4a5a94f26..fc3420af0 100644
--- a/src/tools/clippy/clippy_lints/src/types/box_collection.rs
+++ b/src/tools/clippy/clippy_lints/src/types/box_collection.rs
@@ -8,30 +8,26 @@ use rustc_span::{sym, Symbol};
use super::BOX_COLLECTION;
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
- if_chain! {
- if Some(def_id) == cx.tcx.lang_items().owned_box();
- if let Some(item_type) = get_std_collection(cx, qpath);
- then {
- let generic = match item_type {
- sym::String => "",
- _ => "<..>",
- };
+ if Some(def_id) == cx.tcx.lang_items().owned_box()
+ && let Some(item_type) = get_std_collection(cx, qpath)
+ {
+ let generic = match item_type {
+ sym::String => "",
+ _ => "<..>",
+ };
- let box_content = format!("{item_type}{generic}");
- span_lint_and_help(
- cx,
- BOX_COLLECTION,
- hir_ty.span,
- &format!(
- "you seem to be trying to use `Box<{box_content}>`. Consider using just `{box_content}`"),
- None,
- &format!(
- "`{box_content}` is already on the heap, `Box<{box_content}>` makes an extra allocation")
- );
- true
- } else {
- false
- }
+ let box_content = format!("{item_type}{generic}");
+ span_lint_and_help(
+ cx,
+ BOX_COLLECTION,
+ hir_ty.span,
+ &format!("you seem to be trying to use `Box<{box_content}>`. Consider using just `{box_content}`"),
+ None,
+ &format!("`{box_content}` is already on the heap, `Box<{box_content}>` makes an extra allocation"),
+ );
+ true
+ } else {
+ false
}
}
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 6a6160c49..81efec653 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -16,7 +16,7 @@ use rustc_hir::{
TraitItemKind, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
@@ -321,10 +321,10 @@ impl<'tcx> LateLintPass<'tcx> for Types {
_: Span,
def_id: LocalDefId,
) {
- let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(
+ let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx.tcx.opt_hir_node_by_def_id(
cx.tcx
.hir()
- .get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(def_id))
+ .get_parent_item(cx.tcx.local_def_id_to_hir_id(def_id))
.def_id,
) {
matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
@@ -368,8 +368,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
ImplItemKind::Const(ty, _) => {
let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx
.tcx
- .hir()
- .find_by_def_id(cx.tcx.hir().get_parent_item(item.hir_id()).def_id)
+ .opt_hir_node_by_def_id(cx.tcx.hir().get_parent_item(item.hir_id()).def_id)
{
matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
} else {
@@ -490,7 +489,7 @@ impl Types {
// All lints that are being checked in this block are guarded by
// the `avoid_breaking_exported_api` configuration. When adding a
// new lint, please also add the name to the configuration documentation
- // in `clippy_lints::utils::conf.rs`
+ // in `clippy_config::conf`
let mut triggered = false;
triggered |= box_collection::check(cx, hir_ty, qpath, def_id);
diff --git a/src/tools/clippy/clippy_lints/src/types/option_option.rs b/src/tools/clippy/clippy_lints/src/types/option_option.rs
index 60622903a..d12d14f2b 100644
--- a/src/tools/clippy/clippy_lints/src/types/option_option.rs
+++ b/src/tools/clippy/clippy_lints/src/types/option_option.rs
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{path_def_id, qpath_generic_tys};
-use if_chain::if_chain;
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, QPath};
use rustc_lint::LateContext;
@@ -9,21 +8,19 @@ use rustc_span::symbol::sym;
use super::OPTION_OPTION;
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
- if_chain! {
- if cx.tcx.is_diagnostic_item(sym::Option, def_id);
- if let Some(arg) = qpath_generic_tys(qpath).next();
- if path_def_id(cx, arg) == Some(def_id);
- then {
- span_lint(
- cx,
- OPTION_OPTION,
- hir_ty.span,
- "consider using `Option<T>` instead of `Option<Option<T>>` or a custom \
- enum if you need to distinguish all 3 cases",
- );
- true
- } else {
- false
- }
+ if cx.tcx.is_diagnostic_item(sym::Option, def_id)
+ && let Some(arg) = qpath_generic_tys(qpath).next()
+ && path_def_id(cx, arg) == Some(def_id)
+ {
+ span_lint(
+ cx,
+ OPTION_OPTION,
+ hir_ty.span,
+ "consider using `Option<T>` instead of `Option<Option<T>>` or a custom \
+ enum if you need to distinguish all 3 cases",
+ );
+ true
+ } else {
+ false
}
}
diff --git a/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs b/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
index a616c3e4e..afc319217 100644
--- a/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{path_def_id, qpath_generic_tys};
-use if_chain::if_chain;
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, QPath};
use rustc_lint::LateContext;
@@ -9,22 +8,20 @@ use rustc_span::symbol::sym;
use super::RC_MUTEX;
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
- if_chain! {
- if cx.tcx.is_diagnostic_item(sym::Rc, def_id) ;
- if let Some(arg) = qpath_generic_tys(qpath).next();
- if let Some(id) = path_def_id(cx, arg);
- if cx.tcx.is_diagnostic_item(sym::Mutex, id);
- then {
- span_lint_and_help(
- cx,
- RC_MUTEX,
- hir_ty.span,
- "usage of `Rc<Mutex<_>>`",
- None,
- "consider using `Rc<RefCell<_>>` or `Arc<Mutex<_>>` instead",
- );
- return true;
- }
+ if cx.tcx.is_diagnostic_item(sym::Rc, def_id)
+ && let Some(arg) = qpath_generic_tys(qpath).next()
+ && let Some(id) = path_def_id(cx, arg)
+ && cx.tcx.is_diagnostic_item(sym::Mutex, id)
+ {
+ span_lint_and_help(
+ cx,
+ RC_MUTEX,
+ hir_ty.span,
+ "usage of `Rc<Mutex<_>>`",
+ None,
+ "consider using `Rc<RefCell<_>>` or `Arc<Mutex<_>>` instead",
+ );
+ return true;
}
false
diff --git a/src/tools/clippy/clippy_lints/src/types/utils.rs b/src/tools/clippy/clippy_lints/src/types/utils.rs
index 39469841b..0bca56b8d 100644
--- a/src/tools/clippy/clippy_lints/src/types/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/types/utils.rs
@@ -1,22 +1,19 @@
use clippy_utils::last_path_segment;
-use if_chain::if_chain;
use rustc_hir::{GenericArg, GenericArgsParentheses, QPath, TyKind};
use rustc_lint::LateContext;
use rustc_span::Span;
pub(super) fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Span> {
let last = last_path_segment(qpath);
- if_chain! {
- if let Some(params) = last.args;
- if params.parenthesized == GenericArgsParentheses::No;
- if let Some(ty) = params.args.iter().find_map(|arg| match arg {
+ if let Some(params) = last.args
+ && params.parenthesized == GenericArgsParentheses::No
+ && let Some(ty) = params.args.iter().find_map(|arg| match arg {
GenericArg::Type(ty) => Some(ty),
_ => None,
- });
- if let TyKind::Ref(..) = ty.kind;
- then {
- return Some(ty.span);
- }
+ })
+ && let TyKind::Ref(..) = ty.kind
+ {
+ return Some(ty.span);
}
None
}
diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
index decc183ad..9d5066199 100644
--- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::last_path_segment;
+use clippy_utils::paths::ALLOCATOR_GLOBAL;
use clippy_utils::source::snippet;
-use if_chain::if_chain;
+use clippy_utils::{last_path_segment, match_def_path};
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, GenericArg, QPath, TyKind};
@@ -21,43 +21,57 @@ pub(super) fn check(
box_size_threshold: u64,
) -> bool {
if cx.tcx.is_diagnostic_item(sym::Vec, def_id) {
- if_chain! {
+ if let Some(last) = last_path_segment(qpath).args
// Get the _ part of Vec<_>
- if let Some(last) = last_path_segment(qpath).args;
- if let Some(ty) = last.args.iter().find_map(|arg| match arg {
- GenericArg::Type(ty) => Some(ty),
- _ => None,
- });
+ && let Some(GenericArg::Type(ty)) = last.args.first()
+ // extract allocator from the Vec for later
+ && let vec_alloc_ty = last.args.get(1)
// ty is now _ at this point
- if let TyKind::Path(ref ty_qpath) = ty.kind;
- let res = cx.qpath_res(ty_qpath, ty.hir_id);
- if let Some(def_id) = res.opt_def_id();
- if Some(def_id) == cx.tcx.lang_items().owned_box();
+ && let TyKind::Path(ref ty_qpath) = ty.kind
+ && let res = cx.qpath_res(ty_qpath, ty.hir_id)
+ && let Some(def_id) = res.opt_def_id()
+ && Some(def_id) == cx.tcx.lang_items().owned_box()
// At this point, we know ty is Box<T>, now get T
- if let Some(last) = last_path_segment(ty_qpath).args;
- if let Some(boxed_ty) = last.args.iter().find_map(|arg| match arg {
- GenericArg::Type(ty) => Some(ty),
- _ => None,
- });
- let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty);
- if !ty_ty.has_escaping_bound_vars();
- if ty_ty.is_sized(cx.tcx, cx.param_env);
- if let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes());
- if ty_ty_size < box_size_threshold;
- then {
- span_lint_and_sugg(
- cx,
- VEC_BOX,
- hir_ty.span,
- "`Vec<T>` is already on the heap, the boxing is unnecessary",
- "try",
- format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")),
- Applicability::MachineApplicable,
- );
- true
- } else {
- false
+ && let Some(last) = last_path_segment(ty_qpath).args
+ && let Some(GenericArg::Type(boxed_ty)) = last.args.first()
+ // extract allocator from the Box for later
+ && let boxed_alloc_ty = last.args.get(1)
+ && let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty)
+ && !ty_ty.has_escaping_bound_vars()
+ && ty_ty.is_sized(cx.tcx, cx.param_env)
+ && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes())
+ && ty_ty_size < box_size_threshold
+ // https://github.com/rust-lang/rust-clippy/issues/7114
+ && match (vec_alloc_ty, boxed_alloc_ty) {
+ (None, None) => true,
+ // this is in the event that we have something like
+ // Vec<_, Global>, in which case is equivalent to
+ // Vec<_>
+ (None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => {
+ if let TyKind::Path(path) = inner.kind
+ && let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() {
+ match_def_path(cx, did, &ALLOCATOR_GLOBAL)
+ } else {
+ false
+ }
+ },
+ (Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) =>
+ hir_ty_to_ty(cx.tcx, l) == hir_ty_to_ty(cx.tcx, r),
+ _ => false
}
+ {
+ span_lint_and_sugg(
+ cx,
+ VEC_BOX,
+ hir_ty.span,
+ "`Vec<T>` is already on the heap, the boxing is unnecessary",
+ "try",
+ format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")),
+ Applicability::Unspecified,
+ );
+ true
+ } else {
+ false
}
} else {
false
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 32aebdd8c..7a6549a7c 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -11,7 +11,7 @@ use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{BytePos, Pos, RelativeBytePos, Span, SyntaxContext};
declare_clippy_lint! {
@@ -349,7 +349,7 @@ fn block_parents_have_safety_comment(
span,
owner_id,
..
- })) => (*span, cx.tcx.hir().local_def_id_to_hir_id(owner_id.def_id)),
+ })) => (*span, cx.tcx.local_def_id_to_hir_id(owner_id.def_id)),
_ => {
if is_branchy(expr) {
return false;
@@ -370,7 +370,7 @@ fn block_parents_have_safety_comment(
span,
owner_id,
..
- }) => (*span, cx.tcx.hir().local_def_id_to_hir_id(owner_id.def_id)),
+ }) => (*span, cx.tcx.local_def_id_to_hir_id(owner_id.def_id)),
_ => return false,
};
// if unsafe block is part of a let/const/static statement,
diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs
index b824deac2..3d319b9fe 100644
--- a/src/tools/clippy/clippy_lints/src/unicode.rs
+++ b/src/tools/clippy/clippy_lints/src/unicode.rs
@@ -6,7 +6,7 @@ use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, HirId};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
use unicode_normalization::UnicodeNormalization;
diff --git a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs
new file mode 100644
index 000000000..903593ecf
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs
@@ -0,0 +1,84 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnRetTy, TyKind, UnOp};
+use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::declare_lint_pass;
+use rustc_span::def_id::LocalDefId;
+use rustc_span::Span;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// It detects references to uninhabited types, such as `!` and
+ /// warns when those are either dereferenced or returned from a function.
+ ///
+ /// ### Why is this bad?
+ /// Dereferencing a reference to an uninhabited type would create
+ /// an instance of such a type, which cannot exist. This constitutes
+ /// undefined behaviour. Such a reference could have been created
+ /// by `unsafe` code.
+ ///
+ /// ### Example
+ /// The following function can return a reference to an uninhabited type
+ /// (`Infallible`) because it uses `unsafe` code to create it. However,
+ /// the user of such a function could dereference the return value and
+ /// trigger an undefined behavior from safe code.
+ ///
+ /// ```no_run
+ /// fn create_ref() -> &'static std::convert::Infallible {
+ /// unsafe { std::mem::transmute(&()) }
+ /// }
+ /// ```
+ #[clippy::version = "1.76.0"]
+ pub UNINHABITED_REFERENCES,
+ nursery,
+ "reference to uninhabited type"
+}
+
+declare_lint_pass!(UninhabitedReferences => [UNINHABITED_REFERENCES]);
+
+impl LateLintPass<'_> for UninhabitedReferences {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
+ if in_external_macro(cx.tcx.sess, expr.span) {
+ return;
+ }
+
+ if let ExprKind::Unary(UnOp::Deref, _) = expr.kind {
+ let ty = cx.typeck_results().expr_ty_adjusted(expr);
+ if ty.is_privately_uninhabited(cx.tcx, cx.param_env) {
+ span_lint(
+ cx,
+ UNINHABITED_REFERENCES,
+ expr.span,
+ "dereferencing a reference to an uninhabited type is undefined behavior",
+ );
+ }
+ }
+ }
+
+ fn check_fn(
+ &mut self,
+ cx: &LateContext<'_>,
+ kind: FnKind<'_>,
+ fndecl: &'_ FnDecl<'_>,
+ _: &'_ Body<'_>,
+ span: Span,
+ _: LocalDefId,
+ ) {
+ if in_external_macro(cx.tcx.sess, span) || matches!(kind, FnKind::Closure) {
+ return;
+ }
+ if let FnRetTy::Return(hir_ty) = fndecl.output
+ && let TyKind::Ref(_, mut_ty) = hir_ty.kind
+ && hir_ty_to_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.param_env)
+ {
+ span_lint(
+ cx,
+ UNINHABITED_REFERENCES,
+ hir_ty.span,
+ "dereferencing a reference to an uninhabited type would be undefined behavior",
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index 72569e10f..fc8519d56 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -6,7 +6,7 @@ use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKi
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, Span};
// TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std
@@ -83,41 +83,39 @@ fn handle_uninit_vec_pair<'tcx>(
maybe_init_or_reserve: &'tcx Stmt<'tcx>,
maybe_set_len: &'tcx Expr<'tcx>,
) {
- if_chain! {
- if let Some(vec) = extract_init_or_reserve_target(cx, maybe_init_or_reserve);
- if let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len);
- if vec.location.eq_expr(cx, set_len_self);
- if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind();
- if let ty::Adt(_, args) = vec_ty.kind();
+ if let Some(vec) = extract_init_or_reserve_target(cx, maybe_init_or_reserve)
+ && let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len)
+ && vec.location.eq_expr(cx, set_len_self)
+ && let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind()
+ && let ty::Adt(_, args) = vec_ty.kind()
// `#[allow(...)]` attribute can be set on enclosing unsafe block of `set_len()`
- if !is_lint_allowed(cx, UNINIT_VEC, maybe_set_len.hir_id);
- then {
- if vec.has_capacity() {
- // with_capacity / reserve -> set_len
+ && !is_lint_allowed(cx, UNINIT_VEC, maybe_set_len.hir_id)
+ {
+ if vec.has_capacity() {
+ // with_capacity / reserve -> set_len
- // Check T of Vec<T>
- if !is_uninit_value_valid_for_ty(cx, args.type_at(0)) {
- // FIXME: #7698, false positive of the internal lints
- #[expect(clippy::collapsible_span_lint_calls)]
- span_lint_and_then(
- cx,
- UNINIT_VEC,
- vec![call_span, maybe_init_or_reserve.span],
- "calling `set_len()` immediately after reserving a buffer creates uninitialized values",
- |diag| {
- diag.help("initialize the buffer or wrap the content in `MaybeUninit`");
- },
- );
- }
- } else {
- // new / default -> set_len
- span_lint(
+ // Check T of Vec<T>
+ if !is_uninit_value_valid_for_ty(cx, args.type_at(0)) {
+ // FIXME: #7698, false positive of the internal lints
+ #[expect(clippy::collapsible_span_lint_calls)]
+ span_lint_and_then(
cx,
UNINIT_VEC,
vec![call_span, maybe_init_or_reserve.span],
- "calling `set_len()` on empty `Vec` creates out-of-bound values",
+ "calling `set_len()` immediately after reserving a buffer creates uninitialized values",
+ |diag| {
+ diag.help("initialize the buffer or wrap the content in `MaybeUninit`");
+ },
);
}
+ } else {
+ // new / default -> set_len
+ span_lint(
+ cx,
+ UNINIT_VEC,
+ vec![call_span, maybe_init_or_reserve.span],
+ "calling `set_len()` on empty `Vec` creates out-of-bound values",
+ );
}
}
}
@@ -156,16 +154,14 @@ impl<'tcx> VecLocation<'tcx> {
fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> Option<TargetVec<'tcx>> {
match stmt.kind {
StmtKind::Local(local) => {
- if_chain! {
- if let Some(init_expr) = local.init;
- if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind;
- if let Some(init_kind) = get_vec_init_kind(cx, init_expr);
- then {
- return Some(TargetVec {
- location: VecLocation::Local(hir_id),
- init_kind: Some(init_kind),
- })
- }
+ if let Some(init_expr) = local.init
+ && let PatKind::Binding(_, hir_id, _, None) = local.pat.kind
+ && let Some(init_kind) = get_vec_init_kind(cx, init_expr)
+ {
+ return Some(TargetVec {
+ location: VecLocation::Local(hir_id),
+ init_kind: Some(init_kind),
+ });
}
},
StmtKind::Expr(expr) | StmtKind::Semi(expr) => match expr.kind {
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index e76cc65fd..729972de6 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use if_chain::if_chain;
use rustc_hir::def_id::DefId;
use rustc_hir::{Closure, Expr, ExprKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::{ClauseKind, GenericPredicates, ProjectionPredicate, TraitPredicate};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, BytePos, Span};
declare_clippy_lint! {
@@ -44,14 +43,14 @@ fn get_trait_predicates_for_trait_id<'tcx>(
) -> Vec<TraitPredicate<'tcx>> {
let mut preds = Vec::new();
for (pred, _) in generics.predicates {
- if_chain! {
- if let ClauseKind::Trait(poly_trait_pred) = pred.kind().skip_binder();
- let trait_pred = cx.tcx.erase_late_bound_regions(pred.kind().rebind(poly_trait_pred));
- if let Some(trait_def_id) = trait_id;
- if trait_def_id == trait_pred.trait_ref.def_id;
- then {
- preds.push(trait_pred);
- }
+ if let ClauseKind::Trait(poly_trait_pred) = pred.kind().skip_binder()
+ && let trait_pred = cx
+ .tcx
+ .instantiate_bound_regions_with_erased(pred.kind().rebind(poly_trait_pred))
+ && let Some(trait_def_id) = trait_id
+ && trait_def_id == trait_pred.trait_ref.def_id
+ {
+ preds.push(trait_pred);
}
}
preds
@@ -64,7 +63,9 @@ fn get_projection_pred<'tcx>(
) -> Option<ProjectionPredicate<'tcx>> {
generics.predicates.iter().find_map(|(proj_pred, _)| {
if let ClauseKind::Projection(pred) = proj_pred.kind().skip_binder() {
- let projection_pred = cx.tcx.erase_late_bound_regions(proj_pred.kind().rebind(pred));
+ let projection_pred = cx
+ .tcx
+ .instantiate_bound_regions_with_erased(proj_pred.kind().rebind(pred));
if projection_pred.projection_ty.args == trait_pred.trait_ref.args {
return Some(projection_pred);
}
@@ -82,10 +83,10 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
let ord_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.get_diagnostic_item(sym::Ord));
let partial_ord_preds =
get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().partial_ord_trait());
- // Trying to call erase_late_bound_regions on fn_sig.inputs() gives the following error
+ // Trying to call instantiate_bound_regions_with_erased on fn_sig.inputs() gives the following error
// The trait `rustc::ty::TypeFoldable<'_>` is not implemented for
// `&[rustc_middle::ty::Ty<'_>]`
- let inputs_output = cx.tcx.erase_late_bound_regions(fn_sig.inputs_and_output());
+ let inputs_output = cx.tcx.instantiate_bound_regions_with_erased(fn_sig.inputs_and_output());
inputs_output
.iter()
.rev()
@@ -94,21 +95,19 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
.enumerate()
.for_each(|(i, inp)| {
for trait_pred in &fn_mut_preds {
- if_chain! {
- if trait_pred.self_ty() == inp;
- if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
- then {
- if ord_preds
- .iter()
- .any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty())
- {
- args_to_check.push((i, "Ord".to_string()));
- } else if partial_ord_preds
- .iter()
- .any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap())
- {
- args_to_check.push((i, "PartialOrd".to_string()));
- }
+ if trait_pred.self_ty() == inp
+ && let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred)
+ {
+ if ord_preds
+ .iter()
+ .any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty())
+ {
+ args_to_check.push((i, "Ord".to_string()));
+ } else if partial_ord_preds
+ .iter()
+ .any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap())
+ {
+ args_to_check.push((i, "PartialOrd".to_string()));
}
}
}
@@ -118,30 +117,26 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
}
fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Span, Option<Span>)> {
- if_chain! {
- if let ExprKind::Closure(&Closure { body, fn_decl_span, .. }) = arg.kind;
- if let ty::Closure(_def_id, args) = &cx.typeck_results().node_type(arg.hir_id).kind();
- let ret_ty = args.as_closure().sig().output();
- let ty = cx.tcx.erase_late_bound_regions(ret_ty);
- if ty.is_unit();
- then {
- let body = cx.tcx.hir().body(body);
- if_chain! {
- if let ExprKind::Block(block, _) = body.value.kind;
- if block.expr.is_none();
- if let Some(stmt) = block.stmts.last();
- if let StmtKind::Semi(_) = stmt.kind;
- then {
- let data = stmt.span.data();
- // Make a span out of the semicolon for the help message
- Some((fn_decl_span, Some(data.with_lo(data.hi-BytePos(1)))))
- } else {
- Some((fn_decl_span, None))
- }
- }
+ if let ExprKind::Closure(&Closure { body, fn_decl_span, .. }) = arg.kind
+ && let ty::Closure(_def_id, args) = &cx.typeck_results().node_type(arg.hir_id).kind()
+ && let ret_ty = args.as_closure().sig().output()
+ && let ty = cx.tcx.instantiate_bound_regions_with_erased(ret_ty)
+ && ty.is_unit()
+ {
+ let body = cx.tcx.hir().body(body);
+ if let ExprKind::Block(block, _) = body.value.kind
+ && block.expr.is_none()
+ && let Some(stmt) = block.stmts.last()
+ && let StmtKind::Semi(_) = stmt.kind
+ {
+ let data = stmt.span.data();
+ // Make a span out of the semicolon for the help message
+ Some((fn_decl_span, Some(data.with_lo(data.hi - BytePos(1)))))
} else {
- None
+ Some((fn_decl_span, None))
}
+ } else {
+ None
}
}
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
index 884c6ca4d..0abd48e64 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
@@ -5,7 +5,7 @@ mod utils;
use rustc_hir::{Expr, Local};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
index 462b1aa81..44cff78a7 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_from_proc_macro;
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{self as hir, Block, Expr, ExprKind, MatchSource, Node, StmtKind};
use rustc_lint::LateContext;
@@ -22,12 +21,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
}
let map = &cx.tcx.hir();
let opt_parent_node = map.find_parent(expr.hir_id);
- if_chain! {
- if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node;
- if is_questionmark_desugar_marked_call(parent_expr);
- then {
- return;
- }
+ if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node
+ && is_questionmark_desugar_marked_call(parent_expr)
+ {
+ return;
}
let args: Vec<_> = match expr.kind {
@@ -80,21 +77,15 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
args_to_recover
.iter()
.filter_map(|arg| {
- if_chain! {
- if let ExprKind::Block(block, _) = arg.kind;
- if block.expr.is_none();
- if let Some(last_stmt) = block.stmts.iter().last();
- if let StmtKind::Semi(last_expr) = last_stmt.kind;
- if let Some(snip) = snippet_opt(cx, last_expr.span);
- then {
- Some((
- last_stmt.span,
- snip,
- ))
- }
- else {
- None
- }
+ if let ExprKind::Block(block, _) = arg.kind
+ && block.expr.is_none()
+ && let Some(last_stmt) = block.stmts.iter().last()
+ && let StmtKind::Semi(last_expr) = last_stmt.kind
+ && let Some(snip) = snippet_opt(cx, last_expr.span)
+ {
+ Some((last_stmt.span, snip))
+ } else {
+ None
}
})
.for_each(|(span, sugg)| {
diff --git a/src/tools/clippy/clippy_lints/src/unnamed_address.rs b/src/tools/clippy/clippy_lints/src/unnamed_address.rs
index e7355f923..cd2dacc9f 100644
--- a/src/tools/clippy/clippy_lints/src/unnamed_address.rs
+++ b/src/tools/clippy/clippy_lints/src/unnamed_address.rs
@@ -1,10 +1,8 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use if_chain::if_chain;
+use clippy_utils::diagnostics::span_lint;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -30,31 +28,7 @@ declare_clippy_lint! {
"comparison with an address of a function item"
}
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for comparisons with an address of a trait vtable.
- ///
- /// ### Why is this bad?
- /// Comparing trait objects pointers compares an vtable addresses which
- /// are not guaranteed to be unique and could vary between different code generation units.
- /// Furthermore vtables for different types could have the same address after being merged
- /// together.
- ///
- /// ### Example
- /// ```rust,ignore
- /// let a: Rc<dyn Trait> = ...
- /// let b: Rc<dyn Trait> = ...
- /// if Rc::ptr_eq(&a, &b) {
- /// ...
- /// }
- /// ```
- #[clippy::version = "1.44.0"]
- pub VTABLE_ADDRESS_COMPARISONS,
- correctness,
- "comparison with an address of a trait vtable"
-}
-
-declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS, VTABLE_ADDRESS_COMPARISONS]);
+declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS]);
impl LateLintPass<'_> for UnnamedAddress {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
@@ -65,66 +39,22 @@ impl LateLintPass<'_> for UnnamedAddress {
)
}
- fn is_trait_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- match cx.typeck_results().expr_ty_adjusted(expr).kind() {
- ty::RawPtr(ty::TypeAndMut { ty, .. }) => ty.is_trait(),
- _ => false,
- }
- }
-
fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
matches!(cx.typeck_results().expr_ty(expr).kind(), ty::FnDef(..))
}
- if_chain! {
- if let ExprKind::Binary(binop, left, right) = expr.kind;
- if is_comparison(binop.node);
- if is_trait_ptr(cx, left) && is_trait_ptr(cx, right);
- then {
- span_lint_and_help(
- cx,
- VTABLE_ADDRESS_COMPARISONS,
- expr.span,
- "comparing trait object pointers compares a non-unique vtable address",
- None,
- "consider extracting and comparing data pointers only",
- );
- }
- }
-
- if_chain! {
- if let ExprKind::Call(func, [ref _left, ref _right]) = expr.kind;
- if let ExprKind::Path(ref func_qpath) = func.kind;
- if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
- if cx.tcx.is_diagnostic_item(sym::ptr_eq, def_id);
- let ty_param = cx.typeck_results().node_args(func.hir_id).type_at(0);
- if ty_param.is_trait();
- then {
- span_lint_and_help(
- cx,
- VTABLE_ADDRESS_COMPARISONS,
- expr.span,
- "comparing trait object pointers compares a non-unique vtable address",
- None,
- "consider extracting and comparing data pointers only",
- );
- }
- }
-
- if_chain! {
- if let ExprKind::Binary(binop, left, right) = expr.kind;
- if is_comparison(binop.node);
- if cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr();
- if cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr();
- if is_fn_def(cx, left) || is_fn_def(cx, right);
- then {
- span_lint(
- cx,
- FN_ADDRESS_COMPARISONS,
- expr.span,
- "comparing with a non-unique address of a function item",
- );
- }
+ if let ExprKind::Binary(binop, left, right) = expr.kind
+ && is_comparison(binop.node)
+ && cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr()
+ && cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr()
+ && (is_fn_def(cx, left) || is_fn_def(cx, right))
+ {
+ span_lint(
+ cx,
+ FN_ADDRESS_COMPARISONS,
+ expr.span,
+ "comparing with a non-unique address of a function item",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
index ca159eb4d..f5af540fa 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
@@ -4,7 +4,7 @@ use rustc_errors::Applicability;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::{FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::Symbol;
declare_clippy_lint! {
@@ -71,7 +71,7 @@ impl UnnecessaryBoxReturns {
let return_ty = cx
.tcx
- .erase_late_bound_regions(cx.tcx.fn_sig(def_id).skip_binder())
+ .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(def_id).skip_binder())
.output();
if !return_ty.is_box() {
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
index 9107b2b99..2b0d2d61d 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
@@ -4,26 +4,29 @@ use clippy_utils::ty::get_type_diagnostic_name;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
- /// Suggest removing the use of a may (or map_err) method when an Option or Result is being constructed.
+ /// Suggests removing the use of a `map()` (or `map_err()`) method when an `Option` or `Result`
+ /// is being constructed.
///
/// ### Why is this bad?
- /// It introduces unnecessary complexity. In this case the function can be used directly and
- /// construct the Option or Result from the output.
+ /// It introduces unnecessary complexity. Instead, the function can be called before
+ /// constructing the `Option` or `Result` from its return value.
///
/// ### Example
/// ```no_run
- /// Some(4).map(i32::swap_bytes);
+ /// Some(4).map(i32::swap_bytes)
+ /// # ;
/// ```
/// Use instead:
/// ```no_run
- /// Some(i32::swap_bytes(4));
+ /// Some(i32::swap_bytes(4))
+ /// # ;
/// ```
- #[clippy::version = "1.73.0"]
+ #[clippy::version = "1.74.0"]
pub UNNECESSARY_MAP_ON_CONSTRUCTOR,
complexity,
"using `map`/`map_err` on `Option` or `Result` constructors"
@@ -59,11 +62,11 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor {
}
},
hir::QPath::TypeRelative(_, path) => path.ident.name,
- hir::QPath::LangItem(_, _, _) => return,
+ hir::QPath::LangItem(..) => return,
};
match constructor_symbol {
sym::Some | sym::Ok if path.ident.name == rustc_span::sym::map => (),
- sym::Err if path.ident.name == sym!(map_err) => (),
+ sym::Err if path.ident.name == sym::map_err => (),
_ => return,
}
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
index 28ea02e4d..6b5e6c6ab 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
@@ -1,13 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::is_type_lang_item;
use clippy_utils::{match_def_path, paths};
-use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
declare_clippy_lint! {
@@ -36,46 +35,40 @@ declare_lint_pass!(UnnecessaryOwnedEmptyStrings => [UNNECESSARY_OWNED_EMPTY_STRI
impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if_chain! {
- if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner_expr) = expr.kind;
- if let ExprKind::Call(fun, args) = inner_expr.kind;
- if let ExprKind::Path(ref qpath) = fun.kind;
- if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
- if let ty::Ref(_, inner_str, _) = cx.typeck_results().expr_ty_adjusted(expr).kind();
- if inner_str.is_str();
- then {
- if match_def_path(cx, fun_def_id, &paths::STRING_NEW) {
- span_lint_and_sugg(
- cx,
- UNNECESSARY_OWNED_EMPTY_STRINGS,
- expr.span,
- "usage of `&String::new()` for a function expecting a `&str` argument",
- "try",
- "\"\"".to_owned(),
- Applicability::MachineApplicable,
- );
- } else {
- if_chain! {
- if cx.tcx.is_diagnostic_item(sym::from_fn, fun_def_id);
- if let [.., last_arg] = args;
- if let ExprKind::Lit(spanned) = &last_arg.kind;
- if let LitKind::Str(symbol, _) = spanned.node;
- if symbol.is_empty();
- let inner_expr_type = cx.typeck_results().expr_ty(inner_expr);
- if is_type_lang_item(cx, inner_expr_type, LangItem::String);
- then {
- span_lint_and_sugg(
- cx,
- UNNECESSARY_OWNED_EMPTY_STRINGS,
- expr.span,
- "usage of `&String::from(\"\")` for a function expecting a `&str` argument",
- "try",
- "\"\"".to_owned(),
- Applicability::MachineApplicable,
- );
- }
- }
- }
+ if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner_expr) = expr.kind
+ && let ExprKind::Call(fun, args) = inner_expr.kind
+ && let ExprKind::Path(ref qpath) = fun.kind
+ && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
+ && let ty::Ref(_, inner_str, _) = cx.typeck_results().expr_ty_adjusted(expr).kind()
+ && inner_str.is_str()
+ {
+ if match_def_path(cx, fun_def_id, &paths::STRING_NEW) {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_OWNED_EMPTY_STRINGS,
+ expr.span,
+ "usage of `&String::new()` for a function expecting a `&str` argument",
+ "try",
+ "\"\"".to_owned(),
+ Applicability::MachineApplicable,
+ );
+ } else if cx.tcx.is_diagnostic_item(sym::from_fn, fun_def_id)
+ && let [.., last_arg] = args
+ && let ExprKind::Lit(spanned) = &last_arg.kind
+ && let LitKind::Str(symbol, _) = spanned.node
+ && symbol.is_empty()
+ && let inner_expr_type = cx.typeck_results().expr_ty(inner_expr)
+ && is_type_lang_item(cx, inner_expr_type, LangItem::String)
+ {
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_OWNED_EMPTY_STRINGS,
+ expr.span,
+ "usage of `&String::from(\"\")` for a function expecting a `&str` argument",
+ "try",
+ "\"\"".to_owned(),
+ Applicability::MachineApplicable,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
index a1083a0a6..ddee06b59 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
@@ -1,9 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use if_chain::if_chain;
use rustc_ast::{Item, ItemKind, UseTreeKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::kw;
declare_clippy_lint! {
@@ -36,35 +35,36 @@ declare_lint_pass!(UnnecessarySelfImports => [UNNECESSARY_SELF_IMPORTS]);
impl EarlyLintPass for UnnecessarySelfImports {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
- if_chain! {
- if let ItemKind::Use(use_tree) = &item.kind;
- if let UseTreeKind::Nested(nodes) = &use_tree.kind;
- if let [(self_tree, _)] = &**nodes;
- if let [self_seg] = &*self_tree.prefix.segments;
- if self_seg.ident.name == kw::SelfLower;
- if let Some(last_segment) = use_tree.prefix.segments.last();
-
- then {
- span_lint_and_then(
- cx,
- UNNECESSARY_SELF_IMPORTS,
- item.span,
- "import ending with `::{self}`",
- |diag| {
- diag.span_suggestion(
- last_segment.span().with_hi(item.span.hi()),
- "consider omitting `::{self}`",
- format!(
- "{}{};",
- last_segment.ident,
- if let UseTreeKind::Simple(Some(alias)) = self_tree.kind { format!(" as {alias}") } else { String::new() },
- ),
- Applicability::MaybeIncorrect,
- );
- diag.note("this will slightly change semantics; any non-module items at the same path will also be imported");
- },
- );
- }
+ if let ItemKind::Use(use_tree) = &item.kind
+ && let UseTreeKind::Nested(nodes) = &use_tree.kind
+ && let [(self_tree, _)] = &**nodes
+ && let [self_seg] = &*self_tree.prefix.segments
+ && self_seg.ident.name == kw::SelfLower
+ && let Some(last_segment) = use_tree.prefix.segments.last()
+ {
+ span_lint_and_then(
+ cx,
+ UNNECESSARY_SELF_IMPORTS,
+ item.span,
+ "import ending with `::{self}`",
+ |diag| {
+ diag.span_suggestion(
+ last_segment.span().with_hi(item.span.hi()),
+ "consider omitting `::{self}`",
+ format!(
+ "{}{};",
+ last_segment.ident,
+ if let UseTreeKind::Simple(Some(alias)) = self_tree.kind {
+ format!(" as {alias}")
+ } else {
+ String::new()
+ },
+ ),
+ Applicability::MaybeIncorrect,
+ );
+ diag.note("this will slightly change semantics; any non-module items at the same path will also be imported");
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs
index c35a2afab..333ea0c82 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs
@@ -4,7 +4,7 @@ use clippy_utils::ty::is_copy;
use clippy_utils::{get_parent_expr, path_to_local};
use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -82,7 +82,7 @@ impl LateLintPass<'_> for UnnecessaryStruct {
fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
if let Some(hir_id) = path_to_local(expr)
- && let Node::Pat(pat) = cx.tcx.hir().get(hir_id)
+ && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
{
matches!(pat.kind, PatKind::Binding(BindingAnnotation::MUT, ..))
} else {
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index ab8de17b0..446160f8e 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -2,14 +2,13 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use clippy_utils::visitors::find_all_ret_expressions;
use clippy_utils::{contains_return, is_res_lang_ctor, path_res, return_ty};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::LangItem::{OptionSome, ResultOk};
use rustc_hir::{Body, ExprKind, FnDecl, Impl, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::sym;
use rustc_span::Span;
@@ -92,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
}
// Abort if the method is implementing a trait or of it a trait method.
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
+ let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
if matches!(
item.kind,
@@ -119,28 +118,24 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
// Check if all return expression respect the following condition and collect them.
let mut suggs = Vec::new();
let can_sugg = find_all_ret_expressions(cx, body.value, |ret_expr| {
- if_chain! {
- if !ret_expr.span.from_expansion();
+ if !ret_expr.span.from_expansion()
// Check if a function call.
- if let ExprKind::Call(func, [arg]) = ret_expr.kind;
- if is_res_lang_ctor(cx, path_res(cx, func), lang_item);
+ && let ExprKind::Call(func, [arg]) = ret_expr.kind
+ && is_res_lang_ctor(cx, path_res(cx, func), lang_item)
// Make sure the function argument does not contain a return expression.
- if !contains_return(arg);
- then {
- suggs.push(
- (
- ret_expr.span,
- if inner_type.is_unit() {
- String::new()
- } else {
- snippet(cx, arg.span.source_callsite(), "..").to_string()
- }
- )
- );
- true
- } else {
- false
- }
+ && !contains_return(arg)
+ {
+ suggs.push((
+ ret_expr.span,
+ if inner_type.is_unit() {
+ String::new()
+ } else {
+ snippet(cx, arg.span.source_callsite(), "..").to_string()
+ },
+ ));
+ true
+ } else {
+ false
}
});
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 8ff088a20..65600009c 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -11,7 +11,7 @@ use rustc_ast::{self as ast, Mutability, Pat, PatKind, DUMMY_NODE_ID};
use rustc_ast_pretty::pprust;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::DUMMY_SP;
use std::cell::Cell;
use std::mem;
@@ -226,7 +226,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
// Therefore they are not some form of constructor `C`,
// with which a pattern `C(p_0)` may be formed,
// which we would want to join with other `C(p_j)`s.
- Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_)
+ Ident(.., None) | Lit(_) | Wild | Never | Path(..) | Range(..) | Rest | MacCall(_)
// Skip immutable refs, as grouping them saves few characters,
// and almost always requires adding parens (increasing noisiness).
// In the case of only two patterns, replacement adds net characters.
diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
index c43d5dc94..3f2f765f7 100644
--- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
+++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
@@ -1,9 +1,9 @@
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::Ident;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index aea72c798..9c8c44c0a 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -5,7 +5,7 @@ use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor};
use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::def_id::{LocalDefId, LocalDefIdSet};
use rustc_span::Span;
@@ -148,7 +148,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
// statements, so don't lint at all if there are any such paths.
if let Some(def_id) = path.res.opt_def_id()
&& let Some(local_def_id) = def_id.as_local()
- && let Some(DefKind::Fn) = cx.tcx.opt_def_kind(def_id)
+ && cx.tcx.def_kind(def_id) == DefKind::Fn
&& cx.tcx.asyncness(def_id).is_async()
&& !is_node_func_call(cx.tcx.hir().get_parent(hir_id), path.span)
{
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index 0fcb62017..1de9adfcb 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::{is_trait_method, is_try, match_trait_method, paths};
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
index 0473ecaab..ba72b3450 100644
--- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
@@ -6,7 +6,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter::OnlyBodies;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/unused_rounding.rs b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
index fbb36bea0..d5ca844b9 100644
--- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet;
use rustc_ast::ast::{Expr, ExprKind, MethodCall};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs
index f864c5203..a67f53f00 100644
--- a/src/tools/clippy/clippy_lints/src/unused_self.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_self.rs
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::visitors::is_local_used;
-use if_chain::if_chain;
use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use std::ops::ControlFlow;
declare_clippy_lint! {
@@ -73,25 +72,23 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf {
})
.is_some()
};
- if_chain! {
- if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind;
- if assoc_item.fn_has_self_parameter;
- if let ImplItemKind::Fn(.., body_id) = &impl_item.kind;
- if !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api;
- let body = cx.tcx.hir().body(*body_id);
- if let [self_param, ..] = body.params;
- if !is_local_used(cx, body, self_param.pat.hir_id);
- if !contains_todo(cx, body);
- then {
- span_lint_and_help(
- cx,
- UNUSED_SELF,
- self_param.span,
- "unused `self` argument",
- None,
- "consider refactoring to an associated function",
- );
- }
+ if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind
+ && assoc_item.fn_has_self_parameter
+ && let ImplItemKind::Fn(.., body_id) = &impl_item.kind
+ && (!cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api)
+ && let body = cx.tcx.hir().body(*body_id)
+ && let [self_param, ..] = body.params
+ && !is_local_used(cx, body, self_param.pat.hir_id)
+ && !contains_todo(cx, body)
+ {
+ span_lint_and_help(
+ cx,
+ UNUSED_SELF,
+ self_param.span,
+ "unused `self` argument",
+ None,
+ "consider refactoring to an associated function",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs
index adbf82813..0a73da202 100644
--- a/src/tools/clippy/clippy_lints/src/unused_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{position_before_rarrow, snippet_opt};
-use if_chain::if_chain;
use rustc_ast::visit::FnKind;
use rustc_ast::{ast, ClosureBinder};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{BytePos, Span};
declare_clippy_lint! {
@@ -37,40 +36,39 @@ declare_lint_pass!(UnusedUnit => [UNUSED_UNIT]);
impl EarlyLintPass for UnusedUnit {
fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) {
- if_chain! {
- if let ast::FnRetTy::Ty(ref ty) = kind.decl().output;
- if let ast::TyKind::Tup(ref vals) = ty.kind;
- if vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span);
- then {
- // implicit types in closure signatures are forbidden when `for<...>` is present
- if let FnKind::Closure(&ClosureBinder::For { .. }, ..) = kind {
- return;
- }
-
- lint_unneeded_unit_return(cx, ty, span);
+ if let ast::FnRetTy::Ty(ref ty) = kind.decl().output
+ && let ast::TyKind::Tup(ref vals) = ty.kind
+ && vals.is_empty()
+ && !ty.span.from_expansion()
+ && get_def(span) == get_def(ty.span)
+ {
+ // implicit types in closure signatures are forbidden when `for<...>` is present
+ if let FnKind::Closure(&ClosureBinder::For { .. }, ..) = kind {
+ return;
}
+
+ lint_unneeded_unit_return(cx, ty, span);
}
}
fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
- if_chain! {
- if let Some(stmt) = block.stmts.last();
- if let ast::StmtKind::Expr(ref expr) = stmt.kind;
- if is_unit_expr(expr);
- let ctxt = block.span.ctxt();
- if stmt.span.ctxt() == ctxt && expr.span.ctxt() == ctxt;
- then {
- let sp = expr.span;
- span_lint_and_sugg(
- cx,
- UNUSED_UNIT,
- sp,
- "unneeded unit expression",
- "remove the final `()`",
- String::new(),
- Applicability::MachineApplicable,
- );
- }
+ if let Some(stmt) = block.stmts.last()
+ && let ast::StmtKind::Expr(ref expr) = stmt.kind
+ && is_unit_expr(expr)
+ && let ctxt = block.span.ctxt()
+ && stmt.span.ctxt() == ctxt
+ && expr.span.ctxt() == ctxt
+ {
+ let sp = expr.span;
+ span_lint_and_sugg(
+ cx,
+ UNUSED_UNIT,
+ sp,
+ "unneeded unit expression",
+ "remove the final `()`",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
}
}
@@ -96,16 +94,14 @@ impl EarlyLintPass for UnusedUnit {
fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef) {
let segments = &poly.trait_ref.path.segments;
- if_chain! {
- if segments.len() == 1;
- if ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str());
- if let Some(args) = &segments[0].args;
- if let ast::GenericArgs::Parenthesized(generic_args) = &**args;
- if let ast::FnRetTy::Ty(ty) = &generic_args.output;
- if ty.kind.is_unit();
- then {
- lint_unneeded_unit_return(cx, ty, generic_args.span);
- }
+ if segments.len() == 1
+ && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str())
+ && let Some(args) = &segments[0].args
+ && let ast::GenericArgs::Parenthesized(generic_args) = &**args
+ && let ast::FnRetTy::Ty(ty) = &generic_args.output
+ && ty.kind.is_unit()
+ {
+ lint_unneeded_unit_return(cx, ty, generic_args.span);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index cdfcb8500..ae2ac38cf 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::usage::is_potentially_local_place;
use clippy_utils::{higher, path_to_local};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegment, UnOp};
@@ -13,7 +12,7 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro;
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span};
@@ -155,41 +154,35 @@ fn collect_unwrap_info<'tcx>(
}
} else if let ExprKind::Unary(UnOp::Not, expr) = &expr.kind {
return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false);
- } else {
- if_chain! {
- if let ExprKind::MethodCall(method_name, receiver, args, _) = &expr.kind;
- if let Some(local_id) = path_to_local(receiver);
- let ty = cx.typeck_results().expr_ty(receiver);
- let name = method_name.ident.as_str();
- if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name);
- then {
- assert!(args.is_empty());
- let unwrappable = match name {
- "is_some" | "is_ok" => true,
- "is_err" | "is_none" => false,
- _ => unreachable!(),
- };
- let safe_to_unwrap = unwrappable != invert;
- let kind = if is_type_diagnostic_item(cx, ty, sym::Option) {
- UnwrappableKind::Option
- } else {
- UnwrappableKind::Result
- };
+ } else if let ExprKind::MethodCall(method_name, receiver, args, _) = &expr.kind
+ && let Some(local_id) = path_to_local(receiver)
+ && let ty = cx.typeck_results().expr_ty(receiver)
+ && let name = method_name.ident.as_str()
+ && (is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name))
+ {
+ assert!(args.is_empty());
+ let unwrappable = match name {
+ "is_some" | "is_ok" => true,
+ "is_err" | "is_none" => false,
+ _ => unreachable!(),
+ };
+ let safe_to_unwrap = unwrappable != invert;
+ let kind = if is_type_diagnostic_item(cx, ty, sym::Option) {
+ UnwrappableKind::Option
+ } else {
+ UnwrappableKind::Result
+ };
- return vec![
- UnwrapInfo {
- local_id,
- if_expr,
- check: expr,
- check_name: method_name,
- branch,
- safe_to_unwrap,
- kind,
- is_entire_condition,
- }
- ]
- }
- }
+ return vec![UnwrapInfo {
+ local_id,
+ if_expr,
+ check: expr,
+ check_name: method_name,
+ branch,
+ safe_to_unwrap,
+ kind,
+ is_entire_condition,
+ }];
}
Vec::new()
}
@@ -319,73 +312,72 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
}
} else {
// find `unwrap[_err]()` calls:
- if_chain! {
- if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind;
- let (self_arg, as_ref_kind) = consume_option_as_ref(self_arg);
- if let Some(id) = path_to_local(self_arg);
- if [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name);
- let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name);
- if let Some(unwrappable) = self.unwrappables.iter()
- .find(|u| u.local_id == id);
+ if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind
+ && let (self_arg, as_ref_kind) = consume_option_as_ref(self_arg)
+ && let Some(id) = path_to_local(self_arg)
+ && [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name)
+ && let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name)
+ && let Some(unwrappable) = self.unwrappables.iter()
+ .find(|u| u.local_id == id)
// Span contexts should not differ with the conditional branch
- let span_ctxt = expr.span.ctxt();
- if unwrappable.branch.span.ctxt() == span_ctxt;
- if unwrappable.check.span.ctxt() == span_ctxt;
- then {
- if call_to_unwrap == unwrappable.safe_to_unwrap {
- let is_entire_condition = unwrappable.is_entire_condition;
- let unwrappable_variable_name = self.cx.tcx.hir().name(unwrappable.local_id);
- let suggested_pattern = if call_to_unwrap {
- unwrappable.kind.success_variant_pattern()
- } else {
- unwrappable.kind.error_variant_pattern()
- };
-
- span_lint_hir_and_then(
- self.cx,
- UNNECESSARY_UNWRAP,
- expr.hir_id,
- expr.span,
- &format!(
- "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`",
- method_name.ident.name,
- unwrappable.check_name.ident.as_str(),
- ),
- |diag| {
- if is_entire_condition {
- diag.span_suggestion(
- unwrappable.check.span.with_lo(unwrappable.if_expr.span.lo()),
- "try",
- format!(
- "if let {suggested_pattern} = {borrow_prefix}{unwrappable_variable_name}",
- borrow_prefix = match as_ref_kind {
- Some(AsRefKind::AsRef) => "&",
- Some(AsRefKind::AsMut) => "&mut ",
- None => "",
- },
- ),
- // We don't track how the unwrapped value is used inside the
- // block or suggest deleting the unwrap, so we can't offer a
- // fixable solution.
- Applicability::Unspecified,
- );
- } else {
- diag.span_label(unwrappable.check.span, "the check is happening here");
- diag.help("try using `if let` or `match`");
- }
- },
- );
+ && let span_ctxt = expr.span.ctxt()
+ && unwrappable.branch.span.ctxt() == span_ctxt
+ && unwrappable.check.span.ctxt() == span_ctxt
+ {
+ if call_to_unwrap == unwrappable.safe_to_unwrap {
+ let is_entire_condition = unwrappable.is_entire_condition;
+ let unwrappable_variable_name = self.cx.tcx.hir().name(unwrappable.local_id);
+ let suggested_pattern = if call_to_unwrap {
+ unwrappable.kind.success_variant_pattern()
} else {
- span_lint_hir_and_then(
- self.cx,
- PANICKING_UNWRAP,
- expr.hir_id,
- expr.span,
- &format!("this call to `{}()` will always panic",
- method_name.ident.name),
- |diag| { diag.span_label(unwrappable.check.span, "because of this check"); },
- );
- }
+ unwrappable.kind.error_variant_pattern()
+ };
+
+ span_lint_hir_and_then(
+ self.cx,
+ UNNECESSARY_UNWRAP,
+ expr.hir_id,
+ expr.span,
+ &format!(
+ "called `{}` on `{unwrappable_variable_name}` after checking its variant with `{}`",
+ method_name.ident.name,
+ unwrappable.check_name.ident.as_str(),
+ ),
+ |diag| {
+ if is_entire_condition {
+ diag.span_suggestion(
+ unwrappable.check.span.with_lo(unwrappable.if_expr.span.lo()),
+ "try",
+ format!(
+ "if let {suggested_pattern} = {borrow_prefix}{unwrappable_variable_name}",
+ borrow_prefix = match as_ref_kind {
+ Some(AsRefKind::AsRef) => "&",
+ Some(AsRefKind::AsMut) => "&mut ",
+ None => "",
+ },
+ ),
+ // We don't track how the unwrapped value is used inside the
+ // block or suggest deleting the unwrap, so we can't offer a
+ // fixable solution.
+ Applicability::Unspecified,
+ );
+ } else {
+ diag.span_label(unwrappable.check.span, "the check is happening here");
+ diag.help("try using `if let` or `match`");
+ }
+ },
+ );
+ } else {
+ span_lint_hir_and_then(
+ self.cx,
+ PANICKING_UNWRAP,
+ expr.hir_id,
+ expr.span,
+ &format!("this call to `{}()` will always panic", method_name.ident.name),
+ |diag| {
+ diag.span_label(unwrappable.check.span, "because of this check");
+ },
+ );
}
}
walk_expr(self, expr);
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index 21592abbf..a615ef116 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -3,11 +3,10 @@ use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::for_each_expr;
use clippy_utils::{method_chain_args, return_ty};
use core::ops::ControlFlow;
-use if_chain::if_chain;
use rustc_hir as hir;
use rustc_hir::ImplItemKind;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::{sym, Span};
declare_clippy_lint! {
@@ -60,15 +59,13 @@ declare_lint_pass!(UnwrapInResult=> [UNWRAP_IN_RESULT]);
impl<'tcx> LateLintPass<'tcx> for UnwrapInResult {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
- if_chain! {
+ if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind
// first check if it's a method or function
- if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind;
// checking if its return type is `result` or `option`
- if is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Result)
- || is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Option);
- then {
- lint_impl_body(cx, impl_item.span, impl_item);
- }
+ && (is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Result)
+ || is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Option))
+ {
+ lint_impl_body(cx, impl_item.span, impl_item);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
index de6a75b79..d2a1d42f2 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -1,10 +1,10 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
use itertools::Itertools;
use rustc_errors::Applicability;
-use rustc_hir::{Item, ItemKind};
+use rustc_hir::{HirId, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::Ident;
declare_clippy_lint! {
@@ -77,7 +77,7 @@ fn correct_ident(ident: &str) -> String {
ident
}
-fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) {
+fn check_ident(cx: &LateContext<'_>, ident: &Ident, hir_id: HirId, be_aggressive: bool) {
let span = ident.span;
let ident = ident.as_str();
let corrected = correct_ident(ident);
@@ -89,14 +89,20 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) {
// upper-case-acronyms-aggressive config option enabled
|| (be_aggressive && ident != corrected)
{
- span_lint_and_sugg(
+ span_lint_hir_and_then(
cx,
UPPER_CASE_ACRONYMS,
+ hir_id,
span,
&format!("name `{ident}` contains a capitalized acronym"),
- "consider making the acronym lowercase, except the initial letter",
- corrected,
- Applicability::MaybeIncorrect,
+ |diag| {
+ diag.span_suggestion(
+ span,
+ "consider making the acronym lowercase, except the initial letter",
+ corrected,
+ Applicability::MaybeIncorrect,
+ );
+ },
);
}
}
@@ -111,16 +117,15 @@ impl LateLintPass<'_> for UpperCaseAcronyms {
}
match it.kind {
ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..) => {
- check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive);
+ check_ident(cx, &it.ident, it.hir_id(), self.upper_case_acronyms_aggressive);
},
ItemKind::Enum(ref enumdef, _) => {
- check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive);
+ check_ident(cx, &it.ident, it.hir_id(), self.upper_case_acronyms_aggressive);
// check enum variants separately because again we only want to lint on private enums and
// the fn check_variant does not know about the vis of the enum of its variants
- enumdef
- .variants
- .iter()
- .for_each(|variant| check_ident(cx, &variant.ident, self.upper_case_acronyms_aggressive));
+ enumdef.variants.iter().for_each(|variant| {
+ check_ident(cx, &variant.ident, variant.hir_id, self.upper_case_acronyms_aggressive);
+ });
},
_ => {},
}
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index c3fe16ad5..fa033838e 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -2,7 +2,6 @@ use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_from_proc_macro;
use clippy_utils::ty::same_type_and_consts;
-use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -14,7 +13,7 @@ use rustc_hir::{
};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
@@ -93,32 +92,40 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
// relevant for linting, since this is the self type of the `impl` we're currently in. To
// avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that
// we're in an `impl` or nested item, that we don't want to lint
- let stack_item = if_chain! {
- if let ItemKind::Impl(Impl { self_ty, generics,.. }) = item.kind;
- if let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind;
- let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
- if parameters.as_ref().map_or(true, |params| {
- params.parenthesized == GenericArgsParentheses::No
+ let stack_item = if let ItemKind::Impl(Impl { self_ty, generics, .. }) = item.kind
+ && let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind
+ && let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args
+ && parameters.as_ref().map_or(true, |params| {
+ params.parenthesized == GenericArgsParentheses::No
&& !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
- });
- if !item.span.from_expansion();
- if !is_from_proc_macro(cx, item); // expensive, should be last check
- then {
- // Self cannot be used inside const generic parameters
- let types_to_skip = generics.params.iter().filter_map(|param| {
- match param {
- GenericParam { kind: GenericParamKind::Const { ty: Ty { hir_id, ..}, ..}, ..} => Some(*hir_id),
- _ => None,
- }
- }).chain(std::iter::once(self_ty.hir_id)).collect();
- StackItem::Check {
- impl_id: item.owner_id.def_id,
- in_body: 0,
- types_to_skip,
- }
- } else {
- StackItem::NoCheck
+ })
+ && !item.span.from_expansion()
+ && !is_from_proc_macro(cx, item)
+ // expensive, should be last check
+ {
+ // Self cannot be used inside const generic parameters
+ let types_to_skip = generics
+ .params
+ .iter()
+ .filter_map(|param| match param {
+ GenericParam {
+ kind:
+ GenericParamKind::Const {
+ ty: Ty { hir_id, .. }, ..
+ },
+ ..
+ } => Some(*hir_id),
+ _ => None,
+ })
+ .chain(std::iter::once(self_ty.hir_id))
+ .collect();
+ StackItem::Check {
+ impl_id: item.owner_id.def_id,
+ in_body: 0,
+ types_to_skip,
}
+ } else {
+ StackItem::NoCheck
};
self.stack.push(stack_item);
}
@@ -132,56 +139,54 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
// We want to skip types in trait `impl`s that aren't declared as `Self` in the trait
// declaration. The collection of those types is all this method implementation does.
- if_chain! {
- if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind;
- if let Some(&mut StackItem::Check {
+ if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind
+ && let Some(&mut StackItem::Check {
impl_id,
ref mut types_to_skip,
..
- }) = self.stack.last_mut();
- if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_id);
- then {
- // `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
- // `Self`.
- let self_ty = impl_trait_ref.instantiate_identity().self_ty();
+ }) = self.stack.last_mut()
+ && let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_id)
+ {
+ // `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
+ // `Self`.
+ let self_ty = impl_trait_ref.instantiate_identity().self_ty();
- // `trait_method_sig` is the signature of the function, how it is declared in the
- // trait, not in the impl of the trait.
- let trait_method = cx
- .tcx
- .associated_item(impl_item.owner_id)
- .trait_item_def_id
- .expect("impl method matches a trait method");
- let trait_method_sig = cx.tcx.fn_sig(trait_method).instantiate_identity();
- let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig);
+ // `trait_method_sig` is the signature of the function, how it is declared in the
+ // trait, not in the impl of the trait.
+ let trait_method = cx
+ .tcx
+ .associated_item(impl_item.owner_id)
+ .trait_item_def_id
+ .expect("impl method matches a trait method");
+ let trait_method_sig = cx.tcx.fn_sig(trait_method).instantiate_identity();
+ let trait_method_sig = cx.tcx.instantiate_bound_regions_with_erased(trait_method_sig);
- // `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the
- // implementation of the trait.
- let output_hir_ty = if let FnRetTy::Return(ty) = &decl.output {
- Some(&**ty)
- } else {
- None
- };
- let impl_inputs_outputs = decl.inputs.iter().chain(output_hir_ty);
+ // `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the
+ // implementation of the trait.
+ let output_hir_ty = if let FnRetTy::Return(ty) = &decl.output {
+ Some(&**ty)
+ } else {
+ None
+ };
+ let impl_inputs_outputs = decl.inputs.iter().chain(output_hir_ty);
- // `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature.
- //
- // `trait_sem_ty` (of type `ty::Ty`) is the semantic type for the signature in the
- // trait declaration. This is used to check if `Self` was used in the trait
- // declaration.
- //
- // If `any`where in the `trait_sem_ty` the `self_ty` was used verbatim (as opposed
- // to `Self`), we want to skip linting that type and all subtypes of it. This
- // avoids suggestions to e.g. replace `Vec<u8>` with `Vec<Self>`, in an `impl Trait
- // for u8`, when the trait always uses `Vec<u8>`.
- //
- // See also https://github.com/rust-lang/rust-clippy/issues/2894.
- for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) {
- if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) {
- let mut visitor = SkipTyCollector::default();
- visitor.visit_ty(impl_hir_ty);
- types_to_skip.extend(visitor.types_to_skip);
- }
+ // `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature.
+ //
+ // `trait_sem_ty` (of type `ty::Ty`) is the semantic type for the signature in the
+ // trait declaration. This is used to check if `Self` was used in the trait
+ // declaration.
+ //
+ // If `any`where in the `trait_sem_ty` the `self_ty` was used verbatim (as opposed
+ // to `Self`), we want to skip linting that type and all subtypes of it. This
+ // avoids suggestions to e.g. replace `Vec<u8>` with `Vec<Self>`, in an `impl Trait
+ // for u8`, when the trait always uses `Vec<u8>`.
+ //
+ // See also https://github.com/rust-lang/rust-clippy/issues/2894.
+ for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) {
+ if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) {
+ let mut visitor = SkipTyCollector::default();
+ visitor.visit_ty(impl_hir_ty);
+ types_to_skip.extend(visitor.types_to_skip);
}
}
}
@@ -203,41 +208,38 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
}
fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
- if_chain! {
- if !hir_ty.span.from_expansion();
- if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS);
- if let Some(&StackItem::Check {
+ if !hir_ty.span.from_expansion()
+ && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS)
+ && let Some(&StackItem::Check {
impl_id,
in_body,
ref types_to_skip,
- }) = self.stack.last();
- if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
- if !matches!(
+ }) = self.stack.last()
+ && let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind
+ && !matches!(
path.res,
- Res::SelfTyParam { .. }
- | Res::SelfTyAlias { .. }
- | Res::Def(DefKind::TyParam, _)
- );
- if !types_to_skip.contains(&hir_ty.hir_id);
- let ty = if in_body > 0 {
+ Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
+ )
+ && !types_to_skip.contains(&hir_ty.hir_id)
+ && let ty = if in_body > 0 {
cx.typeck_results().node_type(hir_ty.hir_id)
} else {
hir_ty_to_ty(cx.tcx, hir_ty)
- };
- if same_type_and_consts(ty, cx.tcx.type_of(impl_id).instantiate_identity());
- then {
- span_lint(cx, hir_ty.span);
}
+ && same_type_and_consts(ty, cx.tcx.type_of(impl_id).instantiate_identity())
+ {
+ span_lint(cx, hir_ty.span);
}
}
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- if_chain! {
- if !expr.span.from_expansion();
- if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS);
- if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
- if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id).instantiate_identity();
- then {} else { return; }
+ if !expr.span.from_expansion()
+ && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS)
+ && let Some(&StackItem::Check { impl_id, .. }) = self.stack.last()
+ && cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id).instantiate_identity()
+ {
+ } else {
+ return;
}
match expr.kind {
ExprKind::Struct(QPath::Resolved(_, path), ..) => check_path(cx, path),
@@ -252,18 +254,16 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
}
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) {
- if_chain! {
- if !pat.span.from_expansion();
- if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS);
- if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
+ if !pat.span.from_expansion()
+ && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS)
+ && let Some(&StackItem::Check { impl_id, .. }) = self.stack.last()
// get the path from the pattern
- if let PatKind::Path(QPath::Resolved(_, path))
+ && let PatKind::Path(QPath::Resolved(_, path))
| PatKind::TupleStruct(QPath::Resolved(_, path), _, _)
- | PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind;
- if cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id).instantiate_identity();
- then {
- check_path(cx, path);
- }
+ | PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind
+ && cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id).instantiate_identity()
+ {
+ check_path(cx, path);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 28f1d487e..2e0a0f6cb 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -3,9 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_con
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts};
use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, path_to_local};
-use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind};
use rustc_infer::infer::TyCtxtInferExt;
@@ -13,7 +11,7 @@ use rustc_infer::traits::Obligation;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{sym, Span};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -209,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
&& let Some(did) = cx.qpath_res(qpath, recv.hir_id).opt_def_id()
// make sure that the path indeed points to a fn-like item, so that
// `fn_sig` does not ICE. (see #11065)
- && cx.tcx.opt_def_kind(did).is_some_and(DefKind::is_fn_like) =>
+ && cx.tcx.def_kind(did).is_fn_like() =>
{
Some((
did,
@@ -283,7 +281,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
}
if let Some(id) = path_to_local(recv)
- && let Node::Pat(pat) = cx.tcx.hir().get(id)
+ && let Node::Pat(pat) = cx.tcx.hir_node(id)
&& let PatKind::Binding(ann, ..) = pat.kind
&& ann != BindingAnnotation::MUT
{
@@ -311,76 +309,63 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
);
}
}
- if_chain! {
- if is_trait_method(cx, e, sym::TryInto) && name.ident.name == sym::try_into;
- let a = cx.typeck_results().expr_ty(e);
- let b = cx.typeck_results().expr_ty(recv);
- if is_type_diagnostic_item(cx, a, sym::Result);
- if let ty::Adt(_, args) = a.kind();
- if let Some(a_type) = args.types().next();
- if same_type_and_consts(a_type, b);
+ if is_trait_method(cx, e, sym::TryInto)
+ && name.ident.name == sym::try_into
+ && let a = cx.typeck_results().expr_ty(e)
+ && let b = cx.typeck_results().expr_ty(recv)
+ && is_type_diagnostic_item(cx, a, sym::Result)
+ && let ty::Adt(_, args) = a.kind()
+ && let Some(a_type) = args.types().next()
+ && same_type_and_consts(a_type, b)
+ {
+ span_lint_and_help(
+ cx,
+ USELESS_CONVERSION,
+ e.span,
+ &format!("useless conversion to the same type: `{b}`"),
+ None,
+ "consider removing `.try_into()`",
+ );
+ }
+ },
- then {
+ ExprKind::Call(path, [arg]) => {
+ if let ExprKind::Path(ref qpath) = path.kind
+ && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+ && !is_ty_alias(qpath)
+ {
+ let a = cx.typeck_results().expr_ty(e);
+ let b = cx.typeck_results().expr_ty(arg);
+ if cx.tcx.is_diagnostic_item(sym::try_from_fn, def_id)
+ && is_type_diagnostic_item(cx, a, sym::Result)
+ && let ty::Adt(_, args) = a.kind()
+ && let Some(a_type) = args.types().next()
+ && same_type_and_consts(a_type, b)
+ {
+ let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from"));
span_lint_and_help(
cx,
USELESS_CONVERSION,
e.span,
&format!("useless conversion to the same type: `{b}`"),
None,
- "consider removing `.try_into()`",
+ &hint,
);
}
- }
- },
-
- ExprKind::Call(path, [arg]) => {
- if_chain! {
- if let ExprKind::Path(ref qpath) = path.kind;
- if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
- if !is_ty_alias(qpath);
- then {
- let a = cx.typeck_results().expr_ty(e);
- let b = cx.typeck_results().expr_ty(arg);
- if_chain! {
- if cx.tcx.is_diagnostic_item(sym::try_from_fn, def_id);
- if is_type_diagnostic_item(cx, a, sym::Result);
- if let ty::Adt(_, args) = a.kind();
- if let Some(a_type) = args.types().next();
- if same_type_and_consts(a_type, b);
- then {
- let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from"));
- span_lint_and_help(
- cx,
- USELESS_CONVERSION,
- e.span,
- &format!("useless conversion to the same type: `{b}`"),
- None,
- &hint,
- );
- }
- }
-
- if_chain! {
- if cx.tcx.is_diagnostic_item(sym::from_fn, def_id);
- if same_type_and_consts(a, b);
-
- then {
- let mut app = Applicability::MachineApplicable;
- let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "<expr>", &mut app).maybe_par();
- let sugg_msg =
- format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
- span_lint_and_sugg(
- cx,
- USELESS_CONVERSION,
- e.span,
- &format!("useless conversion to the same type: `{b}`"),
- &sugg_msg,
- sugg.to_string(),
- app,
- );
- }
- }
+ if cx.tcx.is_diagnostic_item(sym::from_fn, def_id) && same_type_and_consts(a, b) {
+ let mut app = Applicability::MachineApplicable;
+ let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "<expr>", &mut app).maybe_par();
+ let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
+ span_lint_and_sugg(
+ cx,
+ USELESS_CONVERSION,
+ e.span,
+ &format!("useless conversion to the same type: `{b}`"),
+ &sugg_msg,
+ sugg.to_string(),
+ app,
+ );
}
}
},
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 152248afc..e83c04eda 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -7,7 +7,7 @@ use rustc_ast::LitIntType;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_hir::{
- ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, CaptureBy
+ ArrayLen, BindingAnnotation, CaptureBy, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::declare_lint_pass;
@@ -629,6 +629,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
match pat.value.kind {
PatKind::Wild => kind!("Wild"),
+ PatKind::Never => kind!("Never"),
PatKind::Binding(ann, _, name, sub) => {
bind!(self, name);
opt_bind!(self, sub);
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index ddcb9f27c..877a77fd6 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -1,7 +1,6 @@
pub mod almost_standard_lint_formulation;
pub mod collapsible_calls;
pub mod compiler_lint_functions;
-pub mod if_chain_style;
pub mod interning_defined_symbol;
pub mod invalid_paths;
pub mod lint_without_lint_pass;
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
index d78f67c05..5ddedb24b 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
@@ -4,7 +4,7 @@ use regex::Regex;
use rustc_ast as ast;
use rustc_hir::{Item, ItemKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
index d7666b77f..7c70d3f45 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
@@ -1,12 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::{is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt, SpanlessEq};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::{Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use std::borrow::{Borrow, Cow};
@@ -78,45 +77,43 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
return;
}
- if_chain! {
- if let ExprKind::Call(func, and_then_args) = expr.kind;
- if is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]);
- if and_then_args.len() == 5;
- if let ExprKind::Closure(&Closure { body, .. }) = &and_then_args[4].kind;
- let body = cx.tcx.hir().body(body);
- let only_expr = peel_blocks_with_stmt(body.value);
- if let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind;
- if let ExprKind::Path(..) = recv.kind;
- then {
- let and_then_snippets = get_and_then_snippets(cx, and_then_args);
- let mut sle = SpanlessEq::new(cx).deny_side_effects();
- match ps.ident.as_str() {
- "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
- suggest_suggestion(
- cx,
- expr,
- &and_then_snippets,
- &span_suggestion_snippets(cx, span_call_args),
- );
- },
- "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
- let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
- suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true);
- },
- "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
- let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
- suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true);
- },
- "help" => {
- let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#);
- suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false);
- },
- "note" => {
- let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#);
- suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false);
- },
- _ => (),
- }
+ if let ExprKind::Call(func, and_then_args) = expr.kind
+ && is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"])
+ && and_then_args.len() == 5
+ && let ExprKind::Closure(&Closure { body, .. }) = &and_then_args[4].kind
+ && let body = cx.tcx.hir().body(body)
+ && let only_expr = peel_blocks_with_stmt(body.value)
+ && let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind
+ && let ExprKind::Path(..) = recv.kind
+ {
+ let and_then_snippets = get_and_then_snippets(cx, and_then_args);
+ let mut sle = SpanlessEq::new(cx).deny_side_effects();
+ match ps.ident.as_str() {
+ "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
+ suggest_suggestion(
+ cx,
+ expr,
+ &and_then_snippets,
+ &span_suggestion_snippets(cx, span_call_args),
+ );
+ },
+ "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
+ let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
+ suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true);
+ },
+ "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
+ let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
+ suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true);
+ },
+ "help" => {
+ let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#);
+ suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false);
+ },
+ "note" => {
+ let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#);
+ suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false);
+ },
+ _ => (),
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
index cacd05262..5059712d6 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::match_type;
use clippy_utils::{is_lint_allowed, paths};
-use if_chain::if_chain;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -56,22 +55,20 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
return;
}
- if_chain! {
- if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind;
- let fn_name = path.ident;
- if let Some(sugg) = self.map.get(fn_name.as_str());
- let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
- if match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT);
- then {
- span_lint_and_help(
- cx,
- COMPILER_LINT_FUNCTIONS,
- path.ident.span,
- "usage of a compiler lint function",
- None,
- &format!("please use the Clippy variant of this function: `{sugg}`"),
- );
- }
+ if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind
+ && let fn_name = path.ident
+ && let Some(sugg) = self.map.get(fn_name.as_str())
+ && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
+ && (match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT))
+ {
+ span_lint_and_help(
+ cx,
+ COMPILER_LINT_FUNCTIONS,
+ path.ident.span,
+ "usage of a compiler lint function",
+ None,
+ &format!("please use the Clippy variant of this function: `{sugg}`"),
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
deleted file mode 100644
index 8cdd5ea89..000000000
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
+++ /dev/null
@@ -1,166 +0,0 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
-use clippy_utils::{higher, is_else_clause, is_expn_of};
-use if_chain::if_chain;
-use rustc_hir as hir;
-use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Local, Node, Stmt, StmtKind};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{BytePos, Span};
-
-declare_clippy_lint! {
- /// Finds unidiomatic usage of `if_chain!`
- pub IF_CHAIN_STYLE,
- internal,
- "non-idiomatic `if_chain!` usage"
-}
-
-declare_lint_pass!(IfChainStyle => [IF_CHAIN_STYLE]);
-
-impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
- fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
- let (local, after, if_chain_span) = if_chain! {
- if let [Stmt { kind: StmtKind::Local(local), .. }, after @ ..] = block.stmts;
- if let Some(if_chain_span) = is_expn_of(block.span, "if_chain");
- then { (local, after, if_chain_span) } else { return }
- };
- if is_first_if_chain_expr(cx, block.hir_id, if_chain_span) {
- span_lint(
- cx,
- IF_CHAIN_STYLE,
- if_chain_local_span(cx, local, if_chain_span),
- "`let` expression should be above the `if_chain!`",
- );
- } else if local.span.eq_ctxt(block.span) && is_if_chain_then(after, block.expr, if_chain_span) {
- span_lint(
- cx,
- IF_CHAIN_STYLE,
- if_chain_local_span(cx, local, if_chain_span),
- "`let` expression should be inside `then { .. }`",
- );
- }
- }
-
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
- let (cond, then, els) = if let Some(higher::IfOrIfLet { cond, r#else, then }) = higher::IfOrIfLet::hir(expr) {
- (cond, then, r#else.is_some())
- } else {
- return;
- };
- let ExprKind::Block(then_block, _) = then.kind else {
- return;
- };
- let if_chain_span = is_expn_of(expr.span, "if_chain");
- if !els {
- check_nested_if_chains(cx, expr, then_block, if_chain_span);
- }
- let Some(if_chain_span) = if_chain_span else { return };
- // check for `if a && b;`
- if_chain! {
- if let ExprKind::Binary(op, _, _) = cond.kind;
- if op.node == BinOpKind::And;
- if cx.sess().source_map().is_multiline(cond.span);
- then {
- span_lint(cx, IF_CHAIN_STYLE, cond.span, "`if a && b;` should be `if a; if b;`");
- }
- }
- if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span)
- && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span)
- {
- span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`");
- }
- }
-}
-
-fn check_nested_if_chains(
- cx: &LateContext<'_>,
- if_expr: &Expr<'_>,
- then_block: &Block<'_>,
- if_chain_span: Option<Span>,
-) {
- #[rustfmt::skip]
- let (head, tail) = match *then_block {
- Block { stmts, expr: Some(tail), .. } => (stmts, tail),
- Block {
- stmts: &[
- ref head @ ..,
- Stmt { kind: StmtKind::Expr(tail) | StmtKind::Semi(tail), .. }
- ],
- ..
- } => (head, tail),
- _ => return,
- };
- if_chain! {
- if let Some(higher::IfOrIfLet { r#else: None, .. }) = higher::IfOrIfLet::hir(tail);
- let sm = cx.sess().source_map();
- if head
- .iter()
- .all(|stmt| matches!(stmt.kind, StmtKind::Local(..)) && !sm.is_multiline(stmt.span));
- if if_chain_span.is_some() || !is_else_clause(cx.tcx, if_expr);
- then {
- } else {
- return;
- }
- }
- let (span, msg) = match (if_chain_span, is_expn_of(tail.span, "if_chain")) {
- (None, Some(_)) => (if_expr.span, "this `if` can be part of the inner `if_chain!`"),
- (Some(_), None) => (tail.span, "this `if` can be part of the outer `if_chain!`"),
- (Some(a), Some(b)) if a != b => (b, "this `if_chain!` can be merged with the outer `if_chain!`"),
- _ => return,
- };
- span_lint_and_then(cx, IF_CHAIN_STYLE, span, msg, |diag| {
- let (span, msg) = match head {
- [] => return,
- [stmt] => (stmt.span, "this `let` statement can also be in the `if_chain!`"),
- [a, .., b] => (
- a.span.to(b.span),
- "these `let` statements can also be in the `if_chain!`",
- ),
- };
- diag.span_help(span, msg);
- });
-}
-
-fn is_first_if_chain_expr(cx: &LateContext<'_>, hir_id: HirId, if_chain_span: Span) -> bool {
- cx.tcx
- .hir()
- .parent_iter(hir_id)
- .find(|(_, node)| {
- #[rustfmt::skip]
- !matches!(node, Node::Expr(Expr { kind: ExprKind::Block(..), .. }) | Node::Stmt(_))
- })
- .map_or(false, |(id, _)| {
- is_expn_of(cx.tcx.hir().span(id), "if_chain") != Some(if_chain_span)
- })
-}
-
-/// Checks a trailing slice of statements and expression of a `Block` to see if they are part
-/// of the `then {..}` portion of an `if_chain!`
-fn is_if_chain_then(stmts: &[Stmt<'_>], expr: Option<&Expr<'_>>, if_chain_span: Span) -> bool {
- let span = if let [stmt, ..] = stmts {
- stmt.span
- } else if let Some(expr) = expr {
- expr.span
- } else {
- // empty `then {}`
- return true;
- };
- is_expn_of(span, "if_chain").map_or(true, |span| span != if_chain_span)
-}
-
-/// Creates a `Span` for `let x = ..;` in an `if_chain!` call.
-fn if_chain_local_span(cx: &LateContext<'_>, local: &Local<'_>, if_chain_span: Span) -> Span {
- let mut span = local.pat.span;
- if let Some(init) = local.init {
- span = span.to(init.span);
- }
- span.adjust(if_chain_span.ctxt().outer_expn());
- let sm = cx.sess().source_map();
- let span = sm.span_extend_to_prev_str(span, "let", false, true).unwrap_or(span);
- let span = sm.span_extend_to_next_char(span, ';', false);
- Span::new(
- span.lo() - BytePos(3),
- span.hi() + BytePos(1),
- span.ctxt(),
- span.parent(),
- )
-}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
index fc9afe5ca..07879e81f 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::ty::match_type;
use clippy_utils::{def_path_def_ids, is_expn_of, match_def_path, paths};
-use if_chain::if_chain;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
@@ -12,7 +11,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::ConstValue;
use rustc_middle::ty;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::sym;
use rustc_span::symbol::Symbol;
@@ -77,15 +76,13 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
for def_id in def_path_def_ids(cx, module) {
for item in cx.tcx.module_children(def_id) {
- if_chain! {
- if let Res::Def(DefKind::Const, item_def_id) = item.res;
- let ty = cx.tcx.type_of(item_def_id).instantiate_identity();
- if match_type(cx, ty, &paths::SYMBOL);
- if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id);
- if let Ok(value) = value.to_u32();
- then {
- self.symbol_map.insert(value, item_def_id);
- }
+ if let Res::Def(DefKind::Const, item_def_id) = item.res
+ && let ty = cx.tcx.type_of(item_def_id).instantiate_identity()
+ && match_type(cx, ty, &paths::SYMBOL)
+ && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id)
+ && let Ok(value) = value.to_u32()
+ {
+ self.symbol_map.insert(value, item_def_id);
}
}
}
@@ -93,24 +90,22 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
}
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if_chain! {
- if let ExprKind::Call(func, [arg]) = &expr.kind;
- if let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind();
- if match_def_path(cx, *def_id, &paths::SYMBOL_INTERN);
- if let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg);
- let value = Symbol::intern(&arg).as_u32();
- if let Some(&def_id) = self.symbol_map.get(&value);
- then {
- span_lint_and_sugg(
- cx,
- INTERNING_DEFINED_SYMBOL,
- is_expn_of(expr.span, "sym").unwrap_or(expr.span),
- "interning a defined symbol",
- "try",
- cx.tcx.def_path_str(def_id),
- Applicability::MachineApplicable,
- );
- }
+ if let ExprKind::Call(func, [arg]) = &expr.kind
+ && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind()
+ && match_def_path(cx, *def_id, &paths::SYMBOL_INTERN)
+ && let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg)
+ && let value = Symbol::intern(&arg).as_u32()
+ && let Some(&def_id) = self.symbol_map.get(&value)
+ {
+ span_lint_and_sugg(
+ cx,
+ INTERNING_DEFINED_SYMBOL,
+ is_expn_of(expr.span, "sym").unwrap_or(expr.span),
+ "interning a defined symbol",
+ "try",
+ cx.tcx.def_path_str(def_id),
+ Applicability::MachineApplicable,
+ );
}
if let ExprKind::Binary(op, left, right) = expr.kind {
if matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) {
@@ -163,27 +158,28 @@ impl InterningDefinedSymbol {
fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> {
static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR];
static SYMBOL_STR_PATHS: &[&[&str]] = &[&paths::SYMBOL_AS_STR, &paths::SYMBOL_TO_IDENT_STRING];
- let call = if_chain! {
- if let ExprKind::AddrOf(_, _, e) = expr.kind;
- if let ExprKind::Unary(UnOp::Deref, e) = e.kind;
- then { e } else { expr }
+ let call = if let ExprKind::AddrOf(_, _, e) = expr.kind
+ && let ExprKind::Unary(UnOp::Deref, e) = e.kind
+ {
+ e
+ } else {
+ expr
};
- if_chain! {
+ if let ExprKind::MethodCall(_, item, [], _) = call.kind
// is a method call
- if let ExprKind::MethodCall(_, item, [], _) = call.kind;
- if let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id);
- let ty = cx.typeck_results().expr_ty(item);
+ && let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id)
+ && let ty = cx.typeck_results().expr_ty(item)
// ...on either an Ident or a Symbol
- if let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) {
+ && let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) {
Some(false)
} else if match_type(cx, ty, &paths::IDENT) {
Some(true)
} else {
None
- };
+ }
// ...which converts it to a string
- let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS };
- if let Some(is_to_owned) = paths
+ && let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS }
+ && let Some(is_to_owned) = paths
.iter()
.find_map(|path| if match_def_path(cx, did, path) {
Some(path == &paths::SYMBOL_TO_IDENT_STRING)
@@ -194,14 +190,13 @@ impl InterningDefinedSymbol {
Some(true)
} else {
None
- });
- then {
- return Some(SymbolStrExpr::Expr {
- item,
- is_ident,
- is_to_owned,
- });
- }
+ })
+ {
+ return Some(SymbolStrExpr::Expr {
+ item,
+ is_ident,
+ is_to_owned,
+ });
}
// is a string constant
if let Some(Constant::Str(s)) = constant_simple(cx, cx.typeck_results(), expr) {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index 250772238..4fb615e1d 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -1,14 +1,13 @@
use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::def_path_res;
use clippy_utils::diagnostics::span_lint;
-use if_chain::if_chain;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::Item;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::FloatTy;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::Symbol;
declare_clippy_lint! {
@@ -31,13 +30,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
let local_def_id = &cx.tcx.parent_module(item.hir_id());
let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
- if_chain! {
- if mod_name.as_str() == "paths";
- if let hir::ItemKind::Const(.., body_id) = item.kind;
- let body = cx.tcx.hir().body(body_id);
- let typeck_results = cx.tcx.typeck_body(body_id);
- if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value);
- if let Some(path) = path
+ if mod_name.as_str() == "paths"
+ && let hir::ItemKind::Const(.., body_id) = item.kind
+ && let body = cx.tcx.hir().body(body_id)
+ && let typeck_results = cx.tcx.typeck_body(body_id)
+ && let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value)
+ && let Some(path) = path
.iter()
.map(|x| {
if let Constant::Str(s) = x {
@@ -46,11 +44,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
None
}
})
- .collect::<Option<Vec<&str>>>();
- if !check_path(cx, &path[..]);
- then {
- span_lint(cx, INVALID_PATHS, item.span, "invalid path");
- }
+ .collect::<Option<Vec<&str>>>()
+ && !check_path(cx, &path[..])
+ {
+ span_lint(cx, INVALID_PATHS, item.span, "invalid path");
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
index 00e352961..370ed430b 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
@@ -2,7 +2,6 @@ use crate::utils::internal_lints::metadata_collector::is_deprecated_lint;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::{is_lint_allowed, match_def_path, paths};
-use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def::{DefKind, Res};
@@ -12,7 +11,7 @@ use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_semver::RustcVersion;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::Symbol;
use rustc_span::{sym, Span};
@@ -309,14 +308,16 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'
pub(super) fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Option<Symbol> {
let attrs = cx.tcx.hir().attrs(item.hir_id());
attrs.iter().find_map(|attr| {
- if_chain! {
+ if let ast::AttrKind::Normal(ref attr_kind) = &attr.kind
// Identify attribute
- if let ast::AttrKind::Normal(ref attr_kind) = &attr.kind;
- if let [tool_name, attr_name] = &attr_kind.item.path.segments[..];
- if tool_name.ident.name == sym::clippy;
- if attr_name.ident.name == sym::version;
- if let Some(version) = attr.value_str();
- then { Some(version) } else { None }
+ && let [tool_name, attr_name] = &attr_kind.item.path.segments[..]
+ && tool_name.ident.name == sym::clippy
+ && attr_name.ident.name == sym::version
+ && let Some(version) = attr.value_str()
+ {
+ Some(version)
+ } else {
+ None
}
})
}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 51abe0c1d..fae1b90ac 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -14,27 +14,26 @@ use clippy_config::{get_configuration_metadata, ClippyConfiguration};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
use clippy_utils::{last_path_segment, match_def_path, match_function_call, match_path, paths};
-use if_chain::if_chain;
use itertools::Itertools;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::DefKind;
use rustc_hir::intravisit::Visitor;
use rustc_hir::{self as hir, intravisit, Closure, ExprKind, Item, ItemKind, Mutability, QPath};
-use rustc_lint::{CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId};
+use rustc_lint::{unerased_lint_store, CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId};
use rustc_middle::hir::nested_filter;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::Ident;
use rustc_span::{sym, Loc, Span, Symbol};
use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer};
use std::collections::{BTreeSet, BinaryHeap};
-use std::fmt;
use std::fmt::Write as _;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::Command;
+use std::{env, fmt};
/// This is the json output file of the lint collector.
const JSON_OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
@@ -416,7 +415,7 @@ fn get_lint_output(lint_name: &str, example: &[&mut String], clippy_project_root
let prefixed_name = format!("{CLIPPY_LINT_GROUP_PREFIX}{lint_name}");
- let mut cmd = Command::new("cargo");
+ let mut cmd = Command::new(env::var("CARGO").unwrap_or("cargo".into()));
cmd.current_dir(clippy_project_root)
.env("CARGO_INCREMENTAL", "0")
@@ -543,49 +542,45 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) {
if let ItemKind::Static(ty, Mutability::Not, _) = item.kind {
// Normal lint
- if_chain! {
+ if is_lint_ref_type(cx, ty)
// item validation
- if is_lint_ref_type(cx, ty);
// disallow check
- let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
+ && let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase()
// metadata extraction
- if let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item);
- if let Some(mut raw_docs) = extract_attr_docs_or_lint(cx, item);
- then {
- if let Some(configuration_section) = self.get_lint_configs(&lint_name) {
- raw_docs.push_str(&configuration_section);
- }
- let version = get_lint_version(cx, item);
-
- self.lints.push(LintMetadata::new(
- lint_name,
- SerializableSpan::from_item(cx, item),
- group,
- level,
- version,
- raw_docs,
- ));
+ && let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item)
+ && let Some(mut raw_docs) = extract_attr_docs_or_lint(cx, item)
+ {
+ if let Some(configuration_section) = self.get_lint_configs(&lint_name) {
+ raw_docs.push_str(&configuration_section);
}
+ let version = get_lint_version(cx, item);
+
+ self.lints.push(LintMetadata::new(
+ lint_name,
+ SerializableSpan::from_item(cx, item),
+ group,
+ level,
+ version,
+ raw_docs,
+ ));
}
- if_chain! {
- if is_deprecated_lint(cx, ty);
+ if is_deprecated_lint(cx, ty)
// disallow check
- let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
+ && let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase()
// Metadata the little we can get from a deprecated lint
- if let Some(raw_docs) = extract_attr_docs_or_lint(cx, item);
- then {
- let version = get_lint_version(cx, item);
-
- self.lints.push(LintMetadata::new(
- lint_name,
- SerializableSpan::from_item(cx, item),
- DEPRECATED_LINT_GROUP_STR.to_string(),
- DEPRECATED_LINT_LEVEL,
- version,
- raw_docs,
- ));
- }
+ && let Some(raw_docs) = extract_attr_docs_or_lint(cx, item)
+ {
+ let version = get_lint_version(cx, item);
+
+ self.lints.push(LintMetadata::new(
+ lint_name,
+ SerializableSpan::from_item(cx, item),
+ DEPRECATED_LINT_GROUP_STR.to_string(),
+ DEPRECATED_LINT_LEVEL,
+ version,
+ raw_docs,
+ ));
}
}
}
@@ -719,7 +714,7 @@ fn get_lint_group_and_level_or_lint(
lint_name: &str,
item: &Item<'_>,
) -> Option<(String, &'static str)> {
- let result = cx.lint_store.check_lint_name(
+ let result = unerased_lint_store(cx.tcx.sess).check_lint_name(
lint_name,
Some(sym::clippy),
&std::iter::once(Ident::with_dummy_span(sym::clippy)).collect(),
@@ -751,7 +746,7 @@ fn get_lint_group_and_level_or_lint(
}
fn get_lint_group(cx: &LateContext<'_>, lint_id: LintId) -> Option<String> {
- for (group_name, lints, _) in cx.lint_store.get_lint_groups() {
+ for (group_name, lints, _) in unerased_lint_store(cx.tcx.sess).get_lint_groups() {
if IGNORED_LINT_GROUPS.contains(&group_name) {
continue;
}
@@ -789,15 +784,13 @@ fn collect_renames(lints: &mut Vec<LintMetadata>) {
loop {
if let Some(lint_name) = names.pop() {
for (k, v) in RENAMED_LINTS {
- if_chain! {
- if let Some(name) = v.strip_prefix(CLIPPY_LINT_GROUP_PREFIX);
- if name == lint_name;
- if let Some(past_name) = k.strip_prefix(CLIPPY_LINT_GROUP_PREFIX);
- then {
- lint.former_ids.insert(past_name.to_owned());
- writeln!(collected, "* `{past_name}`").unwrap();
- names.push(past_name.to_string());
- }
+ if let Some(name) = v.strip_prefix(CLIPPY_LINT_GROUP_PREFIX)
+ && name == lint_name
+ && let Some(past_name) = k.strip_prefix(CLIPPY_LINT_GROUP_PREFIX)
+ {
+ lint.former_ids.insert(past_name.to_owned());
+ writeln!(collected, "* `{past_name}`").unwrap();
+ names.push(past_name.to_string());
}
}
@@ -927,20 +920,17 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> {
}
fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
- if_chain! {
- if let ExprKind::Path(qpath) = &expr.kind;
- if let QPath::Resolved(_, path) = qpath;
-
- let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
- if match_type(self.cx, expr_ty, &paths::LINT);
- then {
- if let hir::def::Res::Def(DefKind::Static(..), _) = path.res {
- let lint_name = last_path_segment(qpath).ident.name;
- self.lints.push(sym_to_string(lint_name).to_ascii_lowercase());
- } else if let Some(local) = get_parent_local(self.cx, expr) {
- if let Some(local_init) = local.init {
- intravisit::walk_expr(self, local_init);
- }
+ if let ExprKind::Path(qpath) = &expr.kind
+ && let QPath::Resolved(_, path) = qpath
+ && let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr))
+ && match_type(self.cx, expr_ty, &paths::LINT)
+ {
+ if let hir::def::Res::Def(DefKind::Static(..), _) = path.res {
+ let lint_name = last_path_segment(qpath).ident.name;
+ self.lints.push(sym_to_string(lint_name).to_ascii_lowercase());
+ } else if let Some(local) = get_parent_local(self.cx, expr) {
+ if let Some(local_init) = local.init {
+ intravisit::walk_expr(self, local_init);
}
}
}
@@ -992,13 +982,11 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> {
fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
- if_chain! {
- if match_type(self.cx, expr_ty, &paths::APPLICABILITY);
- if let Some(local) = get_parent_local(self.cx, expr);
- if let Some(local_init) = local.init;
- then {
- intravisit::walk_expr(self, local_init);
- }
+ if match_type(self.cx, expr_ty, &paths::APPLICABILITY)
+ && let Some(local) = get_parent_local(self.cx, expr)
+ && let Some(local_init) = local.init
+ {
+ intravisit::walk_expr(self, local_init);
};
intravisit::walk_expr(self, expr);
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
index 86b77a77f..6d5240db8 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
@@ -2,12 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::ty::match_type;
use clippy_utils::{match_def_path, paths};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::{self, EarlyBinder, GenericArgKind};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -22,40 +21,41 @@ declare_lint_pass!(MsrvAttrImpl => [MISSING_MSRV_ATTR_IMPL]);
impl LateLintPass<'_> for MsrvAttrImpl {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if_chain! {
- if let hir::ItemKind::Impl(hir::Impl {
- of_trait: Some(_),
- items,
- ..
- }) = &item.kind;
- if let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::instantiate_identity);
- let is_late_pass = match_def_path(cx, trait_ref.def_id, &paths::LATE_LINT_PASS);
- if is_late_pass || match_def_path(cx, trait_ref.def_id, &paths::EARLY_LINT_PASS);
- if let ty::Adt(self_ty_def, _) = trait_ref.self_ty().kind();
- if self_ty_def.is_struct();
- if self_ty_def.all_fields().any(|f| {
+ if let hir::ItemKind::Impl(hir::Impl {
+ of_trait: Some(_),
+ items,
+ ..
+ }) = &item.kind
+ && let Some(trait_ref) = cx
+ .tcx
+ .impl_trait_ref(item.owner_id)
+ .map(EarlyBinder::instantiate_identity)
+ && let is_late_pass = match_def_path(cx, trait_ref.def_id, &paths::LATE_LINT_PASS)
+ && (is_late_pass || match_def_path(cx, trait_ref.def_id, &paths::EARLY_LINT_PASS))
+ && let ty::Adt(self_ty_def, _) = trait_ref.self_ty().kind()
+ && self_ty_def.is_struct()
+ && self_ty_def.all_fields().any(|f| {
cx.tcx
.type_of(f.did)
.instantiate_identity()
.walk()
.filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
.any(|t| match_type(cx, t.expect_ty(), &paths::MSRV))
- });
- if !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs));
- then {
- let context = if is_late_pass { "LateContext" } else { "EarlyContext" };
- let lint_pass = if is_late_pass { "LateLintPass" } else { "EarlyLintPass" };
- let span = cx.sess().source_map().span_through_char(item.span, '{');
- span_lint_and_sugg(
- cx,
- MISSING_MSRV_ATTR_IMPL,
- span,
- &format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"),
- &format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"),
- format!("{}\n extract_msrv_attr!({context});", snippet(cx, span, "..")),
- Applicability::MachineApplicable,
- );
- }
+ })
+ && !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs))
+ {
+ let context = if is_late_pass { "LateContext" } else { "EarlyContext" };
+ let lint_pass = if is_late_pass { "LateLintPass" } else { "EarlyLintPass" };
+ let span = cx.sess().source_map().span_through_char(item.span, '{');
+ span_lint_and_sugg(
+ cx,
+ MISSING_MSRV_ATTR_IMPL,
+ span,
+ &format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"),
+ &format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"),
+ format!("{}\n extract_msrv_attr!({context});", snippet(cx, span, "..")),
+ Applicability::MachineApplicable,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs
index 2b13fad80..326e17214 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::match_type;
use clippy_utils::{is_lint_allowed, method_calls, paths};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::Symbol;
declare_clippy_lint! {
@@ -40,23 +39,21 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
let (method_names, arg_lists, spans) = method_calls(expr, 2);
let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect();
- if_chain! {
- if let ["expn_data", "outer_expn"] = method_names.as_slice();
- let (self_arg, args) = arg_lists[1];
- if args.is_empty();
- let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
- if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
- then {
- span_lint_and_sugg(
- cx,
- OUTER_EXPN_EXPN_DATA,
- spans[1].with_hi(expr.span.hi()),
- "usage of `outer_expn().expn_data()`",
- "try",
- "outer_expn_data()".to_string(),
- Applicability::MachineApplicable,
- );
- }
+ if let ["expn_data", "outer_expn"] = method_names.as_slice()
+ && let (self_arg, args) = arg_lists[1]
+ && args.is_empty()
+ && let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
+ && match_type(cx, self_ty, &paths::SYNTAX_CONTEXT)
+ {
+ span_lint_and_sugg(
+ cx,
+ OUTER_EXPN_EXPN_DATA,
+ spans[1].with_hi(expr.span.hi()),
+ "usage of `outer_expn().expn_data()`",
+ "try",
+ "outer_expn_data()".to_string(),
+ Applicability::MachineApplicable,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs
index 5899b94e1..9169e2968 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs
@@ -1,7 +1,7 @@
use rustc_ast::ast::NodeId;
use rustc_ast::visit::FnKind;
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
index 81be04659..6e449dc98 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs};
-use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::Applicability;
@@ -13,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::interpret::{Allocation, GlobalAlloc};
use rustc_middle::mir::ConstValue;
use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::Symbol;
use rustc_span::Span;
@@ -102,108 +101,106 @@ impl UnnecessaryDefPath {
&["clippy_utils", "is_expr_path_def_path"],
];
- if_chain! {
- if let [cx_arg, def_arg, args @ ..] = args;
- if let ExprKind::Path(path) = &func.kind;
- if let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id();
- if let Some(which_path) = match_any_def_paths(cx, id, PATHS);
- let item_arg = if which_path == 4 { &args[1] } else { &args[0] };
+ if let [cx_arg, def_arg, args @ ..] = args
+ && let ExprKind::Path(path) = &func.kind
+ && let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id()
+ && let Some(which_path) = match_any_def_paths(cx, id, PATHS)
+ && let item_arg = if which_path == 4 { &args[1] } else { &args[0] }
// Extract the path to the matched type
- if let Some(segments) = path_to_matched_type(cx, item_arg);
- let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
- if let Some(def_id) = def_path_def_ids(cx, &segments[..]).next();
- then {
- // Check if the target item is a diagnostic item or LangItem.
- #[rustfmt::skip]
- let (msg, item) = if let Some(item_name)
- = cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id)
- {
- (
- "use of a def path to a diagnostic item",
- Item::DiagnosticItem(*item_name),
- )
- } else if let Some(item_name) = get_lang_item_name(cx, def_id) {
- (
- "use of a def path to a `LangItem`",
- Item::LangItem(item_name),
- )
- } else {
- return;
- };
+ && let Some(segments) = path_to_matched_type(cx, item_arg)
+ && let segments = segments.iter().map(|sym| &**sym).collect::<Vec<_>>()
+ && let Some(def_id) = def_path_def_ids(cx, &segments[..]).next()
+ {
+ // Check if the target item is a diagnostic item or LangItem.
+ #[rustfmt::skip]
+ let (msg, item) = if let Some(item_name)
+ = cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id)
+ {
+ (
+ "use of a def path to a diagnostic item",
+ Item::DiagnosticItem(*item_name),
+ )
+ } else if let Some(item_name) = get_lang_item_name(cx, def_id) {
+ (
+ "use of a def path to a `LangItem`",
+ Item::LangItem(item_name),
+ )
+ } else {
+ return;
+ };
- let has_ctor = match cx.tcx.def_kind(def_id) {
- DefKind::Struct => {
- let variant = cx.tcx.adt_def(def_id).non_enum_variant();
- variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
- },
- DefKind::Variant => {
- let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id);
- variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
- },
- _ => false,
- };
+ let has_ctor = match cx.tcx.def_kind(def_id) {
+ DefKind::Struct => {
+ let variant = cx.tcx.adt_def(def_id).non_enum_variant();
+ variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
+ },
+ DefKind::Variant => {
+ let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id);
+ variant.ctor.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
+ },
+ _ => false,
+ };
- let mut app = Applicability::MachineApplicable;
- let cx_snip = snippet_with_applicability(cx, cx_arg.span, "..", &mut app);
- let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app);
- let (sugg, with_note) = match (which_path, item) {
- // match_def_path
- (0, Item::DiagnosticItem(item)) => (
- format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"),
- has_ctor,
- ),
- (0, Item::LangItem(item)) => (
- format!("{cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some({def_snip})"),
- has_ctor,
- ),
- // match_trait_method
- (1, Item::DiagnosticItem(item)) => {
- (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false)
- },
- // match_type
- (2, Item::DiagnosticItem(item)) => (
- format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"),
- false,
- ),
- (2, Item::LangItem(item)) => (
- format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"),
- false,
- ),
- // is_expr_path_def_path
- (3, Item::DiagnosticItem(item)) if has_ctor => (
- format!("is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})",),
- false,
- ),
- (3, Item::LangItem(item)) if has_ctor => (
- format!("is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})",),
- false,
- ),
- (3, Item::DiagnosticItem(item)) => (
- format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"),
- false,
- ),
- (3, Item::LangItem(item)) => (
- format!(
- "path_res({cx_snip}, {def_snip}).opt_def_id()\
- .map_or(false, |id| {cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some(id))",
- ),
- false,
+ let mut app = Applicability::MachineApplicable;
+ let cx_snip = snippet_with_applicability(cx, cx_arg.span, "..", &mut app);
+ let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app);
+ let (sugg, with_note) = match (which_path, item) {
+ // match_def_path
+ (0, Item::DiagnosticItem(item)) => (
+ format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"),
+ has_ctor,
+ ),
+ (0, Item::LangItem(item)) => (
+ format!("{cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some({def_snip})"),
+ has_ctor,
+ ),
+ // match_trait_method
+ (1, Item::DiagnosticItem(item)) => {
+ (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false)
+ },
+ // match_type
+ (2, Item::DiagnosticItem(item)) => (
+ format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"),
+ false,
+ ),
+ (2, Item::LangItem(item)) => (
+ format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"),
+ false,
+ ),
+ // is_expr_path_def_path
+ (3, Item::DiagnosticItem(item)) if has_ctor => (
+ format!("is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})",),
+ false,
+ ),
+ (3, Item::LangItem(item)) if has_ctor => (
+ format!("is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})",),
+ false,
+ ),
+ (3, Item::DiagnosticItem(item)) => (
+ format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"),
+ false,
+ ),
+ (3, Item::LangItem(item)) => (
+ format!(
+ "path_res({cx_snip}, {def_snip}).opt_def_id()\
+ .map_or(false, |id| {cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some(id))",
),
- _ => return,
- };
+ false,
+ ),
+ _ => return,
+ };
- span_lint_and_then(cx, UNNECESSARY_DEF_PATH, span, msg, |diag| {
- diag.span_suggestion(span, "try", sugg, app);
- if with_note {
- diag.help(
- "if this `DefId` came from a constructor expression or pattern then the \
- parent `DefId` should be used instead",
- );
- }
- });
+ span_lint_and_then(cx, UNNECESSARY_DEF_PATH, span, msg, |diag| {
+ diag.span_suggestion(span, "try", sugg, app);
+ if with_note {
+ diag.help(
+ "if this `DefId` came from a constructor expression or pattern then the \
+ parent `DefId` should be used instead",
+ );
+ }
+ });
- self.linted_def_ids.insert(def_id);
- }
+ self.linted_def_ids.insert(def_id);
}
}
@@ -221,7 +218,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) {
Res::Local(hir_id) => {
let parent_id = cx.tcx.hir().parent_id(hir_id);
- if let Some(Node::Local(Local { init: Some(init), .. })) = cx.tcx.hir().find(parent_id) {
+ if let Node::Local(Local { init: Some(init), .. }) = cx.tcx.hir_node(parent_id) {
path_to_matched_type(cx, init)
} else {
None
@@ -249,7 +246,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option<Vec<String>> {
let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() {
let &alloc = alloc.provenance().ptrs().values().next()?;
- if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) {
+ if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc.alloc_id()) {
(alloc.inner(), ty)
} else {
return None;
@@ -267,7 +264,7 @@ fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation
.ptrs()
.values()
.map(|&alloc| {
- if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) {
+ if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc.alloc_id()) {
let alloc = alloc.inner();
str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()))
.ok()
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs
index fd51bca9e..a5c4bf474 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast::{Crate, ItemKind, ModKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index a9a3aaad3..5e13c73f0 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -1,26 +1,27 @@
+use std::collections::BTreeMap;
use std::ops::ControlFlow;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{constant, Constant};
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_copy;
use clippy_utils::visitors::for_each_local_use_after_expr;
use clippy_utils::{get_parent_expr, higher, is_trait_method};
-use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Node, PatKind};
+use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{sym, Span};
+use rustc_session::impl_lint_pass;
+use rustc_span::{sym, DesugaringKind, Span};
#[expect(clippy::module_name_repetitions)]
#[derive(Clone)]
pub struct UselessVec {
pub too_large_for_stack: u64,
pub msrv: Msrv,
+ pub span_to_lint_map: BTreeMap<Span, Option<(HirId, SuggestedType, String, Applicability)>>,
}
declare_clippy_lint! {
@@ -58,7 +59,7 @@ fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
/// Checks if the given expression is a method call to a `Vec` method
/// that also exists on slices. If this returns true, it means that
/// this expression does not actually require a `Vec` and could just work with an array.
-fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
+pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
const ALLOWED_METHOD_NAMES: &[&str] = &["len", "as_ptr", "is_empty"];
if let ExprKind::MethodCall(path, ..) = e.kind {
@@ -70,11 +71,56 @@ fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
impl<'tcx> LateLintPass<'tcx> for UselessVec {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- // search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]`
- if_chain! {
- if adjusts_to_slice(cx, expr);
- if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows());
- then {
+ if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) {
+ // search for `let foo = vec![_]` expressions where all uses of `foo`
+ // adjust to slices or call a method that exist on slices (e.g. len)
+ if let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id)
+ // for now ignore locals with type annotations.
+ // this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..];
+ && local.ty.is_none()
+ && let PatKind::Binding(_, id, ..) = local.pat.kind
+ && is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(expr.peel_borrows())))
+ {
+ let only_slice_uses = for_each_local_use_after_expr(cx, id, expr.hir_id, |expr| {
+ // allow indexing into a vec and some set of allowed method calls that exist on slices, too
+ if let Some(parent) = get_parent_expr(cx, expr)
+ && (adjusts_to_slice(cx, expr)
+ || matches!(parent.kind, ExprKind::Index(..))
+ || is_allowed_vec_method(cx, parent))
+ {
+ ControlFlow::Continue(())
+ } else {
+ ControlFlow::Break(())
+ }
+ })
+ .is_continue();
+
+ let span = expr.span.ctxt().outer_expn_data().call_site;
+ if only_slice_uses {
+ self.check_vec_macro(cx, &vec_args, span, expr.hir_id, SuggestedType::Array);
+ } else {
+ self.span_to_lint_map.insert(span, None);
+ }
+ }
+ // if the local pattern has a specified type, do not lint.
+ else if let Some(_) = higher::VecArgs::hir(cx, expr)
+ && let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id)
+ && local.ty.is_some()
+ {
+ let span = expr.span.ctxt().outer_expn_data().call_site;
+ self.span_to_lint_map.insert(span, None);
+ }
+ // search for `for _ in vec![...]`
+ else if let Some(parent) = get_parent_expr(cx, expr)
+ && parent.span.is_desugaring(DesugaringKind::ForLoop)
+ && self.msrv.meets(msrvs::ARRAY_INTO_ITERATOR)
+ {
+ // report the error around the `vec!` not inside `<std macros>:`
+ let span = expr.span.ctxt().outer_expn_data().call_site;
+ self.check_vec_macro(cx, &vec_args, span, expr.hir_id, SuggestedType::Array);
+ }
+ // search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]`
+ else {
let (suggest_slice, span) = if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind {
// `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.)
(SuggestedType::SliceRef(mutability), expr.span)
@@ -84,53 +130,28 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
(SuggestedType::Array, expr.span.ctxt().outer_expn_data().call_site)
};
- self.check_vec_macro(cx, &vec_args, span, suggest_slice);
- }
- }
-
- // search for `let foo = vec![_]` expressions where all uses of `foo`
- // adjust to slices or call a method that exist on slices (e.g. len)
- if let Some(vec_args) = higher::VecArgs::hir(cx, expr)
- && let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id)
- // for now ignore locals with type annotations.
- // this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..];
- && local.ty.is_none()
- && let PatKind::Binding(_, id, ..) = local.pat.kind
- && is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(expr)))
- {
- let only_slice_uses = for_each_local_use_after_expr(cx, id, expr.hir_id, |expr| {
- // allow indexing into a vec and some set of allowed method calls that exist on slices, too
- if let Some(parent) = get_parent_expr(cx, expr)
- && (adjusts_to_slice(cx, expr)
- || matches!(parent.kind, ExprKind::Index(..))
- || is_allowed_vec_method(cx, parent))
- {
- ControlFlow::Continue(())
+ if adjusts_to_slice(cx, expr) {
+ self.check_vec_macro(cx, &vec_args, span, expr.hir_id, suggest_slice);
} else {
- ControlFlow::Break(())
+ self.span_to_lint_map.insert(span, None);
}
- })
- .is_continue();
-
- if only_slice_uses {
- self.check_vec_macro(
- cx,
- &vec_args,
- expr.span.ctxt().outer_expn_data().call_site,
- SuggestedType::Array,
- );
}
}
+ }
- // search for `for _ in vec![…]`
- if_chain! {
- if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr);
- if let Some(vec_args) = higher::VecArgs::hir(cx, arg);
- if self.msrv.meets(msrvs::ARRAY_INTO_ITERATOR);
- then {
- // report the error around the `vec!` not inside `<std macros>:`
- let span = arg.span.ctxt().outer_expn_data().call_site;
- self.check_vec_macro(cx, &vec_args, span, SuggestedType::Array);
+ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+ for (span, lint_opt) in &self.span_to_lint_map {
+ if let Some((hir_id, suggest_slice, snippet, applicability)) = lint_opt {
+ let help_msg = format!(
+ "you can use {} directly",
+ match suggest_slice {
+ SuggestedType::SliceRef(_) => "a slice",
+ SuggestedType::Array => "an array",
+ }
+ );
+ span_lint_hir_and_then(cx, USELESS_VEC, *hir_id, *span, "useless use of `vec!`", |diag| {
+ diag.span_suggestion(*span, help_msg, snippet, *applicability);
+ });
}
}
}
@@ -139,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
}
#[derive(Copy, Clone)]
-enum SuggestedType {
+pub(crate) enum SuggestedType {
/// Suggest using a slice `&[..]` / `&mut [..]`
SliceRef(Mutability),
/// Suggest using an array: `[..]`
@@ -152,6 +173,7 @@ impl UselessVec {
cx: &LateContext<'tcx>,
vec_args: &higher::VecArgs<'tcx>,
span: Span,
+ hir_id: HirId,
suggest_slice: SuggestedType,
) {
if span.from_expansion() {
@@ -209,21 +231,9 @@ impl UselessVec {
},
};
- span_lint_and_sugg(
- cx,
- USELESS_VEC,
- span,
- "useless use of `vec!`",
- &format!(
- "you can use {} directly",
- match suggest_slice {
- SuggestedType::SliceRef(_) => "a slice",
- SuggestedType::Array => "an array",
- }
- ),
- snippet,
- applicability,
- );
+ self.span_to_lint_map
+ .entry(span)
+ .or_insert(Some((hir_id, suggest_slice, snippet, applicability)));
}
}
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index c8b9402f1..ac3b2bdaf 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -11,7 +11,7 @@ use rustc_hir::{
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{Span, Symbol};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/visibility.rs b/src/tools/clippy/clippy_lints/src/visibility.rs
index 8abcc964b..83369c663 100644
--- a/src/tools/clippy/clippy_lints/src/visibility.rs
+++ b/src/tools/clippy/clippy_lints/src/visibility.rs
@@ -4,7 +4,7 @@ use rustc_ast::ast::{Item, VisibilityKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::kw;
use rustc_span::Span;
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index d88ede763..9b0dac6af 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -1,13 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_test_module_or_function;
use clippy_utils::source::{snippet, snippet_with_applicability};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Item, ItemKind, PathSegment, UseKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::symbol::kw;
use rustc_span::{sym, BytePos};
@@ -127,70 +126,55 @@ impl LateLintPass<'_> for WildcardImports {
if cx.tcx.visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
return;
}
- if_chain! {
- if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind;
- if self.warn_on_all || !self.check_exceptions(item, use_path.segments);
- let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id);
- if !used_imports.is_empty(); // Already handled by `unused_imports`
- if !used_imports.contains(&kw::Underscore);
- then {
- let mut applicability = Applicability::MachineApplicable;
- let import_source_snippet = snippet_with_applicability(cx, use_path.span, "..", &mut applicability);
- let (span, braced_glob) = if import_source_snippet.is_empty() {
- // This is a `_::{_, *}` import
- // In this case `use_path.span` is empty and ends directly in front of the `*`,
- // so we need to extend it by one byte.
- (
- use_path.span.with_hi(use_path.span.hi() + BytePos(1)),
- true,
- )
- } else {
- // In this case, the `use_path.span` ends right before the `::*`, so we need to
- // extend it up to the `*`. Since it is hard to find the `*` in weird
- // formattings like `use _ :: *;`, we extend it up to, but not including the
- // `;`. In nested imports, like `use _::{inner::*, _}` there is no `;` and we
- // can just use the end of the item span
- let mut span = use_path.span.with_hi(item.span.hi());
- if snippet(cx, span, "").ends_with(';') {
- span = use_path.span.with_hi(item.span.hi() - BytePos(1));
- }
- (
- span, false,
- )
- };
+ if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind
+ && (self.warn_on_all || !self.check_exceptions(item, use_path.segments))
+ && let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id)
+ && !used_imports.is_empty() // Already handled by `unused_imports`
+ && !used_imports.contains(&kw::Underscore)
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let import_source_snippet = snippet_with_applicability(cx, use_path.span, "..", &mut applicability);
+ let (span, braced_glob) = if import_source_snippet.is_empty() {
+ // This is a `_::{_, *}` import
+ // In this case `use_path.span` is empty and ends directly in front of the `*`,
+ // so we need to extend it by one byte.
+ (use_path.span.with_hi(use_path.span.hi() + BytePos(1)), true)
+ } else {
+ // In this case, the `use_path.span` ends right before the `::*`, so we need to
+ // extend it up to the `*`. Since it is hard to find the `*` in weird
+ // formattings like `use _ :: *;`, we extend it up to, but not including the
+ // `;`. In nested imports, like `use _::{inner::*, _}` there is no `;` and we
+ // can just use the end of the item span
+ let mut span = use_path.span.with_hi(item.span.hi());
+ if snippet(cx, span, "").ends_with(';') {
+ span = use_path.span.with_hi(item.span.hi() - BytePos(1));
+ }
+ (span, false)
+ };
- let mut imports = used_imports.items().map(ToString::to_string).into_sorted_stable_ord();
- let imports_string = if imports.len() == 1 {
- imports.pop().unwrap()
- } else if braced_glob {
- imports.join(", ")
- } else {
- format!("{{{}}}", imports.join(", "))
- };
+ let mut imports = used_imports.items().map(ToString::to_string).into_sorted_stable_ord();
+ let imports_string = if imports.len() == 1 {
+ imports.pop().unwrap()
+ } else if braced_glob {
+ imports.join(", ")
+ } else {
+ format!("{{{}}}", imports.join(", "))
+ };
- let sugg = if braced_glob {
- imports_string
- } else {
- format!("{import_source_snippet}::{imports_string}")
- };
+ let sugg = if braced_glob {
+ imports_string
+ } else {
+ format!("{import_source_snippet}::{imports_string}")
+ };
- // Glob imports always have a single resolution.
- let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res[0] {
- (ENUM_GLOB_USE, "usage of wildcard import for enum variants")
- } else {
- (WILDCARD_IMPORTS, "usage of wildcard import")
- };
+ // Glob imports always have a single resolution.
+ let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res[0] {
+ (ENUM_GLOB_USE, "usage of wildcard import for enum variants")
+ } else {
+ (WILDCARD_IMPORTS, "usage of wildcard import")
+ };
- span_lint_and_sugg(
- cx,
- lint,
- span,
- message,
- "try",
- sugg,
- applicability,
- );
- }
+ span_lint_and_sugg(cx, lint, span, message, "try", sugg, applicability);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index b6f942a90..be16d2e5c 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -10,7 +10,7 @@ use rustc_ast::{
use rustc_errors::Applicability;
use rustc_hir::{Expr, Impl, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{sym, BytePos, Span};
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
index f2f0699ef..d3623d6fd 100644
--- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
@@ -1,9 +1,8 @@
use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint_and_help;
-use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -32,35 +31,30 @@ declare_lint_pass!(ZeroDiv => [ZERO_DIVIDED_BY_ZERO]);
impl<'tcx> LateLintPass<'tcx> for ZeroDiv {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// check for instances of 0.0/0.0
- if_chain! {
- if let ExprKind::Binary(ref op, left, right) = expr.kind;
- if op.node == BinOpKind::Div;
+ if let ExprKind::Binary(ref op, left, right) = expr.kind
+ && op.node == BinOpKind::Div
// TODO - constant_simple does not fold many operations involving floats.
// That's probably fine for this lint - it's pretty unlikely that someone would
// do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too.
- if let Some(lhs_value) = constant_simple(cx, cx.typeck_results(), left);
- if let Some(rhs_value) = constant_simple(cx, cx.typeck_results(), right);
- if Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value;
- if Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value;
- then {
- // since we're about to suggest a use of f32::NAN or f64::NAN,
- // match the precision of the literals that are given.
- let float_type = match (lhs_value, rhs_value) {
- (Constant::F64(_), _)
- | (_, Constant::F64(_)) => "f64",
- _ => "f32"
- };
- span_lint_and_help(
- cx,
- ZERO_DIVIDED_BY_ZERO,
- expr.span,
- "constant division of `0.0` with `0.0` will always result in NaN",
- None,
- &format!(
- "consider using `{float_type}::NAN` if you would like a constant representing NaN",
- ),
- );
- }
+ && let Some(lhs_value) = constant_simple(cx, cx.typeck_results(), left)
+ && let Some(rhs_value) = constant_simple(cx, cx.typeck_results(), right)
+ && (Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value)
+ && (Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value)
+ {
+ // since we're about to suggest a use of f32::NAN or f64::NAN,
+ // match the precision of the literals that are given.
+ let float_type = match (lhs_value, rhs_value) {
+ (Constant::F64(_), _) | (_, Constant::F64(_)) => "f64",
+ _ => "f32",
+ };
+ span_lint_and_help(
+ cx,
+ ZERO_DIVIDED_BY_ZERO,
+ expr.span,
+ "constant division of `0.0` with `0.0` will always result in NaN",
+ None,
+ &format!("consider using `{float_type}::NAN` if you would like a constant representing NaN",),
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index fee100fe1..b36c4ef91 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -1,12 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item};
-use if_chain::if_chain;
use rustc_hir::{self as hir, HirId, ItemKind, Node};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf as _;
use rustc_middle::ty::{Adt, Ty, TypeVisitableExt};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
@@ -46,23 +45,28 @@ declare_lint_pass!(ZeroSizedMapValues => [ZERO_SIZED_MAP_VALUES]);
impl LateLintPass<'_> for ZeroSizedMapValues {
fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
- if_chain! {
- if !hir_ty.span.from_expansion();
- if !in_trait_impl(cx, hir_ty.hir_id);
- let ty = ty_from_hir_ty(cx, hir_ty);
- if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap);
- if let Adt(_, args) = ty.kind();
- let ty = args.type_at(1);
+ if !hir_ty.span.from_expansion()
+ && !in_trait_impl(cx, hir_ty.hir_id)
+ && let ty = ty_from_hir_ty(cx, hir_ty)
+ && (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap))
+ && let Adt(_, args) = ty.kind()
+ && let ty = args.type_at(1)
// Fixes https://github.com/rust-lang/rust-clippy/issues/7447 because of
// https://github.com/rust-lang/rust/blob/master/compiler/rustc_middle/src/ty/sty.rs#L968
- if !ty.has_escaping_bound_vars();
+ && !ty.has_escaping_bound_vars()
// Do this to prevent `layout_of` crashing, being unable to fully normalize `ty`.
- if is_normalizable(cx, cx.param_env, ty);
- if let Ok(layout) = cx.layout_of(ty);
- if layout.is_zst();
- then {
- span_lint_and_help(cx, ZERO_SIZED_MAP_VALUES, hir_ty.span, "map with zero-sized value type", None, "consider using a set instead");
- }
+ && is_normalizable(cx, cx.param_env, ty)
+ && let Ok(layout) = cx.layout_of(ty)
+ && layout.is_zst()
+ {
+ span_lint_and_help(
+ cx,
+ ZERO_SIZED_MAP_VALUES,
+ hir_ty.span,
+ "map with zero-sized value type",
+ None,
+ "consider using a set instead",
+ );
}
}
}
@@ -70,7 +74,7 @@ impl LateLintPass<'_> for ZeroSizedMapValues {
fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool {
let parent_id = cx.tcx.hir().get_parent_item(hir_id);
let second_parent_id = cx.tcx.hir().get_parent_item(parent_id.into()).def_id;
- if let Some(Node::Item(item)) = cx.tcx.hir().find_by_def_id(second_parent_id) {
+ if let Some(Node::Item(item)) = cx.tcx.opt_hir_node_by_def_id(second_parent_id) {
if let ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind {
return true;
}