summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/clippy')
-rw-r--r--src/tools/clippy/.github/workflows/clippy.yml2
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml31
-rw-r--r--src/tools/clippy/CHANGELOG.md197
-rw-r--r--src/tools/clippy/Cargo.toml13
-rw-r--r--src/tools/clippy/README.md2
-rw-r--r--src/tools/clippy/book/src/README.md2
-rw-r--r--src/tools/clippy/book/src/development/infrastructure/changelog_update.md22
-rw-r--r--src/tools/clippy/book/src/development/speedtest.md24
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md23
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs26
-rw-r--r--src/tools/clippy/clippy_dev/src/setup/intellij.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/setup/vscode.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs5
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/absolute_paths.rs100
-rw-r--r--src/tools/clippy/clippy_lints/src/allow_attributes.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_constants.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/copy_iterator.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/dbg_macro.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs1070
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_methods.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_names.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_forget_ref.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_drop.rs3
-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.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/endian_bytes.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/error_impl_error.rs87
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs337
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_nesting.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/explicit_write.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/fn_null_check.rs102
-rw-r--r--src/tools/clippy/clippy_lints/src/format.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/format_impl.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/four_forward_slashes.rs99
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/result.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs2
-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.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_return.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/incorrect_impls.rs213
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_impl.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/init_numbered_fields.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/instant_subtraction.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_test_module.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/large_futures.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/large_include_file.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/large_stack_frames.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/let_if_seq.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_find.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_bits.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_clamp.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_float_methods.rs175
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_range_patterns.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.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_strip.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/match_result_ok.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_filter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_utils.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs196
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs152
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/try_err.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytecount.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/drain_collect.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/err_expect.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_used.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs324
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_next.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/format_collect.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_first.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_clone.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_flatten.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_identity.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs351
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/ok_expect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/open_options.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs124
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs74
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs83
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/useless_asref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/utils.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/min_ident_chars.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_assert_message.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/module_style.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_else.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_if.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_late_init.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs441
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs75
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/bit_mask.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs207
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/eq_op.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/op_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/option_env_unwrap.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_unimplemented.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_to_none.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs72
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark_used.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/raw_strings.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_async_block.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs126
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/reference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs90
-rw-r--r--src/tools/clippy/clippy_lints/src/self_named_constructors.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_block.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs65
-rw-r--r--src/tools/clippy/clippy_lints/src/single_call_fn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/single_component_path_imports.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs133
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs8
-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.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/to_digit_is_some.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/utils.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs324
-rw-r--r--src/tools/clippy/clippy_lints/src/types/borrowed_box.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/types/box_collection.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/types/linked_list.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/option_option.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/types/rc_buffer.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/types/rc_mutex.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/types/vec_box.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/uninit_vec.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnamed_address.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs108
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_unit.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/visibility.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs4
-rw-r--r--src/tools/clippy/clippy_test_deps/Cargo.toml23
-rw-r--r--src/tools/clippy/clippy_test_deps/src/lib.rs14
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/attrs.rs7
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs24
-rw-r--r--src/tools/clippy/clippy_utils/src/comparisons.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs32
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs39
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs9
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs32
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs420
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs20
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_origin.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs16
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs66
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs8
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs282
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/certainty.rs122
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs320
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs55
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs16
-rw-r--r--src/tools/clippy/declare_clippy_lint/Cargo.toml2
-rw-r--r--src/tools/clippy/lintcheck/src/config.rs3
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs4
-rw-r--r--src/tools/clippy/lintcheck/src/recursive.rs3
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/rustfmt.toml1
-rw-r--r--src/tools/clippy/src/driver.rs9
-rw-r--r--src/tools/clippy/src/main.rs3
-rw-r--r--src/tools/clippy/tests/compile-test.rs199
-rw-r--r--src/tools/clippy/tests/integration.rs24
-rw-r--r--src/tools/clippy/tests/lint_message_convention.rs6
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.stderr5
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr28
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr70
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs97
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml2
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs11
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs11
-rw-r--r--src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr4
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs1
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.stderr4
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr4
-rw-r--r--src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs4
-rw-r--r--src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr125
-rw-r--r--src/tools/clippy/tests/ui/arc_with_non_send_sync.rs30
-rw-r--r--src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr6
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.rs12
-rw-r--r--src/tools/clippy/tests/ui/as_conversions.rs3
-rw-r--r--src/tools/clippy/tests/ui/as_conversions.stderr6
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs3
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs4
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macros.rs11
-rw-r--r--src/tools/clippy/tests/ui/bind_instead_of_map.stderr2
-rw-r--r--src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr10
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.fixed1
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.rs1
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.stderr44
-rw-r--r--src/tools/clippy/tests/ui/borrow_box.rs6
-rw-r--r--src/tools/clippy/tests/ui/borrow_box.stderr20
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.fixed12
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.rs12
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.stderr40
-rw-r--r--src/tools/clippy/tests/ui/const_comparisons.rs93
-rw-r--r--src/tools/clippy/tests/ui/const_comparisons.stderr228
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6256.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-7169.stderr2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-8250.stderr2
-rw-r--r--src/tools/clippy/tests/ui/default_trait_access.fixed3
-rw-r--r--src/tools/clippy/tests/ui/default_trait_access.rs3
-rw-r--r--src/tools/clippy/tests/ui/default_trait_access.stderr16
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof.stderr20
-rw-r--r--src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr6
-rw-r--r--src/tools/clippy/tests/ui/derive.rs6
-rw-r--r--src/tools/clippy/tests/ui/derive.stderr20
-rw-r--r--src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs1
-rw-r--r--src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr16
-rw-r--r--src/tools/clippy/tests/ui/entry.stderr20
-rw-r--r--src/tools/clippy/tests/ui/entry_btree.stderr2
-rw-r--r--src/tools/clippy/tests/ui/entry_with_else.stderr14
-rw-r--r--src/tools/clippy/tests/ui/error_impl_error.rs90
-rw-r--r--src/tools/clippy/tests/ui/error_impl_error.stderr45
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed57
-rw-r--r--src/tools/clippy/tests/ui/eta.rs57
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr8
-rw-r--r--src/tools/clippy/tests/ui/expect.stderr6
-rw-r--r--src/tools/clippy/tests/ui/expect_fun_call.stderr30
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.stderr78
-rw-r--r--src/tools/clippy/tests/ui/explicit_deref_methods.fixed1
-rw-r--r--src/tools/clippy/tests/ui/explicit_deref_methods.rs1
-rw-r--r--src/tools/clippy/tests/ui/explicit_deref_methods.stderr48
-rw-r--r--src/tools/clippy/tests/ui/explicit_write.stderr26
-rw-r--r--src/tools/clippy/tests/ui/extend_with_drain.stderr8
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then.fixed58
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then.rs58
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then.stderr40
-rw-r--r--src/tools/clippy/tests/ui/filter_map_next_fixable.stderr4
-rw-r--r--src/tools/clippy/tests/ui/fn_null_check.rs22
-rw-r--r--src/tools/clippy/tests/ui/fn_null_check.stderr43
-rw-r--r--src/tools/clippy/tests/ui/format_collect.rs31
-rw-r--r--src/tools/clippy/tests/ui/format_collect.stderr62
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes.fixed48
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes.rs48
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes.stderr68
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed7
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs7
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr15
-rw-r--r--src/tools/clippy/tests/ui/get_first.fixed4
-rw-r--r--src/tools/clippy/tests/ui/get_first.rs4
-rw-r--r--src/tools/clippy/tests/ui/get_first.stderr6
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.fixed4
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.rs4
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.stderr133
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else.rs41
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else.stderr20
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else2.rs2
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else2.stderr21
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.rs4
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.stderr4
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.fixed17
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.rs17
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.stderr28
-rw-r--r--src/tools/clippy/tests/ui/incorrect_clone_impl_on_copy_type.stderr4
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed145
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs149
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr31
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs51
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr31
-rw-r--r--src/tools/clippy/tests/ui/infallible_destructuring_match.stderr8
-rw-r--r--src/tools/clippy/tests/ui/inherent_to_string.rs26
-rw-r--r--src/tools/clippy/tests/ui/inherent_to_string.stderr10
-rw-r--r--src/tools/clippy/tests/ui/issue-7447.rs5
-rw-r--r--src/tools/clippy/tests/ui/issue-7447.stderr4
-rw-r--r--src/tools/clippy/tests/ui/iter_cloned_collect.fixed3
-rw-r--r--src/tools/clippy/tests/ui/iter_cloned_collect.rs3
-rw-r--r--src/tools/clippy/tests/ui/iter_cloned_collect.stderr10
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.stderr14
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_zero.fixed25
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_zero.rs25
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_zero.stderr43
-rw-r--r--src/tools/clippy/tests/ui/iter_with_drain.stderr12
-rw-r--r--src/tools/clippy/tests/ui/let_and_return.rs71
-rw-r--r--src/tools/clippy/tests/ui/let_and_return.stderr22
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_lock.rs3
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_lock.stderr8
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_untyped.rs3
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_untyped.stderr20
-rw-r--r--src/tools/clippy/tests/ui/manual_filter.stderr30
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.fixed24
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.rs28
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.stderr73
-rw-r--r--src/tools/clippy/tests/ui/manual_find_map.stderr53
-rw-r--r--src/tools/clippy/tests/ui/manual_float_methods.rs55
-rw-r--r--src/tools/clippy/tests/ui/manual_float_methods.stderr80
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else.rs8
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else.stderr2
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_question_mark.fixed63
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_question_mark.rs68
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr55
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option.stderr42
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option_2.stderr10
-rw-r--r--src/tools/clippy/tests/ui/manual_range_patterns.fixed4
-rw-r--r--src/tools/clippy/tests/ui/manual_range_patterns.rs4
-rw-r--r--src/tools/clippy/tests/ui/manual_range_patterns.stderr16
-rw-r--r--src/tools/clippy/tests/ui/manual_retain.fixed7
-rw-r--r--src/tools/clippy/tests/ui/manual_retain.rs7
-rw-r--r--src/tools/clippy/tests/ui/manual_retain.stderr38
-rw-r--r--src/tools/clippy/tests/ui/manual_split_once.stderr28
-rw-r--r--src/tools/clippy/tests/ui/manual_str_repeat.stderr20
-rw-r--r--src/tools/clippy/tests/ui/manual_try_fold.rs4
-rw-r--r--src/tools/clippy/tests/ui/manual_try_fold.stderr8
-rw-r--r--src/tools/clippy/tests/ui/map_collect_result_unit.stderr4
-rw-r--r--src/tools/clippy/tests/ui/map_unwrap_or.stderr2
-rw-r--r--src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr4
-rw-r--r--src/tools/clippy/tests/ui/match_as_ref.fixed4
-rw-r--r--src/tools/clippy/tests/ui/match_as_ref.rs4
-rw-r--r--src/tools/clippy/tests/ui/match_as_ref.stderr8
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed3
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs3
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr56
-rw-r--r--src/tools/clippy/tests/ui/match_on_vec_items.stderr16
-rw-r--r--src/tools/clippy/tests/ui/match_ref_pats.stderr4
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.stderr2
-rw-r--r--src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr20
-rw-r--r--src/tools/clippy/tests/ui/methods.rs5
-rw-r--r--src/tools/clippy/tests/ui/methods.stderr4
-rw-r--r--src/tools/clippy/tests/ui/methods_fixable.stderr2
-rw-r--r--src/tools/clippy/tests/ui/methods_unfixable.rs10
-rw-r--r--src/tools/clippy/tests/ui/methods_unfixable.stderr15
-rw-r--r--src/tools/clippy/tests/ui/min_ident_chars.rs7
-rw-r--r--src/tools/clippy/tests/ui/min_ident_chars.stderr58
-rw-r--r--src/tools/clippy/tests/ui/min_max.rs4
-rw-r--r--src/tools/clippy/tests/ui/min_max.stderr26
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs1
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr8
-rw-r--r--src/tools/clippy/tests/ui/missing_doc.rs4
-rw-r--r--src/tools/clippy/tests/ui/missing_spin_loop.stderr12
-rw-r--r--src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr2
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.fixed7
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.rs7
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.stderr10
-rw-r--r--src/tools/clippy/tests/ui/mut_from_ref.rs2
-rw-r--r--src/tools/clippy/tests/ui/mut_key.rs3
-rw-r--r--src/tools/clippy/tests/ui/mut_key.stderr34
-rw-r--r--src/tools/clippy/tests/ui/mut_mut.rs7
-rw-r--r--src/tools/clippy/tests/ui/mut_mut.stderr18
-rw-r--r--src/tools/clippy/tests/ui/mut_reference.rs15
-rw-r--r--src/tools/clippy/tests/ui/mut_reference.stderr6
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow_pat.stderr24
-rw-r--r--src/tools/clippy/tests/ui/needless_else.stderr2
-rw-r--r--src/tools/clippy/tests/ui/needless_if.fixed3
-rw-r--r--src/tools/clippy/tests/ui/needless_if.rs3
-rw-r--r--src/tools/clippy/tests/ui/needless_if.stderr14
-rw-r--r--src/tools/clippy/tests/ui/needless_option_as_deref.stderr6
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs254
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr110
-rw-r--r--src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed40
-rw-r--r--src/tools/clippy/tests/ui/needless_return_with_question_mark.rs40
-rw-r--r--src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr10
-rw-r--r--src/tools/clippy/tests/ui/needless_splitn.stderr26
-rw-r--r--src/tools/clippy/tests/ui/numbered_fields.stderr4
-rw-r--r--src/tools/clippy/tests/ui/option_env_unwrap.rs1
-rw-r--r--src/tools/clippy/tests/ui/option_env_unwrap.stderr18
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed3
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.rs3
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.stderr46
-rw-r--r--src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr38
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed66
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.rs58
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr178
-rw-r--r--src/tools/clippy/tests/ui/or_then_unwrap.stderr6
-rw-r--r--src/tools/clippy/tests/ui/panic_in_result_fn.stderr74
-rw-r--r--src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr12
-rw-r--r--src/tools/clippy/tests/ui/print_literal.stderr24
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.rs16
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.stderr46
-rw-r--r--src/tools/clippy/tests/ui/ptr_as_ptr.fixed16
-rw-r--r--src/tools/clippy/tests/ui/ptr_as_ptr.rs16
-rw-r--r--src/tools/clippy/tests/ui/ptr_as_ptr.stderr28
-rw-r--r--src/tools/clippy/tests/ui/question_mark.fixed17
-rw-r--r--src/tools/clippy/tests/ui/question_mark.rs17
-rw-r--r--src/tools/clippy/tests/ui/question_mark.stderr6
-rw-r--r--src/tools/clippy/tests/ui/range_contains.fixed2
-rw-r--r--src/tools/clippy/tests/ui/range_contains.rs2
-rw-r--r--src/tools/clippy/tests/ui/range_contains.stderr42
-rw-r--r--src/tools/clippy/tests/ui/read_line_without_trim.fixed36
-rw-r--r--src/tools/clippy/tests/ui/read_line_without_trim.rs36
-rw-r--r--src/tools/clippy/tests/ui/read_line_without_trim.stderr73
-rw-r--r--src/tools/clippy/tests/ui/read_zero_byte_vec.rs6
-rw-r--r--src/tools/clippy/tests/ui/read_zero_byte_vec.stderr20
-rw-r--r--src/tools/clippy/tests/ui/readonly_write_lock.rs42
-rw-r--r--src/tools/clippy/tests/ui/readonly_write_lock.stderr16
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation.rs9
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation.stderr40
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed12
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation_fixable.rs12
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr24
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.fixed146
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.rs146
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.stderr98
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.rs120
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.stderr136
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr44
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed6
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs6
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr72
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed14
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs14
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr128
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr36
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr56
-rw-r--r--src/tools/clippy/tests/ui/ref_binding_to_reference.stderr14
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed6
-rw-r--r--src/tools/clippy/tests/ui/rename.rs6
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr118
-rw-r--r--src/tools/clippy/tests/ui/result_map_or_into_option.fixed2
-rw-r--r--src/tools/clippy/tests/ui/result_map_or_into_option.rs2
-rw-r--r--src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr36
-rw-r--r--src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr12
-rw-r--r--src/tools/clippy/tests/ui/self_assignment.rs4
-rw-r--r--src/tools/clippy/tests/ui/self_assignment.stderr6
-rw-r--r--src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed123
-rw-r--r--src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs7
-rw-r--r--src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr10
-rw-r--r--src/tools/clippy/tests/ui/shadow.rs7
-rw-r--r--src/tools/clippy/tests/ui/shadow.stderr92
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs3
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr52
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.fixed50
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.rs50
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.stderr6
-rw-r--r--src/tools/clippy/tests/ui/single_component_path_imports.fixed4
-rw-r--r--src/tools/clippy/tests/ui/single_component_path_imports.rs4
-rw-r--r--src/tools/clippy/tests/ui/single_component_path_imports.stderr4
-rw-r--r--src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs2
-rw-r--r--src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr4
-rw-r--r--src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs1
-rw-r--r--src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs1
-rw-r--r--src/tools/clippy/tests/ui/single_match.fixed1
-rw-r--r--src/tools/clippy/tests/ui/single_match.rs1
-rw-r--r--src/tools/clippy/tests/ui/single_match.stderr72
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.stderr18
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.rs16
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.stderr62
-rw-r--r--src/tools/clippy/tests/ui/string_extend.stderr8
-rw-r--r--src/tools/clippy/tests/ui/string_lit_chars_any.fixed50
-rw-r--r--src/tools/clippy/tests/ui/string_lit_chars_any.rs50
-rw-r--r--src/tools/clippy/tests/ui/string_lit_chars_any.stderr58
-rw-r--r--src/tools/clippy/tests/ui/strlen_on_c_strings.stderr14
-rw-r--r--src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr10
-rw-r--r--src/tools/clippy/tests/ui/swap.fixed3
-rw-r--r--src/tools/clippy/tests/ui/swap.rs3
-rw-r--r--src/tools/clippy/tests/ui/swap.stderr34
-rw-r--r--src/tools/clippy/tests/ui/to_digit_is_some.stderr4
-rw-r--r--src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs3
-rw-r--r--src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr36
-rw-r--r--src/tools/clippy/tests/ui/try_err.fixed6
-rw-r--r--src/tools/clippy/tests/ui/try_err.rs6
-rw-r--r--src/tools/clippy/tests/ui/try_err.stderr44
-rw-r--r--src/tools/clippy/tests/ui/tuple_array_conversions.rs30
-rw-r--r--src/tools/clippy/tests/ui/tuple_array_conversions.stderr36
-rw-r--r--src/tools/clippy/tests/ui/type_id_on_box.fixed40
-rw-r--r--src/tools/clippy/tests/ui/type_id_on_box.rs40
-rw-r--r--src/tools/clippy/tests/ui/type_id_on_box.stderr36
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.fixed17
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.rs17
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.stderr88
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast_unfixable.rs22
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr16
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_clone.stderr12
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_filter_map.rs6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_filter_map.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_find_map.rs6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_find_map.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed21
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs21
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr86
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.fixed3
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.rs3
-rw-r--r--src/tools/clippy/tests/ui/unsafe_removed_from_name.rs8
-rw-r--r--src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr16
-rw-r--r--src/tools/clippy/tests/ui/unused_async.rs17
-rw-r--r--src/tools/clippy/tests/ui/unused_async.stderr14
-rw-r--r--src/tools/clippy/tests/ui/unused_io_amount.rs2
-rw-r--r--src/tools/clippy/tests/ui/unused_peekable.rs3
-rw-r--r--src/tools/clippy/tests/ui/unused_peekable.stderr16
-rw-r--r--src/tools/clippy/tests/ui/unwrap.stderr9
-rw-r--r--src/tools/clippy/tests/ui/unwrap_expect_used.rs11
-rw-r--r--src/tools/clippy/tests/ui/unwrap_expect_used.stderr24
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or.stderr4
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or_else_default.fixed62
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or_else_default.rs62
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or_else_default.stderr100
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.fixed6
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.rs6
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.stderr44
-rw-r--r--src/tools/clippy/tests/ui/vec.fixed40
-rw-r--r--src/tools/clippy/tests/ui/vec.rs40
-rw-r--r--src/tools/clippy/tests/ui/vec.stderr24
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr12
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.fixed1
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.rs1
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.stderr24
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed1
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr24
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed1
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr24
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.rs1
-rw-r--r--src/tools/clippy/tests/ui/write_literal.stderr24
-rw-r--r--src/tools/clippy/tests/ui/write_literal_2.stderr28
-rw-r--r--src/tools/clippy/triagebot.toml5
-rwxr-xr-xsrc/tools/clippy/util/fetch_prs_between.sh22
750 files changed, 14301 insertions, 5174 deletions
diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml
index c582c28cd..410ff53a2 100644
--- a/src/tools/clippy/.github/workflows/clippy.yml
+++ b/src/tools/clippy/.github/workflows/clippy.yml
@@ -50,7 +50,7 @@ jobs:
echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV
- name: Build
- run: cargo build --features deny-warnings,internal
+ run: cargo build --tests --features deny-warnings,internal
- name: Test
run: cargo test --features deny-warnings,internal
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index d5ab313ba..5c69714bc 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -106,7 +106,7 @@ jobs:
echo "$SYSROOT/bin" >> $GITHUB_PATH
- name: Build
- run: cargo build --features deny-warnings,internal
+ run: cargo build --tests --features deny-warnings,internal
- name: Test
if: runner.os == 'Linux'
@@ -187,16 +187,14 @@ jobs:
- name: Extract Binaries
run: |
DIR=$CARGO_TARGET_DIR/debug
- rm $DIR/deps/integration-*.d
- mv $DIR/deps/integration-* $DIR/integration
+ find $DIR/deps/integration-* -executable ! -type d | xargs -I {} mv {} $DIR/integration
find $DIR ! -executable -o -type d ! -path $DIR | xargs rm -rf
- rm -rf $CARGO_TARGET_DIR/release
- name: Upload Binaries
- uses: actions/upload-artifact@v1
+ uses: actions/upload-artifact@v3
with:
- name: target
- path: target
+ name: binaries
+ path: target/debug
integration:
needs: integration_build
@@ -206,22 +204,20 @@ jobs:
matrix:
integration:
- 'rust-lang/cargo'
- # FIXME: re-enable once fmt_macros is renamed in RLS
- # - 'rust-lang/rls'
- 'rust-lang/chalk'
- 'rust-lang/rustfmt'
- 'Marwes/combine'
- 'Geal/nom'
- 'rust-lang/stdarch'
- 'serde-rs/serde'
- # FIXME: chrono currently cannot be compiled with `--all-targets`
- # - 'chronotope/chrono'
+ - 'chronotope/chrono'
- 'hyperium/hyper'
- 'rust-random/rand'
- 'rust-lang/futures-rs'
- 'rust-itertools/itertools'
- 'rust-lang-nursery/failure'
- 'rust-lang/log'
+ - 'matthiaskrgr/clippy_ci_panic_test'
runs-on: ubuntu-latest
@@ -237,12 +233,17 @@ jobs:
- name: Install toolchain
run: rustup show active-toolchain
+ - name: Set LD_LIBRARY_PATH
+ run: |
+ SYSROOT=$(rustc --print sysroot)
+ echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV
+
# Download
- name: Download target dir
- uses: actions/download-artifact@v1
+ uses: actions/download-artifact@v3
with:
- name: target
- path: target
+ name: binaries
+ path: target/debug
- name: Make Binaries Executable
run: chmod +x $CARGO_TARGET_DIR/debug/*
@@ -251,7 +252,7 @@ jobs:
- name: Test ${{ matrix.integration }}
run: |
RUSTUP_TOOLCHAIN="$(rustup show active-toolchain | grep -o -E "nightly-[0-9]{4}-[0-9]{2}-[0-9]{2}")" \
- $CARGO_TARGET_DIR/debug/integration
+ $CARGO_TARGET_DIR/debug/integration --show-output
env:
INTEGRATION: ${{ matrix.integration }}
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 14d822083..71671273c 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,13 +6,74 @@ document.
## Unreleased / Beta / In Rust Nightly
-[83e42a23...master](https://github.com/rust-lang/rust-clippy/compare/83e42a23...master)
+[435a8ad8...master](https://github.com/rust-lang/rust-clippy/compare/435a8ad8...master)
+
+## Rust 1.71
+
+Current stable, released 2023-07-13
+
+<!-- FIXME: Remove the request for feedback, with the next changelog -->
+
+We're trying out a new shorter changelog format, that only contains significant changes.
+You can check out the list of merged pull requests for a list of all changes.
+If you have any feedback related to the new format, please share it in
+[#10847](https://github.com/rust-lang/rust-clippy/issues/10847)
+
+[View all 78 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-04-11T20%3A05%3A26Z..2023-05-20T13%3A48%3A17Z+base%3Amaster)
+
+### New Lints
+
+* [`non_minimal_cfg`]
+ [#10763](https://github.com/rust-lang/rust-clippy/pull/10763)
+* [`manual_next_back`]
+ [#10769](https://github.com/rust-lang/rust-clippy/pull/10769)
+* [`ref_patterns`]
+ [#10736](https://github.com/rust-lang/rust-clippy/pull/10736)
+* [`default_constructed_unit_structs`]
+ [#10716](https://github.com/rust-lang/rust-clippy/pull/10716)
+* [`manual_while_let_some`]
+ [#10647](https://github.com/rust-lang/rust-clippy/pull/10647)
+* [`needless_bool_assign`]
+ [#10432](https://github.com/rust-lang/rust-clippy/pull/10432)
+* [`items_after_test_module`]
+ [#10578](https://github.com/rust-lang/rust-clippy/pull/10578)
+
+### Moves and Deprecations
+
+* Rename `integer_arithmetic` to `arithmetic_side_effects`
+ [#10674](https://github.com/rust-lang/rust-clippy/pull/10674)
+* Moved [`redundant_clone`] to `nursery` (Now allow-by-default)
+ [#10873](https://github.com/rust-lang/rust-clippy/pull/10873)
+
+### Enhancements
+
+* [`invalid_regex`]: Now supports the new syntax introduced after regex v1.8.0
+ [#10682](https://github.com/rust-lang/rust-clippy/pull/10682)
+* [`semicolon_outside_block`]: Added [`semicolon-outside-block-ignore-multiline`] as a new config value.
+ [#10656](https://github.com/rust-lang/rust-clippy/pull/10656)
+* [`semicolon_inside_block`]: Added [`semicolon-inside-block-ignore-singleline`] as a new config value.
+ [#10656](https://github.com/rust-lang/rust-clippy/pull/10656)
+* [`unnecessary_box_returns`]: Added [`unnecessary-box-size`] as a new config value to set the maximum
+ size of `T` in `Box<T>` to be linted.
+ [#10651](https://github.com/rust-lang/rust-clippy/pull/10651)
+
+### Documentation Improvements
+
+* `cargo clippy --explain LINT` now shows possible configuration options for the explained lint
+ [#10751](https://github.com/rust-lang/rust-clippy/pull/10751)
+* New config values mentioned in this changelog will now be linked.
+ [#10889](https://github.com/rust-lang/rust-clippy/pull/10889)
+* Several sections of [Clippy's book] have been reworked
+ [#10652](https://github.com/rust-lang/rust-clippy/pull/10652)
+ [#10622](https://github.com/rust-lang/rust-clippy/pull/10622)
+
+[Clippy's book]: https://doc.rust-lang.org/clippy/
## Rust 1.70
-Current stable, released 2023-06-01
+Released 2023-06-01
-[**View 85 PRs merged since 1.69**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-04-20..2023-06-01+base%3Amaster+sort%3Amerged-desc+)
+[View all 91 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-02-26T01%3A05%3A43Z..2023-04-11T13%3A27%3A30Z+base%3Amaster)
### New Lints
@@ -137,7 +198,7 @@ Current stable, released 2023-06-01
Released 2023-04-20
-[**View 86 PRs merged since 1.68**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-03-09..2023-04-20+base%3Amaster+sort%3Amerged-desc+)
+[View all 72 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-01-13T06%3A12%3A46Z..2023-02-25T23%3A48%3A10Z+base%3Amaster)
### New Lints
@@ -252,7 +313,7 @@ Released 2023-04-20
Released 2023-03-09
-[**View 85 PRs merged since 1.67**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-01-26..2023-03-09+base%3Amaster+sort%3Amerged-desc+)
+[View all 76 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-12-01T20%3A40%3A04Z..2023-01-12T18%3A58%3A59Z+base%3Amaster)
### New Lints
@@ -399,7 +460,7 @@ Released 2023-03-09
Released 2023-01-26
-[**View 68 PRs merged since 1.66**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-12-15..2023-01-26+base%3Amaster+sort%3Amerged-desc+)
+[View all 104 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-10-23T13%3A35%3A19Z..2022-12-01T13%3A34%3A39Z+base%3Amaster)
### New Lints
@@ -590,8 +651,7 @@ Released 2023-01-26
Released 2022-12-15
-[**View 93 PRs merged since 1.65**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-11-03..2022-12-15+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 116 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-09-09T17%3A32%3A39Z..2022-10-23T11%3A27%3A24Z+base%3Amaster)
### New Lints
@@ -762,8 +822,7 @@ Released 2022-12-15
Released 2022-11-03
-[**View 129 PRs merged since 1.64**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-09-22..2022-11-03+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 86 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-07-29T01%3A09%3A31Z..2022-09-09T00%3A01%3A54Z+base%3Amaster)
### Important Changes
@@ -907,8 +966,7 @@ Released 2022-11-03
Released 2022-09-22
-[**View 92 PRs merged since 1.63**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-08-11..2022-09-22+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 110 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-06-17T21%3A25%3A31Z..2022-07-28T17%3A11%3A18Z+base%3Amaster)
### New Lints
@@ -1058,8 +1116,7 @@ Released 2022-09-22
Released 2022-08-11
-[**View 100 PRs merged since 1.62**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-06-30..2022-08-11+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 91 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-05-05T17%3A24%3A22Z..2022-06-16T14%3A24%3A48Z+base%3Amaster)
### New Lints
@@ -1205,8 +1262,7 @@ Released 2022-08-11
Released 2022-06-30
-[**View 104 PRs merged since 1.61**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-05-19..2022-06-30+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 90 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-03-25T17%3A22%3A30Z..2022-05-05T13%3A29%3A44Z+base%3Amaster)
### New Lints
@@ -1363,8 +1419,7 @@ Released 2022-06-30
Released 2022-05-19
-[**View 93 PRs merged since 1.60**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-04-07..2022-05-19+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 60 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-02-11T16%3A54%3A41Z..2022-03-24T13%3A42%3A25Z+base%3Amaster)
### New Lints
@@ -1465,8 +1520,7 @@ Released 2022-05-19
Released 2022-04-07
-[**View 75 PRs merged since 1.59**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-02-24..2022-04-07+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 73 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-12-31T17%3A53%3A37Z..2022-02-10T17%3A31%3A37Z+base%3Amaster)
### New Lints
@@ -1598,8 +1652,7 @@ Released 2022-04-07
Released 2022-02-24
-[**View 63 PRs merged since 1.58**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-01-13..2022-02-24+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 94 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-11-04T12%3A40%3A18Z..2021-12-30T13%3A36%3A20Z+base%3Amaster)
### New Lints
@@ -1763,8 +1816,7 @@ Released 2022-02-24
Released 2022-01-13
-[**View 73 PRs merged since 1.57**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-12-02..2022-01-13+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 68 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-10-07T09%3A49%3A18Z..2021-11-04T12%3A20%3A12Z+base%3Amaster)
### Rust 1.58.1
@@ -1885,8 +1937,7 @@ Released 2022-01-13
Released 2021-12-02
-[**View 92 PRs merged since 1.56**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-10-21..2021-12-02+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 148 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-08-12T20%3A36%3A04Z..2021-11-03T17%3A57%3A59Z+base%3Amaster)
### New Lints
@@ -2037,7 +2088,7 @@ Released 2021-12-02
Released 2021-10-21
-[**View 92 PRs merged since 1.55**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-09-09..2021-10-21+base%3Amaster+sort%3Amerged-desc+)
+[View all 38 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-07-19T14%3A33%3A33Z..2021-08-12T09%3A28%3A38Z+base%3Amaster)
### New Lints
@@ -2103,7 +2154,7 @@ Released 2021-10-21
Released 2021-09-09
-[**View 61 PRs merged since 1.54**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-07-29..2021-09-09+base%3Amaster+sort%3Amerged-desc+)
+[View all 83 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-06-03T07%3A23%3A59Z..2021-07-29T11%3A47%3A32Z+base%3Amaster)
### Important Changes
@@ -2221,8 +2272,7 @@ Released 2021-09-09
Released 2021-07-29
-[**View 68 PRs merged since 1.53**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-06-17..2021-07-29+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 74 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-04-27T23%3A51%3A18Z..2021-06-03T06%3A54%3A07Z+base%3Amaster)
### New Lints
@@ -2350,7 +2400,7 @@ Released 2021-07-29
Released 2021-06-17
-[**View 80 PRs merged since 1.52**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-05-06..2021-06-17+base%3Amaster+sort%3Amerged-desc+)
+[View all 126 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-03-12T22%3A49%3A20Z..2021-04-27T14%3A38%3A20Z+base%3Amaster)
### New Lints
@@ -2534,8 +2584,7 @@ Released 2021-06-17
Released 2021-05-06
-[**View 113 PRs merged since 1.51**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-03-25..2021-05-06+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 102 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-02-03T15%3A59%3A06Z..2021-03-11T20%3A06%3A43Z+base%3Amaster)
### New Lints
@@ -2670,8 +2719,7 @@ Released 2021-05-06
Released 2021-03-25
-[**View 117 PRs merged since 1.50**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-02-11..2021-03-25+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 78 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-12-21T15%3A43%3A04Z..2021-02-03T04%3A21%3A10Z+base%3Amaster)
### New Lints
@@ -2786,8 +2834,7 @@ Released 2021-03-25
Released 2021-02-11
-[**View 90 PRs merged since 1.49**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-12-31..2021-02-11+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 119 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-11-06T18%3A32%3A40Z..2021-01-03T14%3A51%3A18Z+base%3Amaster)
### New Lints
@@ -2916,8 +2963,7 @@ Released 2021-02-11
Released 2020-12-31
-[**View 85 PRs merged since 1.48**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-11-19..2020-12-31+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 107 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-09-24T14%3A05%3A12Z..2020-11-05T13%3A35%3A44Z+base%3Amaster)
### New Lints
@@ -3023,7 +3069,7 @@ Released 2020-12-31
Released 2020-11-19
-[**View 112 PRs merged since 1.47**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-10-08..2020-11-19+base%3Amaster+sort%3Amerged-desc+)
+[View all 99 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-08-11T13%3A14%3A38Z..2020-09-23T18%3A55%3A22Z+base%3Amaster)
### New lints
@@ -3141,8 +3187,7 @@ Released 2020-11-19
Released 2020-10-08
-[**View 80 PRs merged since 1.46**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-08-27..2020-10-08+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 76 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-06-23T16%3A27%3A11Z..2020-08-11T12%3A52%3A41Z+base%3Amaster)
### New lints
@@ -3244,8 +3289,7 @@ Released 2020-10-08
Released 2020-08-27
-[**View 93 PRs merged since 1.45**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-07-16..2020-08-27+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 48 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-05-31T12%3A50%3A53Z..2020-06-23T15%3A00%3A32Z+base%3Amaster)
### New lints
@@ -3307,8 +3351,7 @@ Released 2020-08-27
Released 2020-07-16
-[**View 65 PRs merged since 1.44**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-06-04..2020-07-16+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 81 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-04-18T20%3A18%3A04Z..2020-05-27T19%3A25%3A04Z+base%3Amaster)
### New lints
@@ -3385,8 +3428,7 @@ and [`similar_names`]. [#5651](https://github.com/rust-lang/rust-clippy/pull/565
Released 2020-06-04
-[**View 88 PRs merged since 1.43**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-04-23..2020-06-04+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 124 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-03-05T17%3A30%3A53Z..2020-04-18T09%3A20%3A51Z+base%3Amaster)
### New lints
@@ -3469,8 +3511,7 @@ Released 2020-06-04
Released 2020-04-23
-[**View 121 PRs merged since 1.42**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-03-12..2020-04-23+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 91 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-01-26T16%3A01%3A11Z..2020-03-04T16%3A45%3A37Z+base%3Amaster)
### New lints
@@ -3528,7 +3569,7 @@ Released 2020-04-23
Released 2020-03-12
-[**View 106 PRs merged since 1.41**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-01-30..2020-03-12+base%3Amaster+sort%3Amerged-desc+)
+[View all 101 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-12-15T01%3A40%3A34Z..2020-01-26T11%3A22%3A13Z+base%3Amaster)
### New lints
@@ -3595,7 +3636,7 @@ Released 2020-03-12
Released 2020-01-30
-[**View 107 PRs merged since 1.40**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-12-19..2020-01-30+base%3Amaster+sort%3Amerged-desc+)
+[View all 74 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-10-28T20%3A50%3A24Z..2019-12-12T00%3A53%3A03Z+base%3Amaster)
* New Lints:
* [`exit`] [#4697](https://github.com/rust-lang/rust-clippy/pull/4697)
@@ -3640,8 +3681,7 @@ Released 2020-01-30
Released 2019-12-19
-[**View 69 😺 PRs merged since 1.39**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-11-07..2019-12-19+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 76 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-09-23T06%3A18%3A04Z..2019-10-28T17%3A34%3A55Z+base%3Amaster)
* New Lints:
* [`unneeded_wildcard_pattern`] [#4537](https://github.com/rust-lang/rust-clippy/pull/4537)
@@ -3683,7 +3723,7 @@ Released 2019-12-19
Released 2019-11-07
-[**View 84 PRs merged since 1.38**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-09-26..2019-11-07+base%3Amaster+sort%3Amerged-desc+)
+[View all 100 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-08-11T19%3A21%3A38Z..2019-09-22T12%3A07%3A39Z+base%3Amaster)
* New Lints:
* [`uninit_assumed_init`] [#4479](https://github.com/rust-lang/rust-clippy/pull/4479)
@@ -3727,7 +3767,7 @@ Released 2019-11-07
Released 2019-09-26
-[**View 102 PRs merged since 1.37**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-08-15..2019-09-26+base%3Amaster+sort%3Amerged-desc+)
+[View all 76 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-06-30T13%3A40%3A26Z..2019-08-11T09%3A47%3A27Z+base%3Amaster)
* New Lints:
* [`main_recursion`] [#4203](https://github.com/rust-lang/rust-clippy/pull/4203)
@@ -3757,7 +3797,7 @@ Released 2019-09-26
Released 2019-08-15
-[**View 83 PRs merged since 1.36**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-07-04..2019-08-15+base%3Amaster+sort%3Amerged-desc+)
+[View all 72 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-05-19T08%3A11%3A23Z..2019-06-25T23%3A22%3A22Z+base%3Amaster)
* New Lints:
* [`checked_conversions`] [#4088](https://github.com/rust-lang/rust-clippy/pull/4088)
@@ -3781,8 +3821,7 @@ Released 2019-08-15
Released 2019-07-04
-[**View 75 PRs merged since 1.35**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-05-20..2019-07-04+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 81 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-04-10T09%3A41%3A56Z..2019-05-18T00%3A29%3A40Z+base%3Amaster)
* New lints: [`find_map`], [`filter_map_next`] [#4039](https://github.com/rust-lang/rust-clippy/pull/4039)
* New lint: [`path_buf_push_overwrite`] [#3954](https://github.com/rust-lang/rust-clippy/pull/3954)
@@ -3813,8 +3852,7 @@ Released 2019-07-04
Released 2019-05-20
-[**View 90 PRs merged since 1.34**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-04-10..2019-05-20+base%3Amaster+sort%3Amerged-desc+)
-
+[1fac380..37f5c1e](https://github.com/rust-lang/rust-clippy/compare/1fac380...37f5c1e)
* New lint: `drop_bounds` to detect `T: Drop` bounds
* Split [`redundant_closure`] into [`redundant_closure`] and [`redundant_closure_for_method_calls`] [#4110](https://github.com/rust-lang/rust-clippy/pull/4101)
@@ -3842,8 +3880,7 @@ Released 2019-05-20
Released 2019-04-10
-[**View 66 PRs merged since 1.33**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-02-26..2019-04-10+base%3Amaster+sort%3Amerged-desc+)
-
+[View all 61 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-01-17T17%3A45%3A39Z..2019-02-19T08%3A24%3A05Z+base%3Amaster)
* New lint: [`assertions_on_constants`] to detect for example `assert!(true)`
* New lint: [`dbg_macro`] to detect uses of the `dbg!` macro
@@ -3873,7 +3910,7 @@ Released 2019-04-10
Released 2019-02-26
-[**View 83 PRs merged since 1.32**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-01-17..2019-02-26+base%3Amaster+sort%3Amerged-desc+)
+[View all 120 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2018-11-28T06%3A19%3A50Z..2019-01-15T09%3A27%3A02Z+base%3Amaster)
* New lints: [`implicit_return`], [`vec_box`], [`cast_ref_to_mut`]
* The `rust-clippy` repository is now part of the `rust-lang` org.
@@ -3906,7 +3943,7 @@ Released 2019-02-26
Released 2019-01-17
-[**View 106 PRs merged since 1.31**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2018-12-06..2019-01-17+base%3Amaster+sort%3Amerged-desc+)
+[View all 71 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2018-10-24T05%3A02%3A21Z..2018-11-27T17%3A29%3A34Z+base%3Amaster)
* New lints: [`slow_vector_initialization`], `mem_discriminant_non_enum`,
[`redundant_clone`], [`wildcard_dependencies`],
@@ -3936,8 +3973,7 @@ Released 2019-01-17
Released 2018-12-06
-[**View 85 PRs merged since 1.30**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2018-10-25..2018-12-06+base%3Amaster+sort%3Amerged-desc+)
-
+[125907ad..2e26fdc2](https://github.com/rust-lang/rust-clippy/compare/125907ad..2e26fdc2)
* Clippy has been relicensed under a dual MIT / Apache license.
See [#3093](https://github.com/rust-lang/rust-clippy/issues/3093) for more
@@ -3977,9 +4013,7 @@ Released 2018-12-06
Released 2018-10-25
-[**View 106 PRs merged since 1.29**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2018-09-13..2018-10-25+base%3Amaster+sort%3Amerged-desc+)
-
-
+[View all 88 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2018-08-02T16%3A54%3A12Z..2018-09-17T09%3A44%3A06Z+base%3Amaster)
* Deprecate `assign_ops` lint
* New lints: [`mistyped_literal_suffixes`], [`ptr_offset_with_cast`],
[`needless_collect`], [`copy_iterator`]
@@ -4646,6 +4680,7 @@ Released 2018-09-13
<!-- lint disable no-unused-definitions -->
<!-- begin autogenerated links to lint list -->
+[`absolute_paths`]: https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths
[`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
[`alloc_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#alloc_instead_of_core
[`allow_attributes`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes
@@ -4785,6 +4820,7 @@ Released 2018-09-13
[`equatable_if_let`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_if_let
[`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op
[`err_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#err_expect
+[`error_impl_error`]: https://rust-lang.github.io/rust-clippy/master/index.html#error_impl_error
[`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
[`excessive_nesting`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_nesting
[`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision
@@ -4808,6 +4844,7 @@ Released 2018-09-13
[`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
[`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file
[`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map
+[`filter_map_bool_then`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_bool_then
[`filter_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_identity
[`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next
[`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next
@@ -4831,8 +4868,10 @@ Released 2018-09-13
[`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
[`forget_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_non_drop
[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
+[`format_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_collect
[`format_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_in_format_args
[`format_push_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_push_string
+[`four_forward_slashes`]: https://rust-lang.github.io/rust-clippy/master/index.html#four_forward_slashes
[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
[`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
[`from_raw_with_void_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_raw_with_void_ptr
@@ -4851,16 +4890,19 @@ Released 2018-09-13
[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
+[`ignored_unit_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ignored_unit_patterns
[`impl_trait_in_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_in_params
[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
[`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
[`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
[`implicit_saturating_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_add
[`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub
+[`impossible_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#impossible_comparisons
[`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
[`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
[`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor
[`incorrect_clone_impl_on_copy_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#incorrect_clone_impl_on_copy_type
+[`incorrect_partial_ord_impl_on_ord_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#incorrect_partial_ord_impl_on_ord_type
[`index_refutable_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice
[`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing
[`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask
@@ -4902,6 +4944,7 @@ Released 2018-09-13
[`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items
[`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned
[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
+[`iter_skip_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_zero
[`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain
[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
@@ -4941,6 +4984,8 @@ Released 2018-09-13
[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
[`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed
[`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check
+[`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite
+[`manual_is_infinite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_infinite
[`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else
[`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str
[`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
@@ -5047,6 +5092,7 @@ Released 2018-09-13
[`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref
[`needless_option_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_take
[`needless_parens_on_range_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_parens_on_range_literals
+[`needless_pass_by_ref_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
[`needless_pub_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pub_self
[`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark
@@ -5054,6 +5100,7 @@ Released 2018-09-13
[`needless_raw_string_hashes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_string_hashes
[`needless_raw_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_strings
[`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
+[`needless_return_with_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return_with_question_mark
[`needless_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_splitn
[`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update
[`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord
@@ -5134,7 +5181,9 @@ Released 2018-09-13
[`rc_buffer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer
[`rc_clone_in_vec_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_clone_in_vec_init
[`rc_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex
+[`read_line_without_trim`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_line_without_trim
[`read_zero_byte_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_zero_byte_vec
+[`readonly_write_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#readonly_write_lock
[`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl
[`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
[`redundant_async_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_async_block
@@ -5143,9 +5192,12 @@ Released 2018-09-13
[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
[`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call
[`redundant_closure_for_method_calls`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_for_method_calls
+[`redundant_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_comparisons
[`redundant_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else
[`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names
[`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
+[`redundant_guards`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_guards
+[`redundant_locals`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_locals
[`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
[`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
[`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
@@ -5215,6 +5267,7 @@ Released 2018-09-13
[`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
[`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
+[`string_lit_chars_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_chars_any
[`string_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_slice
[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
[`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
@@ -5266,6 +5319,7 @@ Released 2018-09-13
[`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err
[`tuple_array_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions
[`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
+[`type_id_on_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_id_on_box
[`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
[`unchecked_duration_subtraction`]: https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction
[`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks
@@ -5322,6 +5376,7 @@ Released 2018-09-13
[`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
[`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
[`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result
+[`unwrap_or_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_default
[`unwrap_or_else_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_else_default
[`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
[`upper_case_acronyms`]: https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms
@@ -5422,4 +5477,6 @@ Released 2018-09-13
[`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement
[`accept-comment-above-attributes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-attributes
[`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings
+[`absolute-paths-max-segments`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-max-segments
+[`absolute-paths-allowed-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-allowed-crates
<!-- end autogenerated links to configuration documentation -->
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 76c804f93..0fb3a3a98 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy"
-version = "0.1.72"
+version = "0.1.73"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@@ -36,6 +36,17 @@ walkdir = "2.3"
filetime = "0.2"
itertools = "0.10.1"
+# UI test dependencies
+clippy_utils = { path = "clippy_utils" }
+derive-new = "0.5"
+if_chain = "1.0"
+quote = "1.0"
+serde = { version = "1.0.125", features = ["derive"] }
+syn = { version = "2.0", features = ["full"] }
+futures = "0.3"
+parking_lot = "0.12"
+tokio = { version = "1", features = ["io-util"] }
+
[build-dependencies]
rustc_tools_util = "0.3.0"
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index d712d3e67..5d490645d 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -5,7 +5,7 @@
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
-[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.
diff --git a/src/tools/clippy/book/src/README.md b/src/tools/clippy/book/src/README.md
index 3b6270962..486ea3df7 100644
--- a/src/tools/clippy/book/src/README.md
+++ b/src/tools/clippy/book/src/README.md
@@ -6,7 +6,7 @@
A collection of lints to catch common mistakes and improve your
[Rust](https://github.com/rust-lang/rust) code.
-[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
Lints are divided into categories, each with a default [lint
level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how
diff --git a/src/tools/clippy/book/src/development/infrastructure/changelog_update.md b/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
index 524454944..df9b1bbe1 100644
--- a/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
+++ b/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
@@ -56,28 +56,6 @@ and open that file in your editor of choice.
When updating the changelog it's also a good idea to make sure that `commit1` is
already correct in the current changelog.
-#### PR ranges
-
-We developed the concept of PR ranges to help the user understand the size of a new update. To create a PR range,
-get the current release date and the date that the last version was released (YYYY-MM-DD) and use the following link:
-
-```
-[**View <NUMBER OF PRs> PRs merged since 1.<LAST VERSION NUM>**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A<LAST VERSION DATE>..<CURRENT VERSION DATE>+base%3Amaster+sort%3Amerged-desc+)
-```
-
-> Note: Be sure to check click the link and check how many PRs got merged between
-
-Example:
-
-```
-[**View 85 PRs merged since 1.69**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-04-20..2023-06-01+base%3Amaster+sort%3Amerged-desc+)
-```
-
-Which renders to:
-[**View 85 PRs merged since 1.69**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-04-20..2023-06-01+base%3Amaster+sort%3Amerged-desc+)
-
-Note that **commit ranges should not be included**, only PR ranges.
-
### 3. Authoring the final changelog
The above script should have dumped all the relevant PRs to the file you
diff --git a/src/tools/clippy/book/src/development/speedtest.md b/src/tools/clippy/book/src/development/speedtest.md
new file mode 100644
index 000000000..0db718e6a
--- /dev/null
+++ b/src/tools/clippy/book/src/development/speedtest.md
@@ -0,0 +1,24 @@
+# Speedtest
+`SPEEDTEST` is the tool we use to measure lint's performance, it works by executing the same test several times.
+
+It's useful for measuring changes to current lints and deciding if the performance changes too much. `SPEEDTEST` is
+accessed by the `SPEEDTEST` (and `SPEEDTEST_*`) environment variables.
+
+## Checking Speedtest
+
+To do a simple speed test of a lint (e.g. `allow_attributes`), use this command.
+
+```sh
+$ SPEEDTEST=ui TESTNAME="allow_attributes" cargo uitest -- --nocapture
+```
+
+This will test all `ui` tests (`SPEEDTEST=ui`) whose names start with `allow_attributes`. By default, `SPEEDTEST` will
+iterate your test 1000 times. But you can change this with `SPEEDTEST_ITERATIONS`.
+
+```sh
+$ SPEEDTEST=toml SPEEDTEST_ITERATIONS=100 TESTNAME="semicolon_block" cargo uitest -- --nocapture
+```
+
+> **WARNING**: Be sure to use `-- --nocapture` at the end of the command to see the average test time. If you don't
+> use `-- --nocapture` (e.g. `SPEEDTEST=ui` `TESTNAME="let_underscore_untyped" cargo uitest -- --nocapture`), this
+> will not show up.
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 60d7ce6e6..caaad6d11 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -175,7 +175,7 @@ The maximum amount of nesting a block can reside in
## `disallowed-names`
The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
-`".."` can be used as part of the list to indicate, that the configured values should be appended to the
+`".."` can be used as part of the list to indicate that the configured values should be appended to the
default configuration of Clippy. By default, any configuration will replace the default value.
**Default Value:** `["foo", "baz", "quux"]` (`Vec<String>`)
@@ -730,3 +730,24 @@ Whether to allow `r#""#` when `r""` can be used
* [`unnecessary_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_raw_string_hashes)
+## `absolute-paths-max-segments`
+The maximum number of segments a path can have before being linted, anything above this will
+be linted.
+
+**Default Value:** `2` (`u64`)
+
+---
+**Affected lints:**
+* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths)
+
+
+## `absolute-paths-allowed-crates`
+Which crates to allow absolute paths from
+
+**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
+
+---
+**Affected lints:**
+* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths)
+
+
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 4624451cf..c4ae4f0e2 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -51,7 +51,7 @@ pub fn clippy_project_root() -> PathBuf {
for path in current_dir.ancestors() {
let result = std::fs::read_to_string(path.join("Cargo.toml"));
if let Err(err) = &result {
- if err.kind() == std::io::ErrorKind::NotFound {
+ if err.kind() == io::ErrorKind::NotFound {
continue;
}
}
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 43eaccdf5..fca750faf 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -41,7 +41,7 @@ fn main() {
matches.get_one::<String>("type").map(String::as_str),
matches.get_flag("msrv"),
) {
- Ok(_) => update_lints::update(update_lints::UpdateMode::Change),
+ Ok(()) => update_lints::update(update_lints::UpdateMode::Change),
Err(e) => eprintln!("Unable to create lint: {e}"),
}
},
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index f11aa547b..e64cf2c87 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -96,8 +96,7 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
path.push("src");
fs::create_dir(&path)?;
- let header = format!("//@compile-flags: --crate-name={lint_name}");
- write_file(path.join("main.rs"), get_test_file_contents(lint_name, Some(&header)))?;
+ write_file(path.join("main.rs"), get_test_file_contents(lint_name))?;
Ok(())
}
@@ -113,7 +112,7 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`");
} else {
let test_path = format!("tests/ui/{}.rs", lint.name);
- let test_contents = get_test_file_contents(lint.name, None);
+ let test_contents = get_test_file_contents(lint.name);
write_file(lint.project_root.join(&test_path), test_contents)?;
println!("Generated test file: `{test_path}`");
@@ -195,23 +194,16 @@ pub(crate) fn get_stabilization_version() -> String {
parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
}
-fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String {
- let mut contents = formatdoc!(
+fn get_test_file_contents(lint_name: &str) -> String {
+ formatdoc!(
r#"
- #![allow(unused)]
#![warn(clippy::{lint_name})]
fn main() {{
// test code goes here
}}
"#
- );
-
- if let Some(header) = header_commands {
- contents = format!("{header}\n{contents}");
- }
-
- contents
+ )
}
fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
@@ -358,6 +350,10 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
let mod_file_path = ty_dir.join("mod.rs");
let context_import = setup_mod_file(&mod_file_path, lint)?;
+ let pass_lifetimes = match context_import {
+ "LateContext" => "<'_>",
+ _ => "",
+ };
let name_upper = lint.name.to_uppercase();
let mut lint_file_contents = String::new();
@@ -372,7 +368,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
use super::{name_upper};
// TODO: Adjust the parameters as necessary
- pub(super) fn check(cx: &{context_import}, msrv: &Msrv) {{
+ pub(super) fn check(cx: &{context_import}{pass_lifetimes}, msrv: &Msrv) {{
if !msrv.meets(todo!("Add a new entry in `clippy_utils/src/msrvs`")) {{
return;
}}
@@ -389,7 +385,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
use super::{name_upper};
// TODO: Adjust the parameters as necessary
- pub(super) fn check(cx: &{context_import}) {{
+ pub(super) fn check(cx: &{context_import}{pass_lifetimes}) {{
todo!();
}}
"#
diff --git a/src/tools/clippy/clippy_dev/src/setup/intellij.rs b/src/tools/clippy/clippy_dev/src/setup/intellij.rs
index efdb158c2..a7138f36a 100644
--- a/src/tools/clippy/clippy_dev/src/setup/intellij.rs
+++ b/src/tools/clippy/clippy_dev/src/setup/intellij.rs
@@ -37,7 +37,7 @@ impl ClippyProjectInfo {
pub fn setup_rustc_src(rustc_path: &str) {
let Ok(rustc_source_dir) = check_and_get_rustc_dir(rustc_path) else {
- return
+ return;
};
for project in CLIPPY_PROJECTS {
diff --git a/src/tools/clippy/clippy_dev/src/setup/vscode.rs b/src/tools/clippy/clippy_dev/src/setup/vscode.rs
index dbcdc9b59..204f4af2c 100644
--- a/src/tools/clippy/clippy_dev/src/setup/vscode.rs
+++ b/src/tools/clippy/clippy_dev/src/setup/vscode.rs
@@ -47,7 +47,7 @@ fn check_install_precondition(force_override: bool) -> bool {
}
} else {
match fs::create_dir(vs_dir_path) {
- Ok(_) => {
+ Ok(()) => {
println!("info: created `{VSCODE_DIR}` directory for clippy");
},
Err(err) => {
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 7213c9dfe..7c2e06ea6 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -340,7 +340,10 @@ pub fn deprecate(name: &str, reason: Option<&String>) {
let name_upper = name.to_uppercase();
let (mut lints, deprecated_lints, renamed_lints) = gather_all();
- let Some(lint) = lints.iter().find(|l| l.name == name_lower) else { eprintln!("error: failed to find lint `{name}`"); return; };
+ let Some(lint) = lints.iter().find(|l| l.name == name_lower) else {
+ eprintln!("error: failed to find lint `{name}`");
+ return;
+ };
let mod_path = {
let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module));
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index c23054443..11136867f 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.72"
+version = "0.1.73"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/absolute_paths.rs b/src/tools/clippy/clippy_lints/src/absolute_paths.rs
new file mode 100644
index 000000000..04417c4c4
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/absolute_paths.rs
@@ -0,0 +1,100 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::source::snippet_opt;
+use rustc_data_structures::fx::FxHashSet;
+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_span::symbol::kw;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usage of items through absolute paths, like `std::env::current_dir`.
+ ///
+ /// ### Why is this bad?
+ /// Many codebases have their own style when it comes to importing, but one that is seldom used
+ /// is using absolute paths *everywhere*. This is generally considered unidiomatic, and you
+ /// should add a `use` statement.
+ ///
+ /// The default maximum segments (2) is pretty strict, you may want to increase this in
+ /// `clippy.toml`.
+ ///
+ /// Note: One exception to this is code from macro expansion - this does not lint such cases, as
+ /// using absolute paths is the proper way of referencing items in one.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let x = std::f64::consts::PI;
+ /// ```
+ /// Use any of the below instead, or anything else:
+ /// ```rust
+ /// use std::f64;
+ /// use std::f64::consts;
+ /// use std::f64::consts::PI;
+ /// let x = f64::consts::PI;
+ /// let x = consts::PI;
+ /// let x = PI;
+ /// use std::f64::consts as f64_consts;
+ /// let x = f64_consts::PI;
+ /// ```
+ #[clippy::version = "1.73.0"]
+ pub ABSOLUTE_PATHS,
+ restriction,
+ "checks for usage of an item without a `use` statement"
+}
+impl_lint_pass!(AbsolutePaths => [ABSOLUTE_PATHS]);
+
+pub struct AbsolutePaths {
+ pub absolute_paths_max_segments: u64,
+ pub absolute_paths_allowed_crates: FxHashSet<String>,
+}
+
+impl LateLintPass<'_> for AbsolutePaths {
+ // We should only lint `QPath::Resolved`s, but since `Path` is only used in `Resolved` and `UsePath`
+ // we don't need to use a visitor or anything as we can just check if the `Node` for `hir_id` isn't
+ // a `Use`
+ #[expect(clippy::cast_possible_truncation)]
+ fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
+ let Self {
+ absolute_paths_max_segments,
+ absolute_paths_allowed_crates,
+ } = self;
+
+ if !path.span.from_expansion()
+ && let Some(node) = cx.tcx.hir().find(hir_id)
+ && !matches!(node, Node::Item(item) if matches!(item.kind, ItemKind::Use(_, _)))
+ && let [first, rest @ ..] = path.segments
+ // Handle `::std`
+ && let (segment, len) = if first.ident.name == kw::PathRoot {
+ // Indexing is fine as `PathRoot` must be followed by another segment. `len() - 1`
+ // is fine here for the same reason
+ (&rest[0], path.segments.len() - 1)
+ } else {
+ (first, path.segments.len())
+ }
+ && len > *absolute_paths_max_segments as usize
+ && let Some(segment_snippet) = snippet_opt(cx, segment.ident.span)
+ && segment_snippet == segment.ident.as_str()
+ {
+ let is_abs_external =
+ matches!(segment.res, Res::Def(DefKind::Mod, DefId { index, .. }) if index == CRATE_DEF_INDEX);
+ let is_abs_crate = segment.ident.name == kw::Crate;
+
+ if is_abs_external && absolute_paths_allowed_crates.contains(segment.ident.name.as_str())
+ || is_abs_crate && absolute_paths_allowed_crates.contains("crate")
+ {
+ return;
+ }
+
+ if is_abs_external || is_abs_crate {
+ span_lint(
+ cx,
+ ABSOLUTE_PATHS,
+ path.span,
+ "consider bringing this path into scope with the `use` keyword",
+ );
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
index eb2118471..e1ef514ed 100644
--- a/src/tools/clippy/clippy_lints/src/allow_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
@@ -1,5 +1,6 @@
use ast::{AttrStyle, Attribute};
-use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_from_proc_macro;
use rustc_ast as ast;
use rustc_errors::Applicability;
use rustc_lint::{LateContext, LateLintPass, LintContext};
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 98ee8a9a8..35a04b5e4 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
@@ -1,9 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::last_path_segment;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::{is_from_proc_macro, last_path_segment};
use rustc_hir::{Expr, ExprKind};
-use rustc_lint::LateContext;
-use rustc_lint::LateLintPass;
+use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::GenericArgKind;
@@ -39,10 +38,11 @@ declare_clippy_lint! {
}
declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]);
-impl LateLintPass<'_> for ArcWithNonSendSync {
- fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- let ty = cx.typeck_results().expr_ty(expr);
- if is_type_diagnostic_item(cx, ty, sym::Arc)
+impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+ if !expr.span.from_expansion()
+ && let ty = cx.typeck_results().expr_ty(expr)
+ && is_type_diagnostic_item(cx, ty, sym::Arc)
&& let ExprKind::Call(func, [arg]) = expr.kind
&& let ExprKind::Path(func_path) = func.kind
&& last_path_segment(&func_path).ident.name == sym::new
@@ -55,6 +55,7 @@ impl LateLintPass<'_> for ArcWithNonSendSync {
&& let Some(sync) = cx.tcx.lang_items().sync_trait()
&& let [is_send, is_sync] = [send, sync].map(|id| implements_trait(cx, arg_ty, id, &[]))
&& !(is_send && is_sync)
+ && !is_from_proc_macro(cx, expr)
{
span_lint_and_then(
cx,
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 a8dc0cb3b..b90914e93 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -31,14 +31,20 @@ declare_lint_pass!(AssertionsOnConstants => [ASSERTIONS_ON_CONSTANTS]);
impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
- let Some(macro_call) = root_macro_call_first_node(cx, e) else { return };
+ let Some(macro_call) = root_macro_call_first_node(cx, e) else {
+ return;
+ };
let is_debug = match cx.tcx.get_diagnostic_name(macro_call.def_id) {
Some(sym::debug_assert_macro) => true,
Some(sym::assert_macro) => false,
_ => return,
};
- let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else { return };
- let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else { return };
+ let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else {
+ return;
+ };
+ let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else {
+ return;
+ };
if val {
span_lint_and_help(
cx,
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 f6d6c23bb..2980c9d6d 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
@@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
&& let result_type_with_refs = cx.typeck_results().expr_ty(recv)
&& let result_type = result_type_with_refs.peel_refs()
&& is_type_diagnostic_item(cx, result_type, sym::Result)
- && let ty::Adt(_, substs) = result_type.kind()
+ && let ty::Adt(_, args) = result_type.kind()
{
if !is_copy(cx, result_type) {
if result_type_with_refs != result_type {
@@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
let semicolon = if is_expr_final_block_expr(cx.tcx, e) {";"} else {""};
let mut app = Applicability::MachineApplicable;
match method_segment.ident.as_str() {
- "is_ok" if type_suitable_to_unwrap(cx, substs.type_at(1)) => {
+ "is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => {
span_lint_and_sugg(
cx,
ASSERTIONS_ON_RESULT_STATES,
@@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
app,
);
}
- "is_err" if type_suitable_to_unwrap(cx, substs.type_at(0)) => {
+ "is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => {
span_lint_and_sugg(
cx,
ASSERTIONS_ON_RESULT_STATES,
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index 2ba78f995..2a5be2756 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -1,12 +1,10 @@
//! checks for attributes
+use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::is_from_proc_macro;
use clippy_utils::macros::{is_panic, macro_backtrace};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
-use clippy_utils::{
- diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then},
- is_from_proc_macro,
-};
use if_chain::if_chain;
use rustc_ast::{AttrKind, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
use rustc_errors::Applicability;
diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
index 9c0532474..1593d7b0f 100644
--- a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
+++ b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
@@ -1,9 +1,8 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::get_parent_expr;
-use clippy_utils::higher;
use clippy_utils::source::snippet_block_with_applicability;
use clippy_utils::ty::implements_trait;
use clippy_utils::visitors::{for_each_expr, Descend};
+use clippy_utils::{get_parent_expr, higher};
use core::ops::ControlFlow;
use if_chain::if_chain;
use rustc_errors::Applicability;
@@ -85,8 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
);
}
} else {
- let span =
- block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
+ let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
if span.from_expansion() || expr.span.from_expansion() {
return;
}
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 e8775b081..450359771 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -61,7 +61,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -
)
})
.map_or(false, |assoc_item| {
- let proj = Ty::new_projection(cx.tcx,assoc_item.def_id, cx.tcx.mk_substs_trait(ty, []));
+ let proj = Ty::new_projection(cx.tcx, assoc_item.def_id, cx.tcx.mk_args_trait(ty, []));
let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj);
nty.is_bool()
@@ -70,14 +70,18 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -
impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
+ let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
+ return;
+ };
let macro_name = cx.tcx.item_name(macro_call.def_id);
let eq_macro = match macro_name.as_str() {
"assert_eq" | "debug_assert_eq" => true,
"assert_ne" | "debug_assert_ne" => false,
_ => return,
};
- let Some ((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
+ let Some((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else {
+ return;
+ };
let a_span = a.span.source_callsite();
let b_span = b.span.source_callsite();
@@ -126,7 +130,9 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
let mut suggestions = vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())];
if bool_value ^ eq_macro {
- let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) else { return };
+ let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) else {
+ return;
+ };
suggestions.push((non_lit_expr.span, (!sugg).to_string()));
}
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 bdb3a0116..1828dd651 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
@@ -4,7 +4,9 @@ use rustc_hir::{Block, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use clippy_utils::{diagnostics::span_lint_and_then, in_constant, is_else_clause, is_integer_literal, sugg::Sugg};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::sugg::Sugg;
+use clippy_utils::{in_constant, is_else_clause, is_integer_literal};
use rustc_errors::Applicability;
declare_clippy_lint! {
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 814108ed8..b3dbbb08f 100644
--- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
@@ -1,9 +1,8 @@
use crate::reference::DEREF_ADDROF;
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_from_proc_macro;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_parent_expr, is_lint_allowed};
+use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed};
use rustc_errors::Applicability;
use rustc_hir::{ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index e42c3fe24..fa9c525fc 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -1,12 +1,10 @@
-use clippy_utils::{
- diagnostics::span_lint_and_sugg, get_parent_node, is_default_equivalent, macros::macro_backtrace, match_path,
- path_def_id, paths, ty::expr_sig,
-};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::macros::macro_backtrace;
+use clippy_utils::ty::expr_sig;
+use clippy_utils::{get_parent_node, is_default_equivalent, match_path, path_def_id, paths};
use rustc_errors::Applicability;
-use rustc_hir::{
- intravisit::{walk_ty, Visitor},
- Block, Expr, ExprKind, Local, Node, QPath, TyKind,
-};
+use rustc_hir::intravisit::{walk_ty, Visitor};
+use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::print::with_forced_trimmed_paths;
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 1633ffd58..1e56ed5f4 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
@@ -3,10 +3,8 @@ use clippy_utils::source::snippet_opt;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
-use rustc_middle::{
- mir::Mutability,
- ty::{self, Ty, TypeAndMut},
-};
+use rustc_middle::mir::Mutability;
+use rustc_middle::ty::{self, Ty, TypeAndMut};
use super::AS_PTR_CAST_MUT;
@@ -17,7 +15,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
&& let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind
&& method_name.ident.name == rustc_span::sym::as_ptr
&& let Some(as_ptr_did) = cx.typeck_results().type_dependent_def_id(cast_expr.peel_blocks().hir_id)
- && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).subst_identity()
+ && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).instantiate_identity()
&& let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next()
&& let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind()
&& let Some(recv) = snippet_opt(cx, receiver.span)
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index 6c8ee296c..5bf467efa 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -66,7 +66,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned")
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
&& let Some(def_id) = cx.tcx.impl_of_method(def_id)
- && cx.tcx.type_of(def_id).subst_identity().is_unsafe_ptr()
+ && cx.tcx.type_of(def_id).instantiate_identity().is_unsafe_ptr()
{
true
} else {
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 27cc5a1c3..4d9cc4cac 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,10 +1,12 @@
+use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::{diagnostics::span_lint_and_then, source};
+use clippy_utils::source;
use if_chain::if_chain;
use rustc_ast::Mutability;
use rustc_hir::{Expr, ExprKind, Node};
use rustc_lint::LateContext;
-use rustc_middle::ty::{self, layout::LayoutOf, Ty, TypeAndMut};
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::{self, Ty, TypeAndMut};
use super::CAST_SLICE_DIFFERENT_SIZES;
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 1233c632a..5e0123842 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
@@ -4,7 +4,8 @@ use clippy_utils::source::snippet_with_context;
use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::{def_id::DefId, Expr, ExprKind};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index 0ac6ef649..d34de305f 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -181,6 +181,14 @@ declare_clippy_lint! {
/// ### Why is this bad?
/// It's just unnecessary.
///
+ /// ### Known problems
+ /// When the expression on the left is a function call, the lint considers the return type to be
+ /// a type alias if it's aliased through a `use` statement
+ /// (like `use std::io::Result as IoResult`). It will not lint such cases.
+ ///
+ /// This check is also rather primitive. It will only work on primitive types without any
+ /// intermediate references, raw pointers and trait objects may or may not work.
+ ///
/// ### Example
/// ```rust
/// let _ = 2i32 as i32;
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 15ffb00da..181dbcf6e 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
@@ -1,9 +1,7 @@
-use std::borrow::Cow;
-
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Mutability, TyKind};
use rustc_lint::LateContext;
@@ -16,33 +14,41 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
return;
}
- if_chain! {
- if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind;
- let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr));
- if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind();
- if let ty::RawPtr(TypeAndMut { ty: to_pointee_ty, mutbl: to_mutbl }) = cast_to.kind();
- if matches!((from_mutbl, to_mutbl),
- (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut));
+ if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind
+ && let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr))
+ && let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind()
+ && let ty::RawPtr(TypeAndMut { ty: to_pointee_ty, mutbl: to_mutbl }) = cast_to.kind()
+ && matches!((from_mutbl, to_mutbl),
+ (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut))
// The `U` in `pointer::cast` have to be `Sized`
// as explained here: https://github.com/rust-lang/rust/issues/60602.
- if to_pointee_ty.is_sized(cx.tcx, cx.param_env);
- then {
- let mut applicability = Applicability::MachineApplicable;
- let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut applicability);
- let turbofish = match &cast_to_hir_ty.kind {
- TyKind::Infer => Cow::Borrowed(""),
- TyKind::Ptr(mut_ty) if matches!(mut_ty.ty.kind, TyKind::Infer) => Cow::Borrowed(""),
- _ => Cow::Owned(format!("::<{to_pointee_ty}>")),
- };
- 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()),
- applicability,
- );
- }
+ && 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) => {
+ if matches!(mut_ty.ty.kind, TyKind::Infer) {
+ String::new()
+ } else {
+ format!(
+ "::<{}>",
+ snippet_with_applicability(cx, mut_ty.ty.span, "/* type */", &mut app)
+ )
+ }
+ },
+ _ => return,
+ };
+
+ 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()),
+ 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 f0c1df014..ce1ab1091 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,6 +1,6 @@
-use clippy_utils::msrvs::POINTER_CAST_CONSTNESS;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{Msrv, POINTER_CAST_CONSTNESS};
use clippy_utils::sugg::Sugg;
-use clippy_utils::{diagnostics::span_lint_and_sugg, msrvs::Msrv};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, Mutability};
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 71cf2aea0..86057bb74 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -56,7 +56,7 @@ pub(super) fn check<'tcx>(
&format!("casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"),
"try",
cast_str.clone(),
- Applicability::MachineApplicable,
+ Applicability::MaybeIncorrect,
);
}
}
@@ -85,11 +85,6 @@ pub(super) fn check<'tcx>(
}
}
- // skip cast of fn call that returns type alias
- if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) {
- return false;
- }
-
// skip cast to non-primitive type
if_chain! {
if let ExprKind::Cast(_, cast_to) = expr.kind;
@@ -101,6 +96,11 @@ pub(super) fn check<'tcx>(
}
}
+ // skip cast of fn call that returns type alias
+ if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) {
+ return false;
+ }
+
if let Some(lit) = get_numeric_literal(cast_expr) {
let literal_str = &cast_str;
@@ -254,14 +254,12 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
// function's declaration snippet is exactly equal to the `Ty`. That way, we can
// see whether it's a type alias.
//
- // Will this work for more complex types? Probably not!
+ // FIXME: This won't work if the type is given an alias through `use`, should we
+ // consider this a type alias as well?
if !snippet
.split("->")
- .skip(0)
- .map(|s| {
- s.trim() == cast_from.to_string()
- || s.split("where").any(|ty| ty.trim() == cast_from.to_string())
- })
+ .skip(1)
+ .map(|s| snippet_eq_ty(s, cast_from) || s.split("where").any(|ty| snippet_eq_ty(ty, cast_from)))
.any(|a| a)
{
return ControlFlow::Break(());
@@ -288,3 +286,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
})
.is_some()
}
+
+fn snippet_eq_ty(snippet: &str, ty: Ty<'_>) -> bool {
+ snippet.trim() == ty.to_string() || snippet.trim().contains(&format!("::{ty}"))
+}
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 1c321f46e..e3a09636e 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -10,8 +10,7 @@ use core::iter;
use core::ops::ControlFlow;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefIdSet;
-use rustc_hir::intravisit;
-use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind};
+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};
diff --git a/src/tools/clippy/clippy_lints/src/copy_iterator.rs b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
index 0fc115232..5d04ad011 100644
--- a/src/tools/clippy/clippy_lints/src/copy_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
@@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for CopyIterator {
of_trait: Some(ref trait_ref),
..
}) = item.kind;
- let ty = cx.tcx.type_of(item.owner_id).subst_identity();
+ 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);
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 7436e9ce8..726674d88 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
@@ -5,7 +5,8 @@ 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_span::{symbol::sym, Span};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
index ea17e7a60..49452136d 100644
--- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs
+++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
@@ -71,7 +71,9 @@ impl DbgMacro {
impl LateLintPass<'_> for DbgMacro {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
+ let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
+ return;
+ };
if cx.tcx.is_diagnostic_item(sym::dbg_macro, macro_call.def_id) {
// allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml
if self.allow_dbg_in_tests
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 9d9ee6ba3..db114abfc 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -37,6 +37,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
+ crate::absolute_paths::ABSOLUTE_PATHS_INFO,
crate::allow_attributes::ALLOW_ATTRIBUTES_INFO,
crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
crate::approx_const::APPROX_CONSTANT_INFO,
@@ -155,6 +156,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::enum_variants::MODULE_INCEPTION_INFO,
crate::enum_variants::MODULE_NAME_REPETITIONS_INFO,
crate::equatable_if_let::EQUATABLE_IF_LET_INFO,
+ crate::error_impl_error::ERROR_IMPL_ERROR_INFO,
crate::escape::BOXED_LOCAL_INFO,
crate::eta_reduction::REDUNDANT_CLOSURE_INFO,
crate::eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS_INFO,
@@ -171,7 +173,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO,
crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO,
- crate::fn_null_check::FN_NULL_CHECK_INFO,
crate::format::USELESS_FORMAT_INFO,
crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO,
crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO,
@@ -184,6 +185,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING_INFO,
crate::formatting::SUSPICIOUS_ELSE_FORMATTING_INFO,
crate::formatting::SUSPICIOUS_UNARY_OP_FORMATTING_INFO,
+ crate::four_forward_slashes::FOUR_FORWARD_SLASHES_INFO,
crate::from_over_into::FROM_OVER_INTO_INFO,
crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
@@ -201,12 +203,14 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::if_let_mutex::IF_LET_MUTEX_INFO,
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::implicit_hasher::IMPLICIT_HASHER_INFO,
crate::implicit_return::IMPLICIT_RETURN_INFO,
crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO,
crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO,
crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO,
crate::incorrect_impls::INCORRECT_CLONE_IMPL_ON_COPY_TYPE_INFO,
+ crate::incorrect_impls::INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE_INFO,
crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO,
crate::indexing_slicing::INDEXING_SLICING_INFO,
crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO,
@@ -273,6 +277,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::manual_async_fn::MANUAL_ASYNC_FN_INFO,
crate::manual_bits::MANUAL_BITS_INFO,
crate::manual_clamp::MANUAL_CLAMP_INFO,
+ crate::manual_float_methods::MANUAL_IS_FINITE_INFO,
+ crate::manual_float_methods::MANUAL_IS_INFINITE_INFO,
crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO,
crate::manual_let_else::MANUAL_LET_ELSE_INFO,
crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
@@ -303,6 +309,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS_INFO,
crate::matches::MATCH_WILD_ERR_ARM_INFO,
crate::matches::NEEDLESS_MATCH_INFO,
+ crate::matches::REDUNDANT_GUARDS_INFO,
crate::matches::REDUNDANT_PATTERN_MATCHING_INFO,
crate::matches::REST_PAT_IN_FULLY_BOUND_STRUCTS_INFO,
crate::matches::SIGNIFICANT_DROP_IN_SCRUTINEE_INFO,
@@ -331,11 +338,13 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::methods::EXPECT_USED_INFO,
crate::methods::EXTEND_WITH_DRAIN_INFO,
crate::methods::FILETYPE_IS_FILE_INFO,
+ crate::methods::FILTER_MAP_BOOL_THEN_INFO,
crate::methods::FILTER_MAP_IDENTITY_INFO,
crate::methods::FILTER_MAP_NEXT_INFO,
crate::methods::FILTER_NEXT_INFO,
crate::methods::FLAT_MAP_IDENTITY_INFO,
crate::methods::FLAT_MAP_OPTION_INFO,
+ crate::methods::FORMAT_COLLECT_INFO,
crate::methods::FROM_ITER_INSTEAD_OF_COLLECT_INFO,
crate::methods::GET_FIRST_INFO,
crate::methods::GET_LAST_WITH_LEN_INFO,
@@ -356,6 +365,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::methods::ITER_ON_SINGLE_ITEMS_INFO,
crate::methods::ITER_OVEREAGER_CLONED_INFO,
crate::methods::ITER_SKIP_NEXT_INFO,
+ crate::methods::ITER_SKIP_ZERO_INFO,
crate::methods::ITER_WITH_DRAIN_INFO,
crate::methods::MANUAL_FILTER_MAP_INFO,
crate::methods::MANUAL_FIND_MAP_INFO,
@@ -389,6 +399,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::methods::OR_THEN_UNWRAP_INFO,
crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO,
crate::methods::RANGE_ZIP_WITH_LEN_INFO,
+ crate::methods::READONLY_WRITE_LOCK_INFO,
+ crate::methods::READ_LINE_WITHOUT_TRIM_INFO,
crate::methods::REPEAT_ONCE_INFO,
crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
crate::methods::SEARCH_IS_SOME_INFO,
@@ -400,10 +412,12 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::methods::SKIP_WHILE_NEXT_INFO,
crate::methods::STABLE_SORT_PRIMITIVE_INFO,
crate::methods::STRING_EXTEND_CHARS_INFO,
+ crate::methods::STRING_LIT_CHARS_ANY_INFO,
crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO,
crate::methods::SUSPICIOUS_MAP_INFO,
crate::methods::SUSPICIOUS_SPLITN_INFO,
crate::methods::SUSPICIOUS_TO_OWNED_INFO,
+ crate::methods::TYPE_ID_ON_BOX_INFO,
crate::methods::UNINIT_ASSUMED_INIT_INFO,
crate::methods::UNIT_HASH_INFO,
crate::methods::UNNECESSARY_FILTER_MAP_INFO,
@@ -414,7 +428,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,
crate::methods::UNNECESSARY_SORT_BY_INFO,
crate::methods::UNNECESSARY_TO_OWNED_INFO,
- crate::methods::UNWRAP_OR_ELSE_DEFAULT_INFO,
+ crate::methods::UNWRAP_OR_DEFAULT_INFO,
crate::methods::UNWRAP_USED_INFO,
crate::methods::USELESS_ASREF_INFO,
crate::methods::VEC_RESIZE_TO_ZERO_INFO,
@@ -469,6 +483,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::needless_if::NEEDLESS_IF_INFO,
crate::needless_late_init::NEEDLESS_LATE_INIT_INFO,
crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO,
+ crate::needless_pass_by_ref_mut::NEEDLESS_PASS_BY_REF_MUT_INFO,
crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO,
crate::needless_question_mark::NEEDLESS_QUESTION_MARK_INFO,
crate::needless_update::NEEDLESS_UPDATE_INFO,
@@ -503,6 +518,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::operators::FLOAT_CMP_CONST_INFO,
crate::operators::FLOAT_EQUALITY_WITHOUT_ABS_INFO,
crate::operators::IDENTITY_OP_INFO,
+ crate::operators::IMPOSSIBLE_COMPARISONS_INFO,
crate::operators::INEFFECTIVE_BIT_MASK_INFO,
crate::operators::INTEGER_DIVISION_INFO,
crate::operators::MISREFACTORED_ASSIGN_OP_INFO,
@@ -511,6 +527,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::operators::NEEDLESS_BITWISE_BOOL_INFO,
crate::operators::OP_REF_INFO,
crate::operators::PTR_EQ_INFO,
+ crate::operators::REDUNDANT_COMPARISONS_INFO,
crate::operators::SELF_ASSIGNMENT_INFO,
crate::operators::VERBOSE_BIT_MASK_INFO,
crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO,
@@ -550,6 +567,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::redundant_closure_call::REDUNDANT_CLOSURE_CALL_INFO,
crate::redundant_else::REDUNDANT_ELSE_INFO,
crate::redundant_field_names::REDUNDANT_FIELD_NAMES_INFO,
+ crate::redundant_locals::REDUNDANT_LOCALS_INFO,
crate::redundant_pub_crate::REDUNDANT_PUB_CRATE_INFO,
crate::redundant_slicing::DEREF_BY_SLICING_INFO,
crate::redundant_slicing::REDUNDANT_SLICING_INFO,
@@ -563,6 +581,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
crate::returns::LET_AND_RETURN_INFO,
crate::returns::NEEDLESS_RETURN_INFO,
+ crate::returns::NEEDLESS_RETURN_WITH_QUESTION_MARK_INFO,
crate::same_name_method::SAME_NAME_METHOD_INFO,
crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO,
crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 80c22742b..763ad0264 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -150,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
.fields
.iter()
.all(|field| {
- is_copy(cx, cx.tcx.type_of(field.did).subst_identity())
+ is_copy(cx, cx.tcx.type_of(field.did).instantiate_identity())
});
if !has_drop(cx, binding_type) || all_fields_are_copy;
then {
@@ -219,11 +219,11 @@ impl<'tcx> LateLintPass<'tcx> for Default {
// give correct suggestion if generics are involved (see #6944)
let binding_type = if_chain! {
- if let ty::Adt(adt_def, substs) = binding_type.kind();
- if !substs.is_empty();
+ 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 = substs.iter().collect::<Vec<_>>();
+ let generic_args = args.iter().collect::<Vec<_>>();
let tys_str = generic_args
.iter()
.map(ToString::to_string)
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 ca9514ccc..a294c6937 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
@@ -1,5 +1,7 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, is_ty_alias, match_def_path, paths};
-use hir::{def::Res, ExprKind};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::{is_ty_alias, match_def_path, paths};
+use hir::def::Res;
+use hir::ExprKind;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
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 f296b80d2..572990aab 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
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::last_path_segment;
use clippy_utils::source::snippet_with_context;
-use clippy_utils::{match_def_path, paths};
+use clippy_utils::{last_path_segment, match_def_path, paths};
use rustc_errors::Applicability;
use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
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 e53a9877b..d09428dbc 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -4,15 +4,11 @@ use clippy_utils::{get_parent_node, numeric_literal};
use if_chain::if_chain;
use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
use rustc_errors::Applicability;
-use rustc_hir::{
- intravisit::{walk_expr, walk_stmt, Visitor},
- Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind,
-};
+use rustc_hir::intravisit::{walk_expr, walk_stmt, Visitor};
+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,
- ty::{self, FloatTy, IntTy, PolyFnSig, Ty},
-};
+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 std::iter;
@@ -141,7 +137,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
ExprKind::MethodCall(_, receiver, args, _) => {
if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
- let fn_sig = self.cx.tcx.fn_sig(def_id).subst_identity().skip_binder();
+ let fn_sig = self.cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) {
self.ty_bounds.push((*bound).into());
self.visit_expr(expr);
@@ -167,7 +163,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
.iter()
.find_map(|f_def| {
if f_def.ident(self.cx.tcx) == field.ident
- { Some(self.cx.tcx.type_of(f_def.did).subst_identity()) }
+ { Some(self.cx.tcx.type_of(f_def.did).instantiate_identity()) }
else { None }
});
self.ty_bounds.push(bound.into());
@@ -213,9 +209,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<'tcx>> {
let node_ty = cx.typeck_results().node_type_opt(hir_id)?;
- // We can't use `Ty::fn_sig` because it automatically performs substs, this may result in FNs.
+ // We can't use `Ty::fn_sig` because it automatically performs args, this may result in FNs.
match node_ty.kind() {
- ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id).subst_identity()),
+ ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id).instantiate_identity()),
ty::FnPtr(fn_sig) => Some(*fn_sig),
_ => None,
}
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 12f2f37e3..58c278550 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -3,22 +3,23 @@ use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exact
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{adt_and_variant_of_res, expr_sig, is_copy, peel_mid_ty_refs, ty_sig};
+use clippy_utils::ty::{is_copy, peel_mid_ty_refs};
use clippy_utils::{
- fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage,
+ expr_use_ctxt, get_parent_expr, get_parent_node, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
};
+use hir::def::DefKind;
+use hir::MatchSource;
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch};
use rustc_errors::Applicability;
+use rustc_hir::def::Res;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_ty, Visitor};
use rustc_hir::{
- self as hir,
- def_id::{DefId, LocalDefId},
- BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId, ImplItem,
- ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem,
- TraitItemKind, TyKind, UnOp,
+ self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind,
+ Path, QPath, TyKind, UnOp,
};
use rustc_index::bit_set::BitSet;
use rustc_infer::infer::TyCtxtInferExt;
@@ -26,13 +27,15 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::{Rvalue, StatementKind};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::{
- self, Binder, BoundVariableKind, ClauseKind, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy,
- ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults,
+ self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, List, ParamEnv, ParamTy, ProjectionPredicate, Ty,
+ TyCtxt, TypeVisitableExt, TypeckResults,
};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{symbol::sym, Span, Symbol};
+use rustc_span::symbol::sym;
+use rustc_span::{Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
+use rustc_trait_selection::traits::{Obligation, ObligationCause};
use std::collections::VecDeque;
declare_clippy_lint! {
@@ -77,6 +80,11 @@ declare_clippy_lint! {
/// Suggests that the receiver of the expression borrows
/// the expression.
///
+ /// ### Known problems
+ /// The lint cannot tell when the implementation of a trait
+ /// for `&T` and `T` do different things. Removing a borrow
+ /// in such a case can change the semantics of the code.
+ ///
/// ### Example
/// ```rust
/// fn fun(_a: &i32) {}
@@ -157,7 +165,7 @@ impl_lint_pass!(Dereferencing<'_> => [
#[derive(Default)]
pub struct Dereferencing<'tcx> {
- state: Option<(State, StateData)>,
+ state: Option<(State, StateData<'tcx>)>,
// While parsing a `deref` method call in ufcs form, the path to the function is itself an
// expression. This is to store the id of that expression so it can be skipped when
@@ -197,29 +205,28 @@ impl<'tcx> Dereferencing<'tcx> {
}
#[derive(Debug)]
-struct StateData {
+struct StateData<'tcx> {
/// Span of the top level expression
span: Span,
hir_id: HirId,
- position: Position,
+ adjusted_ty: Ty<'tcx>,
}
-#[derive(Debug)]
struct DerefedBorrow {
count: usize,
msg: &'static str,
- snip_expr: Option<HirId>,
+ stability: TyCoercionStability,
+ for_field_access: Option<Symbol>,
}
-#[derive(Debug)]
enum State {
// Any number of deref method calls.
DerefMethod {
// The number of calls in a sequence which changed the referenced type
ty_changed_count: usize,
- is_final_ufcs: bool,
+ is_ufcs: bool,
/// The required mutability
- target_mut: Mutability,
+ mutbl: Mutability,
},
DerefedBorrow(DerefedBorrow),
ExplicitDeref {
@@ -238,7 +245,7 @@ enum State {
// A reference operation considered by this lint pass
enum RefOp {
- Method(Mutability),
+ Method { mutbl: Mutability, is_ufcs: bool },
Deref,
AddrOf(Mutability),
}
@@ -288,48 +295,115 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
match (self.state.take(), kind) {
(None, kind) => {
let expr_ty = typeck.expr_ty(expr);
- let (position, adjustments) = walk_parents(cx, &mut self.possible_borrowers, expr, &self.msrv);
- match kind {
- RefOp::Deref => {
+ let use_cx = expr_use_ctxt(cx, expr);
+ let adjusted_ty = match &use_cx {
+ Some(use_cx) => match use_cx.adjustments {
+ [.., a] => a.target,
+ _ => expr_ty,
+ },
+ _ => typeck.expr_ty_adjusted(expr),
+ };
+
+ match (use_cx, kind) {
+ (Some(use_cx), RefOp::Deref) => {
let sub_ty = typeck.expr_ty(sub_expr);
- if let Position::FieldAccess {
- name,
- of_union: false,
- } = position
- && !ty_contains_field(sub_ty, name)
+ if let ExprUseNode::FieldAccess(name) = use_cx.node
+ && adjusted_ty.ty_adt_def().map_or(true, |adt| !adt.is_union())
+ && !ty_contains_field(sub_ty, name.name)
{
self.state = Some((
- State::ExplicitDerefField { name },
- StateData { span: expr.span, hir_id: expr.hir_id, position },
+ State::ExplicitDerefField { name: name.name },
+ StateData {
+ span: expr.span,
+ hir_id: expr.hir_id,
+ adjusted_ty,
+ },
));
- } else if position.is_deref_stable() && sub_ty.is_ref() {
+ } else if sub_ty.is_ref()
+ // Linting method receivers would require verifying that name lookup
+ // would resolve the same way. This is complicated by trait methods.
+ && !use_cx.node.is_recv()
+ && let Some(ty) = use_cx.node.defined_ty(cx)
+ && TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return()).is_deref_stable()
+ {
self.state = Some((
State::ExplicitDeref { mutability: None },
- StateData { span: expr.span, hir_id: expr.hir_id, position },
+ StateData {
+ span: expr.span,
+ hir_id: expr.hir_id,
+ adjusted_ty,
+ },
));
}
},
- RefOp::Method(target_mut)
+ (_, RefOp::Method { mutbl, is_ufcs })
if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
- && position.lint_explicit_deref() =>
+ // Allow explicit deref in method chains. e.g. `foo.deref().bar()`
+ && (is_ufcs || !in_postfix_position(cx, expr)) =>
{
let ty_changed_count = usize::from(!deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)));
self.state = Some((
State::DerefMethod {
ty_changed_count,
- is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
- target_mut,
+ is_ufcs,
+ mutbl,
},
StateData {
span: expr.span,
hir_id: expr.hir_id,
- position,
+ adjusted_ty,
},
));
},
- RefOp::AddrOf(mutability) => {
+ (Some(use_cx), RefOp::AddrOf(mutability)) => {
+ let defined_ty = use_cx.node.defined_ty(cx);
+
+ // Check needless_borrow for generic arguments.
+ if !use_cx.is_ty_unified
+ && let Some(DefinedTy::Mir(ty)) = defined_ty
+ && let ty::Param(ty) = *ty.value.skip_binder().kind()
+ && let Some((hir_id, fn_id, i)) = match use_cx.node {
+ ExprUseNode::MethodArg(_, _, 0) => None,
+ ExprUseNode::MethodArg(hir_id, None, i) => {
+ typeck.type_dependent_def_id(hir_id).map(|id| (hir_id, id, i))
+ },
+ ExprUseNode::FnArg(&Expr { kind: ExprKind::Path(ref p), hir_id, .. }, i)
+ if !path_has_args(p) => match typeck.qpath_res(p, hir_id) {
+ Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) => {
+ Some((hir_id, id, i))
+ },
+ _ => None,
+ },
+ _ => None,
+ } && let count = needless_borrow_generic_arg_count(
+ cx,
+ &mut self.possible_borrowers,
+ fn_id,
+ typeck.node_args(hir_id),
+ i,
+ ty,
+ expr,
+ &self.msrv,
+ ) && count != 0
+ {
+ self.state = Some((
+ State::DerefedBorrow(DerefedBorrow {
+ count: count - 1,
+ msg: "the borrowed expression implements the required traits",
+ stability: TyCoercionStability::None,
+ for_field_access: None,
+ }),
+ StateData {
+ span: expr.span,
+ hir_id: expr.hir_id,
+ adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
+ },
+ ));
+ return;
+ }
+
// Find the number of times the borrow is auto-derefed.
- let mut iter = adjustments.iter();
+ let mut iter = use_cx.adjustments.iter();
let mut deref_count = 0usize;
let next_adjust = loop {
match iter.next() {
@@ -346,6 +420,58 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
};
};
+ let stability = defined_ty.map_or(TyCoercionStability::None, |ty| {
+ 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::MethodArg(hir_id, _, 0) if !use_cx.moved_before_use => {
+ // Check for calls to trait methods where the trait is implemented
+ // on a reference.
+ // Two cases need to be handled:
+ // * `self` methods on `&T` will never have auto-borrow
+ // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
+ // priority.
+ if let Some(fn_id) = typeck.type_dependent_def_id(hir_id)
+ && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+ && let arg_ty
+ = cx.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 impl_ty = if cx.tcx.fn_sig(fn_id)
+ .instantiate_identity()
+ .skip_binder()
+ .inputs()[0].is_ref()
+ {
+ // Trait methods taking `&self`
+ sub_ty
+ } else {
+ // Trait methods taking `self`
+ arg_ty
+ } && impl_ty.is_ref()
+ && cx.tcx.infer_ctxt().build()
+ .type_implements_trait(
+ trait_id,
+ [impl_ty.into()].into_iter().chain(args.iter().copied()),
+ cx.param_env,
+ )
+ .must_apply_modulo_regions()
+ {
+ false
+ } else {
+ true
+ }
+ },
+ _ => false,
+ };
+
+ let deref_msg =
+ "this expression creates a reference which is immediately dereferenced by the compiler";
+ let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
+
// Determine the required number of references before any can be removed. In all cases the
// reference made by the current expression will be removed. After that there are four cases to
// handle.
@@ -368,26 +494,18 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
// };
// }
// ```
- let deref_msg =
- "this expression creates a reference which is immediately dereferenced by the compiler";
- let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
- let impl_msg = "the borrowed expression implements the required traits";
-
- let (required_refs, msg, snip_expr) = if position.can_auto_borrow() {
- (1, if deref_count == 1 { borrow_msg } else { deref_msg }, None)
- } else if let Position::ImplArg(hir_id) = position {
- (0, impl_msg, Some(hir_id))
- } else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) =
- next_adjust.map(|a| &a.kind)
+ let (required_refs, msg) = if can_auto_borrow {
+ (1, if deref_count == 1 { borrow_msg } else { deref_msg })
+ } else if let Some(&Adjustment {
+ kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)),
+ ..
+ }) = next_adjust
+ && matches!(mutability, AutoBorrowMutability::Mut { .. })
+ && !stability.is_reborrow_stable()
{
- if matches!(mutability, AutoBorrowMutability::Mut { .. }) && !position.is_reborrow_stable()
- {
- (3, deref_msg, None)
- } else {
- (2, deref_msg, None)
- }
+ (3, deref_msg)
} else {
- (2, deref_msg, None)
+ (2, deref_msg)
};
if deref_count >= required_refs {
@@ -397,15 +515,19 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
// can't be removed without breaking the code. See earlier comment.
count: deref_count - required_refs,
msg,
- snip_expr,
+ stability,
+ for_field_access: match use_cx.node {
+ ExprUseNode::FieldAccess(name) => Some(name.name),
+ _ => None,
+ },
}),
StateData {
span: expr.span,
hir_id: expr.hir_id,
- position,
+ adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
},
));
- } else if position.is_deref_stable()
+ } else if stability.is_deref_stable()
// Auto-deref doesn't combine with other adjustments
&& next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
&& iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
@@ -415,24 +537,24 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
StateData {
span: expr.span,
hir_id: expr.hir_id,
- position,
+ adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
},
));
}
},
- RefOp::Method(..) => (),
+ (None, _) | (_, RefOp::Method { .. }) => (),
}
},
(
Some((
State::DerefMethod {
- target_mut,
+ mutbl,
ty_changed_count,
..
},
data,
)),
- RefOp::Method(_),
+ RefOp::Method { is_ufcs, .. },
) => {
self.state = Some((
State::DerefMethod {
@@ -441,8 +563,8 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
} else {
ty_changed_count + 1
},
- is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
- target_mut,
+ is_ufcs,
+ mutbl,
},
data,
));
@@ -457,33 +579,44 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
));
},
(Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => {
- let position = data.position;
+ let adjusted_ty = data.adjusted_ty;
+ let stability = state.stability;
report(cx, expr, State::DerefedBorrow(state), data);
- if position.is_deref_stable() {
+ if stability.is_deref_stable() {
self.state = Some((
State::Borrow { mutability },
StateData {
span: expr.span,
hir_id: expr.hir_id,
- position,
+ adjusted_ty,
},
));
}
},
(Some((State::DerefedBorrow(state), data)), RefOp::Deref) => {
- let position = data.position;
+ 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);
- if let Position::FieldAccess{name, ..} = position
+ if let Some(name) = for_field_access
&& !ty_contains_field(typeck.expr_ty(sub_expr), name)
{
self.state = Some((
State::ExplicitDerefField { name },
- StateData { span: expr.span, hir_id: expr.hir_id, position },
+ StateData {
+ span: expr.span,
+ hir_id: expr.hir_id,
+ adjusted_ty,
+ },
));
- } else if position.is_deref_stable() {
+ } else if stability.is_deref_stable() {
self.state = Some((
State::ExplicitDeref { mutability: None },
- StateData { span: expr.span, hir_id: expr.hir_id, position },
+ StateData {
+ span: expr.span,
+ hir_id: expr.hir_id,
+ adjusted_ty,
+ },
));
}
},
@@ -589,7 +722,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
pat.spans,
"this pattern creates a reference to a reference",
|diag| {
- diag.multipart_suggestion("try this", replacements, app);
+ diag.multipart_suggestion("try", replacements, app);
},
);
}
@@ -605,8 +738,8 @@ fn try_parse_ref_op<'tcx>(
typeck: &'tcx TypeckResults<'_>,
expr: &'tcx Expr<'_>,
) -> Option<(RefOp, &'tcx Expr<'tcx>)> {
- let (def_id, arg) = match expr.kind {
- ExprKind::MethodCall(_, arg, [], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
+ let (is_ufcs, def_id, arg) = match expr.kind {
+ ExprKind::MethodCall(_, arg, [], _) => (false, typeck.type_dependent_def_id(expr.hir_id)?, arg),
ExprKind::Call(
Expr {
kind: ExprKind::Path(path),
@@ -614,7 +747,7 @@ fn try_parse_ref_op<'tcx>(
..
},
[arg],
- ) => (typeck.qpath_res(path, *hir_id).opt_def_id()?, arg),
+ ) => (true, typeck.qpath_res(path, *hir_id).opt_def_id()?, arg),
ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => {
return Some((RefOp::Deref, sub_expr));
},
@@ -622,9 +755,21 @@ fn try_parse_ref_op<'tcx>(
_ => return None,
};
if tcx.is_diagnostic_item(sym::deref_method, def_id) {
- Some((RefOp::Method(Mutability::Not), arg))
+ Some((
+ RefOp::Method {
+ mutbl: Mutability::Not,
+ is_ufcs,
+ },
+ arg,
+ ))
} else if tcx.trait_of_item(def_id)? == tcx.lang_items().deref_mut_trait()? {
- Some((RefOp::Method(Mutability::Mut), arg))
+ Some((
+ RefOp::Method {
+ mutbl: Mutability::Mut,
+ is_ufcs,
+ },
+ arg,
+ ))
} else {
None
}
@@ -643,420 +788,165 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
}
}
-/// The position of an expression relative to it's parent.
-#[derive(Clone, Copy, Debug)]
-enum Position {
- MethodReceiver,
- /// The method is defined on a reference type. e.g. `impl Foo for &T`
- MethodReceiverRefImpl,
- Callee,
- ImplArg(HirId),
- FieldAccess {
- name: Symbol,
- of_union: bool,
- }, // union fields cannot be auto borrowed
- Postfix,
- Deref,
- /// Any other location which will trigger auto-deref to a specific time.
- /// Contains the precedence of the parent expression and whether the target type is sized.
- DerefStable(i8, bool),
- /// Any other location which will trigger auto-reborrowing.
- /// Contains the precedence of the parent expression.
- ReborrowStable(i8),
- /// Contains the precedence of the parent expression.
- Other(i8),
-}
-impl Position {
- fn is_deref_stable(self) -> bool {
- matches!(self, Self::DerefStable(..))
+fn path_has_args(p: &QPath<'_>) -> bool {
+ match *p {
+ QPath::Resolved(_, Path { segments: [.., s], .. }) | QPath::TypeRelative(_, s) => s.args.is_some(),
+ _ => false,
}
+}
- fn is_reborrow_stable(self) -> bool {
- matches!(self, Self::DerefStable(..) | Self::ReborrowStable(_))
+fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
+ if let Some(parent) = get_parent_expr(cx, e)
+ && parent.span.ctxt() == e.span.ctxt()
+ {
+ match parent.kind {
+ ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _, _)
+ if child.hir_id == e.hir_id => true,
+ ExprKind::Match(.., MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar)
+ | ExprKind::Field(_, _) => true,
+ _ => false,
+ }
+ } else {
+ false
}
+}
- fn can_auto_borrow(self) -> bool {
- matches!(
- self,
- Self::MethodReceiver | Self::FieldAccess { of_union: false, .. } | Self::Callee
- )
+#[derive(Clone, Copy)]
+enum TyCoercionStability {
+ Deref,
+ Reborrow,
+ None,
+}
+impl TyCoercionStability {
+ fn is_deref_stable(self) -> bool {
+ matches!(self, Self::Deref)
}
- fn lint_explicit_deref(self) -> bool {
- matches!(self, Self::Other(_) | Self::DerefStable(..) | Self::ReborrowStable(_))
+ fn is_reborrow_stable(self) -> bool {
+ matches!(self, Self::Deref | Self::Reborrow)
}
- fn precedence(self) -> i8 {
- match self {
- Self::MethodReceiver
- | Self::MethodReceiverRefImpl
- | Self::Callee
- | Self::FieldAccess { .. }
- | Self::Postfix => PREC_POSTFIX,
- Self::ImplArg(_) | Self::Deref => PREC_PREFIX,
- Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p,
+ fn for_defined_ty<'tcx>(cx: &LateContext<'tcx>, ty: DefinedTy<'tcx>, for_return: bool) -> Self {
+ match ty {
+ DefinedTy::Hir(ty) => Self::for_hir_ty(ty),
+ DefinedTy::Mir(ty) => Self::for_mir_ty(
+ cx.tcx,
+ ty.param_env,
+ cx.tcx.erase_late_bound_regions(ty.value),
+ for_return,
+ ),
}
}
-}
-
-/// Walks up the parent expressions attempting to determine both how stable the auto-deref result
-/// is, and which adjustments will be applied to it. Note this will not consider auto-borrow
-/// locations as those follow different rules.
-#[expect(clippy::too_many_lines)]
-fn walk_parents<'tcx>(
- cx: &LateContext<'tcx>,
- possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
- e: &'tcx Expr<'_>,
- msrv: &Msrv,
-) -> (Position, &'tcx [Adjustment<'tcx>]) {
- let mut adjustments = [].as_slice();
- let mut precedence = 0i8;
- let ctxt = e.span.ctxt();
- let position = walk_to_expr_usage(cx, e, &mut |parent, child_id| {
- // LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead.
- if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir().get(child_id) {
- adjustments = cx.typeck_results().expr_adjustments(e);
- }
- match parent {
- Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => {
- Some(binding_ty_auto_deref_stability(cx, ty, precedence, List::empty()))
- },
- Node::Item(&Item {
- kind: ItemKind::Static(..) | ItemKind::Const(..),
- owner_id,
- span,
- ..
- })
- | Node::TraitItem(&TraitItem {
- kind: TraitItemKind::Const(..),
- owner_id,
- span,
- ..
- })
- | Node::ImplItem(&ImplItem {
- kind: ImplItemKind::Const(..),
- owner_id,
- span,
- ..
- }) if span.ctxt() == ctxt => {
- let ty = cx.tcx.type_of(owner_id.def_id).subst_identity();
- Some(ty_auto_deref_stability(cx.tcx, cx.param_env, ty, precedence).position_for_result(cx))
- },
- Node::Item(&Item {
- kind: ItemKind::Fn(..),
- owner_id,
- span,
- ..
- })
- | Node::TraitItem(&TraitItem {
- kind: TraitItemKind::Fn(..),
- owner_id,
- span,
- ..
- })
- | Node::ImplItem(&ImplItem {
- kind: ImplItemKind::Fn(..),
- owner_id,
- span,
- ..
- }) if span.ctxt() == ctxt => {
- let output = cx
- .tcx
- .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
- Some(ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx))
- },
-
- Node::ExprField(field) if field.span.ctxt() == ctxt => match get_parent_expr_for_hir(cx, field.hir_id) {
- Some(Expr {
- hir_id,
- kind: ExprKind::Struct(path, ..),
- ..
- }) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
- .and_then(|(adt, variant)| {
- variant
- .fields
- .iter()
- .find(|f| f.name == field.ident.name)
- .map(|f| (adt, f))
- })
- .map(|(adt, field_def)| {
- ty_auto_deref_stability(
- cx.tcx,
- // Use the param_env of the target type.
- cx.tcx.param_env(adt.did()),
- cx.tcx.type_of(field_def.did).subst_identity(),
- precedence,
- )
- .position_for_arg()
- }),
- _ => None,
- },
+ // Checks the stability of type coercions when assigned to a binding with the given explicit type.
+ //
+ // e.g.
+ // let x = Box::new(Box::new(0u32));
+ // let y1: &Box<_> = x.deref();
+ // let y2: &Box<_> = &x;
+ //
+ // Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
+ // switching to auto-dereferencing.
+ fn for_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Self {
+ let TyKind::Ref(_, ty) = &ty.kind else {
+ return Self::None;
+ };
+ let mut ty = ty;
- Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
- ExprKind::Ret(_) => {
- let owner_id = cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap());
- Some(
- if let Node::Expr(
- closure_expr @ Expr {
- kind: ExprKind::Closure(closure),
- ..
- },
- ) = cx.tcx.hir().get_by_def_id(owner_id)
- {
- closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence)
- } else {
- let output = cx
- .tcx
- .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
- ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx)
- },
- )
- },
- ExprKind::Closure(closure) => Some(closure_result_position(
- cx,
- closure,
- cx.typeck_results().expr_ty(parent),
- precedence,
- )),
- ExprKind::Call(func, _) if func.hir_id == child_id => {
- (child_id == e.hir_id).then_some(Position::Callee)
+ loop {
+ break match ty.ty.kind {
+ TyKind::Ref(_, ref ref_ty) => {
+ ty = ref_ty;
+ continue;
},
- ExprKind::Call(func, args) => args
- .iter()
- .position(|arg| arg.hir_id == child_id)
- .zip(expr_sig(cx, func))
- .and_then(|(i, sig)| {
- sig.input_with_hir(i).map(|(hir_ty, ty)| {
- match hir_ty {
- // Type inference for closures can depend on how they're called. Only go by the explicit
- // types here.
- Some(hir_ty) => {
- binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars())
- },
- None => {
- // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
- // `!call_is_qualified(func)` for https://github.com/rust-lang/rust-clippy/issues/9782
- if e.hir_id == child_id
- && !call_is_qualified(func)
- && let ty::Param(param_ty) = ty.skip_binder().kind()
- {
- needless_borrow_impl_arg_position(
- cx,
- possible_borrowers,
- parent,
- i,
- *param_ty,
- e,
- precedence,
- msrv,
- )
- } else {
- ty_auto_deref_stability(
- cx.tcx,
- // Use the param_env of the target function.
- sig.predicates_id().map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id)),
- cx.tcx.erase_late_bound_regions(ty),
- precedence
- ).position_for_arg()
- }
- },
- }
+ TyKind::Path(
+ QPath::TypeRelative(_, path)
+ | QPath::Resolved(
+ _,
+ Path {
+ segments: [.., path], ..
+ },
+ ),
+ ) => {
+ if let Some(args) = path.args
+ && args.args.iter().any(|arg| match arg {
+ hir::GenericArg::Infer(_) => true,
+ hir::GenericArg::Type(ty) => ty_contains_infer(ty),
+ _ => false,
})
- }),
- ExprKind::MethodCall(method, receiver, args, _) => {
- let fn_id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
- if receiver.hir_id == child_id {
- // Check for calls to trait methods where the trait is implemented on a reference.
- // Two cases need to be handled:
- // * `self` methods on `&T` will never have auto-borrow
- // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
- // priority.
- if e.hir_id != child_id {
- return Some(Position::ReborrowStable(precedence))
- } else if let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
- && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
- && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
- && let subs = cx
- .typeck_results()
- .node_substs_opt(parent.hir_id).map(|subs| &subs[1..]).unwrap_or_default()
- && let impl_ty = if cx.tcx.fn_sig(fn_id)
- .subst_identity()
- .skip_binder()
- .inputs()[0].is_ref()
- {
- // Trait methods taking `&self`
- sub_ty
- } else {
- // Trait methods taking `self`
- arg_ty
- } && impl_ty.is_ref()
- && let infcx = cx.tcx.infer_ctxt().build()
- && infcx
- .type_implements_trait(
- trait_id,
- [impl_ty.into()].into_iter().chain(subs.iter().copied()),
- cx.param_env,
- )
- .must_apply_modulo_regions()
- {
- return Some(Position::MethodReceiverRefImpl)
- }
- return Some(Position::MethodReceiver);
+ {
+ Self::Reborrow
+ } else {
+ Self::Deref
}
- args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
- let ty = cx.tcx.fn_sig(fn_id).subst_identity().input(i + 1);
- // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
- // `method.args.is_none()` for https://github.com/rust-lang/rust-clippy/issues/9782
- if e.hir_id == child_id
- && method.args.is_none()
- && let ty::Param(param_ty) = ty.skip_binder().kind()
- {
- needless_borrow_impl_arg_position(
- cx,
- possible_borrowers,
- parent,
- i + 1,
- *param_ty,
- e,
- precedence,
- msrv,
- )
- } else {
- ty_auto_deref_stability(
- cx.tcx,
- // Use the param_env of the target function.
- cx.tcx.param_env(fn_id),
- cx.tcx.erase_late_bound_regions(ty),
- precedence,
- )
- .position_for_arg()
- }
- })
- },
- ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess {
- name: name.name,
- of_union: is_union(cx.typeck_results(), child),
- }),
- ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
- ExprKind::Match(child, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
- | ExprKind::Index(child, _)
- if child.hir_id == e.hir_id =>
- {
- Some(Position::Postfix)
},
- _ if child_id == e.hir_id => {
- precedence = parent.precedence().order();
- None
- },
- _ => None,
- },
- _ => None,
+ TyKind::Slice(_)
+ | TyKind::Array(..)
+ | TyKind::Ptr(_)
+ | TyKind::BareFn(_)
+ | TyKind::Never
+ | TyKind::Tup(_)
+ | TyKind::Path(_) => Self::Deref,
+ TyKind::OpaqueDef(..)
+ | TyKind::Infer
+ | TyKind::Typeof(..)
+ | TyKind::TraitObject(..)
+ | TyKind::Err(_) => Self::Reborrow,
+ };
}
- })
- .unwrap_or(Position::Other(precedence));
- (position, adjustments)
-}
-
-fn is_union<'tcx>(typeck: &'tcx TypeckResults<'_>, path_expr: &'tcx Expr<'_>) -> bool {
- typeck
- .expr_ty_adjusted(path_expr)
- .ty_adt_def()
- .map_or(false, rustc_middle::ty::AdtDef::is_union)
-}
-
-fn closure_result_position<'tcx>(
- cx: &LateContext<'tcx>,
- closure: &'tcx Closure<'_>,
- ty: Ty<'tcx>,
- precedence: i8,
-) -> Position {
- match closure.fn_decl.output {
- FnRetTy::Return(hir_ty) => {
- if let Some(sig) = ty_sig(cx, ty)
- && let Some(output) = sig.output()
- {
- binding_ty_auto_deref_stability(cx, hir_ty, precedence, output.bound_vars())
- } else {
- Position::Other(precedence)
- }
- },
- FnRetTy::DefaultReturn(_) => Position::Other(precedence),
}
-}
-// Checks the stability of auto-deref when assigned to a binding with the given explicit type.
-//
-// e.g.
-// let x = Box::new(Box::new(0u32));
-// let y1: &Box<_> = x.deref();
-// let y2: &Box<_> = &x;
-//
-// Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
-// switching to auto-dereferencing.
-fn binding_ty_auto_deref_stability<'tcx>(
- cx: &LateContext<'tcx>,
- ty: &'tcx hir::Ty<'_>,
- precedence: i8,
- binder_args: &'tcx List<BoundVariableKind>,
-) -> Position {
- let TyKind::Ref(_, ty) = &ty.kind else {
- return Position::Other(precedence);
- };
- let mut ty = ty;
+ fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>, for_return: bool) -> Self {
+ let ty::Ref(_, mut ty, _) = *ty.kind() else {
+ return Self::None;
+ };
- loop {
- break match ty.ty.kind {
- TyKind::Ref(_, ref ref_ty) => {
- ty = ref_ty;
- continue;
- },
- TyKind::Path(
- QPath::TypeRelative(_, path)
- | QPath::Resolved(
- _,
- Path {
- segments: [.., path], ..
- },
- ),
- ) => {
- if let Some(args) = path.args
- && args.args.iter().any(|arg| match arg {
- GenericArg::Infer(_) => true,
- GenericArg::Type(ty) => ty_contains_infer(ty),
- _ => false,
- })
+ ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
+ loop {
+ break match *ty.kind() {
+ ty::Ref(_, ref_ty, _) => {
+ ty = ref_ty;
+ continue;
+ },
+ ty::Param(_) if for_return => Self::Deref,
+ ty::Alias(ty::Weak | ty::Inherent, _) => unreachable!("should have been normalized away above"),
+ ty::Alias(ty::Projection, _) if !for_return && ty.has_non_region_param() => Self::Reborrow,
+ ty::Infer(_)
+ | ty::Error(_)
+ | ty::Bound(..)
+ | ty::Alias(ty::Opaque, ..)
+ | ty::Placeholder(_)
+ | ty::Dynamic(..)
+ | ty::Param(_) => Self::Reborrow,
+ ty::Adt(_, args)
+ if ty.has_placeholders()
+ || ty.has_opaque_types()
+ || (!for_return && args.has_non_region_param()) =>
{
- Position::ReborrowStable(precedence)
- } else {
- Position::DerefStable(
- precedence,
- cx.tcx
- .erase_late_bound_regions(Binder::bind_with_vars(
- cx.typeck_results().node_type(ty.ty.hir_id),
- binder_args,
- ))
- .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
- )
- }
- },
- TyKind::Slice(_) => Position::DerefStable(precedence, false),
- TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) => Position::DerefStable(precedence, true),
- TyKind::Never
- | TyKind::Tup(_)
- | TyKind::Path(_) => Position::DerefStable(
- precedence,
- cx.tcx
- .erase_late_bound_regions(Binder::bind_with_vars(
- cx.typeck_results().node_type(ty.ty.hir_id),
- binder_args,
- ))
- .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
- ),
- TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err(_) => {
- Position::ReborrowStable(precedence)
- },
- };
+ Self::Reborrow
+ },
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Array(..)
+ | ty::Float(_)
+ | ty::RawPtr(..)
+ | ty::FnPtr(_)
+ | ty::Str
+ | ty::Slice(..)
+ | ty::Adt(..)
+ | ty::Foreign(_)
+ | ty::FnDef(..)
+ | ty::Generator(..)
+ | ty::GeneratorWitness(..)
+ | ty::GeneratorWitnessMIR(..)
+ | ty::Closure(..)
+ | ty::Never
+ | ty::Tuple(_)
+ | ty::Alias(ty::Projection, _) => Self::Deref,
+ };
+ }
}
}
@@ -1078,10 +968,10 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
}
}
- fn visit_generic_arg(&mut self, arg: &GenericArg<'_>) {
- if self.0 || matches!(arg, GenericArg::Infer(_)) {
+ fn visit_generic_arg(&mut self, arg: &hir::GenericArg<'_>) {
+ if self.0 || matches!(arg, hir::GenericArg::Infer(_)) {
self.0 = true;
- } else if let GenericArg::Type(ty) = arg {
+ } else if let hir::GenericArg::Type(ty) = arg {
self.visit_ty(ty);
}
}
@@ -1091,49 +981,29 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
v.0
}
-fn call_is_qualified(expr: &Expr<'_>) -> bool {
- if let ExprKind::Path(path) = &expr.kind {
- match path {
- QPath::Resolved(_, path) => path.segments.last().map_or(false, |segment| segment.args.is_some()),
- QPath::TypeRelative(_, segment) => segment.args.is_some(),
- QPath::LangItem(..) => false,
- }
- } else {
- false
- }
-}
-
-// Checks whether:
-// * child is an expression of the form `&e` in an argument position requiring an `impl Trait`
-// * `e`'s type implements `Trait` and is copyable
-// If the conditions are met, returns `Some(Position::ImplArg(..))`; otherwise, returns `None`.
-// The "is copyable" condition is to avoid the case where removing the `&` means `e` would have to
-// be moved, but it cannot be.
-#[expect(clippy::too_many_arguments, clippy::too_many_lines)]
-fn needless_borrow_impl_arg_position<'tcx>(
+/// Checks for the number of borrow expressions which can be removed from the given expression
+/// where the expression is used as an argument to a function expecting a generic type.
+///
+/// The following constraints will be checked:
+/// * The borrowed expression meets all the generic type's constraints.
+/// * The generic type appears only once in the functions signature.
+/// * The borrowed value will not be moved if it is used later in the function.
+#[expect(clippy::too_many_arguments)]
+fn needless_borrow_generic_arg_count<'tcx>(
cx: &LateContext<'tcx>,
possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
- parent: &Expr<'tcx>,
+ fn_id: DefId,
+ callee_args: &'tcx List<GenericArg<'tcx>>,
arg_index: usize,
param_ty: ParamTy,
mut expr: &Expr<'tcx>,
- precedence: i8,
msrv: &Msrv,
-) -> Position {
+) -> usize {
let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
- let Some(callee_def_id) = fn_def_id(cx, parent) else { return Position::Other(precedence) };
- let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
- let substs_with_expr_ty = cx
- .typeck_results()
- .node_substs(if let ExprKind::Call(callee, _) = parent.kind {
- callee.hir_id
- } else {
- parent.hir_id
- });
-
- let predicates = cx.tcx.param_env(callee_def_id).caller_bounds();
+ let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder();
+ let predicates = cx.tcx.param_env(fn_id).caller_bounds();
let projection_predicates = predicates
.iter()
.filter_map(|predicate| {
@@ -1168,7 +1038,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
|| cx.tcx.is_diagnostic_item(sym::Any, trait_def_id)
})
{
- return Position::Other(precedence);
+ return 0;
}
// See:
@@ -1176,14 +1046,14 @@ fn needless_borrow_impl_arg_position<'tcx>(
// - https://github.com/rust-lang/rust-clippy/pull/9674#issuecomment-1292225232
if projection_predicates
.iter()
- .any(|projection_predicate| is_mixed_projection_predicate(cx, callee_def_id, projection_predicate))
+ .any(|projection_predicate| is_mixed_projection_predicate(cx, fn_id, projection_predicate))
{
- return Position::Other(precedence);
+ return 0;
}
- // `substs_with_referent_ty` can be constructed outside of `check_referent` because the same
+ // `args_with_referent_ty` can be constructed outside of `check_referent` because the same
// elements are modified each time `check_referent` is called.
- let mut substs_with_referent_ty = substs_with_expr_ty.to_vec();
+ let mut args_with_referent_ty = callee_args.to_vec();
let mut check_reference_and_referent = |reference, referent| {
let referent_ty = cx.typeck_results().expr_ty(referent);
@@ -1207,7 +1077,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
fn_sig,
arg_index,
&projection_predicates,
- &mut substs_with_referent_ty,
+ &mut args_with_referent_ty,
) {
return false;
}
@@ -1216,34 +1086,29 @@ fn needless_borrow_impl_arg_position<'tcx>(
if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
&& cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id)
&& let ty::Param(param_ty) = trait_predicate.self_ty().kind()
- && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack()
+ && let GenericArgKind::Type(ty) = args_with_referent_ty[param_ty.index as usize].unpack()
&& ty.is_array()
&& !msrv.meets(msrvs::ARRAY_INTO_ITERATOR)
{
return false;
}
- let predicate = EarlyBinder::bind(predicate).subst(cx.tcx, &substs_with_referent_ty);
+ let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, &args_with_referent_ty);
let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
let infcx = cx.tcx.infer_ctxt().build();
infcx.predicate_must_hold_modulo_regions(&obligation)
})
};
- let mut needless_borrow = false;
+ let mut count = 0;
while let ExprKind::AddrOf(_, _, referent) = expr.kind {
if !check_reference_and_referent(expr, referent) {
break;
}
expr = referent;
- needless_borrow = true;
- }
-
- if needless_borrow {
- Position::ImplArg(expr.hir_id)
- } else {
- Position::Other(precedence)
+ count += 1;
}
+ count
}
fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
@@ -1252,7 +1117,12 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
.in_definition_order()
.any(|assoc_item| {
if assoc_item.fn_has_self_parameter {
- let self_ty = cx.tcx.fn_sig(assoc_item.def_id).subst_identity().skip_binder().inputs()[0];
+ let self_ty = cx
+ .tcx
+ .fn_sig(assoc_item.def_id)
+ .instantiate_identity()
+ .skip_binder()
+ .inputs()[0];
matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Mut))
} else {
false
@@ -1301,7 +1171,7 @@ fn referent_used_exactly_once<'tcx>(
&& let [location] = *local_assignments(mir, local).as_slice()
&& let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index)
&& let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
- && !place.has_deref()
+ && !place.is_indirect_first_projection()
// Ensure not in a loop (https://github.com/rust-lang/rust-clippy/issues/9710)
&& TriColorDepthFirstSearch::new(&mir.basic_blocks).run_from(location.block, &mut CycleDetector).is_none()
{
@@ -1323,7 +1193,7 @@ fn referent_used_exactly_once<'tcx>(
}
}
-// Iteratively replaces `param_ty` with `new_ty` in `substs`, and similarly for each resulting
+// Iteratively replaces `param_ty` with `new_ty` in `args`, and similarly for each resulting
// projected type that is a type parameter. Returns `false` if replacing the types would have an
// effect on the function signature beyond substituting `new_ty` for `param_ty`.
// See: https://github.com/rust-lang/rust-clippy/pull/9136#discussion_r927212757
@@ -1334,11 +1204,11 @@ fn replace_types<'tcx>(
fn_sig: FnSig<'tcx>,
arg_index: usize,
projection_predicates: &[ProjectionPredicate<'tcx>],
- substs: &mut [ty::GenericArg<'tcx>],
+ args: &mut [ty::GenericArg<'tcx>],
) -> bool {
- let mut replaced = BitSet::new_empty(substs.len());
+ let mut replaced = BitSet::new_empty(args.len());
- let mut deque = VecDeque::with_capacity(substs.len());
+ let mut deque = VecDeque::with_capacity(args.len());
deque.push_back((param_ty, new_ty));
while let Some((param_ty, new_ty)) = deque.pop_front() {
@@ -1352,7 +1222,7 @@ fn replace_types<'tcx>(
return false;
}
- substs[param_ty.index as usize] = ty::GenericArg::from(new_ty);
+ args[param_ty.index as usize] = ty::GenericArg::from(new_ty);
// The `replaced.insert(...)` check provides some protection against infinite loops.
if replaced.insert(param_ty.index) {
@@ -1367,7 +1237,7 @@ fn replace_types<'tcx>(
));
if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection)
- && substs[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty)
+ && args[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty)
{
deque.push_back((*term_param_ty, projected_ty));
}
@@ -1379,95 +1249,6 @@ fn replace_types<'tcx>(
true
}
-struct TyPosition<'tcx> {
- position: Position,
- ty: Option<Ty<'tcx>>,
-}
-impl From<Position> for TyPosition<'_> {
- fn from(position: Position) -> Self {
- Self { position, ty: None }
- }
-}
-impl<'tcx> TyPosition<'tcx> {
- fn new_deref_stable_for_result(precedence: i8, ty: Ty<'tcx>) -> Self {
- Self {
- position: Position::ReborrowStable(precedence),
- ty: Some(ty),
- }
- }
- fn position_for_result(self, cx: &LateContext<'tcx>) -> Position {
- match (self.position, self.ty) {
- (Position::ReborrowStable(precedence), Some(ty)) => {
- Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env))
- },
- (position, _) => position,
- }
- }
- fn position_for_arg(self) -> Position {
- self.position
- }
-}
-
-// Checks whether a type is stable when switching to auto dereferencing,
-fn ty_auto_deref_stability<'tcx>(
- tcx: TyCtxt<'tcx>,
- param_env: ParamEnv<'tcx>,
- ty: Ty<'tcx>,
- precedence: i8,
-) -> TyPosition<'tcx> {
- let ty::Ref(_, mut ty, _) = *ty.kind() else {
- return Position::Other(precedence).into();
- };
-
- ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
-
- loop {
- break match *ty.kind() {
- ty::Ref(_, ref_ty, _) => {
- ty = ref_ty;
- continue;
- },
- ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
- ty::Alias(ty::Weak, _) => unreachable!("should have been normalized away above"),
- ty::Alias(ty::Inherent, _) => unreachable!("inherent projection should have been normalized away above"),
- ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
- TyPosition::new_deref_stable_for_result(precedence, ty)
- },
- ty::Infer(_)
- | ty::Error(_)
- | ty::Bound(..)
- | ty::Alias(ty::Opaque, ..)
- | ty::Placeholder(_)
- | ty::Dynamic(..) => Position::ReborrowStable(precedence).into(),
- ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
- Position::ReborrowStable(precedence).into()
- },
- ty::Adt(_, substs) if substs.has_non_region_param() => {
- TyPosition::new_deref_stable_for_result(precedence, ty)
- },
- ty::Bool
- | ty::Char
- | ty::Int(_)
- | ty::Uint(_)
- | ty::Array(..)
- | ty::Float(_)
- | ty::RawPtr(..)
- | ty::FnPtr(_) => Position::DerefStable(precedence, true).into(),
- ty::Str | ty::Slice(..) => Position::DerefStable(precedence, false).into(),
- ty::Adt(..)
- | ty::Foreign(_)
- | ty::FnDef(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
- | ty::Closure(..)
- | ty::Never
- | ty::Tuple(_)
- | ty::Alias(ty::Projection, _) => Position::DerefStable(precedence, ty.is_sized(tcx, param_env)).into(),
- };
- }
-}
-
fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool {
if let ty::Adt(adt, _) = *ty.kind() {
adt.is_struct() && adt.all_fields().any(|f| f.name == name)
@@ -1477,12 +1258,12 @@ 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) {
+fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData<'tcx>) {
match state {
State::DerefMethod {
ty_changed_count,
- is_final_ufcs,
- target_mut,
+ is_ufcs,
+ mutbl,
} => {
let mut app = Applicability::MachineApplicable;
let (expr_str, _expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
@@ -1497,12 +1278,12 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
};
let addr_of_str = if ty_changed_count < ref_count {
// Check if a reborrow from &mut T -> &T is required.
- if target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
+ if mutbl == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
"&*"
} else {
""
}
- } else if target_mut == Mutability::Mut {
+ } else if mutbl == Mutability::Mut {
"&mut "
} else {
"&"
@@ -1519,7 +1300,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
*/
// Fix #10850, do not lint if it's `Foo::deref` instead of `foo.deref()`.
- if is_final_ufcs {
+ if is_ufcs {
return;
}
@@ -1527,24 +1308,30 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
cx,
EXPLICIT_DEREF_METHODS,
data.span,
- match target_mut {
+ match mutbl {
Mutability::Not => "explicit `deref` method call",
Mutability::Mut => "explicit `deref_mut` method call",
},
- "try this",
+ "try",
format!("{addr_of_str}{deref_str}{expr_str}"),
app,
);
},
State::DerefedBorrow(state) => {
let mut app = Applicability::MachineApplicable;
- let snip_expr = state.snip_expr.map_or(expr, |hir_id| cx.tcx.hir().expect_expr(hir_id));
- let (snip, snip_is_macro) = snippet_with_context(cx, snip_expr.span, data.span.ctxt(), "..", &mut app);
+ 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 calls_field = matches!(expr.kind, ExprKind::Field(..)) && matches!(data.position, Position::Callee);
+ 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)
- && (expr.precedence().order() < data.position.precedence() || calls_field)
{
format!("({snip})")
} else {
@@ -1561,7 +1348,8 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
| ExprKind::If(..)
| ExprKind::Loop(..)
| ExprKind::Match(..)
- ) && matches!(data.position, Position::DerefStable(_, true))
+ ) && let ty::Ref(_, ty, _) = data.adjusted_ty.kind()
+ && ty.is_sized(cx.tcx, cx.param_env)
{
// Rustc bug: auto deref doesn't work on block expression when targeting sized types.
return;
@@ -1574,9 +1362,9 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
Mutability::Not => "&",
Mutability::Mut => "&mut ",
};
- (prefix, 0)
+ (prefix, PREC_PREFIX)
} else {
- ("", data.position.precedence())
+ ("", 0)
};
span_lint_hir_and_then(
cx,
@@ -1593,7 +1381,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
} else {
format!("{prefix}{snip}")
};
- diag.span_suggestion(data.span, "try this", sugg, app);
+ diag.span_suggestion(data.span, "try", sugg, app);
},
);
},
@@ -1605,7 +1393,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
| ExprKind::If(..)
| ExprKind::Loop(..)
| ExprKind::Match(..)
- ) && matches!(data.position, Position::DerefStable(_, true))
+ ) && 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;
@@ -1620,7 +1408,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
|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 this", snip.into_owned(), app);
+ diag.span_suggestion(data.span, "try", snip.into_owned(), app);
},
);
},
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index 020ffe7f8..9a85cc4ce 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -3,14 +3,13 @@ use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::indent_of;
use clippy_utils::{is_default_equivalent, peel_blocks};
use rustc_errors::Applicability;
+use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::{
- self as hir,
- def::{CtorKind, CtorOf, DefKind, Res},
- Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
+ self as hir, Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::adjustment::{Adjust, PointerCoercion};
-use rustc_middle::ty::{self, Adt, AdtDef, SubstsRef, Ty, TypeckResults};
+use rustc_middle::ty::{self, Adt, AdtDef, GenericArgsRef, Ty, TypeckResults};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::sym;
@@ -80,7 +79,7 @@ fn is_path_self(e: &Expr<'_>) -> bool {
fn contains_trait_object(ty: Ty<'_>) -> bool {
match ty.kind() {
ty::Ref(_, ty, _) => contains_trait_object(*ty),
- ty::Adt(def, substs) => def.is_box() && substs[0].as_type().map_or(false, contains_trait_object),
+ ty::Adt(def, args) => def.is_box() && args[0].as_type().map_or(false, contains_trait_object),
ty::Dynamic(..) => true,
_ => false,
}
@@ -92,18 +91,19 @@ fn check_struct<'tcx>(
self_ty: &hir::Ty<'_>,
func_expr: &Expr<'_>,
adt_def: AdtDef<'_>,
- substs: SubstsRef<'_>,
+ ty_args: GenericArgsRef<'_>,
typeck_results: &'tcx TypeckResults<'tcx>,
) {
if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind {
if let Some(PathSegment { args, .. }) = p.segments.last() {
let args = args.map(|a| a.args).unwrap_or(&[]);
- // substs contains the generic parameters of the type declaration, while args contains the arguments
- // used at instantiation time. If both len are not equal, it means that some parameters were not
- // provided (which means that the default values were used); in this case we will not risk
- // suggesting too broad a rewrite. We won't either if any argument is a type or a const.
- if substs.len() != args.len() || args.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_))) {
+ // ty_args contains the generic parameters of the type declaration, while args contains the
+ // arguments used at instantiation time. If both len are not equal, it means that some
+ // parameters were not provided (which means that the default values were used); in this
+ // case we will not risk suggesting too broad a rewrite. We won't either if any argument
+ // is a type or a const.
+ if ty_args.len() != args.len() || args.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_))) {
return;
}
}
@@ -214,7 +214,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
if let ImplItemKind::Fn(_, b) = &impl_item.kind;
if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
- if let &Adt(adt_def, substs) = cx.tcx.type_of(item.owner_id).subst_identity().kind();
+ 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 let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
@@ -222,7 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
then {
if adt_def.is_struct() {
- check_struct(cx, item, self_ty, func_expr, adt_def, substs, cx.tcx.typeck_body(*b));
+ 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 a005a360e..d3311792c 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -1,21 +1,19 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::paths;
use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
-use clippy_utils::{is_lint_allowed, match_def_path};
+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};
use rustc_hir::{
- self as hir, BlockCheckMode, BodyId, Constness, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource,
- Unsafety,
+ self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource, Unsafety,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::traits::Reveal;
use rustc_middle::ty::{
- self, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate,
- TraitPredicate, Ty, TyCtxt,
+ self, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate, TraitPredicate, Ty,
+ TyCtxt,
};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId;
@@ -211,7 +209,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
..
}) = item.kind
{
- let ty = cx.tcx.type_of(item.owner_id).subst_identity();
+ let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
let is_automatically_derived = cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
@@ -252,7 +250,7 @@ fn check_hash_peq<'tcx>(
// Only care about `impl PartialEq<Foo> for Foo`
// For `impl PartialEq<B> for A, input_types is [A, B]
- if trait_ref.subst_identity().substs.type_at(1) == ty {
+ if trait_ref.instantiate_identity().args.type_at(1) == ty {
span_lint_and_then(
cx,
DERIVED_HASH_WITH_MANUAL_EQ,
@@ -300,7 +298,7 @@ fn check_ord_partial_ord<'tcx>(
// Only care about `impl PartialOrd<Foo> for Foo`
// For `impl PartialOrd<B> for A, input_types is [A, B]
- if trait_ref.subst_identity().substs.type_at(1) == ty {
+ 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 {
@@ -334,7 +332,9 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h
Some(id) if trait_ref.trait_def_id() == Some(id) => id,
_ => return,
};
- let Some(copy_id) = cx.tcx.lang_items().copy_trait() else { return };
+ let Some(copy_id) = cx.tcx.lang_items().copy_trait() else {
+ return;
+ };
let (ty_adt, ty_subs) = match *ty.kind() {
// Unions can't derive clone.
ty::Adt(adt, subs) if !adt.is_union() => (adt, subs),
@@ -345,9 +345,10 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h
if !is_copy(cx, ty) {
if ty_subs.non_erasable_generics().next().is_some() {
let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(&copy_id).map_or(false, |impls| {
- impls
- .iter()
- .any(|&id| matches!(cx.tcx.type_of(id).subst_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did()))
+ impls.iter().any(|&id| {
+ matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _)
+ if ty_adt.did() == adt.did())
+ })
});
if !has_copy_impl {
return;
@@ -464,18 +465,18 @@ 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, substs) = ty.kind();
+ 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 !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]);
// If all of our fields implement `Eq`, we can implement `Eq` too
if adt
.all_fields()
- .map(|f| f.ty(cx.tcx, substs))
- .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, []));
+ .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,
@@ -506,7 +507,6 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
if let ClauseKind::Trait(p) = p.kind().skip_binder()
&& p.trait_ref.def_id == eq_trait_id
&& let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
- && p.constness == BoundConstness::NotConst
{
// Flag types which already have an `Eq` bound.
params[self_ty.index as usize].1 = false;
@@ -518,13 +518,11 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
ClauseKind::Trait(TraitPredicate {
trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
- constness: BoundConstness::NotConst,
polarity: ImplPolarity::Positive,
})
.to_predicate(tcx)
}),
)),
Reveal::UserFacing,
- Constness::NotConst,
)
}
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index ca8671c8f..95d3f7547 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
path_def_id(cx, expr)
};
let Some(def_id) = uncalled_path.or_else(|| fn_def_id(cx, expr)) else {
- return
+ return;
};
let conf = match self.disallowed.get(&def_id) {
Some(&index) => &self.conf_disallowed[index],
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
index 6e6615f08..04c2d4413 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
@@ -1,4 +1,5 @@
-use clippy_utils::{diagnostics::span_lint, is_test_module_or_function};
+use clippy_utils::diagnostics::span_lint;
+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};
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index 87d88f707..e29ab634c 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -16,7 +16,7 @@ use rustc_ast::token::CommentKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::{Applicability, Handler, SuggestionStyle, TerminalUrl};
+use rustc_errors::{Applicability, Handler, SuggestionStyle};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{AnonConst, Expr};
@@ -31,9 +31,8 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::edition::Edition;
use rustc_span::source_map::{BytePos, FilePathMapping, SourceMap, Span};
use rustc_span::{sym, FileName, Pos};
-use std::io;
use std::ops::Range;
-use std::thread;
+use std::{io, thread};
use url::Url;
declare_clippy_lint! {
@@ -295,7 +294,9 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
- let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return };
+ let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
+ return;
+ };
match item.kind {
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)) {
@@ -339,7 +340,9 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
- let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return };
+ let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
+ return;
+ };
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);
@@ -349,7 +352,9 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
- let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return };
+ let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
+ return;
+ };
if self.in_trait_impl || in_external_macro(cx.tcx.sess, item.span) {
return;
}
@@ -711,20 +716,8 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
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()),
- None,
- None,
- fallback_bundle,
- false,
- false,
- false,
- None,
- false,
- false,
- TerminalUrl::No,
- );
- let handler = Handler::with_emitter(false, None, Box::new(emitter));
+ 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) {
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 976ce47e8..14122abbf 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_note;
-use clippy_utils::get_parent_node;
-use clippy_utils::is_must_use_func_call;
use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item};
+use 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};
diff --git a/src/tools/clippy/clippy_lints/src/empty_drop.rs b/src/tools/clippy/clippy_lints/src/empty_drop.rs
index ec063c0f7..209fb66fa 100644
--- a/src/tools/clippy/clippy_lints/src/empty_drop.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_drop.rs
@@ -1,4 +1,5 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, peel_blocks};
+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};
diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs
index d94664daa..1701d0611 100644
--- a/src/tools/clippy/clippy_lints/src/empty_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs
@@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for EmptyEnum {
}
if let ItemKind::Enum(..) = item.kind {
- let ty = cx.tcx.type_of(item.owner_id).subst_identity();
+ let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
if adt.variants().is_empty() {
span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs
index c3a020433..282157181 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
@@ -1,4 +1,5 @@
-use clippy_utils::{diagnostics::span_lint_and_then, source::snippet_opt};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet_opt;
use rustc_ast::ast::{Item, ItemKind, VariantData};
use rustc_errors::Applicability;
use rustc_lexer::TokenKind;
diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
index f47098783..dda14b4df 100644
--- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
@@ -1,8 +1,10 @@
use crate::Lint;
-use clippy_utils::{diagnostics::span_lint_and_then, is_lint_allowed};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_lint_allowed;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::{lint::in_external_macro, ty::Ty};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::Ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Symbol;
use std::borrow::Cow;
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index ee5a875ad..6197b5b19 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -1,18 +1,14 @@
-use clippy_utils::higher;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context};
use clippy_utils::{
- can_move_expr_to_closure_no_visit,
- diagnostics::span_lint_and_sugg,
- is_expr_final_block_expr, is_expr_used_or_unified, match_def_path, paths, peel_hir_expr_while,
- source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context},
- SpanlessEq,
+ can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, match_def_path,
+ paths, peel_hir_expr_while, SpanlessEq,
};
use core::fmt::{self, Write};
use rustc_errors::Applicability;
-use rustc_hir::{
- hir_id::HirIdSet,
- intravisit::{walk_expr, Visitor},
- Block, Expr, ExprKind, Guard, HirId, Let, Pat, Stmt, StmtKind, UnOp,
-};
+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_span::{Span, SyntaxContext, DUMMY_SP};
@@ -69,16 +65,21 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
return;
}
- let Some(higher::If { cond: cond_expr, then: then_expr, r#else: else_expr }) = higher::If::hir(expr) else {
- return
+ let Some(higher::If {
+ cond: cond_expr,
+ then: then_expr,
+ r#else: else_expr,
+ }) = higher::If::hir(expr)
+ else {
+ return;
};
let Some((map_ty, contains_expr)) = try_parse_contains(cx, cond_expr) else {
- return
+ return;
};
let Some(then_search) = find_insert_calls(cx, &contains_expr, then_expr) else {
- return
+ return;
};
let mut app = Applicability::MachineApplicable;
@@ -186,7 +187,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
MAP_ENTRY,
expr.span,
&format!("usage of `contains_key` followed by `insert` on a `{}`", map_ty.name()),
- "try this",
+ "try",
sugg,
app,
);
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index d85650712..96c5c7fc5 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
for var in def.variants {
if let Some(anon_const) = &var.disr_expr {
let def_id = cx.tcx.hir().body_owner_def_id(anon_const.body);
- let mut ty = cx.tcx.type_of(def_id.to_def_id()).subst_identity();
+ let mut ty = cx.tcx.type_of(def_id.to_def_id()).instantiate_identity();
let constant = cx
.tcx
.const_eval_poly(def_id.to_def_id())
diff --git a/src/tools/clippy/clippy_lints/src/error_impl_error.rs b/src/tools/clippy/clippy_lints/src/error_impl_error.rs
new file mode 100644
index 000000000..379af9b22
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/error_impl_error.rs
@@ -0,0 +1,87 @@
+use clippy_utils::diagnostics::{span_lint, span_lint_hir_and_then};
+use clippy_utils::path_res;
+use clippy_utils::ty::implements_trait;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::{Item, ItemKind};
+use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Visibility;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for types named `Error` that implement `Error`.
+ ///
+ /// ### Why is this bad?
+ /// It can become confusing when a codebase has 20 types all named `Error`, requiring either
+ /// aliasing them in the `use` statement or qualifying them like `my_module::Error`. This
+ /// hinders comprehension, as it requires you to memorize every variation of importing `Error`
+ /// used across a codebase.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// #[derive(Debug)]
+ /// pub enum Error { ... }
+ ///
+ /// impl std::fmt::Display for Error { ... }
+ ///
+ /// impl std::error::Error for Error { ... }
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub ERROR_IMPL_ERROR,
+ restriction,
+ "exported types named `Error` that implement `Error`"
+}
+declare_lint_pass!(ErrorImplError => [ERROR_IMPL_ERROR]);
+
+impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+ let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error) else {
+ return;
+ };
+
+ match item.kind {
+ ItemKind::TyAlias(ty, _) if implements_trait(cx, hir_ty_to_ty(cx.tcx, ty), error_def_id, &[])
+ && item.ident.name == sym::Error
+ && is_visible_outside_module(cx, item.owner_id.def_id) =>
+ {
+ span_lint(
+ cx,
+ ERROR_IMPL_ERROR,
+ item.ident.span,
+ "exported type alias named `Error` that implements `Error`",
+ );
+ },
+ ItemKind::Impl(imp) 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 Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id())
+ && ident.name == sym::Error
+ && is_visible_outside_module(cx, def_id) =>
+ {
+ span_lint_hir_and_then(
+ cx,
+ ERROR_IMPL_ERROR,
+ hir_id,
+ ident.span,
+ "exported type named `Error` that implements `Error`",
+ |diag| {
+ diag.span_note(item.span, "`Error` was implemented here");
+ }
+ );
+ }
+ _ => {},
+ }
+ }
+}
+
+/// Do not lint private `Error`s, i.e., ones without any `pub` (minus `pub(self)` of course) and
+/// which aren't reexported
+fn is_visible_outside_module(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
+ !matches!(
+ cx.tcx.visibility(def_id),
+ Visibility::Restricted(mod_def_id) if cx.tcx.parent_module_from_def_id(def_id).to_def_id() == mod_def_id
+ )
+}
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index a51a8ee09..dbe3453e7 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_hir;
-use rustc_hir::intravisit;
-use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind};
+use rustc_hir::{self, 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};
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 58e62d1f3..38066503c 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -1,19 +1,22 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::higher::VecArgs;
use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::usage::local_used_after_expr;
+use clippy_utils::ty::type_diagnostic_name;
+use clippy_utils::usage::{local_used_after_expr, local_used_in};
use clippy_utils::{higher, is_adjusted, path_to_local, path_to_local_id};
-use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
-use rustc_hir::{Closure, Expr, ExprKind, Param, PatKind, Unsafety};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, TyKind, Unsafety};
+use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
-use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::{self, EarlyBinder, SubstsRef, Ty, TypeVisitableExt};
+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_span::symbol::sym;
+use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
declare_clippy_lint! {
/// ### What it does
@@ -72,14 +75,18 @@ declare_clippy_lint! {
declare_lint_pass!(EtaReduction => [REDUNDANT_CLOSURE, REDUNDANT_CLOSURE_FOR_METHOD_CALLS]);
impl<'tcx> LateLintPass<'tcx> for EtaReduction {
+ #[allow(clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if expr.span.from_expansion() {
+ let body = if let ExprKind::Closure(c) = expr.kind
+ && c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer))
+ && matches!(c.fn_decl.output, FnRetTy::DefaultReturn(_))
+ && !expr.span.from_expansion()
+ {
+ cx.tcx.hir().body(c.body)
+ } else {
return;
- }
- let body = match expr.kind {
- ExprKind::Closure(&Closure { body, .. }) => cx.tcx.hir().body(body),
- _ => return,
};
+
if body.value.span.from_expansion() {
if body.params.is_empty() {
if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, body.value) {
@@ -99,149 +106,217 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
return;
}
- let closure_ty = cx.typeck_results().expr_ty(expr);
+ let typeck = cx.typeck_results();
+ let closure = if let ty::Closure(_, closure_subs) = typeck.expr_ty(expr).kind() {
+ closure_subs.as_closure()
+ } else {
+ return;
+ };
- if_chain!(
- if !is_adjusted(cx, body.value);
- if let ExprKind::Call(callee, args) = body.value.kind;
- if let ExprKind::Path(_) = callee.kind;
- if check_inputs(cx, body.params, None, args);
- let callee_ty = cx.typeck_results().expr_ty_adjusted(callee);
- let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id)
- .map_or(callee_ty, |id| cx.tcx.type_of(id).subst_identity());
- if check_sig(cx, closure_ty, call_ty);
- let substs = cx.typeck_results().node_substs(callee.hir_id);
- // This fixes some false positives that I don't entirely understand
- if substs.is_empty() || !cx.typeck_results().expr_ty(expr).has_late_bound_regions();
- // A type param function ref like `T::f` is not 'static, however
- // it is if cast like `T::f as fn()`. This seems like a rustc bug.
- if !substs.types().any(|t| matches!(t.kind(), ty::Param(_)));
- let callee_ty_unadjusted = cx.typeck_results().expr_ty(callee).peel_refs();
- if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Arc);
- if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Rc);
- if let ty::Closure(_, substs) = *closure_ty.kind();
- // Don't lint if this is an inclusive range expression.
- // They desugar to a call to `RangeInclusiveNew` which would have odd suggestions. (#10684)
- if !matches!(higher::Range::hir(body.value), Some(higher::Range {
- start: Some(_),
- end: Some(_),
- limits: rustc_ast::RangeLimits::Closed
- }));
- then {
- span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
- if let Some(mut snippet) = snippet_opt(cx, callee.span) {
- if let Some(fn_mut_id) = cx.tcx.lang_items().fn_mut_trait()
- && let args = cx.tcx.erase_late_bound_regions(substs.as_closure().sig()).inputs()
- && implements_trait(
- cx,
- callee_ty.peel_refs(),
- fn_mut_id,
- &args.iter().copied().map(Into::into).collect::<Vec<_>>(),
- )
- && path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr))
- {
- // Mutable closure is used after current expr; we cannot consume it.
- snippet = format!("&mut {snippet}");
- }
+ if is_adjusted(cx, body.value) {
+ return;
+ }
- diag.span_suggestion(
- expr.span,
- "replace the closure with the function itself",
- snippet,
- Applicability::MachineApplicable,
- );
- }
- });
- }
- );
+ match body.value.kind {
+ ExprKind::Call(callee, args)
+ if matches!(callee.kind, ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))) =>
+ {
+ let callee_ty = typeck.expr_ty(callee).peel_refs();
+ if matches!(
+ type_diagnostic_name(cx, callee_ty),
+ Some(sym::Arc | sym::Rc)
+ ) || !check_inputs(typeck, body.params, None, args) {
+ return;
+ }
+ let callee_ty_adjusted = typeck.expr_adjustments(callee).last().map_or(
+ callee_ty,
+ |a| a.target.peel_refs(),
+ );
- if_chain!(
- if !is_adjusted(cx, body.value);
- if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind;
- if check_inputs(cx, body.params, Some(receiver), args);
- let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
- let substs = cx.typeck_results().node_substs(body.value.hir_id);
- let call_ty = cx.tcx.type_of(method_def_id).subst(cx.tcx, substs);
- if check_sig(cx, closure_ty, call_ty);
- then {
- span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| {
- let name = get_ufcs_type_name(cx, method_def_id, substs);
- diag.span_suggestion(
+ let sig = match callee_ty_adjusted.kind() {
+ ty::FnDef(def, _) => cx.tcx.fn_sig(def).skip_binder().skip_binder(),
+ ty::FnPtr(sig) => sig.skip_binder(),
+ ty::Closure(_, subs) => cx
+ .tcx
+ .signature_unclosure(subs.as_closure().sig(), Unsafety::Normal)
+ .skip_binder(),
+ _ => {
+ if typeck.type_dependent_def_id(body.value.hir_id).is_some()
+ && let subs = typeck.node_args(body.value.hir_id)
+ && let output = typeck.expr_ty(body.value)
+ && let ty::Tuple(tys) = *subs.type_at(1).kind()
+ {
+ cx.tcx.mk_fn_sig(tys, output, false, Unsafety::Normal, Abi::Rust)
+ } else {
+ return;
+ }
+ },
+ };
+ if check_sig(cx, closure, sig)
+ && let generic_args = typeck.node_args(callee.hir_id)
+ // Given some trait fn `fn f() -> ()` and some type `T: Trait`, `T::f` is not
+ // `'static` unless `T: 'static`. The cast `T::f as fn()` will, however, result
+ // in a type which is `'static`.
+ // For now ignore all callee types which reference a type parameter.
+ && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
+ {
+ span_lint_and_then(
+ cx,
+ REDUNDANT_CLOSURE,
expr.span,
- "replace the closure with the method itself",
- format!("{name}::{}", path.ident.name),
- Applicability::MachineApplicable,
+ "redundant closure",
+ |diag| {
+ if let Some(mut snippet) = snippet_opt(cx, callee.span) {
+ if let Ok((ClosureKind::FnMut, _))
+ = cx.tcx.infer_ctxt().build().type_implements_fn_trait(
+ cx.param_env,
+ Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
+ ImplPolarity::Positive,
+ ) && path_to_local(callee)
+ .map_or(
+ false,
+ |l| local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr),
+ )
+ {
+ // Mutable closure is used after current expr; we cannot consume it.
+ snippet = format!("&mut {snippet}");
+ }
+ diag.span_suggestion(
+ expr.span,
+ "replace the closure with the function itself",
+ snippet,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
);
- })
- }
- );
+ }
+ },
+ ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
+ if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id)
+ && check_sig(cx, closure, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
+ {
+ span_lint_and_then(
+ cx,
+ REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
+ expr.span,
+ "redundant closure",
+ |diag| {
+ let args = typeck.node_args(body.value.hir_id);
+ let name = get_ufcs_type_name(cx, method_def_id, args);
+ diag.span_suggestion(
+ expr.span,
+ "replace the closure with the method itself",
+ format!("{}::{}", name, path.ident.name),
+ Applicability::MachineApplicable,
+ );
+ },
+ );
+ }
+ },
+ _ => (),
+ }
}
}
fn check_inputs(
- cx: &LateContext<'_>,
+ typeck: &TypeckResults<'_>,
params: &[Param<'_>],
- receiver: Option<&Expr<'_>>,
- call_args: &[Expr<'_>],
+ self_arg: Option<&Expr<'_>>,
+ args: &[Expr<'_>],
) -> bool {
- if receiver.map_or(params.len() != call_args.len(), |_| params.len() != call_args.len() + 1) {
- return false;
+ 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)
+ if path_to_local_id(arg, id)
+ )
+ // Only allow adjustments which change regions (i.e. re-borrowing).
+ && typeck
+ .expr_adjustments(arg)
+ .last()
+ .map_or(true, |a| a.target == typeck.expr_ty(arg))
+ })
+}
+
+fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<'tcx>, call_sig: FnSig<'_>) -> bool {
+ call_sig.unsafety == Unsafety::Normal
+ && !has_late_bound_to_non_late_bound_regions(
+ cx.tcx
+ .signature_unclosure(closure.sig(), Unsafety::Normal)
+ .skip_binder(),
+ call_sig,
+ )
+}
+
+/// This walks through both signatures and checks for any time a late-bound region is expected by an
+/// `impl Fn` type, but the target signature does not have a late-bound region in the same position.
+///
+/// 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(..))
}
- let binding_modes = cx.typeck_results().pat_binding_modes();
- let check_inputs = |param: &Param<'_>, arg| {
- match param.pat.kind {
- PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
- _ => return false,
- }
- // checks that parameters are not bound as `ref` or `ref mut`
- if let Some(BindingMode::BindByReference(_)) = binding_modes.get(param.pat.hir_id) {
- return false;
- }
- match *cx.typeck_results().expr_adjustments(arg) {
- [] => true,
- [
- Adjustment {
- kind: Adjust::Deref(None),
- ..
+ fn check_subs(from_subs: &[GenericArg<'_>], to_subs: &[GenericArg<'_>]) -> bool {
+ if from_subs.len() != to_subs.len() {
+ return true;
+ }
+ for (from_arg, to_arg) in to_subs.iter().zip(from_subs) {
+ match (from_arg.unpack(), to_arg.unpack()) {
+ (GenericArgKind::Lifetime(from_region), GenericArgKind::Lifetime(to_region)) => {
+ if check_region(from_region, to_region) {
+ return true;
+ }
},
- Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
- ..
+ (GenericArgKind::Type(from_ty), GenericArgKind::Type(to_ty)) => {
+ if check_ty(from_ty, to_ty) {
+ return true;
+ }
},
- ] => {
- // re-borrow with the same mutability is allowed
- let ty = cx.typeck_results().expr_ty(arg);
- matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into())
- },
- _ => false,
+ (GenericArgKind::Const(_), GenericArgKind::Const(_)) => (),
+ _ => return true,
+ }
}
- };
- std::iter::zip(params, receiver.into_iter().chain(call_args.iter())).all(|(param, arg)| check_inputs(param, arg))
-}
-
-fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
- let call_sig = call_ty.fn_sig(cx.tcx);
- if call_sig.unsafety() == Unsafety::Unsafe {
- return false;
+ false
}
- if !closure_ty.has_late_bound_regions() {
- return true;
+
+ fn check_ty(from_ty: Ty<'_>, to_ty: Ty<'_>) -> bool {
+ match (from_ty.kind(), to_ty.kind()) {
+ (&ty::Adt(_, from_subs), &ty::Adt(_, to_subs)) => check_subs(from_subs, to_subs),
+ (&ty::Array(from_ty, _), &ty::Array(to_ty, _)) | (&ty::Slice(from_ty), &ty::Slice(to_ty)) => {
+ check_ty(from_ty, to_ty)
+ },
+ (&ty::Ref(from_region, from_ty, _), &ty::Ref(to_region, to_ty, _)) => {
+ check_region(from_region, to_region) || check_ty(from_ty, to_ty)
+ },
+ (&ty::Tuple(from_tys), &ty::Tuple(to_tys)) => {
+ from_tys.len() != to_tys.len()
+ || from_tys
+ .iter()
+ .zip(to_tys)
+ .any(|(from_ty, to_ty)| check_ty(from_ty, to_ty))
+ },
+ _ => from_ty.has_late_bound_regions(),
+ }
}
- let ty::Closure(_, substs) = closure_ty.kind() else {
- return false;
- };
- let closure_sig = cx.tcx.signature_unclosure(substs.as_closure().sig(), Unsafety::Normal);
- cx.tcx.erase_late_bound_regions(closure_sig) == cx.tcx.erase_late_bound_regions(call_sig)
+
+ assert!(from_sig.inputs_and_output.len() == to_sig.inputs_and_output.len());
+ from_sig
+ .inputs_and_output
+ .iter()
+ .zip(to_sig.inputs_and_output)
+ .any(|(from_ty, to_ty)| check_ty(from_ty, to_ty))
}
-fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs: SubstsRef<'tcx>) -> String {
+fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, args: GenericArgsRef<'tcx>) -> String {
let assoc_item = cx.tcx.associated_item(method_def_id);
let def_id = assoc_item.container_id(cx.tcx);
match assoc_item.container {
ty::TraitContainer => cx.tcx.def_path_str(def_id),
ty::ImplContainer => {
- let ty = cx.tcx.type_of(def_id).skip_binder();
+ let ty = cx.tcx.type_of(def_id).instantiate_identity();
match ty.kind() {
ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()),
ty::Array(..)
@@ -251,7 +326,7 @@ fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs
| ty::Ref(..)
| ty::Slice(_)
| ty::Tuple(_) => {
- format!("<{}>", EarlyBinder::bind(ty).subst(cx.tcx, substs))
+ format!("<{}>", EarlyBinder::bind(ty).instantiate(cx.tcx, args))
},
_ => ty.to_string(),
}
diff --git a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
index d04d833e6..8911f1872 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
@@ -1,9 +1,8 @@
-use clippy_utils::{diagnostics::span_lint_and_help, source::snippet};
-use rustc_ast::{
- node_id::NodeSet,
- visit::{walk_block, walk_item, Visitor},
- Block, Crate, Inline, Item, ItemKind, ModKind, NodeId,
-};
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::source::snippet;
+use rustc_ast::node_id::NodeSet;
+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};
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index 315df6c71..4b9ca8c91 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
EXPLICIT_WRITE,
expr.span,
&format!("use of `{used}.unwrap()`"),
- "try this",
+ "try",
format!("{prefix}{sugg_mac}!({inputs_snippet})"),
applicability,
);
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 126bed678..c18006a71 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
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
-use clippy_utils::is_from_proc_macro;
-use clippy_utils::trait_ref_of_method;
+use clippy_utils::{is_from_proc_macro, trait_ref_of_method};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor};
@@ -12,10 +11,8 @@ 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_span::{
- def_id::{DefId, LocalDefId},
- Span,
-};
+use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
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 5e0fcd743..29e5315f8 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -1,10 +1,8 @@
-use clippy_utils::consts::{
- constant, constant_simple, Constant,
- Constant::{Int, F32, F64},
-};
+use clippy_utils::consts::Constant::{Int, F32, F64};
+use clippy_utils::consts::{constant, constant_simple, Constant};
+use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::{
- diagnostics::span_lint_and_sugg, eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate,
- numeric_literal, peel_blocks, sugg,
+ 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;
diff --git a/src/tools/clippy/clippy_lints/src/fn_null_check.rs b/src/tools/clippy/clippy_lints/src/fn_null_check.rs
deleted file mode 100644
index 521045a9f..000000000
--- a/src/tools/clippy/clippy_lints/src/fn_null_check.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-use clippy_utils::consts::{constant, Constant};
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
-use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for comparing a function pointer to null.
- ///
- /// ### Why is this bad?
- /// Function pointers are assumed to not be null.
- ///
- /// ### Example
- /// ```rust,ignore
- /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */
- ///
- /// if (fn_ptr as *const ()).is_null() { ... }
- /// ```
- /// Use instead:
- /// ```rust,ignore
- /// let fn_ptr: Option<fn()> = /* somehow obtained nullable function pointer */
- ///
- /// if fn_ptr.is_none() { ... }
- /// ```
- #[clippy::version = "1.68.0"]
- pub FN_NULL_CHECK,
- correctness,
- "`fn()` type assumed to be nullable"
-}
-declare_lint_pass!(FnNullCheck => [FN_NULL_CHECK]);
-
-fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
- span_lint_and_help(
- cx,
- FN_NULL_CHECK,
- expr.span,
- "function pointer assumed to be nullable, even though it isn't",
- None,
- "try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value",
- );
-}
-
-fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- if let ExprKind::Cast(cast_expr, cast_ty) = expr.kind
- && let TyKind::Ptr(_) = cast_ty.kind
- {
- cx.typeck_results().expr_ty_adjusted(cast_expr).is_fn()
- } else {
- false
- }
-}
-
-impl<'tcx> LateLintPass<'tcx> for FnNullCheck {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- match expr.kind {
- // Catching:
- // (fn_ptr as *<const/mut> <ty>).is_null()
- ExprKind::MethodCall(method_name, receiver, _, _)
- if method_name.ident.as_str() == "is_null" && is_fn_ptr_cast(cx, receiver) =>
- {
- lint_expr(cx, expr);
- },
-
- ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => {
- let to_check: &Expr<'_>;
- if is_fn_ptr_cast(cx, left) {
- to_check = right;
- } else if is_fn_ptr_cast(cx, right) {
- to_check = left;
- } else {
- return;
- }
-
- match to_check.kind {
- // Catching:
- // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>)
- ExprKind::Cast(cast_expr, _) if is_integer_literal(cast_expr, 0) => {
- lint_expr(cx, expr);
- },
-
- // Catching:
- // (fn_ptr as *<const/mut> <ty>) == std::ptr::null()
- ExprKind::Call(func, []) if is_path_diagnostic_item(cx, func, sym::ptr_null) => {
- lint_expr(cx, expr);
- },
-
- // Catching:
- // (fn_ptr as *<const/mut> <ty>) == <const that evaluates to null_ptr>
- _ if matches!(constant(cx, cx.typeck_results(), to_check), Some(Constant::RawPtr(0))) => {
- lint_expr(cx, expr);
- },
-
- _ => {},
- }
- },
- _ => {},
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index d34d6e927..f4f8bdc2c 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -43,7 +43,9 @@ declare_lint_pass!(UselessFormat => [USELESS_FORMAT]);
impl<'tcx> LateLintPass<'tcx> for UselessFormat {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
+ let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
+ return;
+ };
if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 08e45ed7d..01c714c41 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -14,10 +14,8 @@ use rustc_ast::{
FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions,
FormatPlaceholder, FormatTrait,
};
-use rustc_errors::{
- Applicability,
- SuggestionStyle::{CompletelyHidden, ShowCode},
-};
+use rustc_errors::Applicability;
+use rustc_errors::SuggestionStyle::{CompletelyHidden, ShowCode};
use rustc_hir::{Expr, ExprKind, LangItem};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
@@ -188,7 +186,9 @@ impl FormatArgs {
impl<'tcx> LateLintPass<'tcx> for FormatArgs {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
+ let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
+ return;
+ };
if !is_format_macro(cx, macro_call.def_id) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs
index 3ddee1842..76369bccf 100644
--- a/src/tools/clippy/clippy_lints/src/format_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/format_impl.rs
@@ -7,8 +7,8 @@ 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_span::Span;
-use rustc_span::{sym, symbol::kw, Symbol};
+use rustc_span::symbol::kw;
+use rustc_span::{sym, Span, Symbol};
declare_clippy_lint! {
/// ### What it does
@@ -127,7 +127,9 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl {
}
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- let Some(format_trait_impl) = self.format_trait_impl else { return };
+ let Some(format_trait_impl) = self.format_trait_impl else {
+ return;
+ };
if format_trait_impl.name == sym::Display {
check_to_string_in_display(cx, expr);
diff --git a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
new file mode 100644
index 000000000..419c77343
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
@@ -0,0 +1,99 @@
+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_span::Span;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for outer doc comments written with 4 forward slashes (`////`).
+ ///
+ /// ### Why is this bad?
+ /// This is (probably) a typo, and results in it not being a doc comment; just a regular
+ /// comment.
+ ///
+ /// ### Example
+ /// ```rust
+ /// //// My amazing data structure
+ /// pub struct Foo {
+ /// // ...
+ /// }
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust
+ /// /// My amazing data structure
+ /// pub struct Foo {
+ /// // ...
+ /// }
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub FOUR_FORWARD_SLASHES,
+ suspicious,
+ "comments with 4 forward slashes (`////`) likely intended to be doc comments (`///`)"
+}
+declare_lint_pass!(FourForwardSlashes => [FOUR_FORWARD_SLASHES]);
+
+impl<'tcx> LateLintPass<'tcx> for FourForwardSlashes {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+ if item.span.from_expansion() {
+ return;
+ }
+ let sm = cx.sess().source_map();
+ let mut span = cx
+ .tcx
+ .hir()
+ .attrs(item.hir_id())
+ .iter()
+ .fold(item.span.shrink_to_lo(), |span, attr| span.to(attr.span));
+ let (Some(file), _, _, end_line, _) = sm.span_to_location_info(span) else {
+ return;
+ };
+ let mut bad_comments = vec![];
+ for line in (0..end_line.saturating_sub(1)).rev() {
+ let Some(contents) = file.get_line(line).map(|c| c.trim().to_owned()) else {
+ return;
+ };
+ // Keep searching until we find the next item
+ if !contents.is_empty() && !contents.starts_with("//") && !contents.starts_with("#[") {
+ break;
+ }
+
+ if contents.starts_with("////") && !matches!(contents.chars().nth(4), Some('/' | '!')) {
+ let bounds = file.line_bounds(line);
+ let line_span = Span::with_root_ctxt(bounds.start, bounds.end);
+ span = line_span.to(span);
+ bad_comments.push((line_span, contents));
+ }
+ }
+
+ if !bad_comments.is_empty() {
+ span_lint_and_then(
+ cx,
+ FOUR_FORWARD_SLASHES,
+ span,
+ "this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't",
+ |diag| {
+ let msg = if bad_comments.len() == 1 {
+ "make this a doc comment by removing one `/`"
+ } else {
+ "turn these into doc comments by removing one `/`"
+ };
+
+ diag.multipart_suggestion(
+ msg,
+ bad_comments
+ .into_iter()
+ // It's a little unfortunate but the span includes the `\n` yet the contents
+ // do not, so we must add it back. If some codebase uses `\r\n` instead they
+ // will need normalization but it should be fine
+ .map(|(span, c)| (span, c.replacen("////", "///", 1) + "\n"))
+ .collect(),
+ Applicability::MachineApplicable,
+ );
+ },
+ );
+ }
+ }
+}
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 92d67ef35..2b899e21e 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -10,7 +10,8 @@ use rustc_hir::{
TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::{hir::nested_filter::OnlyBodies, ty};
+use rustc_middle::hir::nested_filter::OnlyBodies;
+use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::{kw, sym};
use rustc_span::{Span, Symbol};
@@ -76,9 +77,10 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
&& let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
// `impl Into<target_ty> for self_ty`
&& let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
- && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(ty::EarlyBinder::subst_identity)
+ && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+ .map(ty::EarlyBinder::instantiate_identity)
&& cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
- && !matches!(middle_trait_ref.substs.type_at(1).kind(), ty::Alias(ty::Opaque, _))
+ && !matches!(middle_trait_ref.args.type_at(1).kind(), ty::Alias(ty::Opaque, _))
{
span_lint_and_then(
cx,
@@ -163,10 +165,14 @@ fn convert_to_from(
return None;
}
let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
- let ImplItemKind::Fn(ref sig, body_id) = impl_item.kind else { return None };
+ let ImplItemKind::Fn(ref sig, body_id) = impl_item.kind else {
+ return None;
+ };
let body = cx.tcx.hir().body(body_id);
let [input] = body.params else { return None };
- let PatKind::Binding(.., self_ident, None) = input.pat.kind else { return None };
+ let PatKind::Binding(.., self_ident, None) = input.pat.kind else {
+ return None;
+ };
let from = snippet_opt(cx, self_ty.span)?;
let into = snippet_opt(cx, target_ty.span)?;
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 096508dc4..5e859d97c 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
@@ -4,8 +4,7 @@ use clippy_utils::{match_def_path, path_def_id, paths};
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::RawPtr;
-use rustc_middle::ty::TypeAndMut;
+use rustc_middle::ty::{RawPtr, TypeAndMut};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
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 d3d0d91c1..597fca888 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
@@ -1,6 +1,8 @@
-use clippy_utils::{diagnostics::span_lint_and_then, is_in_test_function};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_in_test_function;
-use rustc_hir::{intravisit::FnKind, Body, HirId};
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Body, HirId};
use rustc_lint::LateContext;
use rustc_span::Span;
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 b244b9133..18f7368da 100644
--- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
@@ -1,7 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
-use rustc_hir::{intravisit::FnKind, Body, ExprKind, FnDecl, ImplicitSelfKind, Unsafety};
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Body, ExprKind, FnDecl, ImplicitSelfKind, Unsafety};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::Span;
@@ -12,8 +13,8 @@ use super::MISNAMED_GETTERS;
pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: &Body<'_>, span: Span) {
let FnKind::Method(ref ident, sig) = kind else {
- return;
- };
+ return;
+ };
// Takes only &(mut) self
if decl.inputs.len() != 1 {
@@ -25,8 +26,8 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
let name = match decl.implicit_self {
ImplicitSelfKind::MutRef => {
let Some(name) = name.strip_suffix("_mut") else {
- return;
- };
+ return;
+ };
name
},
ImplicitSelfKind::Imm | ImplicitSelfKind::Mut | ImplicitSelfKind::ImmRef => name,
@@ -76,7 +77,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
for adjusted_type in iter::once(typeck_results.expr_ty(self_data))
.chain(typeck_results.expr_adjustments(self_data).iter().map(|adj| adj.target))
{
- let ty::Adt(def,_) = adjusted_type.kind() else {
+ let ty::Adt(def, _) = adjusted_type.kind() else {
continue;
};
@@ -91,13 +92,15 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
}
let Some(used_field) = used_field else {
- // Can happen if the field access is a tuple. We don't lint those because the getter name could not start with a number.
+ // Can happen if the field access is a tuple. We don't lint those because the getter name could not
+ // start with a number.
return;
};
let Some(correct_field) = correct_field else {
// There is no field corresponding to the getter name.
- // FIXME: This can be a false positive if the correct field is reachable through deeper autodereferences than used_field is
+ // FIXME: This can be a false positive if the correct field is reachable through deeper
+ // autodereferences than used_field is
return;
};
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index d0ad26282..57df5683c 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -1,14 +1,13 @@
use hir::FnSig;
use rustc_ast::ast::Attribute;
use rustc_errors::Applicability;
+use rustc_hir::def::Res;
use rustc_hir::def_id::DefIdSet;
-use rustc_hir::{self as hir, def::Res, QPath};
+use rustc_hir::{self as hir, QPath};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LintContext};
-use rustc_middle::{
- lint::in_external_macro,
- ty::{self, Ty},
-};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::{self, Ty};
use rustc_span::{sym, Span, Symbol};
use clippy_utils::attrs::is_proc_macro;
@@ -198,14 +197,14 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet)
match *ty.kind() {
// primitive types are never mutable
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
- ty::Adt(adt, substs) => {
+ ty::Adt(adt, args) => {
tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.param_env)
|| KNOWN_WRAPPER_TYS
.iter()
.any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did()))
- && substs.types().any(|ty| is_mutable_ty(cx, ty, tys))
+ && args.types().any(|ty| is_mutable_ty(cx, ty, tys))
},
- ty::Tuple(substs) => substs.iter().any(|ty| is_mutable_ty(cx, ty, tys)),
+ ty::Tuple(args) => args.iter().any(|ty| is_mutable_ty(cx, ty, tys)),
ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, tys),
ty::RawPtr(ty::TypeAndMut { ty, mutbl }) | ty::Ref(_, ty, mutbl) => {
mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys)
@@ -222,7 +221,7 @@ fn is_mutated_static(e: &hir::Expr<'_>) -> bool {
match e.kind {
Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)),
Path(_) => true,
- Field(inner, _) | Index(inner, _) => is_mutated_static(inner),
+ Field(inner, _) | Index(inner, _, _) => is_mutated_static(inner),
_ => false,
}
}
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
index fa2a9b30c..90fc0d4f6 100644
--- a/src/tools/clippy/clippy_lints/src/functions/result.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -21,11 +21,11 @@ fn result_err_ty<'tcx>(
) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> {
if !in_external_macro(cx.sess(), item_span)
&& let hir::FnRetTy::Return(hir_ty) = decl.output
- && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).subst_identity().output())
+ && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).instantiate_identity().output())
&& is_type_diagnostic_item(cx, ty, sym::Result)
- && let ty::Adt(_, substs) = ty.kind()
+ && let ty::Adt(_, args) = ty.kind()
{
- let err_ty = substs.type_at(1);
+ let err_ty = args.type_at(1);
Some((hir_ty, err_ty))
} else {
None
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
index bd473ac7e..34f1bf3b2 100644
--- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
@@ -23,7 +23,7 @@ pub(super) fn check_fn(
}
let Some(code_snippet) = snippet_opt(cx, body.value.span) else {
- return
+ return;
};
let mut line_count: u64 = 0;
let mut in_comment = false;
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 818ebd113..621415c88 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -63,10 +63,10 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
return;
}
let ret_ty = return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(fn_def_id).expect_owner());
- if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() {
+ 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;
- for (p, _span) in preds.subst_iter_copied(cx.tcx, substs) {
+ for (p, _span) in preds.iter_instantiated_copied(cx.tcx, args) {
if let Some(trait_pred) = p.as_trait_clause() {
if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
is_future = true;
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 9ea8c494c..e614a8f69 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::higher;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::SpanlessEq;
+use clippy_utils::{higher, SpanlessEq};
use if_chain::if_chain;
use rustc_errors::Diagnostic;
use rustc_hir::intravisit::{self as visit, Visitor};
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 725bd3d54..ab6ad3f3b 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
@@ -119,7 +119,13 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
fn stmts_contains_early_return(stmts: &[Stmt<'_>]) -> bool {
stmts.iter().any(|stmt| {
- let Stmt { kind: StmtKind::Semi(e), .. } = stmt else { return false };
+ let Stmt {
+ kind: StmtKind::Semi(e),
+ ..
+ } = stmt
+ else {
+ return false;
+ };
contains_return(e)
})
diff --git a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
new file mode 100644
index 000000000..c635120b8
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
@@ -0,0 +1,52 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use hir::PatKind;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usage of `_` in patterns of type `()`.
+ ///
+ /// ### Why is this bad?
+ /// Matching with `()` explicitly instead of `_` outlines
+ /// the fact that the pattern contains no data. Also it
+ /// would detect a type change that `_` would ignore.
+ ///
+ /// ### Example
+ /// ```rust
+ /// match std::fs::create_dir("tmp-work-dir") {
+ /// Ok(_) => println!("Working directory created"),
+ /// Err(s) => eprintln!("Could not create directory: {s}"),
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// match std::fs::create_dir("tmp-work-dir") {
+ /// Ok(()) => println!("Working directory created"),
+ /// Err(s) => eprintln!("Could not create directory: {s}"),
+ /// }
+ /// ```
+ #[clippy::version = "1.73.0"]
+ pub IGNORED_UNIT_PATTERNS,
+ pedantic,
+ "suggest replacing `_` by `()` in patterns where appropriate"
+}
+declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]);
+
+impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
+ fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
+ if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).is_unit() {
+ span_lint_and_sugg(
+ cx,
+ IGNORED_UNIT_PATTERNS,
+ pat.span,
+ "matching over `()` is more explicit",
+ "use `()` instead of `_`",
+ String::from("()"),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index 372b6ead3..a6b035d51 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -1,9 +1,7 @@
-use clippy_utils::{
- diagnostics::span_lint_hir_and_then,
- get_async_fn_body, is_async_fn,
- source::{snippet_with_applicability, snippet_with_context, walk_span_to_context},
- visitors::for_each_expr,
-};
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context};
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{get_async_fn_body, is_async_fn};
use core::ops::ControlFlow;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
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 1e99b6faa..b99d45446 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
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).subst_identity().is_integral();
+ if cx.tcx.type_of(impl_id).instantiate_identity().is_integral();
then {
print_lint_and_sugg(cx, var_name, expr)
}
@@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
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).subst_identity().is_integral();
+ if cx.tcx.type_of(impl_id).instantiate_identity().is_integral();
then {
print_lint_and_sugg(cx, var_name, expr)
}
diff --git a/src/tools/clippy/clippy_lints/src/incorrect_impls.rs b/src/tools/clippy/clippy_lints/src/incorrect_impls.rs
index 7b95116ee..3c59b839a 100644
--- a/src/tools/clippy/clippy_lints/src/incorrect_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/incorrect_impls.rs
@@ -1,11 +1,15 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_node, last_path_segment, ty::implements_trait};
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::paths::ORD_CMP;
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, match_def_path, path_res, std_or_core};
use rustc_errors::Applicability;
-use rustc_hir::{ExprKind, ImplItem, ImplItemKind, ItemKind, Node, UnOp};
-use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::EarlyBinder;
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{sym, symbol};
+use rustc_span::sym;
+use rustc_span::symbol::kw;
declare_clippy_lint! {
/// ### What it does
@@ -46,25 +50,84 @@ declare_clippy_lint! {
correctness,
"manual implementation of `Clone` on a `Copy` type"
}
-declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE]);
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for manual implementations of both `PartialOrd` and `Ord` when only `Ord` is
+ /// necessary.
+ ///
+ /// ### Why is this bad?
+ /// If both `PartialOrd` and `Ord` are implemented, they must agree. This is commonly done by
+ /// wrapping the result of `cmp` in `Some` for `partial_cmp`. Not doing this may silently
+ /// introduce an error upon refactoring.
+ ///
+ /// ### Known issues
+ /// Code that calls the `.into()` method instead will be flagged as incorrect, despite `.into()`
+ /// wrapping it in `Some`.
+ ///
+ /// ### Limitations
+ /// Will not lint if `Self` and `Rhs` do not have the same type.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::cmp::Ordering;
+ /// #[derive(Eq, PartialEq)]
+ /// struct A(u32);
+ ///
+ /// impl Ord for A {
+ /// fn cmp(&self, other: &Self) -> Ordering {
+ /// // ...
+ /// # todo!();
+ /// }
+ /// }
+ ///
+ /// impl PartialOrd for A {
+ /// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ /// // ...
+ /// # todo!();
+ /// }
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # use std::cmp::Ordering;
+ /// #[derive(Eq, PartialEq)]
+ /// struct A(u32);
+ ///
+ /// impl Ord for A {
+ /// fn cmp(&self, other: &Self) -> Ordering {
+ /// // ...
+ /// # todo!();
+ /// }
+ /// }
+ ///
+ /// impl PartialOrd for A {
+ /// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ /// Some(self.cmp(other))
+ /// }
+ /// }
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE,
+ correctness,
+ "manual implementation of `PartialOrd` when `Ord` is already implemented"
+}
+declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE, INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE]);
impl LateLintPass<'_> for IncorrectImpls {
- #[expect(clippy::needless_return)]
+ #[expect(clippy::too_many_lines)]
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
- let node = get_parent_node(cx.tcx, impl_item.hir_id());
- let Some(Node::Item(item)) = node else {
- return;
- };
- let ItemKind::Impl(imp) = item.kind else {
+ let Some(Node::Item(item)) = get_parent_node(cx.tcx, impl_item.hir_id()) else {
return;
};
let Some(trait_impl) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::skip_binder) else {
return;
};
- let trait_impl_def_id = trait_impl.def_id;
if cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) {
return;
}
+ let ItemKind::Impl(_) = item.kind else {
+ return;
+ };
let ImplItemKind::Fn(_, impl_item_id) = cx.tcx.hir().impl_item(impl_item.impl_item_id()).kind else {
return;
};
@@ -72,15 +135,12 @@ impl LateLintPass<'_> for IncorrectImpls {
let ExprKind::Block(block, ..) = body.value.kind else {
return;
};
- // Above is duplicated from the `duplicate_manual_partial_ord_impl` branch.
- // Remove it while solving conflicts once that PR is merged.
- // Actual implementation; remove this comment once aforementioned PR is merged
- if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl_def_id)
+ if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl.def_id)
&& let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy)
&& implements_trait(
cx,
- hir_ty_to_ty(cx.tcx, imp.self_ty),
+ trait_impl.self_ty(),
copy_def_id,
&[],
)
@@ -88,9 +148,9 @@ impl LateLintPass<'_> for IncorrectImpls {
if impl_item.ident.name == sym::clone {
if block.stmts.is_empty()
&& let Some(expr) = block.expr
- && let ExprKind::Unary(UnOp::Deref, inner) = expr.kind
- && let ExprKind::Path(qpath) = inner.kind
- && last_path_segment(&qpath).ident.name == symbol::kw::SelfLower
+ && let ExprKind::Unary(UnOp::Deref, deref) = expr.kind
+ && let ExprKind::Path(qpath) = deref.kind
+ && last_path_segment(&qpath).ident.name == kw::SelfLower
{} else {
span_lint_and_sugg(
cx,
@@ -112,7 +172,7 @@ impl LateLintPass<'_> for IncorrectImpls {
INCORRECT_CLONE_IMPL_ON_COPY_TYPE,
impl_item.span,
"incorrect implementation of `clone_from` on a `Copy` type",
- "remove this",
+ "remove it",
String::new(),
Applicability::MaybeIncorrect,
);
@@ -120,5 +180,116 @@ impl LateLintPass<'_> for IncorrectImpls {
return;
}
}
+
+ if cx.tcx.is_diagnostic_item(sym::PartialOrd, trait_impl.def_id)
+ && impl_item.ident.name == sym::partial_cmp
+ && let Some(ord_def_id) = cx
+ .tcx
+ .diagnostic_items(trait_impl.def_id.krate)
+ .name_to_id
+ .get(&sym::Ord)
+ && implements_trait(
+ cx,
+ trait_impl.self_ty(),
+ *ord_def_id,
+ &[],
+ )
+ {
+ // If the `cmp` call likely needs to be fully qualified in the suggestion
+ // (like `std::cmp::Ord::cmp`). It's unfortunate we must put this here but we can't
+ // access `cmp_expr` in the suggestion without major changes, as we lint in `else`.
+ let mut needs_fully_qualified = false;
+
+ if block.stmts.is_empty()
+ && let Some(expr) = block.expr
+ && let ExprKind::Call(
+ Expr {
+ kind: ExprKind::Path(some_path),
+ hir_id: some_hir_id,
+ ..
+ },
+ [cmp_expr],
+ ) = expr.kind
+ && is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome)
+ // Fix #11178, allow `Self::cmp(self, ..)` too
+ && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, &mut needs_fully_qualified)
+ {} else {
+ // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid
+ // suggestion tons more complex.
+ if let [lhs, rhs, ..] = trait_impl.args.as_slice() && lhs != rhs {
+ return;
+ }
+
+ span_lint_and_then(
+ cx,
+ INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE,
+ item.span,
+ "incorrect implementation of `partial_cmp` on an `Ord` type",
+ |diag| {
+ let [_, other] = body.params else {
+ return;
+ };
+ let Some(std_or_core) = std_or_core(cx) else {
+ return;
+ };
+
+ let suggs = match (other.pat.simple_ident(), needs_fully_qualified) {
+ (Some(other_ident), true) => vec![(
+ block.span,
+ format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, {})) }}", other_ident.name),
+ )],
+ (Some(other_ident), false) => {
+ vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))]
+ },
+ (None, true) => vec![
+ (
+ block.span,
+ format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, other)) }}"),
+ ),
+ (other.pat.span, "other".to_owned()),
+ ],
+ (None, false) => vec![
+ (block.span, "{ Some(self.cmp(other)) }".to_owned()),
+ (other.pat.span, "other".to_owned()),
+ ],
+ };
+
+ diag.multipart_suggestion(
+ "change this to",
+ suggs,
+ Applicability::Unspecified,
+ );
+ }
+ );
+ }
+ }
+ }
+}
+
+/// Returns whether this is any of `self.cmp(..)`, `Self::cmp(self, ..)` or `Ord::cmp(self, ..)`.
+fn self_cmp_call<'tcx>(
+ cx: &LateContext<'tcx>,
+ cmp_expr: &'tcx Expr<'tcx>,
+ def_id: LocalDefId,
+ needs_fully_qualified: &mut bool,
+) -> bool {
+ match cmp_expr.kind {
+ ExprKind::Call(path, [_self, _other]) => path_res(cx, path)
+ .opt_def_id()
+ .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP)),
+ ExprKind::MethodCall(_, _, [_other], ..) => {
+ // We can set this to true here no matter what as if it's a `MethodCall` and goes to the
+ // `else` branch, it must be a method named `cmp` that isn't `Ord::cmp`
+ *needs_fully_qualified = true;
+
+ // It's a bit annoying but `typeck_results` only gives us the CURRENT body, which we
+ // have none, not of any `LocalDefId` we want, so we must call the query itself to avoid
+ // an immediate ICE
+ cx.tcx
+ .typeck(def_id)
+ .type_dependent_def_id(cmp_expr.hir_id)
+ .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP))
+ },
+ _ => false,
}
}
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 7a269e98f..f507f45d5 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -13,7 +13,8 @@ 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_span::{symbol::Ident, Span};
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
@@ -253,7 +254,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
// 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 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;
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index 22c14d9b0..4f4f57177 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
return;
}
- if let ExprKind::Index(array, index) = &expr.kind {
+ if let ExprKind::Index(array, index, _) = &expr.kind {
let note = "the suggestion might not be applicable in constant blocks";
let ty = cx.typeck_results().expr_ty(array).peel_refs();
if let Some(range) = higher::Range::hir(index) {
diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
index 7c41699f3..3d1113ff9 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
@@ -3,7 +3,8 @@
use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::is_lint_allowed;
use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::{def_id::LocalDefId, Item, ItemKind, Node};
+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_span::Span;
@@ -66,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
)
}) {
for impl_id in impl_ids.iter().map(|id| id.expect_local()) {
- let impl_ty = cx.tcx.type_of(impl_id).subst_identity();
+ let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity();
match type_map.entry(impl_ty) {
Entry::Vacant(e) => {
// Store the id for the first impl block of this type. The span is retrieved lazily.
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 d43e5cc9b..bc4ec33b7 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -1,11 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::{implements_trait, is_type_lang_item};
use clippy_utils::{return_ty, trait_ref_of_method};
-use if_chain::if_chain;
-use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem};
+use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem, Unsafety};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
+use rustc_target::spec::abi::Abi;
declare_clippy_lint! {
/// ### What it does
@@ -95,24 +95,23 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
return;
}
- if_chain! {
- // Check if item is a method, called to_string and has a parameter 'self'
- if let ImplItemKind::Fn(ref signature, _) = impl_item.kind;
- if impl_item.ident.name == sym::to_string;
- let decl = &signature.decl;
- if decl.implicit_self.has_implicit_self();
- if decl.inputs.len() == 1;
- if impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }));
-
+ // Check if item is a method called `to_string` and has a parameter 'self'
+ if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
+ // #11201
+ && let header = signature.header
+ && header.unsafety == Unsafety::Normal
+ && header.abi == Abi::Rust
+ && impl_item.ident.name == sym::to_string
+ && let decl = signature.decl
+ && decl.implicit_self.has_implicit_self()
+ && decl.inputs.len() == 1
+ && impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
// Check if return type is String
- if is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String);
-
+ && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String)
// Filters instances of to_string which are required by a trait
- if trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none();
-
- then {
- show_lint(cx, impl_item);
- }
+ && trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none()
+ {
+ show_lint(cx, impl_item);
}
}
}
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 7e1548531..b00fa104f 100644
--- a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
+++ b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
@@ -50,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields {
&& fields
.iter()
.all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
- && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias, ..))
+ && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias { .. }, ..))
{
let expr_spans = fields
.iter()
@@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields {
INIT_NUMBERED_FIELDS,
e.span,
"used a field initializer for a tuple struct",
- "try this instead",
+ "try",
snippet,
appl,
);
diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
index 34e999158..8df7dfb8b 100644
--- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
+++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
@@ -7,7 +7,8 @@ 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_span::{source_map::Spanned, sym};
+use rustc_span::source_map::Spanned;
+use rustc_span::sym;
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 40378ee82..55a43e915 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
@@ -1,4 +1,5 @@
-use clippy_utils::{diagnostics::span_lint_and_help, is_from_proc_macro, is_in_cfg_test};
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::{is_from_proc_macro, is_in_cfg_test};
use rustc_hir::{HirId, ItemId, ItemKind, Mod};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
@@ -32,7 +33,7 @@ declare_clippy_lint! {
/// // [...]
/// }
/// ```
- #[clippy::version = "1.70.0"]
+ #[clippy::version = "1.71.0"]
pub ITEMS_AFTER_TEST_MODULE,
style,
"An item was found after the testing module `tests`"
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 c924d7361..066d2c4b7 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
@@ -1,5 +1,8 @@
-use clippy_utils::{diagnostics::span_lint, get_parent_node, ty::implements_trait};
-use rustc_hir::{def_id::LocalDefId, FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::get_parent_node;
+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_span::symbol::sym;
@@ -68,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).subst_identity().output());
+ .erase_late_bound_regions(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/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index 4dc750c03..9b26c3573 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -50,7 +50,11 @@ 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(hir_ty, _) = &item.kind;
+ if let ItemKind::Const(hir_ty, 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 = hir_ty_to_ty(cx.tcx, hir_ty);
if let ty::Array(element_type, cst) = ty.kind();
if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind();
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 1c99bd2f3..b22b57a30 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -1,10 +1,8 @@
//! lint when there is a large size difference between variants on an enum
+use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{
- diagnostics::span_lint_and_then,
- ty::{approx_ty_size, is_copy, AdtVariantInfo},
-};
+use clippy_utils::ty::{approx_ty_size, is_copy, AdtVariantInfo};
use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -83,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
return;
}
if let ItemKind::Enum(ref def, _) = item.kind {
- let ty = cx.tcx.type_of(item.owner_id).subst_identity();
+ let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
let Adt(adt, subst) = ty.kind() else {
panic!("already checked whether this is an enum")
};
@@ -169,8 +167,8 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
}
fn maybe_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
- if let Adt(_def, substs) = ty.kind()
- && substs.types().next().is_some()
+ if let Adt(_def, args) = ty.kind()
+ && args.types().next().is_some()
&& let Some(copy_trait) = cx.tcx.lang_items().copy_trait()
{
return cx.tcx.non_blanket_impls_for_ty(copy_trait, ty).next().is_some();
diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs
index 087c4a652..d67d58993 100644
--- a/src/tools/clippy/clippy_lints/src/large_futures.rs
+++ b/src/tools/clippy/clippy_lints/src/large_futures.rs
@@ -1,5 +1,6 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
-use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait};
+use clippy_utils::ty::implements_trait;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath};
use rustc_lint::{LateContext, LateLintPass};
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 424c0d9e7..566901de3 100644
--- a/src/tools/clippy/clippy_lints/src/large_include_file.rs
+++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs
@@ -2,8 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::is_lint_allowed;
use clippy_utils::macros::root_macro_call_first_node;
use rustc_ast::LitKind;
-use rustc_hir::Expr;
-use rustc_hir::ExprKind;
+use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::sym;
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 9c0cc978a..7aa1446d5 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs
@@ -4,11 +4,9 @@ use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::fn_has_unsatisfiable_preds;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::FnKind;
-use rustc_hir::Body;
-use rustc_hir::FnDecl;
+use rustc_hir::{Body, FnDecl};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_tool_lint;
-use rustc_session::impl_lint_pass;
+use rustc_session::{declare_tool_lint, 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 17bd89efa..deba232bd 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -1,22 +1,22 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet_with_context;
-use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators, sugg::Sugg};
+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_id::DefIdSet;
+use rustc_hir::def::Res;
+use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::{
- def::Res, def_id::DefId, lang_items::LangItem, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg,
- GenericBound, ImplItem, ImplItemKind, ImplicitSelfKind, Item, ItemKind, Mutability, Node, PathSegment, PrimTy,
- QPath, TraitItemRef, TyKind, TypeBindingKind,
+ AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
+ ImplicitSelfKind, Item, ItemKind, LangItem, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef,
+ TyKind, TypeBindingKind,
};
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::{
- source_map::{Span, Spanned, Symbol},
- symbol::sym,
-};
+use rustc_span::source_map::{Span, Spanned, Symbol};
+use rustc_span::symbol::sym;
declare_clippy_lint! {
/// ### What it does
@@ -145,7 +145,10 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
if let Some(local_id) = ty_id.as_local();
let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
if !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id);
- if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).subst_identity().skip_binder());
+ 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"),
@@ -167,6 +170,31 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
return;
}
+ if let ExprKind::Let(lt) = expr.kind
+ && has_is_empty(cx, lt.init)
+ && match lt.pat.kind {
+ PatKind::Slice([], None, []) => true,
+ PatKind::Lit(lit) if is_empty_string(lit) => true,
+ _ => false,
+ }
+ {
+ let mut applicability = Applicability::MachineApplicable;
+
+ let lit1 = peel_ref_operators(cx, lt.init);
+ let lit_str =
+ Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par();
+
+ span_lint_and_sugg(
+ cx,
+ COMPARISON_TO_EMPTY,
+ lt.span,
+ "comparison to empty slice using `if let`",
+ "using `is_empty` is clearer and more explicit",
+ format!("{lit_str}.is_empty()"),
+ applicability,
+ );
+ }
+
if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind {
// expr.span might contains parenthesis, see issue #10529
let actual_span = left.span.with_hi(right.span.hi());
@@ -425,7 +453,7 @@ fn check_for_is_empty(
if !(is_empty.fn_has_self_parameter
&& check_is_empty_sig(
cx,
- cx.tcx.fn_sig(is_empty.def_id).subst_identity().skip_binder(),
+ cx.tcx.fn_sig(is_empty.def_id).instantiate_identity().skip_binder(),
self_kind,
output,
)) =>
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 db41bc67d..2f6f36c39 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::path_to_local_id;
use clippy_utils::source::snippet;
-use clippy_utils::{path_to_local_id, visitors::is_local_used};
+use clippy_utils::visitors::is_local_used;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index e66141809..e7c875ab3 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -1,12 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_from_proc_macro;
use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
-use clippy_utils::{is_must_use_func_call, paths};
+use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths};
use rustc_hir::{Local, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::IsSuggestable;
+use rustc_middle::ty::{GenericArgKind, IsSuggestable};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{BytePos, Span};
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 87329ee5e..358004cf4 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -65,6 +65,7 @@ mod declared_lints;
mod renamed_lints;
// begin lints modules, do not remove this comment, it’s used in `update_lints`
+mod absolute_paths;
mod allow_attributes;
mod almost_complete_range;
mod approx_const;
@@ -120,6 +121,7 @@ mod entry;
mod enum_clike;
mod enum_variants;
mod equatable_if_let;
+mod error_impl_error;
mod escape;
mod eta_reduction;
mod excessive_bools;
@@ -131,12 +133,12 @@ mod extra_unused_type_parameters;
mod fallible_impl_from;
mod float_literal;
mod floating_point_arithmetic;
-mod fn_null_check;
mod format;
mod format_args;
mod format_impl;
mod format_push_string;
mod formatting;
+mod four_forward_slashes;
mod from_over_into;
mod from_raw_with_void_ptr;
mod from_str_radix_10;
@@ -145,6 +147,7 @@ mod future_not_send;
mod if_let_mutex;
mod if_not_else;
mod if_then_some_else_none;
+mod ignored_unit_patterns;
mod implicit_hasher;
mod implicit_return;
mod implicit_saturating_add;
@@ -184,6 +187,7 @@ mod manual_assert;
mod manual_async_fn;
mod manual_bits;
mod manual_clamp;
+mod manual_float_methods;
mod manual_is_ascii_check;
mod manual_let_else;
mod manual_main_separator_str;
@@ -229,6 +233,7 @@ mod needless_for_each;
mod needless_if;
mod needless_late_init;
mod needless_parens_on_range_literals;
+mod needless_pass_by_ref_mut;
mod needless_pass_by_value;
mod needless_question_mark;
mod needless_update;
@@ -271,6 +276,7 @@ mod redundant_clone;
mod redundant_closure_call;
mod redundant_else;
mod redundant_field_names;
+mod redundant_locals;
mod redundant_pub_crate;
mod redundant_slicing;
mod redundant_static_lifetimes;
@@ -346,11 +352,10 @@ mod zero_div_zero;
mod zero_sized_map_values;
// end lints modules, do not remove this comment, it’s used in `update_lints`
+use crate::utils::conf::metadata::get_configuration_metadata;
+use crate::utils::conf::TryConf;
pub use crate::utils::conf::{lookup_conf_file, Conf};
-use crate::utils::{
- conf::{metadata::get_configuration_metadata, TryConf},
- FindAll,
-};
+use crate::utils::FindAll;
/// Register all pre expansion lints
///
@@ -663,7 +668,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_late_pass(move |_| Box::new(manual_let_else::ManualLetElse::new(msrv(), 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())));
@@ -723,7 +727,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef));
store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
- store.register_late_pass(|_| Box::new(regex::Regex));
+ store.register_late_pass(|_| Box::<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));
@@ -772,7 +776,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::<useless_conversion::UselessConversion>::default());
store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher));
store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom));
- store.register_late_pass(|_| Box::<question_mark::QuestionMark>::default());
+ store.register_late_pass(move |_| Box::new(question_mark::QuestionMark::new(msrv(), matches_for_let_else)));
store.register_late_pass(|_| Box::new(question_mark_used::QuestionMarkUsed));
store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
@@ -910,7 +914,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv())));
store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison));
store.register_early_pass(move || Box::new(module_style::ModStyle));
- store.register_late_pass(|_| Box::new(unused_async::UnusedAsync));
+ store.register_late_pass(|_| Box::<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();
@@ -1003,7 +1007,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
semicolon_outside_block_ignore_multiline,
))
});
- store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock));
@@ -1058,6 +1061,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
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 |_| {
+ Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut::new(
+ avoid_breaking_exported_api,
+ ))
+ });
store.register_late_pass(|_| Box::new(incorrect_impls::IncorrectImpls));
store.register_late_pass(move |_| {
Box::new(single_call_fn::SingleCallFn {
@@ -1074,6 +1082,19 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns));
store.register_early_pass(|| Box::new(visibility::Visibility));
store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() }));
+ 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,
+ absolute_paths_allowed_crates: absolute_paths_allowed_crates.clone(),
+ })
+ });
+ store.register_late_pass(|_| Box::new(redundant_locals::RedundantLocals));
+ store.register_late_pass(|_| Box::new(ignored_unit_patterns::IgnoredUnitPatterns));
// 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 852f67365..0004a150d 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -15,6 +15,7 @@ use rustc_hir::{
PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
};
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};
@@ -620,7 +621,7 @@ impl<'cx, 'tcx, F> Visitor<'tcx> for LifetimeChecker<'cx, 'tcx, F>
where
F: NestedFilter<'tcx>,
{
- type Map = rustc_middle::hir::map::Map<'tcx>;
+ type Map = Map<'tcx>;
type NestedFilter = F;
// for lifetimes as parameters of generics
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 09b2032e2..49425ff0a 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
@@ -1,7 +1,6 @@
-use clippy_utils::{
- diagnostics::span_lint_and_then, is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths,
- ty::match_type,
-};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::match_type;
+use clippy_utils::{is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths};
use rustc_errors::Applicability;
use rustc_hir::{Body, Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index dadcd9c51..09ca03173 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -264,7 +264,7 @@ impl LiteralDigitGrouping {
return;
}
- if Self::is_literal_uuid_formatted(&mut num_lit) {
+ if Self::is_literal_uuid_formatted(&num_lit) {
return;
}
@@ -376,7 +376,7 @@ impl LiteralDigitGrouping {
///
/// Returns `true` if the radix is hexadecimal, and the groups match the
/// UUID format of 8-4-4-4-12.
- fn is_literal_uuid_formatted(num_lit: &mut NumericLiteral<'_>) -> bool {
+ fn is_literal_uuid_formatted(num_lit: &NumericLiteral<'_>) -> bool {
if num_lit.radix != Radix::Hexadecimal {
return false;
}
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 5c5a4cfce..7b8c88235 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
@@ -109,7 +109,7 @@ fn is_ref_iterable<'tcx>(
&& let sig = cx.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, &[])
&& 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)
@@ -125,7 +125,7 @@ fn is_ref_iterable<'tcx>(
}
let res_ty = cx.tcx.erase_regions(EarlyBinder::bind(req_res_ty)
- .subst(cx.tcx, typeck.node_substs(call_expr.hir_id)));
+ .instantiate(cx.tcx, typeck.node_args(call_expr.hir_id)));
let mutbl = if let ty::Ref(_, _, mutbl) = *req_self_ty.kind() {
Some(mutbl)
} else {
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 4bb9936e9..0aaa66e6b 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
@@ -1,14 +1,14 @@
use super::utils::make_iterator_snippet;
use super::MANUAL_FIND;
-use clippy_utils::{
- diagnostics::span_lint_and_then, higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt,
- source::snippet_with_applicability, ty::implements_trait,
-};
+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, lang_items::LangItem, BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind,
-};
+use rustc_hir::def::Res;
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind};
use rustc_lint::LateContext;
use rustc_span::source_map::Span;
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 1e02a30e3..559a2c03f 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -1,9 +1,8 @@
use super::utils::make_iterator_snippet;
use super::MANUAL_FLATTEN;
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::higher;
use clippy_utils::visitors::is_local_used;
-use clippy_utils::{path_to_local_id, peel_blocks_with_stmt};
+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};
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 7d1f8ef29..d3fd0e863 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -60,8 +60,8 @@ pub(super) fn check<'tcx>(
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 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);
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
index cb9c84be4..ca584a454 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
@@ -1,9 +1,6 @@
-use clippy_utils::{
- diagnostics::{multispan_sugg_with_applicability, span_lint_and_then},
- match_def_path, paths,
- source::snippet,
- SpanlessEq,
-};
+use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
+use clippy_utils::source::snippet;
+use clippy_utils::{match_def_path, paths, SpanlessEq};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp};
use rustc_lint::LateContext;
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 8412875b1..7b7d19c75 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
@@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'
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, _substs) = cx.typeck_results().expr_ty(callee).kind();
+ 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(
@@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'
MISSING_SPIN_LOOP,
body.span,
"busy-waiting loop should at least have a spin loop hint",
- "try this",
+ "try",
(if is_no_std_crate(cx) {
"{ core::hint::spin_loop() }"
} else {
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 529189b52..ffd29ab76 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -601,7 +601,7 @@ declare_clippy_lint! {
/// // use `number`
/// }
/// ```
- #[clippy::version = "1.70.0"]
+ #[clippy::version = "1.71.0"]
pub MANUAL_WHILE_LET_SOME,
style,
"checking for emptiness of a `Vec` in the loop condition and popping an element in the body"
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 4dae93f60..b83d148b5 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
@@ -7,7 +7,8 @@ use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind};
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
-use rustc_middle::{mir::FakeReadCause, ty};
+use rustc_middle::mir::FakeReadCause;
+use rustc_middle::ty;
use rustc_span::source_map::Span;
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
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 cb4465675..c4af46b8f 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
@@ -319,7 +319,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
if_chain! {
// an index op
- if let ExprKind::Index(seqexpr, idx) = expr.kind;
+ if let ExprKind::Index(seqexpr, idx, _) = expr.kind;
if !self.check(idx, seqexpr, expr);
then {
return;
@@ -370,7 +370,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
ExprKind::MethodCall(_, receiver, args, _) => {
let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
for (ty, expr) in iter::zip(
- self.cx.tcx.fn_sig(def_id).subst_identity().inputs().skip_binder(),
+ self.cx.tcx.fn_sig(def_id).instantiate_identity().inputs().skip_binder(),
std::iter::once(receiver).chain(args.iter()),
) {
self.prefer_mutable = false;
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 ee338c6be..cc19ac55e 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -1,9 +1,9 @@
use super::utils::make_iterator_snippet;
use super::NEVER_LOOP;
-use clippy_utils::consts::constant;
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::ForLoop;
use clippy_utils::source::snippet;
-use clippy_utils::{consts::Constant, diagnostics::span_lint_and_then};
use rustc_errors::Applicability;
use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind};
use rustc_lint::LateContext;
@@ -162,7 +162,9 @@ fn never_loop_expr<'tcx>(
ExprKind::Binary(_, e1, e2)
| ExprKind::Assign(e1, e2, _)
| ExprKind::AssignOp(_, e1, e2)
- | ExprKind::Index(e1, e2) => never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id),
+ | ExprKind::Index(e1, e2, _) => {
+ never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id)
+ },
ExprKind::Loop(b, _, _, _) => {
// Break can come from the inner loop so remove them.
absorb_break(never_loop_block(cx, b, ignore_ids, main_loop_id))
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 744fd61bd..dfb800ccf 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
@@ -9,6 +9,7 @@ use rustc_errors::Applicability;
use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat};
use rustc_lint::LateContext;
use rustc_span::edition::Edition;
+use rustc_span::sym;
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
@@ -51,7 +52,7 @@ pub(super) fn check<'tcx>(
},
[],
_,
- ) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "),
+ ) if method.ident.name == sym::iter_mut => (arg, "&mut "),
ExprKind::MethodCall(
method,
Expr {
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 28ee24309..6edca2d55 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -76,7 +76,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => {
*state = IncrementVisitorVarState::DontWarn;
},
- ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
+ ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) => {
*state = IncrementVisitorVarState::DontWarn;
},
_ => (),
@@ -226,7 +226,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
InitializeVisitorState::DontWarn
}
},
- ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
+ ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) => {
self.state = InitializeVisitorState::DontWarn;
},
_ => (),
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 d1a1f773f..7f24f3c5d 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
@@ -6,8 +6,7 @@ use if_chain::if_chain;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefIdMap;
use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::HirIdSet;
-use rustc_hir::{Expr, ExprKind, QPath};
+use rustc_hir::{Expr, ExprKind, HirIdSet, QPath};
use rustc_lint::LateContext;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) {
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 55989f8a4..5153070cf 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
@@ -1,18 +1,18 @@
use super::WHILE_LET_ON_ITERATOR;
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{
- get_enclosing_loop_or_multi_call_closure, is_refutable, is_res_lang_ctor, is_trait_method, visitors::is_res_used,
-};
+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};
-use rustc_hir::{def::Res, Closure, Expr, ExprKind, HirId, LangItem, Local, Mutability, PatKind, UnOp};
+use rustc_hir::{Closure, Expr, ExprKind, HirId, LangItem, Local, Mutability, PatKind, UnOp};
use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::ty::adjustment::Adjust;
-use rustc_span::{symbol::sym, Symbol};
+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! {
@@ -113,7 +113,7 @@ fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExp
// Shouldn't have side effects, but there's no way to trace which field is used. So forget which fields have
// already been seen.
- ExprKind::Index(base, idx) if !idx.can_have_side_effects() => {
+ ExprKind::Index(base, idx, _) if !idx.can_have_side_effects() => {
can_move = false;
fields.clear();
e = base;
@@ -332,7 +332,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
if let Some(e) = get_enclosing_loop_or_multi_call_closure(cx, loop_expr) {
let Res::Local(local_id) = iter_expr.path else {
- return true
+ return true;
};
let mut v = NestedLoopVisitor {
cx,
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index 8e322a979..9b158f18f 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -8,7 +8,8 @@ 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_span::{edition::Edition, sym, Span};
+use rustc_span::edition::Edition;
+use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index 4629b22d1..6c7c57ba1 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -110,7 +110,7 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id);
then {
- cx.typeck_results().node_substs(count_func.hir_id).types().next().map(|resolved_ty| (*real_ty, resolved_ty))
+ cx.typeck_results().node_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 440362b96..e75666e61 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -4,21 +4,19 @@ use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::implements_trait;
use clippy_utils::visitors::is_const_evaluatable;
-use clippy_utils::MaybePath;
use clippy_utils::{
eq_expr_value, in_constant, is_diag_trait_item, is_trait_method, path_res, path_to_local_id, peel_blocks,
- peel_blocks_with_stmt,
+ peel_blocks_with_stmt, MaybePath,
};
use itertools::Itertools;
-use rustc_errors::Applicability;
-use rustc_errors::Diagnostic;
-use rustc_hir::{
- def::Res, Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind,
-};
+use rustc_errors::{Applicability, Diagnostic};
+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_span::{symbol::sym, Span};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
use std::ops::Deref;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
new file mode 100644
index 000000000..88db7ae6a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
@@ -0,0 +1,175 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::{is_from_proc_macro, path_to_local};
+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};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for manual `is_infinite` reimplementations
+ /// (i.e., `x == <float>::INFINITY || x == <float>::NEG_INFINITY`).
+ ///
+ /// ### Why is this bad?
+ /// The method `is_infinite` is shorter and more readable.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # let x = 1.0f32;
+ /// if x == f32::INFINITY || x == f32::NEG_INFINITY {}
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # let x = 1.0f32;
+ /// if x.is_infinite() {}
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub MANUAL_IS_INFINITE,
+ style,
+ "use dedicated method to check if a float is infinite"
+}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for manual `is_finite` reimplementations
+ /// (i.e., `x != <float>::INFINITY && x != <float>::NEG_INFINITY`).
+ ///
+ /// ### Why is this bad?
+ /// The method `is_finite` is shorter and more readable.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # let x = 1.0f32;
+ /// if x != f32::INFINITY && x != f32::NEG_INFINITY {}
+ /// if x.abs() < f32::INFINITY {}
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # let x = 1.0f32;
+ /// if x.is_finite() {}
+ /// if x.is_finite() {}
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub MANUAL_IS_FINITE,
+ style,
+ "use dedicated method to check if a float is finite"
+}
+declare_lint_pass!(ManualFloatMethods => [MANUAL_IS_INFINITE, MANUAL_IS_FINITE]);
+
+#[derive(Clone, Copy)]
+enum Variant {
+ ManualIsInfinite,
+ ManualIsFinite,
+}
+
+impl Variant {
+ pub fn lint(self) -> &'static Lint {
+ match self {
+ Self::ManualIsInfinite => MANUAL_IS_INFINITE,
+ Self::ManualIsFinite => MANUAL_IS_FINITE,
+ }
+ }
+
+ pub fn msg(self) -> &'static str {
+ match self {
+ Self::ManualIsInfinite => "manually checking if a float is infinite",
+ Self::ManualIsFinite => "manually checking if a float is finite",
+ }
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+ if !in_external_macro(cx.sess(), expr.span)
+ && (
+ matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
+ || cx.tcx.features().active(sym!(const_float_classify))
+ ) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind
+ && let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind
+ && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind
+ // Checking all possible scenarios using a function would be a hopeless task, as we have
+ // 16 possible alignments of constants/operands. For now, let's use `partition`.
+ && let (operands, constants) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
+ .into_iter()
+ .partition::<Vec<&Expr<'_>>, _>(|i| path_to_local(i).is_some())
+ && let [first, second] = &*operands
+ && let Some([const_1, const_2]) = constants
+ .into_iter()
+ .map(|i| constant(cx, cx.typeck_results(), i))
+ .collect::<Option<Vec<_>>>()
+ .as_deref()
+ && path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
+ // The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
+ // case somebody does that for some reason
+ && (is_infinity(const_1) && is_neg_infinity(const_2)
+ || is_neg_infinity(const_1) && is_infinity(const_2))
+ && !is_from_proc_macro(cx, expr)
+ && let Some(local_snippet) = snippet_opt(cx, first.span)
+ {
+ let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
+ (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite,
+ (BinOpKind::And, BinOpKind::Ne, BinOpKind::Ne) => Variant::ManualIsFinite,
+ _ => return,
+ };
+
+ span_lint_and_then(
+ cx,
+ variant.lint(),
+ expr.span,
+ variant.msg(),
+ |diag| {
+ match variant {
+ Variant::ManualIsInfinite => {
+ diag.span_suggestion(
+ expr.span,
+ "use the dedicated method instead",
+ format!("{local_snippet}.is_infinite()"),
+ Applicability::MachineApplicable,
+ );
+ },
+ Variant::ManualIsFinite => {
+ // TODO: There's probably some better way to do this, i.e., create
+ // multiple suggestions with notes between each of them
+ diag.span_suggestion_verbose(
+ expr.span,
+ "use the dedicated method instead",
+ format!("{local_snippet}.is_finite()"),
+ Applicability::MaybeIncorrect,
+ )
+ .span_suggestion_verbose(
+ expr.span,
+ "this will alter how it handles NaN; if that is a problem, use instead",
+ format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"),
+ Applicability::MaybeIncorrect,
+ )
+ .span_suggestion_verbose(
+ expr.span,
+ "or, for conciseness",
+ format!("!{local_snippet}.is_infinite()"),
+ Applicability::MaybeIncorrect,
+ );
+ },
+ }
+ },
+ );
+ }
+ }
+}
+
+fn is_infinity(constant: &Constant<'_>) -> bool {
+ match constant {
+ Constant::F32(float) => *float == f32::INFINITY,
+ Constant::F64(float) => *float == f64::INFINITY,
+ _ => false,
+ }
+}
+
+fn is_neg_infinity(constant: &Constant<'_>) -> bool {
+ match constant {
+ Constant::F32(float) => *float == f32::NEG_INFINITY,
+ Constant::F64(float) => *float == f64::NEG_INFINITY,
+ _ => false,
+ }
+}
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 31264261f..f26442447 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
@@ -1,12 +1,16 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::macros::root_macro_call;
use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, sugg::Sugg};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::{higher, in_constant};
use rustc_ast::ast::RangeLimits;
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_span::{def_id::DefId, sym, Span};
+use rustc_span::def_id::DefId;
+use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
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 59e421c16..c531137b7 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -1,18 +1,17 @@
+use crate::question_mark::{QuestionMark, QUESTION_MARK};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLetOrMatch;
-use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::peel_blocks;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::{Descend, Visitable};
-use if_chain::if_chain;
+use clippy_utils::{is_lint_allowed, msrvs, 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_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::declare_tool_lint;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use serde::Deserialize;
@@ -50,25 +49,8 @@ declare_clippy_lint! {
"manual implementation of a let...else statement"
}
-pub struct ManualLetElse {
- msrv: Msrv,
- matches_behaviour: MatchLintBehaviour,
-}
-
-impl ManualLetElse {
- #[must_use]
- pub fn new(msrv: Msrv, matches_behaviour: MatchLintBehaviour) -> Self {
- Self {
- msrv,
- matches_behaviour,
- }
- }
-}
-
-impl_lint_pass!(ManualLetElse => [MANUAL_LET_ELSE]);
-
-impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
- fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
+impl<'tcx> QuestionMark {
+ pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) {
return;
}
@@ -81,11 +63,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
{
match if_let_or_match {
- IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => if_chain! {
- if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then);
- if let Some(if_else) = if_else;
- if expr_diverges(cx, if_else);
- then {
+ 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) &&
+ 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())
+ {
emit_manual_let_else(cx, stmt.span, if_let_expr, &ident_map, let_pat, if_else);
}
},
@@ -128,8 +113,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
}
};
}
-
- extract_msrv_attr!(LateContext);
}
fn emit_manual_let_else(
@@ -208,7 +191,9 @@ fn replace_in_pattern(
match pat.kind {
PatKind::Binding(_ann, _id, binding_name, opt_subpt) => {
- let Some(pat_to_put) = ident_map.get(&binding_name.name) else { break 'a };
+ let Some(pat_to_put) = ident_map.get(&binding_name.name) else {
+ break 'a;
+ };
let (sn_ptp, _) = snippet_with_context(cx, pat_to_put.span, span.ctxt(), "", app);
if let Some(subpt) = opt_subpt {
let subpt = replace_in_pattern(cx, span, ident_map, subpt, app, false);
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 65ff55520..39d8b20d3 100644
--- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
@@ -2,12 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use rustc_ast::LitKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
-use rustc_hir::Expr;
-use rustc_hir::ExprKind;
-use rustc_hir::PatKind;
-use rustc_hir::RangeEnd;
-use rustc_lint::LintContext;
-use rustc_lint::{LateContext, LateLintPass};
+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};
@@ -19,6 +15,10 @@ declare_clippy_lint! {
/// ### Why is this bad?
/// Using an explicit range is more concise and easier to read.
///
+ /// ### Known issues
+ /// This lint intentionally does not handle numbers greater than `i128::MAX` for `u128` literals
+ /// in order to support negative numbers.
+ ///
/// ### Example
/// ```rust
/// let x = 6;
@@ -36,11 +36,14 @@ declare_clippy_lint! {
}
declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]);
-fn expr_as_u128(expr: &Expr<'_>) -> Option<u128> {
- if let ExprKind::Lit(lit) = expr.kind
+fn expr_as_i128(expr: &Expr<'_>) -> Option<i128> {
+ if let ExprKind::Unary(UnOp::Neg, expr) = expr.kind {
+ expr_as_i128(expr).map(|num| -num)
+ } else if let ExprKind::Lit(lit) = expr.kind
&& let LitKind::Int(num, _) = lit.node
{
- Some(num)
+ // Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now.
+ num.try_into().ok()
} else {
None
}
@@ -56,22 +59,22 @@ impl LateLintPass<'_> for ManualRangePatterns {
if let PatKind::Or(pats) = pat.kind
&& pats.len() >= 3
{
- let mut min = u128::MAX;
- let mut max = 0;
+ let mut min = i128::MAX;
+ let mut max = i128::MIN;
let mut numbers_found = FxHashSet::default();
let mut ranges_found = Vec::new();
for pat in pats {
if let PatKind::Lit(lit) = pat.kind
- && let Some(num) = expr_as_u128(lit)
+ && let Some(num) = expr_as_i128(lit)
{
numbers_found.insert(num);
min = min.min(num);
max = max.max(num);
} else if let PatKind::Range(Some(left), Some(right), end) = pat.kind
- && let Some(left) = expr_as_u128(left)
- && let Some(right) = expr_as_u128(right)
+ && let Some(left) = expr_as_i128(left)
+ && let Some(right) = expr_as_i128(right)
&& right >= left
{
min = min.min(left);
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 aafee9271..0e89ca132 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -119,7 +119,7 @@ fn check_for_either_unsigned_int_constant<'a>(
}
fn check_for_unsigned_int_constant<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option<u128> {
- let Some(int_const) = constant_full_int(cx, cx.typeck_results(), expr) else { return None };
+ let int_const = constant_full_int(cx, cx.typeck_results(), expr)?;
match int_const {
FullInt::S(s) => s.try_into().ok(),
FullInt::U(u) => Some(u),
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 703a6b258..f97600b53 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
@@ -92,7 +92,7 @@ fn simplify_half<'tcx>(
&& 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_size_of, def_id)
- && let Some(ty2) = cx.typeck_results().node_substs(func.hir_id).types().next()
+ && let Some(ty2) = cx.typeck_results().node_args(func.hir_id).types().next()
// T1 == T2?
&& *ty1 == ty2
{
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 93d977a5c..201bb56ef 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -8,8 +8,7 @@ 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;
-use rustc_hir::{BorrowKind, Expr, ExprKind};
+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};
@@ -205,7 +204,7 @@ fn find_stripping<'tcx>(
if_chain! {
if is_ref_str(self.cx, ex);
let unref = peel_ref(ex);
- if let ExprKind::Index(indexed, index) = &unref.kind;
+ 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;
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 edcab6968..f0a0f482a 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -104,7 +104,7 @@ fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
let ty = cx.typeck_results().expr_ty(expr);
if let ty::FnDef(id, _) = *ty.kind() {
- if let Some(fn_type) = cx.tcx.fn_sig(id).subst_identity().no_bound_vars() {
+ if let Some(fn_type) = cx.tcx.fn_sig(id).instantiate_identity().no_bound_vars() {
return is_unit_type(fn_type.output());
}
}
@@ -226,7 +226,7 @@ fn lint_map_unit_fn(
);
span_lint_and_then(cx, lint, expr.span, &msg, |diag| {
- diag.span_suggestion(stmt.span, "try this", suggestion, applicability);
+ diag.span_suggestion(stmt.span, "try", suggestion, applicability);
});
} else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) {
let msg = suggestion_msg("closure", map_type);
@@ -241,7 +241,7 @@ fn lint_map_unit_fn(
snippet_with_applicability(cx, var_arg.span, "_", &mut applicability),
snippet_with_context(cx, reduced_expr_span, var_arg.span.ctxt(), "_", &mut applicability).0,
);
- diag.span_suggestion(stmt.span, "try this", suggestion, applicability);
+ diag.span_suggestion(stmt.span, "try", suggestion, applicability);
} else {
let suggestion = format!(
"if let {0}({1}) = {2} {{ ... }}",
@@ -249,7 +249,7 @@ fn lint_map_unit_fn(
snippet(cx, binding.pat.span, "_"),
snippet(cx, var_arg.span, "_"),
);
- diag.span_suggestion(stmt.span, "try this", suggestion, Applicability::HasPlaceholders);
+ diag.span_suggestion(stmt.span, "try", suggestion, Applicability::HasPlaceholders);
}
});
}
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 6ec978403..841c020f2 100644
--- a/src/tools/clippy/clippy_lints/src/match_result_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
@@ -1,8 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher;
-use clippy_utils::is_res_lang_ctor;
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};
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 d18c92cab..3329f93b7 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
@@ -28,7 +28,7 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool {
local.span,
"you seem to be trying to use `match` to destructure a single infallible pattern. \
Consider using `let`",
- "try this",
+ "try",
format!(
"let {}({}{}) = {};",
snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
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 f6bf0e7aa..e0181a475 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
@@ -143,7 +143,7 @@ fn check<'tcx>(
MANUAL_FILTER,
expr.span,
"manual implementation of `Option::filter`",
- "try this",
+ "try",
if sugg_info.needs_brackets {
format!(
"{{ {}{}.filter({body_str}) }}",
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_map.rs b/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
index aaba23967..ed3d8b09f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
@@ -58,7 +58,7 @@ fn check<'tcx>(
MANUAL_MAP,
expr.span,
"manual implementation of `Option::map`",
- "try this",
+ "try",
if sugg_info.needs_brackets {
format!(
"{{ {}{}.map({}) }}",
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 5b7644a53..6b611f567 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -1,14 +1,17 @@
-use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF};
+use crate::map_unit_fn::OPTION_MAP_UNIT_FN;
+use crate::matches::MATCH_AS_REF;
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
+use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_copy, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
use clippy_utils::{
can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, path_to_local_id,
- peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, sugg::Sugg, CaptureKind,
+ peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
};
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::Applicability;
+use rustc_hir::def::Res;
use rustc_hir::LangItem::{OptionNone, OptionSome};
-use rustc_hir::{def::Res, BindingAnnotation, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath};
use rustc_lint::LateContext;
use rustc_span::{sym, SyntaxContext};
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 2818f030b..d51cca040 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
@@ -27,10 +27,10 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
let input_ty = cx.typeck_results().expr_ty(ex);
let cast = if_chain! {
- if let ty::Adt(_, substs) = input_ty.kind();
- let input_ty = substs.type_at(0);
- if let ty::Adt(_, substs) = output_ty.kind();
- let output_ty = substs.type_at(0);
+ 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 {
@@ -46,7 +46,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
MATCH_AS_REF,
expr.span,
&format!("use `{suggestion}()` instead"),
- "try this",
+ "try",
format!(
"{}.{suggestion}(){cast}",
snippet_with_applicability(cx, ex.span, "_", &mut applicability),
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 0064619ef..e2ddf11ab 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
@@ -1,9 +1,7 @@
use super::REDUNDANT_PATTERN_MATCHING;
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_lint_allowed;
-use clippy_utils::is_wild;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::span_contains_comment;
+use clippy_utils::{is_lint_allowed, is_wild, span_contains_comment};
use rustc_ast::{Attribute, LitKind};
use rustc_errors::Applicability;
use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat, PatKind, QPath};
@@ -139,7 +137,7 @@ where
MATCH_LIKE_MATCHES_MACRO,
expr.span,
&format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }),
- "try this",
+ "try",
format!(
"{}matches!({}, {pat_and_guard})",
if b0 { "" } else { "!" },
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 2917f85c4..bd53ebd48 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
@@ -12,7 +12,7 @@ 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;
+ if let ExprKind::Index(vec, idx, _) = idx_expr.kind;
then {
// FIXME: could be improved to suggest surrounding every pattern with Some(_),
@@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) {
MATCH_ON_VEC_ITEMS,
scrutinee.span,
"indexing into a vector may panic",
- "try this",
+ "try",
format!(
"{}.get({})",
snippet(cx, vec.span, ".."),
@@ -36,7 +36,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) {
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 let ExprKind::Index(array, index, _) = expr.kind;
if is_vector(cx, array);
if !is_full_range(cx, index);
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 3d2fbea63..6fc79fadd 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
@@ -2,8 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use clippy_utils::{is_lint_allowed, path_to_local, search_same, SpanlessEq, SpanlessHash};
use core::cmp::Ordering;
-use core::iter;
-use core::slice;
+use core::{iter, slice};
use rustc_arena::DroplessArena;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
@@ -240,7 +239,7 @@ impl<'a> NormalizedPat<'a> {
},
PatKind::TupleStruct(ref path, pats, wild_idx) => {
let Some(adt) = cx.typeck_results().pat_ty(pat).ty_adt_def() else {
- return Self::Wild
+ return Self::Wild;
};
let (var_id, variant) = if adt.is_enum() {
match cx.qpath_res(path, pat.hir_id).opt_def_id() {
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index 3126b5901..8d22ceb47 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -143,7 +143,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
wildcard_span,
"wildcard matches only a single variant and will also match any future added variants",
- "try this",
+ "try",
format_suggestion(x),
Applicability::MaybeIncorrect,
),
@@ -161,7 +161,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
WILDCARD_ENUM_MATCH_ARM,
wildcard_span,
message,
- "try this",
+ "try",
suggestions.join(" | "),
Applicability::MaybeIncorrect,
);
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index 00fa3eb9b..930386a60 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -16,6 +16,7 @@ mod match_wild_enum;
mod match_wild_err_arm;
mod needless_match;
mod overlapping_arms;
+mod redundant_guards;
mod redundant_pattern_match;
mod rest_pat_in_fully_bound_struct;
mod significant_drop_in_scrutinee;
@@ -936,6 +937,36 @@ declare_clippy_lint! {
"reimplementation of `filter`"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for unnecessary guards in match expressions.
+ ///
+ /// ### Why is this bad?
+ /// It's more complex and much less readable. Making it part of the pattern can improve
+ /// exhaustiveness checking as well.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// match x {
+ /// Some(x) if matches!(x, Some(1)) => ..,
+ /// Some(x) if x == Some(2) => ..,
+ /// _ => todo!(),
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust,ignore
+ /// match x {
+ /// Some(Some(1)) => ..,
+ /// Some(Some(2)) => ..,
+ /// _ => todo!(),
+ /// }
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub REDUNDANT_GUARDS,
+ complexity,
+ "checks for unnecessary guards in match expressions"
+}
+
#[derive(Default)]
pub struct Matches {
msrv: Msrv,
@@ -978,6 +1009,7 @@ impl_lint_pass!(Matches => [
TRY_ERR,
MANUAL_MAP,
MANUAL_FILTER,
+ REDUNDANT_GUARDS,
]);
impl<'tcx> LateLintPass<'tcx> for Matches {
@@ -1006,7 +1038,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
wild_in_or_pats::check(cx, arms);
}
- if source == MatchSource::TryDesugar {
+ if let MatchSource::TryDesugar(_) = source {
try_err::check(cx, expr, ex);
}
@@ -1025,6 +1057,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
needless_match::check_match(cx, ex, arms, expr);
match_on_vec_items::check(cx, ex);
match_str_case_mismatch::check(cx, ex, arms);
+ redundant_guards::check(cx, arms);
if !in_constant(cx, expr.hir_id) {
manual_unwrap_or::check(cx, expr, ex, arms);
@@ -1125,8 +1158,8 @@ fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, ar
//|^
let found = arm_spans.try_fold(start, |start, range| {
let Some((end, next_start)) = range else {
- // Shouldn't happen as macros can't expand to match arms, but treat this as though a `cfg` attribute were
- // found.
+ // Shouldn't happen as macros can't expand to match arms, but treat this as though a `cfg` attribute
+ // were found.
return Err(());
};
let span = SpanData {
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
new file mode 100644
index 000000000..29af48123
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -0,0 +1,196 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::path_to_local;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::visitors::{for_each_expr, is_local_used};
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+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::Span;
+use std::ops::ControlFlow;
+
+use super::REDUNDANT_GUARDS;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
+ for outer_arm in arms {
+ let Some(guard) = outer_arm.guard else {
+ continue;
+ };
+
+ // `Some(x) if matches!(x, y)`
+ if let Guard::If(if_expr) = guard
+ && let ExprKind::Match(
+ scrutinee,
+ [
+ arm,
+ Arm {
+ pat: Pat {
+ kind: PatKind::Wild,
+ ..
+ },
+ ..
+ },
+ ],
+ MatchSource::Normal,
+ ) = if_expr.kind
+ {
+ emit_redundant_guards(
+ cx,
+ outer_arm,
+ if_expr.span,
+ scrutinee,
+ arm.pat.span,
+ arm.guard,
+ );
+ }
+ // `Some(x) if let Some(2) = x`
+ else if let Guard::IfLet(let_expr) = guard {
+ emit_redundant_guards(
+ cx,
+ outer_arm,
+ let_expr.span,
+ let_expr.init,
+ let_expr.pat.span,
+ None,
+ );
+ }
+ // `Some(x) if x == Some(2)`
+ else if let Guard::If(if_expr) = guard
+ && let ExprKind::Binary(bin_op, local, pat) = if_expr.kind
+ && matches!(bin_op.node, BinOpKind::Eq)
+ && expr_can_be_pat(cx, pat)
+ // Ensure they have the same type. If they don't, we'd need deref coercion which isn't
+ // possible (currently) in a pattern. In some cases, you can use something like
+ // `as_deref` or similar but in general, we shouldn't lint this as it'd create an
+ // extraordinary amount of FPs.
+ //
+ // This isn't necessary in the other two checks, as they must be a pattern already.
+ && cx.typeck_results().expr_ty(local) == cx.typeck_results().expr_ty(pat)
+ {
+ emit_redundant_guards(
+ cx,
+ outer_arm,
+ if_expr.span,
+ local,
+ pat.span,
+ None,
+ );
+ }
+ }
+}
+
+fn get_pat_binding<'tcx>(cx: &LateContext<'tcx>, guard_expr: &Expr<'_>, outer_arm: &Arm<'tcx>) -> Option<(Span, bool)> {
+ if let Some(local) = path_to_local(guard_expr) && !is_local_used(cx, outer_arm.body, local) {
+ let mut span = None;
+ let mut multiple_bindings = false;
+ // `each_binding` gives the `HirId` of the `Pat` itself, not the binding
+ outer_arm.pat.walk(|pat| {
+ if let PatKind::Binding(_, hir_id, _, _) = pat.kind
+ && hir_id == local
+ && span.replace(pat.span).is_some()
+ {
+ multiple_bindings = true;
+ return false;
+ }
+
+ true
+ });
+
+ // Ignore bindings from or patterns, like `First(x) | Second(x, _) | Third(x, _, _)`
+ if !multiple_bindings {
+ return span.map(|span| {
+ (
+ span,
+ !matches!(cx.tcx.hir().get_parent(local), Node::PatField(_)),
+ )
+ });
+ }
+ }
+
+ None
+}
+
+fn emit_redundant_guards<'tcx>(
+ cx: &LateContext<'tcx>,
+ outer_arm: &Arm<'tcx>,
+ guard_span: Span,
+ local: &Expr<'_>,
+ pat_span: Span,
+ inner_guard: Option<Guard<'_>>,
+) {
+ let mut app = Applicability::MaybeIncorrect;
+ let Some((pat_binding, can_use_shorthand)) = get_pat_binding(cx, local, outer_arm) else {
+ return;
+ };
+
+ 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);
+ diag.multipart_suggestion_verbose(
+ "try",
+ vec![
+ if can_use_shorthand {
+ (pat_binding, binding_replacement.into_owned())
+ } else {
+ (pat_binding.shrink_to_hi(), format!(": {binding_replacement}"))
+ },
+ (
+ guard_span.source_callsite().with_lo(outer_arm.pat.span.hi()),
+ inner_guard.map_or_else(String::new, |guard| {
+ let (prefix, span) = match guard {
+ Guard::If(e) => ("if", e.span),
+ Guard::IfLet(l) => ("if let", l.span),
+ };
+
+ format!(
+ " {prefix} {}",
+ snippet_with_applicability(cx, span, "<guard>", &mut app),
+ )
+ }),
+ ),
+ ],
+ app,
+ );
+ },
+ );
+}
+
+/// Checks if the given `Expr` can also be represented as a `Pat`.
+///
+/// All literals generally also work as patterns, however float literals are special.
+/// They are currently (as of 2023/08/08) still allowed in patterns, but that will become
+/// an error in the future, and rustc already actively warns against this (see rust#41620),
+/// so we don't consider those as usable within patterns for linting purposes.
+fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ for_each_expr(expr, |expr| {
+ if match expr.kind {
+ ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat,
+ ExprKind::Call(c, ..) if let ExprKind::Path(qpath) = c.kind => {
+ // Allow ctors
+ matches!(cx.qpath_res(&qpath, c.hir_id), Res::Def(DefKind::Ctor(..), ..))
+ },
+ ExprKind::Path(qpath) => {
+ matches!(
+ cx.qpath_res(&qpath, expr.hir_id),
+ Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Ctor(..), ..),
+ )
+ },
+ ExprKind::AddrOf(..)
+ | ExprKind::Array(..)
+ | ExprKind::Tup(..)
+ | ExprKind::Struct(..) => true,
+ ExprKind::Lit(lit) if !matches!(lit.node, LitKind::Float(..)) => true,
+ _ => false,
+ } {
+ return ControlFlow::Continue(());
+ }
+
+ ControlFlow::Break(())
+ })
+ .is_none()
+}
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 479cfd835..9a7c00823 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
@@ -3,17 +3,19 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, walk_span_to_context};
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;
+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};
use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
-use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp};
+use rustc_hir::{Arm, Expr, ExprKind, Guard, Node, Pat, PatKind, QPath, UnOp};
use rustc_lint::LateContext;
-use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
+use rustc_middle::ty::{self, GenericArgKind, Ty};
use rustc_span::{sym, Symbol};
+use std::fmt::Write;
+use std::ops::ControlFlow;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
@@ -45,49 +47,39 @@ fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
}
}
-fn find_sugg_for_if_let<'tcx>(
+fn find_method_and_type<'tcx>(
cx: &LateContext<'tcx>,
- expr: &'tcx Expr<'_>,
- let_pat: &Pat<'_>,
- let_expr: &'tcx Expr<'_>,
- keyword: &'static str,
- has_else: bool,
-) {
- // also look inside refs
- // if we have &None for example, peel it so we can detect "if let None = x"
- let check_pat = match let_pat.kind {
- PatKind::Ref(inner, _mutability) => inner,
- _ => let_pat,
- };
- let op_ty = cx.typeck_results().expr_ty(let_expr);
- // Determine which function should be used, and the type contained by the corresponding
- // variant.
- let (good_method, inner_ty) = match check_pat.kind {
+ check_pat: &Pat<'_>,
+ op_ty: Ty<'tcx>,
+) -> Option<(&'static str, Ty<'tcx>)> {
+ match check_pat.kind {
PatKind::TupleStruct(ref qpath, args, rest) => {
let is_wildcard = matches!(args.first().map(|p| &p.kind), Some(PatKind::Wild));
let is_rest = matches!((args, rest.as_opt_usize()), ([], Some(_)));
if is_wildcard || is_rest {
let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
- let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
+ let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else {
+ return None;
+ };
let lang_items = cx.tcx.lang_items();
if Some(id) == lang_items.result_ok_variant() {
- ("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty))
+ Some(("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty)))
} else if Some(id) == lang_items.result_err_variant() {
- ("is_err()", try_get_generic_ty(op_ty, 1).unwrap_or(op_ty))
+ Some(("is_err()", try_get_generic_ty(op_ty, 1).unwrap_or(op_ty)))
} else if Some(id) == lang_items.option_some_variant() {
- ("is_some()", op_ty)
+ Some(("is_some()", op_ty))
} else if Some(id) == lang_items.poll_ready_variant() {
- ("is_ready()", op_ty)
+ Some(("is_ready()", op_ty))
} else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V4))) {
- ("is_ipv4()", op_ty)
+ Some(("is_ipv4()", op_ty))
} else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V6))) {
- ("is_ipv6()", op_ty)
+ Some(("is_ipv6()", op_ty))
} else {
- return;
+ None
}
} else {
- return;
+ None
}
},
PatKind::Path(ref path) => {
@@ -99,15 +91,37 @@ fn find_sugg_for_if_let<'tcx>(
} else if cx.tcx.lang_items().poll_pending_variant() == Some(variant_id) {
"is_pending()"
} else {
- return;
+ return None;
};
// `None` and `Pending` don't have an inner type.
- (method, cx.tcx.types.unit)
+ Some((method, cx.tcx.types.unit))
} else {
- return;
+ None
}
},
- _ => return,
+ _ => None,
+ }
+}
+
+fn find_sugg_for_if_let<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ let_pat: &Pat<'_>,
+ let_expr: &'tcx Expr<'_>,
+ keyword: &'static str,
+ has_else: bool,
+) {
+ // also look inside refs
+ // if we have &None for example, peel it so we can detect "if let None = x"
+ let check_pat = match let_pat.kind {
+ PatKind::Ref(inner, _mutability) => inner,
+ _ => let_pat,
+ };
+ let op_ty = cx.typeck_results().expr_ty(let_expr);
+ // Determine which function should be used, and the type contained by the corresponding
+ // variant.
+ let Some((good_method, inner_ty)) = find_method_and_type(cx, check_pat, op_ty) else {
+ return;
};
// If this is the last expression in a block or there is an else clause then the whole
@@ -175,7 +189,7 @@ fn find_sugg_for_if_let<'tcx>(
.maybe_par()
.to_string();
- diag.span_suggestion(span, "try this", format!("{keyword} {sugg}.{good_method}"), app);
+ diag.span_suggestion(span, "try", format!("{keyword} {sugg}.{good_method}"), app);
if needs_drop {
diag.note("this will change drop order of the result, as well as all temporaries");
@@ -189,30 +203,58 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
if arms.len() == 2 {
let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
- if let Some(good_method) = found_good_method(cx, arms, node_pair) {
+ if let Some((good_method, maybe_guard)) = found_good_method(cx, arms, node_pair) {
let span = is_expn_of(expr.span, "matches").unwrap_or(expr.span.to(op.span));
let result_expr = match &op.kind {
ExprKind::AddrOf(_, _, borrowed) => borrowed,
_ => op,
};
+ let mut sugg = format!("{}.{good_method}", snippet(cx, result_expr.span, "_"));
+
+ if let Some(guard) = maybe_guard {
+ let Guard::If(guard) = *guard else { return }; // `...is_none() && let ...` is a syntax error
+
+ // wow, the HIR for match guards in `PAT if let PAT = expr && expr => ...` is annoying!
+ // `guard` here is `Guard::If` with the let expression somewhere deep in the tree of exprs,
+ // counter to the intuition that it should be `Guard::IfLet`, so we need another check
+ // to see that there aren't any let chains anywhere in the guard, as that would break
+ // if we suggest `t.is_none() && (let X = y && z)` for:
+ // `match t { None if let X = y && z => true, _ => false }`
+ let has_nested_let_chain = for_each_expr(guard, |expr| {
+ if matches!(expr.kind, ExprKind::Let(..)) {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(())
+ }
+ })
+ .is_some();
+
+ if has_nested_let_chain {
+ return;
+ }
+
+ let guard = Sugg::hir(cx, guard, "..");
+ let _ = write!(sugg, " && {}", guard.maybe_par());
+ }
+
span_lint_and_sugg(
cx,
REDUNDANT_PATTERN_MATCHING,
span,
&format!("redundant pattern matching, consider using `{good_method}`"),
- "try this",
- format!("{}.{good_method}", snippet(cx, result_expr.span, "_")),
+ "try",
+ sugg,
Applicability::MachineApplicable,
);
}
}
}
-fn found_good_method<'a>(
+fn found_good_method<'tcx>(
cx: &LateContext<'_>,
- arms: &[Arm<'_>],
+ arms: &'tcx [Arm<'tcx>],
node: (&PatKind<'_>, &PatKind<'_>),
-) -> Option<&'a str> {
+) -> Option<(&'static str, Option<&'tcx Guard<'tcx>>)> {
match node {
(
PatKind::TupleStruct(ref path_left, patterns_left, _),
@@ -298,7 +340,11 @@ fn get_ident(path: &QPath<'_>) -> Option<rustc_span::symbol::Ident> {
}
}
-fn get_good_method<'a>(cx: &LateContext<'_>, arms: &[Arm<'_>], path_left: &QPath<'_>) -> Option<&'a str> {
+fn get_good_method<'tcx>(
+ cx: &LateContext<'_>,
+ arms: &'tcx [Arm<'tcx>],
+ path_left: &QPath<'_>,
+) -> Option<(&'static str, Option<&'tcx Guard<'tcx>>)> {
if let Some(name) = get_ident(path_left) {
return match name.as_str() {
"Ok" => {
@@ -336,7 +382,9 @@ enum Item {
}
fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expected_item: Item) -> bool {
- let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else { return false };
+ let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else {
+ return false;
+ };
match expected_item {
Item::Lang(expected_lang_item) => cx
@@ -362,16 +410,16 @@ fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expecte
}
#[expect(clippy::too_many_arguments)]
-fn find_good_method_for_match<'a>(
+fn find_good_method_for_match<'a, 'tcx>(
cx: &LateContext<'_>,
- arms: &[Arm<'_>],
+ arms: &'tcx [Arm<'tcx>],
path_left: &QPath<'_>,
path_right: &QPath<'_>,
expected_item_left: Item,
expected_item_right: Item,
should_be_left: &'a str,
should_be_right: &'a str,
-) -> Option<&'a str> {
+) -> Option<(&'a str, Option<&'tcx Guard<'tcx>>)> {
let first_pat = arms[0].pat;
let second_pat = arms[1].pat;
@@ -389,22 +437,22 @@ fn find_good_method_for_match<'a>(
match body_node_pair {
(ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) {
- (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
- (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
+ (LitKind::Bool(true), LitKind::Bool(false)) => Some((should_be_left, arms[0].guard.as_ref())),
+ (LitKind::Bool(false), LitKind::Bool(true)) => Some((should_be_right, arms[1].guard.as_ref())),
_ => None,
},
_ => None,
}
}
-fn find_good_method_for_matches_macro<'a>(
+fn find_good_method_for_matches_macro<'a, 'tcx>(
cx: &LateContext<'_>,
- arms: &[Arm<'_>],
+ arms: &'tcx [Arm<'tcx>],
path_left: &QPath<'_>,
expected_item_left: Item,
should_be_left: &'a str,
should_be_right: &'a str,
-) -> Option<&'a str> {
+) -> Option<(&'a str, Option<&'tcx Guard<'tcx>>)> {
let first_pat = arms[0].pat;
let body_node_pair = if is_pat_variant(cx, first_pat, path_left, expected_item_left) {
@@ -415,8 +463,8 @@ fn find_good_method_for_matches_macro<'a>(
match body_node_pair {
(ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) {
- (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
- (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
+ (LitKind::Bool(true), LitKind::Bool(false)) => Some((should_be_left, arms[0].guard.as_ref())),
+ (LitKind::Bool(false), LitKind::Bool(true)) => Some((should_be_right, arms[1].guard.as_ref())),
_ => None,
},
_ => None,
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 d06bcdaa2..4efe93d4b 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
@@ -10,7 +10,7 @@ pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) {
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).subst_identity();
+ 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();
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 37528d9f7..ee0fdb353 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -6,8 +6,7 @@ use rustc_errors::{Applicability, Diagnostic};
use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, MatchSource};
use rustc_lint::{LateContext, LintContext};
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{Ty, TypeAndMut};
+use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut};
use rustc_span::Span;
use super::SIGNIFICANT_DROP_IN_SCRUTINEE;
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 35627d6c6..6b05c6bff 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -136,7 +136,7 @@ fn report_single_pattern(
}
};
- span_lint_and_sugg(cx, lint, expr.span, msg, "try this", sugg, app);
+ span_lint_and_sugg(cx, lint, expr.span, msg, "try", sugg, app);
}
fn check_opt_like<'a>(
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 3a7f1e034..0fd6f533d 100644
--- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
@@ -70,7 +70,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
TRY_ERR,
expr.span,
"returning an `Err(_)` with the `?` operator",
- "try this",
+ "try",
suggestion,
applicability,
);
@@ -80,7 +80,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
/// Finds function return type by examining return expressions in match arms.
fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> Option<Ty<'tcx>> {
- if let ExprKind::Match(_, arms, MatchSource::TryDesugar) = expr {
+ if let ExprKind::Match(_, arms, MatchSource::TryDesugar(_)) = expr {
for arm in *arms {
if let ExprKind::Ret(Some(ret)) = arm.body.kind {
return Some(cx.typeck_results().expr_ty(ret));
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 008533488..3a8cc4174 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
@@ -1,7 +1,8 @@
use super::{contains_return, BIND_INSTEAD_OF_MAP};
use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::peel_blocks;
use clippy_utils::source::{snippet, snippet_with_context};
-use clippy_utils::{peel_blocks, visitors::find_all_ret_expressions};
+use clippy_utils::visitors::find_all_ret_expressions;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -87,7 +88,7 @@ pub(crate) trait BindInsteadOfMap {
BIND_INSTEAD_OF_MAP,
expr.span,
&msg,
- "try this",
+ "try",
note,
app,
);
@@ -124,7 +125,7 @@ pub(crate) trait BindInsteadOfMap {
span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, |diag| {
multispan_sugg_with_applicability(
diag,
- "try this",
+ "try",
Applicability::MachineApplicable,
std::iter::once((span, Self::GOOD_METHOD_NAME.into())).chain(
suggs
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
index fef90f6eb..f490a7175 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
@@ -45,7 +45,7 @@ pub(super) fn check<'tcx>(
let haystack = if let ExprKind::MethodCall(path, receiver, [], _) =
filter_recv.kind {
let p = path.ident.name;
- if p == sym::iter || p == sym!(iter_mut) {
+ if p == sym::iter || p == sym::iter_mut {
receiver
} else {
filter_recv
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 46a20ad41..649fc46e4 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
@@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(
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).subst_identity().is_str();
+ 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 {
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 7711aa78b..d5897822e 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,13 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::snippet_opt;
-use clippy_utils::source::{indent_of, reindent_multiline};
+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};
use rustc_lint::LateContext;
-use rustc_span::{source_map::Spanned, Span};
+use rustc_span::source_map::Spanned;
+use rustc_span::Span;
use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS;
@@ -30,7 +30,7 @@ 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).subst_identity().is_str();
+ 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();
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 079df2226..0e41f3c21 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
@@ -4,8 +4,7 @@ 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;
-use rustc_lint::Lint;
+use rustc_lint::{LateContext, Lint};
use rustc_middle::ty;
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
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 8984b2cf8..c9d50a5b0 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
@@ -5,8 +5,7 @@ use if_chain::if_chain;
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_hir as hir;
-use rustc_lint::LateContext;
-use rustc_lint::Lint;
+use rustc_lint::{LateContext, Lint};
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
pub(super) fn check(
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 65fd50dff..eb4f003d3 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
@@ -5,7 +5,9 @@ use clippy_utils::ty::is_copy;
use rustc_errors::Applicability;
use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
use rustc_lint::LateContext;
-use rustc_middle::ty::{self, adjustment::Adjust, print::with_forced_trimmed_paths};
+use rustc_middle::ty::adjustment::Adjust;
+use rustc_middle::ty::print::with_forced_trimmed_paths;
+use rustc_middle::ty::{self};
use rustc_span::symbol::{sym, Symbol};
use super::CLONE_ON_COPY;
@@ -62,7 +64,7 @@ pub(super) fn check(
ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _))
),
ExprKind::MethodCall(_, self_arg, ..) if expr.hir_id == self_arg.hir_id => true,
- ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
+ ExprKind::Match(_, _, MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar)
| ExprKind::Field(..)
| ExprKind::Index(..) => true,
_ => false,
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
index 5e8ad0861..ddf3c9f27 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
@@ -42,7 +42,7 @@ pub(super) fn check(
CLONE_ON_REF_PTR,
expr.span,
"using `.clone()` on a ref-counted pointer",
- "try this",
+ "try",
format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)),
app,
);
diff --git a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
index 5e01ed90f..5409ede60 100644
--- a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
@@ -8,8 +8,7 @@ use rustc_hir as hir;
use rustc_lint::LateContext;
use std::collections::VecDeque;
-use super::method_call;
-use super::COLLAPSIBLE_STR_REPLACE;
+use super::{method_call, COLLAPSIBLE_STR_REPLACE};
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs b/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs
index d0c79dc11..6a82d8f75 100644
--- a/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs
@@ -4,17 +4,12 @@ use clippy_utils::is_range_full;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_lang_item;
use rustc_errors::Applicability;
-use rustc_hir::Expr;
-use rustc_hir::ExprKind;
-use rustc_hir::LangItem;
-use rustc_hir::Path;
-use rustc_hir::QPath;
+use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath};
use rustc_lint::LateContext;
use rustc_middle::query::Key;
use rustc_middle::ty;
use rustc_middle::ty::Ty;
-use rustc_span::sym;
-use rustc_span::Symbol;
+use rustc_span::{sym, Symbol};
/// Checks if both types match the given diagnostic item, e.g.:
///
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 ae03da0d3..3d82441c0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
@@ -1,8 +1,7 @@
use super::ERR_EXPECT;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::ty::has_debug_impl;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item};
use rustc_errors::Applicability;
use rustc_lint::LateContext;
use rustc_middle::ty;
@@ -47,7 +46,7 @@ pub(super) fn check(
/// Given a `Result<T, E>` type, return its data (`T`).
fn get_data_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
match ty.kind() {
- ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::Result) => substs.types().next(),
+ ty::Adt(_, args) if is_type_diagnostic_item(cx, ty, sym::Result) => args.types().next(),
_ => None,
}
}
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 92d21bb89..d3e90e4bb 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
@@ -70,7 +70,7 @@ pub(super) fn check<'tcx>(
if let hir::ExprKind::Path(ref p) = fun.kind {
match cx.qpath_res(p, fun.hir_id) {
hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!(
- cx.tcx.fn_sig(def_id).subst_identity().output().skip_binder().kind(),
+ cx.tcx.fn_sig(def_id).instantiate_identity().output().skip_binder().kind(),
ty::Ref(re, ..) if re.is_static(),
),
_ => false,
@@ -84,7 +84,7 @@ pub(super) fn check<'tcx>(
.type_dependent_def_id(arg.hir_id)
.map_or(false, |method_id| {
matches!(
- cx.tcx.fn_sig(method_id).subst_identity().output().skip_binder().kind(),
+ cx.tcx.fn_sig(method_id).instantiate_identity().output().skip_binder().kind(),
ty::Ref(re, ..) if re.is_static()
)
})
@@ -144,7 +144,7 @@ pub(super) fn check<'tcx>(
EXPECT_FUN_CALL,
span_replace_word,
&format!("use of `{name}` followed by a function call"),
- "try this",
+ "try",
format!("unwrap_or_else({closure_args} panic!({sugg}))"),
applicability,
);
@@ -162,7 +162,7 @@ pub(super) fn check<'tcx>(
EXPECT_FUN_CALL,
span_replace_word,
&format!("use of `{name}` followed by a function call"),
- "try this",
+ "try",
format!("unwrap_or_else({closure_args} {{ panic!(\"{{}}\", {arg_root_snippet}) }})"),
applicability,
);
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
deleted file mode 100644
index 614610335..000000000
--- a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_in_cfg_test, is_in_test_function};
-use rustc_hir as hir;
-use rustc_lint::LateContext;
-use rustc_span::sym;
-
-use super::EXPECT_USED;
-
-/// lint use of `expect()` or `expect_err` for `Result` and `expect()` for `Option`.
-pub(super) fn check(
- cx: &LateContext<'_>,
- expr: &hir::Expr<'_>,
- recv: &hir::Expr<'_>,
- is_err: bool,
- allow_expect_in_tests: bool,
-) {
- let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
-
- let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
- Some((EXPECT_USED, "an `Option`", "None", ""))
- } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
- Some((EXPECT_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
- } else {
- None
- };
-
- let method = if is_err { "expect_err" } else { "expect" };
-
- if allow_expect_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
- return;
- }
-
- if let Some((lint, kind, none_value, none_prefix)) = mess {
- span_lint_and_help(
- cx,
- lint,
- expr.span,
- &format!("used `{method}()` on {kind} value"),
- None,
- &format!("if this value is {none_prefix}`{none_value}`, it will panic"),
- );
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
index 37b284635..495b26652 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
@@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
EXTEND_WITH_DRAIN,
expr.span,
"use of `extend` instead of `append` for adding the full range of a second vector",
- "try this",
+ "try",
format!(
"{}.append({}{})",
snippet_with_applicability(cx, recv.span, "..", &mut applicability),
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 fc80f2eea..c9eaa185a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -1,7 +1,9 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::macros::{is_panic, root_macro_call};
use clippy_utils::source::{indent_of, reindent_multiline, snippet};
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, SpanlessEq};
+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;
@@ -10,12 +12,10 @@ use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp};
use rustc_lint::LateContext;
use rustc_middle::ty::adjustment::Adjust;
use rustc_span::source_map::Span;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::{sym, Ident, Symbol};
use std::borrow::Cow;
-use super::MANUAL_FILTER_MAP;
-use super::MANUAL_FIND_MAP;
-use super::OPTION_FILTER_MAP;
+use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP};
fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
match &expr.kind {
@@ -50,6 +50,214 @@ fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_ar
is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some))
}
+#[derive(Debug, Copy, Clone)]
+enum OffendingFilterExpr<'tcx> {
+ /// `.filter(|opt| opt.is_some())`
+ IsSome {
+ /// The receiver expression
+ receiver: &'tcx Expr<'tcx>,
+ /// If `Some`, then this contains the span of an expression that possibly contains side
+ /// effects: `.filter(|opt| side_effect(opt).is_some())`
+ /// ^^^^^^^^^^^^^^^^
+ ///
+ /// We will use this later for warning the user that the suggested fix may change
+ /// the behavior.
+ side_effect_expr_span: Option<Span>,
+ },
+ /// `.filter(|res| res.is_ok())`
+ IsOk {
+ /// The receiver expression
+ receiver: &'tcx Expr<'tcx>,
+ /// See `IsSome`
+ side_effect_expr_span: Option<Span>,
+ },
+ /// `.filter(|enum| matches!(enum, Enum::A(_)))`
+ Matches {
+ /// The DefId of the variant being matched
+ variant_def_id: hir::def_id::DefId,
+ },
+}
+
+#[derive(Debug)]
+enum CalledMethod {
+ OptionIsSome,
+ ResultIsOk,
+}
+
+/// The result of checking a `map` call, returned by `OffendingFilterExpr::check_map_call`
+#[derive(Debug)]
+enum CheckResult<'tcx> {
+ Method {
+ map_arg: &'tcx Expr<'tcx>,
+ /// The method that was called inside of `filter`
+ method: CalledMethod,
+ /// See `OffendingFilterExpr::IsSome`
+ side_effect_expr_span: Option<Span>,
+ },
+ PatternMatching {
+ /// The span of the variant being matched
+ /// if let Some(s) = enum
+ /// ^^^^^^^
+ variant_span: Span,
+ /// if let Some(s) = enum
+ /// ^
+ variant_ident: Ident,
+ },
+}
+
+impl<'tcx> OffendingFilterExpr<'tcx> {
+ pub fn check_map_call(
+ &mut self,
+ cx: &LateContext<'tcx>,
+ map_body: &'tcx Body<'tcx>,
+ map_param_id: HirId,
+ filter_param_id: HirId,
+ is_filter_param_ref: bool,
+ ) -> Option<CheckResult<'tcx>> {
+ match *self {
+ OffendingFilterExpr::IsSome {
+ receiver,
+ side_effect_expr_span,
+ }
+ | OffendingFilterExpr::IsOk {
+ receiver,
+ side_effect_expr_span,
+ } => {
+ // check if closure ends with expect() or unwrap()
+ if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind
+ && matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or)
+ // .map(|y| f(y).copied().unwrap())
+ // ~~~~
+ && let map_arg_peeled = match map_arg.kind {
+ ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
+ original_arg
+ },
+ _ => map_arg,
+ }
+ // .map(|y| y[.acceptable_method()].unwrap())
+ && let simple_equal = (path_to_local_id(receiver, filter_param_id)
+ && 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 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)
+ && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
+ })
+ && (simple_equal
+ || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(receiver, map_arg_peeled))
+ {
+ Some(CheckResult::Method {
+ map_arg,
+ side_effect_expr_span,
+ method: match self {
+ OffendingFilterExpr::IsSome { .. } => CalledMethod::OptionIsSome,
+ OffendingFilterExpr::IsOk { .. } => CalledMethod::ResultIsOk,
+ OffendingFilterExpr::Matches { .. } => unreachable!("only IsSome and IsOk can get here"),
+ }
+ })
+ } else {
+ None
+ }
+ },
+ OffendingFilterExpr::Matches { variant_def_id } => {
+ let expr_uses_local = |pat: &Pat<'_>, expr: &Expr<'_>| {
+ if let PatKind::TupleStruct(QPath::Resolved(_, path), [subpat], _) = pat.kind
+ && let PatKind::Binding(_, local_id, ident, _) = subpat.kind
+ && path_to_local_id(expr.peel_blocks(), local_id)
+ && let Some(local_variant_def_id) = path.res.opt_def_id()
+ && local_variant_def_id == variant_def_id
+ {
+ Some((ident, pat.span))
+ } else {
+ None
+ }
+ };
+
+ // look for:
+ // `if let Variant (v) = enum { v } else { unreachable!() }`
+ // ^^^^^^^ ^ ^^^^ ^^^^^^^^^^^^^^^^^^
+ // variant_span variant_ident scrutinee else_ (blocks peeled later)
+ // OR
+ // `match enum { Variant (v) => v, _ => unreachable!() }`
+ // ^^^^ ^^^^^^^ ^ ^^^^^^^^^^^^^^
+ // scrutinee variant_span variant_ident else_
+ let (scrutinee, else_, variant_ident, variant_span) =
+ match higher::IfLetOrMatch::parse(cx, map_body.value) {
+ // For `if let` we want to check that the variant matching arm references the local created by its pattern
+ Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_)))
+ if let Some((ident, span)) = expr_uses_local(pat, then) =>
+ {
+ (sc, else_, ident, span)
+ },
+ // For `match` we want to check that the "else" arm is the wildcard (`_`) pattern
+ // and that the variant matching arm references the local created by its pattern
+ Some(higher::IfLetOrMatch::Match(sc, [arm, wild_arm], MatchSource::Normal))
+ if let PatKind::Wild = wild_arm.pat.kind
+ && let Some((ident, span)) = expr_uses_local(arm.pat, arm.body.peel_blocks()) =>
+ {
+ (sc, wild_arm.body, ident, span)
+ },
+ _ => return None,
+ };
+
+ if path_to_local_id(scrutinee, map_param_id)
+ // else branch should be a `panic!` or `unreachable!` macro call
+ && let Some(mac) = root_macro_call(else_.peel_blocks().span)
+ && (is_panic(cx, mac.def_id) || cx.tcx.opt_item_name(mac.def_id) == Some(sym::unreachable))
+ {
+ Some(CheckResult::PatternMatching { variant_span, variant_ident })
+ } else {
+ None
+ }
+ },
+ }
+ }
+
+ fn hir(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, filter_param_id: HirId) -> Option<Self> {
+ if let ExprKind::MethodCall(path, receiver, [], _) = expr.kind
+ && let Some(recv_ty) = cx.typeck_results().expr_ty(receiver).peel_refs().ty_adt_def()
+ {
+ // we still want to lint if the expression possibly contains side effects,
+ // *but* it can't be machine-applicable then, because that can change the behavior of the program:
+ // .filter(|x| effect(x).is_some()).map(|x| effect(x).unwrap())
+ // vs.
+ // .filter_map(|x| effect(x))
+ //
+ // the latter only calls `effect` once
+ let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span);
+
+ if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did())
+ && path.ident.name == sym!(is_some)
+ {
+ Some(Self::IsSome { receiver, side_effect_expr_span })
+ } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did())
+ && path.ident.name == sym!(is_ok)
+ {
+ Some(Self::IsOk { receiver, side_effect_expr_span })
+ } else {
+ None
+ }
+ } else if let Some(macro_call) = root_macro_call(expr.span)
+ && cx.tcx.get_diagnostic_name(macro_call.def_id) == Some(sym::matches_macro)
+ // we know for a fact that the wildcard pattern is the second arm
+ && let ExprKind::Match(scrutinee, [arm, _], _) = expr.kind
+ && path_to_local_id(scrutinee, filter_param_id)
+ && let PatKind::TupleStruct(QPath::Resolved(_, path), ..) = arm.pat.kind
+ && let Some(variant_def_id) = path.res.opt_def_id()
+ {
+ Some(OffendingFilterExpr::Matches { variant_def_id })
+ } else {
+ None
+ }
+ }
+}
+
/// is `filter(|x| x.is_some()).map(|x| x.unwrap())`
fn is_filter_some_map_unwrap(
cx: &LateContext<'_>,
@@ -104,55 +312,18 @@ pub(super) fn check(
} else {
(filter_param.pat, false)
};
- // closure ends with is_some() or is_ok()
+
if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
- if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
- if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
- if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
- Some(false)
- } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) {
- Some(true)
- } else {
- None
- };
- if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
+ if let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id);
- // ...map(|x| ...unwrap())
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;
- // closure ends with expect() or unwrap()
- if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
- if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
-
- // .filter(..).map(|y| f(y).copied().unwrap())
- // ~~~~
- let map_arg_peeled = match map_arg.kind {
- ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
- original_arg
- },
- _ => map_arg,
- };
- // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap())
- let simple_equal = path_to_local_id(filter_arg, filter_param_id)
- && path_to_local_id(map_arg_peeled, map_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 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 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)
- && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
- };
-
- if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled);
then {
let span = filter_span.with_hi(expr.span.hi());
let (filter_name, lint) = if is_find {
@@ -161,22 +332,53 @@ pub(super) fn check(
("filter", MANUAL_FILTER_MAP)
};
let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`");
- let (to_opt, deref) = if is_result {
- (".ok()", String::new())
- } else {
- let derefs = cx.typeck_results()
- .expr_adjustments(map_arg)
- .iter()
- .filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
- .count();
- ("", "*".repeat(derefs))
+ 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))
+ }
+ };
+
+ 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)
+ };
+
+ (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)
+ }
};
- let sugg = format!(
- "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})",
- snippet(cx, map_arg.span, ".."),
- );
- span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, 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);
+ }
+ });
}
}
}
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
new file mode 100644
index 000000000..fafc97097
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
@@ -0,0 +1,53 @@
+use super::FILTER_MAP_BOOL_THEN;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::paths::BOOL_THEN;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::is_copy;
+use clippy_utils::{is_from_proc_macro, is_trait_method, match_def_path, peel_blocks};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::Binder;
+use rustc_span::{sym, Span};
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) {
+ if !in_external_macro(cx.sess(), expr.span)
+ && is_trait_method(cx, expr, sym::Iterator)
+ && let ExprKind::Closure(closure) = arg.kind
+ && let body = cx.tcx.hir().body(closure.body)
+ && let value = peel_blocks(body.value)
+ // Indexing should be fine as `filter_map` always has 1 input, we unfortunately need both
+ // `inputs` and `params` here as we need both the type and the span
+ && let param_ty = closure.fn_decl.inputs[0]
+ && let param = body.params[0]
+ // Issue #11309
+ && let param_ty = cx.tcx.liberate_late_bound_regions(
+ 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)),
+ ),
+ )
+ && is_copy(cx, param_ty)
+ && let ExprKind::MethodCall(_, recv, [then_arg], _) = value.kind
+ && let ExprKind::Closure(then_closure) = then_arg.kind
+ && let then_body = peel_blocks(cx.tcx.hir().body(then_closure.body).value)
+ && let Some(def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id)
+ && match_def_path(cx, def_id, &BOOL_THEN)
+ && !is_from_proc_macro(cx, expr)
+ && let Some(param_snippet) = snippet_opt(cx, param.span)
+ && let Some(filter) = snippet_opt(cx, recv.span)
+ && let Some(map) = snippet_opt(cx, then_body.span)
+ {
+ span_lint_and_sugg(
+ cx,
+ FILTER_MAP_BOOL_THEN,
+ call_span,
+ "usage of `bool::then` in `filter_map`",
+ "use `filter` then `map` instead",
+ format!("filter(|&{param_snippet}| {filter}).map(|{param_snippet}| {map})"),
+ Applicability::MachineApplicable,
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
index d1b5e945d..3337b250c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
@@ -3,7 +3,8 @@ use clippy_utils::{is_expr_identity_function, is_trait_method};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_span::{source_map::Span, sym};
+use rustc_span::source_map::Span;
+use rustc_span::sym;
use super::FILTER_MAP_IDENTITY;
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
index 175e04f8a..3f89e5931 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
@@ -31,7 +31,7 @@ pub(super) fn check<'tcx>(
FILTER_MAP_NEXT,
expr.span,
msg,
- "try this",
+ "try",
format!("{iter_snippet}.find_map({filter_snippet})"),
Applicability::MachineApplicable,
);
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 edcec0fc1..ac7bc9bcc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
@@ -1,6 +1,7 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::ty::implements_trait;
+use rustc_ast::{BindingAnnotation, Mutability};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -8,6 +9,21 @@ use rustc_span::sym;
use super::FILTER_NEXT;
+fn path_to_local(expr: &hir::Expr<'_>) -> Option<hir::HirId> {
+ match expr.kind {
+ hir::ExprKind::Field(f, _) => path_to_local(f),
+ hir::ExprKind::Index(recv, _, _) => path_to_local(recv),
+ hir::ExprKind::Path(hir::QPath::Resolved(
+ _,
+ hir::Path {
+ res: rustc_hir::def::Res::Local(local),
+ ..
+ },
+ )) => Some(*local),
+ _ => None,
+ }
+}
+
/// lint use of `filter().next()` for `Iterators`
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
@@ -26,15 +42,30 @@ pub(super) fn check<'tcx>(
if filter_snippet.lines().count() <= 1 {
let iter_snippet = snippet(cx, recv.span, "..");
// add note if not multi-line
- span_lint_and_sugg(
- cx,
- FILTER_NEXT,
- expr.span,
- msg,
- "try this",
- format!("{iter_snippet}.find({filter_snippet})"),
- Applicability::MachineApplicable,
- );
+ 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 hir::PatKind::Binding(BindingAnnotation(_, Mutability::Not), _, ident, _) = pat.kind
+ {
+ (Applicability::Unspecified, Some((pat.span, ident)))
+ } else {
+ (Applicability::MachineApplicable, None)
+ };
+
+ diag.span_suggestion(
+ expr.span,
+ "try",
+ format!("{iter_snippet}.find({filter_snippet})"),
+ applicability,
+ );
+
+ if let Some((pat_span, ident)) = pat {
+ diag.span_help(
+ pat_span,
+ format!("you will also need to make `{ident}` mutable, because `find` takes `&mut self`"),
+ );
+ }
+ });
} else {
span_lint(cx, FILTER_NEXT, expr.span, msg);
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
index 6f911d79d..84a21de0a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
@@ -3,7 +3,8 @@ use clippy_utils::{is_expr_identity_function, is_trait_method};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_span::{source_map::Span, sym};
+use rustc_span::source_map::Span;
+use rustc_span::sym;
use super::FLAT_MAP_IDENTITY;
diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
index 615bde941..172c397fb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
@@ -4,7 +4,8 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_span::{source_map::Span, sym};
+use rustc_span::source_map::Span;
+use rustc_span::sym;
use super::FLAT_MAP_OPTION;
use clippy_utils::ty::is_type_diagnostic_item;
@@ -15,7 +16,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, arg
}
let arg_ty = cx.typeck_results().expr_ty_adjusted(arg);
let sig = match arg_ty.kind() {
- ty::Closure(_, substs) => substs.as_closure().sig(),
+ ty::Closure(_, args) => args.as_closure().sig(),
_ if arg_ty.is_fn() => arg_ty.fn_sig(cx.tcx),
_ => return,
};
diff --git a/src/tools/clippy/clippy_lints/src/methods/format_collect.rs b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
new file mode 100644
index 000000000..1f8863f85
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
@@ -0,0 +1,33 @@
+use super::FORMAT_COLLECT;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::{is_format_macro, root_macro_call_first_node};
+use clippy_utils::ty::is_type_lang_item;
+use rustc_hir::{Expr, ExprKind, LangItem};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+
+/// Same as `peel_blocks` but only actually considers blocks that are not from an expansion.
+/// This is needed because always calling `peel_blocks` would otherwise remove parts of the
+/// `format!` macro, which would cause `root_macro_call_first_node` to return `None`.
+fn peel_non_expn_blocks<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+ match expr.kind {
+ ExprKind::Block(block, _) if !expr.span.from_expansion() => peel_non_expn_blocks(block.expr?),
+ _ => Some(expr),
+ }
+}
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, map_arg: &Expr<'_>, map_span: Span) {
+ if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String)
+ && let ExprKind::Closure(closure) = map_arg.kind
+ && let body = cx.tcx.hir().body(closure.body)
+ && let Some(value) = peel_non_expn_blocks(body.value)
+ && let Some(mac) = root_macro_call_first_node(cx, value)
+ && is_format_macro(cx, mac.def_id)
+ {
+ span_lint_and_then(cx, FORMAT_COLLECT, expr.span, "use of `format!` to build up a string from an iterator", |diag| {
+ diag.span_help(map_span, "call `fold` instead")
+ .span_help(value.span.source_callsite(), "... and use the `write!` macro here")
+ .note("this can be written more efficiently by appending to a `String` directly");
+ });
+ }
+}
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 945bbf53b..ee063adac 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_first.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
@@ -19,7 +19,7 @@ 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).subst_identity().is_slice();
+ if cx.tcx.type_of(impl_id).instantiate_identity().is_slice();
if let Some(_) = is_slice_of_primitives(cx, recv);
if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind;
then {
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
index e35fb12ed..a8f090d1d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
@@ -71,7 +71,7 @@ pub(super) fn check<'tcx>(
GET_UNWRAP,
span,
&format!("called `.get{mut_str}().unwrap()` on a {caller_type}. Using `[]` is more clear and more concise"),
- "try this",
+ "try",
format!(
"{borrow_str}{}[{get_args_str}]",
snippet_with_applicability(cx, recv.span, "..", &mut applicability)
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index 5a78a4168..043425300 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -54,7 +54,7 @@ pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir
.tcx
.impl_of_method(method_def_id)
.filter(|&impl_did| {
- cx.tcx.type_of(impl_did).subst_identity().is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none()
+ cx.tcx.type_of(impl_did).instantiate_identity().is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none()
})
.is_some(),
_ => false,
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 424482859..631741d92 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
@@ -7,7 +7,7 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
-use rustc_span::symbol::{Symbol, sym};
+use rustc_span::symbol::{sym, Symbol};
use super::INEFFICIENT_TO_STRING;
@@ -23,9 +23,9 @@ pub fn check(
if args.is_empty() && method_name == sym::to_string;
if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
- if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id);
+ 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 = substs.type_at(0);
+ 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);
@@ -64,8 +64,8 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
return true;
}
- if let ty::Adt(adt, substs) = ty.kind() {
- cx.tcx.is_diagnostic_item(sym::Cow, adt.did()) && substs.type_at(1).is_str()
+ if let ty::Adt(adt, args) = ty.kind() {
+ cx.tcx.is_diagnostic_item(sym::Cow, adt.did()) && args.type_at(1).is_str()
} else {
false
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs
index 7fd3ef1a6..23cc192c3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs
@@ -2,7 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_trait_method;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_span::{source_map::Span, sym};
+use rustc_span::source_map::Span;
+use rustc_span::sym;
use super::INSPECT_FOR_EACH;
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
index 301aff5ae..120f3d5f4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
@@ -1,10 +1,10 @@
//! Lint for `c.is_digit(10)`
use super::IS_DIGIT_ASCII_RADIX;
+use clippy_utils::consts::{constant_full_int, FullInt};
+use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::{
- consts::constant_full_int, consts::FullInt, diagnostics::span_lint_and_sugg, source::snippet_with_applicability,
-};
+use clippy_utils::source::snippet_with_applicability;
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
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 c87f5daab..674d34517 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
@@ -9,8 +9,7 @@ use clippy_utils::visitors::is_local_used;
use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty;
-use rustc_span::sym;
-use rustc_span::Span;
+use rustc_span::{sym, Span};
/// lint use of:
/// - `hashmap.iter().map(|(_, v)| v)`
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 e2029da80..8f885e9f7 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
@@ -27,7 +27,7 @@ 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 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;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index b4210d875..9f7ec19aa 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -51,7 +51,7 @@ pub(super) fn check<'tcx>(
if let Some(mut snip) = snippet_opt(cx, method_span) {
snip.push_str(trailing_clone);
let replace_span = expr.span.with_lo(cloned_recv.span.hi());
- diag.span_suggestion(replace_span, "try this", snip, Applicability::MachineApplicable);
+ diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable);
}
}
);
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 279175e20..39af52141 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
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_trait_method;
-use clippy_utils::path_to_local;
use clippy_utils::source::snippet;
+use clippy_utils::{is_trait_method, path_to_local};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::{BindingAnnotation, Node, PatKind};
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
new file mode 100644
index 000000000..6b696b42a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
@@ -0,0 +1,34 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::{is_from_proc_macro, is_trait_method};
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::ITER_SKIP_ZERO;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg_expr: &Expr<'_>) {
+ if !expr.span.from_expansion()
+ && is_trait_method(cx, expr, sym::Iterator)
+ && let Some(arg) = constant(cx, cx.typeck_results(), arg_expr).and_then(|constant| {
+ if let Constant::Int(arg) = constant {
+ Some(arg)
+ } else {
+ None
+ }
+ })
+ && arg == 0
+ && !is_from_proc_macro(cx, expr)
+ {
+ span_lint_and_then(cx, ITER_SKIP_ZERO, arg_expr.span, "usage of `.skip(0)`", |diag| {
+ diag.span_suggestion(
+ arg_expr.span,
+ "if you meant to skip the first element, use",
+ "1",
+ Applicability::MaybeIncorrect,
+ )
+ .note("this call to `skip` does nothing and is useless; remove it");
+ });
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs
index f6772c5c6..2ab721ace 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs
@@ -21,7 +21,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span
ITER_WITH_DRAIN,
span.with_hi(expr.span.hi()),
&format!("`drain(..)` used on a `{ty_name}`"),
- "try this",
+ "try",
"into_iter()".to_string(),
Applicability::MaybeIncorrect,
);
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 b9a0ec779..3031193e5 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
@@ -21,7 +21,7 @@ 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 is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Option);
+ 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);
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 a7284c644..540425eef 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
@@ -21,13 +21,13 @@ pub fn check(
return;
}
- let Some(mm) = is_min_or_max(cx, unwrap_arg) else { return };
+ let Some(mm) = is_min_or_max(cx, unwrap_arg) else {
+ return;
+ };
if ty.is_signed() {
- use self::{
- MinMax::{Max, Min},
- Sign::{Neg, Pos},
- };
+ use self::MinMax::{Max, Min};
+ use self::Sign::{Neg, Pos};
let Some(sign) = lit_sign(arith_rhs) else {
return;
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 a08f72540..ab13d30d8 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
@@ -88,7 +88,7 @@ pub(super) fn check(
MANUAL_STR_REPEAT,
collect_expr.span,
"manual implementation of `str::repeat` using iterators",
- "try this",
+ "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 576a58499..dabed0aff 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,15 +1,11 @@
-use clippy_utils::{
- diagnostics::span_lint_and_sugg,
- is_from_proc_macro,
- msrvs::{Msrv, ITERATOR_TRY_FOLD},
- source::snippet_opt,
- ty::implements_trait,
-};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_from_proc_macro;
+use clippy_utils::msrvs::{Msrv, ITERATOR_TRY_FOLD};
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::implements_trait;
use rustc_errors::Applicability;
-use rustc_hir::{
- def::{DefKind, Res},
- Expr, ExprKind,
-};
+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;
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 2b26ef014..880efe60c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_
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).subst_identity(), sym::Option))
+ .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 {
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 a0300d278..01cdd02e6 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
@@ -15,8 +15,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr
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(_, substs) = collect_ret_ty.kind();
- if let Some(result_t) = substs.types().next();
+ 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 {
@@ -25,7 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr
MAP_COLLECT_RESULT_UNIT,
expr.span,
"`.map().collect()` can be replaced with `.try_for_each()`",
- "try this",
+ "try",
format!(
"{}.try_for_each({})",
snippet(cx, iter.span, ".."),
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
index a5beb291f..fbb83c8ce 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
@@ -9,7 +9,7 @@ use super::MAP_ERR_IGNORE;
pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
- && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Result)
+ && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Result)
&& let ExprKind::Closure(&Closure {
capture_clause: CaptureBy::Ref,
body,
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 361ffcb5e..e74a76455 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
@@ -6,7 +6,8 @@ use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_span::{symbol::sym, Span};
+use rustc_span::symbol::sym;
+use rustc_span::Span;
use super::MAP_FLATTEN;
@@ -59,7 +60,7 @@ fn is_map_to_option(cx: &LateContext<'_>, map_arg: &Expr<'_>) -> bool {
match map_closure_ty.kind() {
ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => {
let map_closure_sig = match map_closure_ty.kind() {
- ty::Closure(_, substs) => substs.as_closure().sig(),
+ 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());
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 0f25ef82e..7be1ce483 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
@@ -4,7 +4,8 @@ use clippy_utils::{is_expr_identity_function, is_trait_method};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_span::{source_map::Span, sym};
+use rustc_span::source_map::Span;
+use rustc_span::sym;
use super::MAP_IDENTITY;
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 3122f72ee..5464e455d 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
@@ -11,7 +11,8 @@ use rustc_span::symbol::sym;
use super::MAP_UNWRAP_OR;
/// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s
-/// Return true if lint triggered
+///
+/// Returns true if the lint was emitted
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx hir::Expr<'_>,
@@ -63,7 +64,7 @@ pub(super) fn check<'tcx>(
MAP_UNWRAP_OR,
expr.span,
msg,
- "try this",
+ "try",
format!("{var_snippet}.map_or_else({unwrap_snippet}, {map_snippet})"),
Applicability::MachineApplicable,
);
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 24dbe8c1d..42756b27d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -17,15 +17,16 @@ mod collapsible_str_replace;
mod drain_collect;
mod err_expect;
mod expect_fun_call;
-mod expect_used;
mod extend_with_drain;
mod filetype_is_file;
mod filter_map;
+mod filter_map_bool_then;
mod filter_map_identity;
mod filter_map_next;
mod filter_next;
mod flat_map_identity;
mod flat_map_option;
+mod format_collect;
mod from_iter_instead_of_collect;
mod get_first;
mod get_last_with_len;
@@ -44,6 +45,7 @@ mod iter_nth_zero;
mod iter_on_single_or_empty_collections;
mod iter_overeager_cloned;
mod iter_skip_next;
+mod iter_skip_zero;
mod iter_with_drain;
mod iterator_step_by_zero;
mod manual_next_back;
@@ -72,6 +74,8 @@ mod or_fun_call;
mod or_then_unwrap;
mod path_buf_push_overwrite;
mod range_zip_with_len;
+mod read_line_without_trim;
+mod readonly_write_lock;
mod repeat_once;
mod search_is_some;
mod seek_from_current;
@@ -84,10 +88,12 @@ mod skip_while_next;
mod stable_sort_primitive;
mod str_splitn;
mod string_extend_chars;
+mod string_lit_chars_any;
mod suspicious_command_arg_space;
mod suspicious_map;
mod suspicious_splitn;
mod suspicious_to_owned;
+mod type_id_on_box;
mod uninit_assumed_init;
mod unit_hash;
mod unnecessary_filter_map;
@@ -98,8 +104,7 @@ mod unnecessary_lazy_eval;
mod unnecessary_literal_unwrap;
mod unnecessary_sort_by;
mod unnecessary_to_owned;
-mod unwrap_or_else_default;
-mod unwrap_used;
+mod unwrap_expect_used;
mod useless_asref;
mod utils;
mod vec_resize_to_zero;
@@ -112,7 +117,7 @@ use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::msrvs::{self, Msrv};
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, return_ty};
+use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
@@ -471,29 +476,40 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
- /// Checks for usage of `_.unwrap_or_else(Default::default)` on `Option` and
- /// `Result` values.
+ /// Checks for usages of the following functions with an argument that constructs a default value
+ /// (e.g., `Default::default` or `String::new`):
+ /// - `unwrap_or`
+ /// - `unwrap_or_else`
+ /// - `or_insert`
+ /// - `or_insert_with`
///
/// ### Why is this bad?
- /// Readability, these can be written as `_.unwrap_or_default`, which is
- /// simpler and more concise.
+ /// Readability. Using `unwrap_or_default` in place of `unwrap_or`/`unwrap_or_else`, or `or_default`
+ /// in place of `or_insert`/`or_insert_with`, is simpler and more concise.
+ ///
+ /// ### Known problems
+ /// In some cases, the argument of `unwrap_or`, etc. is needed for type inference. The lint uses a
+ /// heuristic to try to identify such cases. However, the heuristic can produce false negatives.
///
/// ### Examples
/// ```rust
/// # let x = Some(1);
- /// x.unwrap_or_else(Default::default);
- /// x.unwrap_or_else(u32::default);
+ /// # let mut map = std::collections::HashMap::<u64, String>::new();
+ /// x.unwrap_or(Default::default());
+ /// map.entry(42).or_insert_with(String::new);
/// ```
///
/// Use instead:
/// ```rust
/// # let x = Some(1);
+ /// # let mut map = std::collections::HashMap::<u64, String>::new();
/// x.unwrap_or_default();
+ /// map.entry(42).or_default();
/// ```
#[clippy::version = "1.56.0"]
- pub UNWRAP_OR_ELSE_DEFAULT,
+ pub UNWRAP_OR_DEFAULT,
style,
- "using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`"
+ "using `.unwrap_or`, etc. with an argument that constructs a default value"
}
declare_clippy_lint! {
@@ -2927,6 +2943,37 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
+ /// Looks for calls to `<Box<dyn Any> as Any>::type_id`.
+ ///
+ /// ### Why is this bad?
+ /// This most certainly does not do what the user expects and is very easy to miss.
+ /// Calling `type_id` on a `Box<dyn Any>` calls `type_id` on the `Box<..>` itself,
+ /// so this will return the `TypeId` of the `Box<dyn Any>` type (not the type id
+ /// of the value referenced by the box!).
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// use std::any::{Any, TypeId};
+ ///
+ /// let any_box: Box<dyn Any> = Box::new(42_i32);
+ /// assert_eq!(any_box.type_id(), TypeId::of::<i32>()); // ⚠️ this fails!
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// use std::any::{Any, TypeId};
+ ///
+ /// let any_box: Box<dyn Any> = Box::new(42_i32);
+ /// assert_eq!((*any_box).type_id(), TypeId::of::<i32>());
+ /// // ^ dereference first, to call `type_id` on `dyn Any`
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub TYPE_ID_ON_BOX,
+ suspicious,
+ "calling `.type_id()` on `Box<dyn Any>`"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
/// Detects `().hash(_)`.
///
/// ### Why is this bad?
@@ -3316,6 +3363,181 @@ declare_clippy_lint! {
"checks for usage of `Iterator::fold` with a type that implements `Try`"
}
+declare_clippy_lint! {
+ /// Looks for calls to [`Stdin::read_line`] to read a line from the standard input
+ /// into a string, then later attempting to parse this string into a type without first trimming it, which will
+ /// always fail because the string has a trailing newline in it.
+ ///
+ /// ### Why is this bad?
+ /// The `.parse()` call will always fail.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// let mut input = String::new();
+ /// std::io::stdin().read_line(&mut input).expect("Failed to read a line");
+ /// let num: i32 = input.parse().expect("Not a number!");
+ /// assert_eq!(num, 42); // we never even get here!
+ /// ```
+ /// Use instead:
+ /// ```rust,ignore
+ /// let mut input = String::new();
+ /// std::io::stdin().read_line(&mut input).expect("Failed to read a line");
+ /// let num: i32 = input.trim_end().parse().expect("Not a number!");
+ /// // ^^^^^^^^^^^ remove the trailing newline
+ /// assert_eq!(num, 42);
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub READ_LINE_WITHOUT_TRIM,
+ correctness,
+ "calling `Stdin::read_line`, then trying to parse it without first trimming"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for `<string_lit>.chars().any(|i| i == c)`.
+ ///
+ /// ### Why is this bad?
+ /// It's significantly slower than using a pattern instead, like
+ /// `matches!(c, '\\' | '.' | '+')`.
+ ///
+ /// Despite this being faster, this is not `perf` as this is pretty common, and is a rather nice
+ /// way to check if a `char` is any in a set. In any case, this `restriction` lint is available
+ /// for situations where that additional performance is absolutely necessary.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # let c = 'c';
+ /// "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # let c = 'c';
+ /// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub STRING_LIT_CHARS_ANY,
+ restriction,
+ "checks for `<string_lit>.chars().any(|i| i == c)`"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usage of `.map(|_| format!(..)).collect::<String>()`.
+ ///
+ /// ### Why is this bad?
+ /// This allocates a new string for every element in the iterator.
+ /// This can be done more efficiently by creating the `String` once and appending to it in `Iterator::fold`,
+ /// using either the `write!` macro which supports exactly the same syntax as the `format!` macro,
+ /// or concatenating with `+` in case the iterator yields `&str`/`String`.
+ ///
+ /// Note also that `write!`-ing into a `String` can never fail, despite the return type of `write!` being `std::fmt::Result`,
+ /// so it can be safely ignored or unwrapped.
+ ///
+ /// ### Example
+ /// ```rust
+ /// fn hex_encode(bytes: &[u8]) -> String {
+ /// bytes.iter().map(|b| format!("{b:02X}")).collect()
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// use std::fmt::Write;
+ /// fn hex_encode(bytes: &[u8]) -> String {
+ /// bytes.iter().fold(String::new(), |mut output, b| {
+ /// let _ = write!(output, "{b:02X}");
+ /// output
+ /// })
+ /// }
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub FORMAT_COLLECT,
+ perf,
+ "`format!`ing every element in a collection, then collecting the strings into a new `String`"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usage of `.skip(0)` on iterators.
+ ///
+ /// ### Why is this bad?
+ /// This was likely intended to be `.skip(1)` to skip the first element, as `.skip(0)` does
+ /// nothing. If not, the call should be removed.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let v = vec![1, 2, 3];
+ /// let x = v.iter().skip(0).collect::<Vec<_>>();
+ /// let y = v.iter().collect::<Vec<_>>();
+ /// assert_eq!(x, y);
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub ITER_SKIP_ZERO,
+ correctness,
+ "disallows `.skip(0)`"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usage of `bool::then` in `Iterator::filter_map`.
+ ///
+ /// ### Why is this bad?
+ /// This can be written with `filter` then `map` instead, which would reduce nesting and
+ /// separates the filtering from the transformation phase. This comes with no cost to
+ /// performance and is just cleaner.
+ ///
+ /// ### Limitations
+ /// Does not lint `bool::then_some`, as it eagerly evaluates its arguments rather than lazily.
+ /// This can create differing behavior, so better safe than sorry.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # fn really_expensive_fn(i: i32) -> i32 { i }
+ /// # let v = vec![];
+ /// _ = v.into_iter().filter_map(|i| (i % 2 == 0).then(|| really_expensive_fn(i)));
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # fn really_expensive_fn(i: i32) -> i32 { i }
+ /// # let v = vec![];
+ /// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i));
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub FILTER_MAP_BOOL_THEN,
+ style,
+ "checks for usage of `bool::then` in `Iterator::filter_map`"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Looks for calls to `RwLock::write` where the lock is only used for reading.
+ ///
+ /// ### Why is this bad?
+ /// The write portion of `RwLock` is exclusive, meaning that no other thread
+ /// can access the lock while this writer is active.
+ ///
+ /// ### Example
+ /// ```rust
+ /// use std::sync::RwLock;
+ /// fn assert_is_zero(lock: &RwLock<i32>) {
+ /// let num = lock.write().unwrap();
+ /// assert_eq!(*num, 0);
+ /// }
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust
+ /// use std::sync::RwLock;
+ /// fn assert_is_zero(lock: &RwLock<i32>) {
+ /// let num = lock.read().unwrap();
+ /// assert_eq!(*num, 0);
+ /// }
+ /// ```
+ #[clippy::version = "1.73.0"]
+ pub READONLY_WRITE_LOCK,
+ nursery,
+ "acquiring a write lock when a read lock would work"
+}
+
pub struct Methods {
avoid_breaking_exported_api: bool,
msrv: Msrv,
@@ -3346,7 +3568,7 @@ impl_lint_pass!(Methods => [
SHOULD_IMPLEMENT_TRAIT,
WRONG_SELF_CONVENTION,
OK_EXPECT,
- UNWRAP_OR_ELSE_DEFAULT,
+ UNWRAP_OR_DEFAULT,
MAP_UNWRAP_OR,
RESULT_MAP_OR_INTO_OPTION,
OPTION_MAP_OR_NONE,
@@ -3389,6 +3611,7 @@ impl_lint_pass!(Methods => [
STRING_EXTEND_CHARS,
ITER_CLONED_COLLECT,
ITER_WITH_DRAIN,
+ TYPE_ID_ON_BOX,
USELESS_ASREF,
UNNECESSARY_FOLD,
UNNECESSARY_FILTER_MAP,
@@ -3435,6 +3658,7 @@ impl_lint_pass!(Methods => [
REPEAT_ONCE,
STABLE_SORT_PRIMITIVE,
UNIT_HASH,
+ READ_LINE_WITHOUT_TRIM,
UNNECESSARY_SORT_BY,
VEC_RESIZE_TO_ZERO,
VERBOSE_FILE_READS,
@@ -3448,6 +3672,11 @@ impl_lint_pass!(Methods => [
UNNECESSARY_LITERAL_UNWRAP,
DRAIN_COLLECT,
MANUAL_TRY_FOLD,
+ FORMAT_COLLECT,
+ STRING_LIT_CHARS_ANY,
+ ITER_SKIP_ZERO,
+ FILTER_MAP_BOOL_THEN,
+ READONLY_WRITE_LOCK
]);
/// Extracts a method call name, args, and `Span` of the method name.
@@ -3508,11 +3737,11 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
let name = impl_item.ident.name.as_str();
let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
let item = cx.tcx.hir().expect_item(parent);
- let self_ty = cx.tcx.type_of(item.owner_id).subst_identity();
+ let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
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).subst_identity();
+ 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 first_arg_ty_opt = method_sig.inputs().iter().next().copied();
// if this impl block implements a trait, lint in trait definition instead
@@ -3602,8 +3831,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
then {
let first_arg_span = first_arg_ty.span;
let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
- let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
- .self_ty();
+ 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(),
@@ -3620,8 +3848,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
if item.ident.name == sym::new;
if let TraitItemKind::Fn(_, _) = item.kind;
let ret_ty = return_ty(cx, item.owner_id);
- let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
- .self_ty();
+ let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty();
if !ret_ty.contains(self_ty);
then {
@@ -3653,6 +3880,13 @@ impl Methods {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
}
},
+ ("any", [arg]) if let ExprKind::Closure(arg) = arg.kind
+ && let body = cx.tcx.hir().body(arg.body)
+ && let [param] = body.params
+ && let Some(("chars", recv, _, _, _)) = method_call(recv) =>
+ {
+ string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
+ }
("arg", [arg]) => {
suspicious_command_arg_space::check(cx, recv, arg, span);
}
@@ -3669,8 +3903,9 @@ impl Methods {
Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => {
iter_cloned_collect::check(cx, name, expr, recv2);
},
- Some(("map", m_recv, [m_arg], _, _)) => {
+ Some(("map", m_recv, [m_arg], m_ident_span, _)) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg);
+ format_collect::check(cx, expr, m_arg, m_ident_span);
},
Some(("take", take_self_arg, [take_arg], _, _)) => {
if self.msrv.meets(msrvs::STR_REPEAT) {
@@ -3712,13 +3947,27 @@ impl Methods {
match method_call(recv) {
Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
- _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
+ _ => unwrap_expect_used::check(
+ cx,
+ expr,
+ recv,
+ false,
+ self.allow_expect_in_tests,
+ unwrap_expect_used::Variant::Expect,
+ ),
}
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
},
("expect_err", [_]) => {
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
- expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests);
+ unwrap_expect_used::check(
+ cx,
+ expr,
+ recv,
+ true,
+ self.allow_expect_in_tests,
+ unwrap_expect_used::Variant::Expect,
+ );
},
("extend", [arg]) => {
string_extend_chars::check(cx, expr, recv, arg);
@@ -3726,6 +3975,7 @@ impl Methods {
},
("filter_map", [arg]) => {
unnecessary_filter_map::check(cx, expr, arg, name);
+ filter_map_bool_then::check(cx, expr, arg, call_span);
filter_map_identity::check(cx, expr, arg, span);
},
("find_map", [arg]) => {
@@ -3769,11 +4019,9 @@ impl Methods {
unnecessary_join::check(cx, expr, recv, join_arg, span);
}
},
- ("last", []) | ("skip", [_]) => {
- if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
- if let ("cloned", []) = (name2, args2) {
- iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
- }
+ ("last", []) => {
+ if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+ iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
}
},
("lock", []) => {
@@ -3846,6 +4094,9 @@ impl Methods {
("read_to_string", [_]) => {
verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG);
},
+ ("read_line", [arg]) => {
+ read_line_without_trim::check(cx, expr, recv, arg);
+ }
("repeat", [arg]) => {
repeat_once::check(cx, expr, recv, arg);
},
@@ -3871,6 +4122,13 @@ impl Methods {
seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
}
},
+ ("skip", [arg]) => {
+ iter_skip_zero::check(cx, expr, arg);
+
+ if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+ iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
+ }
+ }
("sort", []) => {
stable_sort_primitive::check(cx, expr, recv);
},
@@ -3893,10 +4151,8 @@ impl Methods {
},
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
("take", [_arg]) => {
- if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
- if let ("cloned", []) = (name2, args2) {
- iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
- }
+ if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+ iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
}
},
("take", []) => needless_option_take::check(cx, expr, recv),
@@ -3914,6 +4170,9 @@ impl Methods {
("to_os_string" | "to_path_buf" | "to_vec", []) => {
implicit_clone::check(cx, name, expr, recv);
},
+ ("type_id", []) => {
+ type_id_on_box::check(cx, recv, expr.span);
+ }
("unwrap", []) => {
match method_call(recv) {
Some(("get", recv, [get_arg], _, _)) => {
@@ -3928,11 +4187,25 @@ impl Methods {
_ => {},
}
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
- unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests);
+ unwrap_expect_used::check(
+ cx,
+ expr,
+ recv,
+ false,
+ self.allow_unwrap_in_tests,
+ unwrap_expect_used::Variant::Unwrap,
+ );
},
("unwrap_err", []) => {
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
- unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests);
+ unwrap_expect_used::check(
+ cx,
+ expr,
+ recv,
+ true,
+ self.allow_unwrap_in_tests,
+ unwrap_expect_used::Variant::Unwrap,
+ );
},
("unwrap_or", [u_arg]) => {
match method_call(recv) {
@@ -3949,7 +4222,7 @@ impl Methods {
}
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
},
- ("unwrap_or_default", []) => {
+ ("unwrap_or_default" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => {
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
}
("unwrap_or_else", [u_arg]) => {
@@ -3957,12 +4230,14 @@ impl Methods {
Some(("map", recv, [map_arg], _, _))
if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {},
_ => {
- unwrap_or_else_default::check(cx, expr, recv, u_arg);
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
},
}
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
},
+ ("write", []) => {
+ readonly_write_lock::check(cx, expr, recv);
+ }
("zip", [arg]) => {
if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
&& name.ident.name == sym::iter
@@ -4113,8 +4388,8 @@ impl SelfKind {
} else if ty.is_box() {
ty.boxed_ty() == parent_ty
} else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) {
- if let ty::Adt(_, substs) = ty.kind() {
- substs.types().next().map_or(false, |t| t == parent_ty)
+ if let ty::Adt(_, args) = ty.kind() {
+ args.types().next().map_or(false, |t| t == parent_ty)
} else {
false
}
@@ -4134,7 +4409,7 @@ impl SelfKind {
};
let Some(trait_def_id) = cx.tcx.get_diagnostic_item(trait_sym) else {
- return false
+ return false;
};
implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
index d0aa39d06..2855e23bf 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,5 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{expr_custom_deref_adjustment, ty::is_type_diagnostic_item};
+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};
@@ -15,7 +16,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'
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).subst_identity(), sym::Mutex);
+ if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Mutex);
then {
span_lint_and_sugg(
cx,
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 8ca7af810..dbd965d65 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -4,10 +4,9 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection};
use clippy_utils::{
- can_move_expr_to_closure, get_enclosing_block, get_parent_node, is_trait_method, path_to_local, path_to_local_id,
- CaptureKind,
+ can_move_expr_to_closure, fn_def_id, get_enclosing_block, get_parent_node, higher, is_trait_method, path_to_local,
+ path_to_local_id, CaptureKind,
};
-use clippy_utils::{fn_def_id, higher};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
@@ -163,7 +162,7 @@ fn check_collect_into_intoiterator<'tcx>(
// that contains `collect_expr`
let inputs = cx
.tcx
- .liberate_late_bound_regions(id, cx.tcx.fn_sig(id).subst_identity())
+ .liberate_late_bound_regions(id, cx.tcx.fn_sig(id).instantiate_identity())
.inputs();
// map IntoIterator generic bounds to their signature
@@ -201,7 +200,7 @@ fn check_collect_into_intoiterator<'tcx>(
/// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool`
fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool {
cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| {
- let sig = cx.tcx.fn_sig(id).subst_identity().skip_binder();
+ let sig = cx.tcx.fn_sig(id).instantiate_identity().skip_binder();
sig.inputs().len() == 1 && sig.output().is_bool()
})
}
@@ -215,7 +214,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty:
&& let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty])
&& let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
cx.param_env,
- Ty::new_projection(cx.tcx,into_iter_item_proj.def_id, into_iter_item_proj.substs)
+ Ty::new_projection(cx.tcx,into_iter_item_proj.def_id, into_iter_item_proj.args)
)
{
iter_item_ty == into_iter_item_ty
@@ -229,7 +228,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty:
fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -> bool {
let typeck = cx.typeck_results();
if let Some(id) = typeck.type_dependent_def_id(call_id)
- && let sig = cx.tcx.fn_sig(id).subst_identity()
+ && 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()
@@ -237,11 +236,11 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -
&& let Some(iter_item) = cx.tcx
.associated_items(iter_trait)
.find_by_name_and_kind(cx.tcx, Ident::with_dummy_span(Symbol::intern("Item")), AssocKind::Type, iter_trait)
- && let substs = cx.tcx.mk_substs(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))])
- && let proj_ty = Ty::new_projection(cx.tcx,iter_item.def_id, substs)
+ && let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))])
+ && let proj_ty = Ty::new_projection(cx.tcx,iter_item.def_id, args)
&& let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty)
{
- item_ty == EarlyBinder::bind(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id))
+ item_ty == EarlyBinder::bind(search_ty).instantiate(cx.tcx, cx.typeck_results().node_args(call_id))
} else {
false
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs b/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs
index 7030baf19..eaae8613d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs
@@ -17,7 +17,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name
if is_type_diagnostic_item(cx, outer_ty, sym::Option) && outer_ty == typeck.expr_ty(recv) {
if name == "as_deref_mut" && recv.is_syntactic_place_expr() {
- let Res::Local(binding_id) = path_res(cx, recv) else { return };
+ let Res::Local(binding_id) = path_res(cx, recv) else {
+ return;
+ };
if local_used_after_expr(cx, binding_id, recv) {
return;
@@ -29,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name
NEEDLESS_OPTION_AS_DEREF,
expr.span,
"derefed type is same as origin",
- "try this",
+ "try",
snippet_opt(cx, recv.span).unwrap(),
Applicability::MachineApplicable,
);
diff --git a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
index eada530d6..697eab32a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
@@ -1,5 +1,6 @@
use super::OBFUSCATED_IF_ELSE;
-use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_with_applicability};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
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 646fc4a7b..f2ef42933 100644
--- a/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
@@ -33,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
/// Given a `Result<T, E>` type, return its error type (`E`).
fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
match ty.kind() {
- ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::Result) => substs.types().nth(1),
+ ty::Adt(_, args) if is_type_diagnostic_item(cx, ty, sym::Result) => args.types().nth(1),
_ => None,
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index bd625a691..1c664e76d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -11,7 +11,7 @@ use super::NONSENSICAL_OPEN_OPTIONS;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
- && match_type(cx, cx.tcx.type_of(impl_id).subst_identity(), &paths::OPEN_OPTIONS)
+ && match_type(cx, cx.tcx.type_of(impl_id).instantiate_identity(), &paths::OPEN_OPTIONS)
{
let mut options = Vec::new();
get_open_options(cx, recv, &mut options);
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 41ceef19e..cb6a23068 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
@@ -8,8 +8,7 @@ use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_lint::LateContext;
use rustc_span::symbol::sym;
-use super::OPTION_MAP_OR_NONE;
-use super::RESULT_MAP_OR_INTO_OPTION;
+use super::{OPTION_MAP_OR_NONE, RESULT_MAP_OR_INTO_OPTION};
// The expression inside a closure may or may not have surrounding braces
// which causes problems when generating a suggestion.
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 f4f158c04..fcbe005fb 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
@@ -1,17 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_copy;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
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::ExprKind;
-use rustc_hir::Node;
-use rustc_hir::PatKind;
-use rustc_hir::QPath;
-use rustc_hir::{self, HirId, Path};
+use rustc_hir::{self, ExprKind, HirId, Node, PatKind, Path, QPath};
use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter;
use rustc_span::source_map::Span;
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 7ce28ea93..8b2f57160 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -1,16 +1,17 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::eager_or_lazy::switch_to_lazy_eval;
use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{contains_return, is_trait_item, last_path_segment};
+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_hir as hir;
use rustc_lint::LateContext;
+use rustc_middle::ty;
use rustc_span::source_map::Span;
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::symbol::{self, sym, Symbol};
+use {rustc_ast as ast, rustc_hir as hir};
-use super::OR_FUN_CALL;
+use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT};
/// Checks for the `OR_FUN_CALL` lint.
#[allow(clippy::too_many_lines)]
@@ -24,53 +25,72 @@ pub(super) fn check<'tcx>(
) {
/// Checks for `unwrap_or(T::new())`, `unwrap_or(T::default())`,
/// `or_insert(T::new())` or `or_insert(T::default())`.
+ /// Similarly checks for `unwrap_or_else(T::new)`, `unwrap_or_else(T::default)`,
+ /// `or_insert_with(T::new)` or `or_insert_with(T::default)`.
#[allow(clippy::too_many_arguments)]
fn check_unwrap_or_default(
cx: &LateContext<'_>,
name: &str,
+ receiver: &hir::Expr<'_>,
fun: &hir::Expr<'_>,
- arg: &hir::Expr<'_>,
- or_has_args: bool,
+ call_expr: Option<&hir::Expr<'_>>,
span: Span,
method_span: Span,
) -> bool {
- let is_default_default = || is_trait_item(cx, fun, sym::Default);
+ if !expr_type_is_certain(cx, receiver) {
+ return false;
+ }
- let implements_default = |arg, default_trait_id| {
- let arg_ty = cx.typeck_results().expr_ty(arg);
- implements_trait(cx, arg_ty, default_trait_id, &[])
+ let is_new = |fun: &hir::Expr<'_>| {
+ if let hir::ExprKind::Path(ref qpath) = fun.kind {
+ let path = last_path_segment(qpath).ident.name;
+ matches!(path, sym::new)
+ } else {
+ false
+ }
};
- if_chain! {
- if !or_has_args;
- if let Some(sugg) = match name {
- "unwrap_or" => Some("unwrap_or_default"),
- "or_insert" => Some("or_default"),
- _ => None,
- };
- if let hir::ExprKind::Path(ref qpath) = fun.kind;
- if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
- let path = last_path_segment(qpath).ident.name;
- // needs to target Default::default in particular or be *::new and have a Default impl
- // available
- if (matches!(path, kw::Default) && is_default_default())
- || (matches!(path, sym::new) && implements_default(arg, default_trait_id));
-
- then {
- span_lint_and_sugg(
- cx,
- OR_FUN_CALL,
- method_span.with_hi(span.hi()),
- &format!("use of `{name}` followed by a call to `{path}`"),
- "try this",
- format!("{sugg}()"),
- Applicability::MachineApplicable,
- );
-
- true
+ let output_type_implements_default = |fun| {
+ let fun_ty = cx.typeck_results().expr_ty(fun);
+ if let ty::FnDef(def_id, args) = fun_ty.kind() {
+ let output_ty = cx.tcx.fn_sig(def_id).instantiate(cx.tcx, args).skip_binder().output();
+ cx.tcx
+ .get_diagnostic_item(sym::Default)
+ .map_or(false, |default_trait_id| {
+ implements_trait(cx, output_ty, default_trait_id, &[])
+ })
} else {
false
}
+ };
+
+ let sugg = match (name, call_expr.is_some()) {
+ ("unwrap_or", true) | ("unwrap_or_else", false) => "unwrap_or_default",
+ ("or_insert", true) | ("or_insert_with", false) => "or_default",
+ _ => return false,
+ };
+
+ // needs to target Default::default in particular or be *::new and have a Default impl
+ // available
+ if (is_new(fun) && output_type_implements_default(fun))
+ || match call_expr {
+ Some(call_expr) => is_default_equivalent(cx, call_expr),
+ None => is_default_equivalent_call(cx, fun) || closure_body_returns_empty_to_string(cx, fun),
+ }
+ {
+ span_lint_and_sugg(
+ cx,
+ UNWRAP_OR_DEFAULT,
+ method_span.with_hi(span.hi()),
+ &format!("use of `{name}` to construct default value"),
+ "try",
+ format!("{sugg}()"),
+ Applicability::MachineApplicable,
+ );
+
+ true
+ } else {
+ false
}
}
@@ -139,7 +159,7 @@ pub(super) fn check<'tcx>(
OR_FUN_CALL,
span_replace_word,
&format!("use of `{name}` followed by a function call"),
- "try this",
+ "try",
format!("{name}_{suffix}({sugg})"),
app,
);
@@ -168,11 +188,16 @@ pub(super) fn check<'tcx>(
match inner_arg.kind {
hir::ExprKind::Call(fun, or_args) => {
let or_has_args = !or_args.is_empty();
- if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
+ if or_has_args
+ || !check_unwrap_or_default(cx, name, receiver, fun, Some(inner_arg), expr.span, method_span)
+ {
let fun_span = if or_has_args { None } else { Some(fun.span) };
check_general_case(cx, name, method_span, receiver, arg, None, expr.span, fun_span);
}
},
+ hir::ExprKind::Path(..) | hir::ExprKind::Closure(..) => {
+ check_unwrap_or_default(cx, name, receiver, inner_arg, None, expr.span, method_span);
+ },
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
check_general_case(cx, name, method_span, receiver, arg, None, expr.span, None);
},
@@ -189,3 +214,22 @@ pub(super) fn check<'tcx>(
}
}
}
+
+fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
+ if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
+ let body = cx.tcx.hir().body(body);
+
+ if body.params.is_empty()
+ && let hir::Expr{ kind, .. } = &body.value
+ && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind
+ && ident.name == sym::to_string
+ && let hir::Expr{ kind, .. } = self_arg
+ && let hir::ExprKind::Lit(lit) = kind
+ && let ast::LitKind::Str(symbol::kw::Empty, _) = lit.node
+ {
+ return true;
+ }
+ }
+
+ false
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
index 55ba6e262..7b0bdcf99 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
@@ -1,8 +1,10 @@
+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::{diagnostics::span_lint_and_sugg, is_res_lang_ctor, path_res};
+use clippy_utils::{is_res_lang_ctor, path_res};
use rustc_errors::Applicability;
-use rustc_hir::{lang_items::LangItem, Expr, ExprKind};
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_span::{sym, Span};
@@ -50,7 +52,7 @@ pub(super) fn check<'tcx>(
OR_THEN_UNWRAP,
unwrap_expr.span.with_lo(or_span.lo()),
title,
- "try this",
+ "try",
suggestion,
applicability,
);
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 0284d9dea..1c07d2a3a 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
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
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).subst_identity(), sym::PathBuf);
+ 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());
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 867a3b402..f253d8de9 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, SpanlessEq};
-use clippy_utils::{is_integer_const, is_trait_method};
+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;
diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
new file mode 100644
index 000000000..81f9e2a77
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
@@ -0,0 +1,74 @@
+use std::ops::ControlFlow;
+
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::for_each_local_use_after_expr;
+use clippy_utils::{get_parent_expr, match_def_path};
+use rustc_errors::Applicability;
+use rustc_hir::def::Res;
+use rustc_hir::{Expr, ExprKind, QPath};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty};
+use rustc_span::sym;
+
+use super::READ_LINE_WITHOUT_TRIM;
+
+/// Will a `.parse::<ty>()` call fail if the input has a trailing newline?
+fn parse_fails_on_trailing_newline(ty: Ty<'_>) -> bool {
+ // only allow a very limited set of types for now, for which we 100% know parsing will fail
+ matches!(ty.kind(), ty::Float(_) | ty::Bool | ty::Int(_) | ty::Uint(_))
+}
+
+pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
+ if let Some(recv_adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
+ && match_def_path(cx, recv_adt.did(), &["std", "io", "stdio", "Stdin"])
+ && let ExprKind::Path(QPath::Resolved(_, path)) = arg.peel_borrows().kind
+ && let Res::Local(local_id) = path.res
+ {
+ // We've checked that `call` is a call to `Stdin::read_line()` with the right receiver,
+ // now let's check if the first use of the string passed to `::read_line()` is
+ // parsed into a type that will always fail if it has a trailing newline.
+ for_each_local_use_after_expr(cx, local_id, call.hir_id, |expr| {
+ if let Some(parent) = get_parent_expr(cx, expr)
+ && let ExprKind::MethodCall(segment, .., span) = parent.kind
+ && segment.ident.name == sym!(parse)
+ && let parse_result_ty = cx.typeck_results().expr_ty(parent)
+ && is_type_diagnostic_item(cx, parse_result_ty, sym::Result)
+ && let ty::Adt(_, args) = parse_result_ty.kind()
+ && let Some(ok_ty) = args[0].as_type()
+ && parse_fails_on_trailing_newline(ok_ty)
+ {
+ let local_snippet = snippet(cx, expr.span, "<expr>");
+ span_lint_and_then(
+ cx,
+ READ_LINE_WITHOUT_TRIM,
+ span,
+ "calling `.parse()` without trimming the trailing newline character",
+ |diag| {
+ diag.span_note(call.span, "call to `.read_line()` here, \
+ which leaves a trailing newline character in the buffer, \
+ which in turn will cause `.parse()` to fail");
+
+ diag.span_suggestion(
+ expr.span,
+ "try",
+ format!("{local_snippet}.trim_end()"),
+ Applicability::MachineApplicable,
+ );
+ }
+ );
+ }
+
+ // only consider the first use to prevent this scenario:
+ // ```
+ // let mut s = String::new();
+ // std::io::stdin().read_line(&mut s);
+ // s.pop();
+ // let _x: i32 = s.parse().unwrap();
+ // ```
+ // this is actually fine, because the pop call removes the trailing newline.
+ ControlFlow::<(), ()>::Break(())
+ });
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
new file mode 100644
index 000000000..e3ec921da
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
@@ -0,0 +1,52 @@
+use super::READONLY_WRITE_LOCK;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::mir::{enclosing_mir, visit_local_usage};
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, Node};
+use rustc_lint::LateContext;
+use rustc_middle::mir::{Location, START_BLOCK};
+use rustc_span::sym;
+
+fn is_unwrap_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ if let ExprKind::MethodCall(path, receiver, ..) = expr.kind
+ && path.ident.name == sym::unwrap
+ {
+ is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::Result)
+ } else {
+ false
+ }
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver: &Expr<'_>) {
+ if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::RwLock)
+ && let Node::Expr(unwrap_call_expr) = cx.tcx.hir().get_parent(expr.hir_id)
+ && is_unwrap_call(cx, unwrap_call_expr)
+ && let parent = cx.tcx.hir().get_parent(unwrap_call_expr.hir_id)
+ && let Node::Local(local) = parent
+ && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id)
+ && let Some((local, _)) = mir.local_decls.iter_enumerated().find(|(_, decl)| {
+ local.span.contains(decl.source_info.span)
+ })
+ && let Some(usages) = visit_local_usage(&[local], mir, Location {
+ block: START_BLOCK,
+ statement_index: 0,
+ })
+ && let [usage] = usages.as_slice()
+ {
+ let writer_never_mutated = usage.local_consume_or_mutate_locs.is_empty();
+
+ if writer_never_mutated {
+ span_lint_and_sugg(
+ cx,
+ READONLY_WRITE_LOCK,
+ expr.span,
+ "this write lock is used only for reading",
+ "consider using a read lock instead",
+ format!("{}.read()", snippet(cx, receiver.span, "<receiver>")),
+ Applicability::MaybeIncorrect // write lock might be intentional for enforcing exclusiveness
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
index c028e9543..f3d6a15ed 100644
--- a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
@@ -3,10 +3,10 @@ use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
-use clippy_utils::{
- diagnostics::span_lint_and_sugg, get_trait_def_id, match_def_path, paths, source::snippet_with_applicability,
- ty::implements_trait,
-};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{get_trait_def_id, match_def_path, paths};
use super::SEEK_FROM_CURRENT;
diff --git a/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
index b5fd0ad8c..0f4c97022 100644
--- a/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
@@ -10,7 +10,7 @@ use super::STABLE_SORT_PRIMITIVE;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
- && cx.tcx.type_of(impl_id).subst_identity().is_slice()
+ && cx.tcx.type_of(impl_id).instantiate_identity().is_slice()
&& let Some(slice_type) = is_slice_of_primitives(cx, recv)
{
span_lint_and_then(
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 88a3c2620..7016ad0a8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -55,7 +55,7 @@ fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_
NEEDLESS_SPLITN,
expr.span,
&format!("unnecessary use of `{r}splitn`"),
- "try this",
+ "try",
format!(
"{}.{r}split({})",
snippet_with_context(cx, self_arg.span, expr.span.ctxt(), "..", &mut app).0,
@@ -110,7 +110,7 @@ fn check_manual_split_once(
IterUsageKind::Nth(_) => return,
};
- span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app);
+ span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try", sugg, app);
}
/// checks for
@@ -236,7 +236,7 @@ fn indirect_usage<'tcx>(
!matches!(
node,
Node::Expr(Expr {
- kind: ExprKind::Match(.., MatchSource::TryDesugar),
+ kind: ExprKind::Match(.., MatchSource::TryDesugar(_)),
..
})
)
diff --git a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
index 2c20c6d75..c7885f689 100644
--- a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
@@ -34,7 +34,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
STRING_EXTEND_CHARS,
expr.span,
"calling `.extend(_.chars())`",
- "try this",
+ "try",
format!(
"{}.push_str({ref_str}{})",
snippet_with_applicability(cx, recv.span, "..", &mut applicability),
diff --git a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs
new file mode 100644
index 000000000..70da6ad58
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs
@@ -0,0 +1,58 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{Msrv, MATCHES_MACRO};
+use clippy_utils::source::snippet_opt;
+use clippy_utils::{is_from_proc_macro, is_trait_method, path_to_local};
+use itertools::Itertools;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind, Param, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::STRING_LIT_CHARS_ANY;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'tcx>,
+ recv: &Expr<'_>,
+ param: &'tcx Param<'tcx>,
+ body: &Expr<'_>,
+ msrv: &Msrv,
+) {
+ if msrv.meets(MATCHES_MACRO)
+ && is_trait_method(cx, expr, sym::Iterator)
+ && let PatKind::Binding(_, arg, _, _) = param.pat.kind
+ && let ExprKind::Lit(lit_kind) = recv.kind
+ && let LitKind::Str(val, _) = lit_kind.node
+ && let ExprKind::Binary(kind, lhs, rhs) = body.kind
+ && let BinOpKind::Eq = kind.node
+ && let Some(lhs_path) = path_to_local(lhs)
+ && let Some(rhs_path) = path_to_local(rhs)
+ && let scrutinee = match (lhs_path == arg, rhs_path == arg) {
+ (true, false) => rhs,
+ (false, true) => lhs,
+ _ => return,
+ }
+ && !is_from_proc_macro(cx, expr)
+ && let Some(scrutinee_snip) = snippet_opt(cx, scrutinee.span)
+ {
+ // Normalize the char using `map` so `join` doesn't use `Display`, if we don't then
+ // something like `r"\"` will become `'\'`, which is of course invalid
+ let pat_snip = val.as_str().chars().map(|c| format!("{c:?}")).join(" | ");
+
+ span_lint_and_then(
+ cx,
+ STRING_LIT_CHARS_ANY,
+ expr.span,
+ "usage of `.chars().any(...)` to check if a char matches any from a string literal",
+ |diag| {
+ diag.span_suggestion_verbose(
+ expr.span,
+ "use `matches!(...)` instead",
+ format!("matches!({scrutinee_snip}, {pat_snip})"),
+ Applicability::MachineApplicable,
+ );
+ }
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs
index 73632c5a3..bc8f01767 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::paths;
use clippy_utils::ty::match_type;
-use rustc_ast as ast;
use rustc_errors::{Applicability, Diagnostic};
-use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::Span;
+use {rustc_ast as ast, rustc_hir as hir};
use super::SUSPICIOUS_COMMAND_ARG_SPACE;
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 90ca66bd7..3cb2719e4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
@@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
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).subst_identity();
+ 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.
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 e818f1892..9eb8d6e6e 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
@@ -5,7 +5,8 @@ use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_middle::ty::{self, print::with_forced_trimmed_paths};
+use rustc_middle::ty::print::with_forced_trimmed_paths;
+use rustc_middle::ty::{self};
use rustc_span::sym;
use super::SUSPICIOUS_TO_OWNED;
diff --git a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
new file mode 100644
index 000000000..3404bdfe7
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
@@ -0,0 +1,62 @@
+use crate::methods::TYPE_ID_ON_BOX;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::adjustment::{Adjust, Adjustment};
+use rustc_middle::ty::{self, ExistentialPredicate, Ty};
+use rustc_span::{sym, Span};
+
+fn is_dyn_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
+ if let ty::Dynamic(preds, ..) = ty.kind() {
+ preds.iter().any(|p| match p.skip_binder() {
+ ExistentialPredicate::Trait(tr) => cx.tcx.is_diagnostic_item(sym::Any, tr.def_id),
+ _ => false,
+ })
+ } else {
+ false
+ }
+}
+
+pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span) {
+ let recv_adjusts = cx.typeck_results().expr_adjustments(receiver);
+
+ if let Some(Adjustment { target: recv_ty, .. }) = recv_adjusts.last()
+ && let ty::Ref(_, ty, _) = recv_ty.kind()
+ && let ty::Adt(adt, args) = ty.kind()
+ && adt.is_box()
+ && is_dyn_any(cx, args.type_at(0))
+ {
+ span_lint_and_then(
+ cx,
+ TYPE_ID_ON_BOX,
+ call_span,
+ "calling `.type_id()` on a `Box<dyn Any>`",
+ |diag| {
+ let derefs = recv_adjusts
+ .iter()
+ .filter(|adj| matches!(adj.kind, Adjust::Deref(None)))
+ .count();
+
+ let mut sugg = "*".repeat(derefs + 1);
+ sugg += &snippet(cx, receiver.span, "<expr>");
+
+ diag.note(
+ "this returns the type id of the literal type `Box<dyn Any>` instead of the \
+ type id of the boxed value, which is most likely not what you want"
+ )
+ .note(
+ "if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, \
+ which makes it more clear"
+ )
+ .span_suggestion(
+ receiver.span,
+ "consider dereferencing first",
+ format!("({sugg})"),
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
+ }
+}
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 a1c629473..bc9c518db 100644
--- a/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
@@ -1,5 +1,6 @@
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_path_diagnostic_item, ty::is_uninit_value_valid_for_ty};
+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;
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
index 1cef6226a..fabf3fa0c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -11,8 +11,7 @@ use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::sym;
-use super::UNNECESSARY_FILTER_MAP;
-use super::UNNECESSARY_FIND_MAP;
+use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP};
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>, name: &str) {
if !is_trait_method(cx, expr, sym::Iterator) {
@@ -78,6 +77,16 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc
}
(true, true)
},
+ hir::ExprKind::MethodCall(segment, recv, [arg], _) => {
+ if segment.ident.name == sym!(then_some)
+ && cx.typeck_results().expr_ty(recv).is_bool()
+ && path_to_local_id(arg, arg_id)
+ {
+ (false, true)
+ } else {
+ (true, true)
+ }
+ },
hir::ExprKind::Block(block, _) => block
.expr
.as_ref()
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 8ec15a1c1..6e23754bf 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -8,7 +8,8 @@ use rustc_hir as hir;
use rustc_hir::PatKind;
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_span::{source_map::Span, sym};
+use rustc_span::source_map::Span;
+use rustc_span::sym;
use super::UNNECESSARY_FOLD;
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 52a4ff7d1..0c72c13a3 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
@@ -5,7 +5,8 @@ use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{get_iterator_item_ty, implements_trait};
use clippy_utils::{fn_def_id, get_parent_expr};
use rustc_errors::Applicability;
-use rustc_hir::{def_id::DefId, Expr, ExprKind};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_span::{sym, Symbol};
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 087e1e434..d0c62fb56 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs
@@ -1,4 +1,5 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_lang_item};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::is_type_lang_item;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem};
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
index ea9b894b6..937aac8d2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
@@ -1,4 +1,5 @@
-use clippy_utils::{diagnostics::span_lint_and_then, is_res_lang_ctor, last_path_segment, path_res, MaybePath};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::{is_res_lang_ctor, last_path_segment, path_res, MaybePath};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -32,6 +33,11 @@ pub(super) fn check(
args: &[hir::Expr<'_>],
) {
let init = clippy_utils::expr_or_init(cx, recv);
+ if init.span.from_expansion() {
+ // don't lint if the receiver or binding initializer comes from a macro
+ // (e.g. `let x = option_env!(..); x.unwrap()`)
+ return;
+ }
let (constructor, call_args, ty) = if let hir::ExprKind::Call(call, call_args) = init.kind {
let Some(qpath) = call.qpath_opt() else { return };
@@ -65,6 +71,22 @@ pub(super) fn check(
(expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()),
(expr.span.with_lo(args[0].span.hi()), ")".to_string()),
]),
+ ("Some" | "Ok", "unwrap_unchecked", _) | ("Err", "unwrap_err_unchecked", _) => {
+ let mut suggs = vec![
+ (recv.span.with_hi(call_args[0].span.lo()), String::new()),
+ (expr.span.with_lo(call_args[0].span.hi()), String::new()),
+ ];
+ // try to also remove the unsafe block if present
+ if let hir::Node::Block(block) = cx.tcx.hir().get_parent(expr.hir_id)
+ && let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules
+ {
+ suggs.extend([
+ (block.span.shrink_to_lo().to(expr.span.shrink_to_lo()), String::new()),
+ (expr.span.shrink_to_hi().to(block.span.shrink_to_hi()), String::new())
+ ]);
+ }
+ Some(suggs)
+ },
("None", "unwrap_or_default", _) => {
let ty = cx.typeck_results().expr_ty(expr);
let default_ty_string = if let ty::Adt(def, ..) = ty.kind() {
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 67618f703..e62a65a27 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
@@ -6,7 +6,7 @@ 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;
-use rustc_middle::ty::{self, subst::GenericArgKind};
+use rustc_middle::ty::{self, GenericArgKind};
use rustc_span::sym;
use rustc_span::symbol::Ident;
use std::iter;
@@ -118,7 +118,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp
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).subst_identity().is_slice();
+ 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 &[
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 6bd5e9e88..5c5ee2620 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
@@ -7,16 +7,20 @@ use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid
use clippy_utils::visitors::find_all_ret_expressions;
use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
use rustc_errors::Applicability;
-use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, Node};
use rustc_hir_typeck::{FnCtxt, Inherited};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, ClauseKind, EarlyBinder, ParamTy, ProjectionPredicate, TraitPredicate, Ty};
+use rustc_middle::ty::{
+ self, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate,
+ TraitPredicate, Ty,
+};
use rustc_span::{sym, Symbol};
-use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
+use rustc_trait_selection::traits::{Obligation, ObligationCause};
use super::UNNECESSARY_TO_OWNED;
@@ -250,8 +254,8 @@ fn check_other_call_arg<'tcx>(
) -> bool {
if_chain! {
if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
- if let Some((callee_def_id, _, recv, call_args)) = get_callee_substs_and_args(cx, maybe_call);
- let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
+ 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);
@@ -315,26 +319,31 @@ fn skip_addr_of_ancestors<'tcx>(
}
/// Checks whether an expression is a function or method call and, if so, returns its `DefId`,
-/// `Substs`, and arguments.
-fn get_callee_substs_and_args<'tcx>(
+/// `GenericArgs`, and arguments.
+fn get_callee_generic_args_and_args<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'tcx>,
-) -> Option<(DefId, SubstsRef<'tcx>, Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>])> {
+) -> Option<(
+ DefId,
+ GenericArgsRef<'tcx>,
+ Option<&'tcx Expr<'tcx>>,
+ &'tcx [Expr<'tcx>],
+)> {
if_chain! {
if let ExprKind::Call(callee, args) = expr.kind;
let callee_ty = cx.typeck_results().expr_ty(callee);
if let ty::FnDef(callee_def_id, _) = callee_ty.kind();
then {
- let substs = cx.typeck_results().node_substs(callee.hir_id);
- return Some((*callee_def_id, substs, None, args));
+ 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 substs = cx.typeck_results().node_substs(expr.hir_id);
- return Some((method_def_id, substs, Some(recv), args));
+ let generic_args = cx.typeck_results().node_args(expr.hir_id);
+ return Some((method_def_id, generic_args, Some(recv), args));
}
}
None
@@ -388,17 +397,18 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
}
}
Node::Expr(parent_expr) => {
- if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr)
+ if let Some((callee_def_id, call_generic_args, recv, call_args))
+ = get_callee_generic_args_and_args(cx, parent_expr)
{
- // FIXME: the `subst_identity()` below seems incorrect, since we eventually
+ // FIXME: the `instantiate_identity()` below seems incorrect, since we eventually
// call `tcx.try_subst_and_normalize_erasing_regions` further down
// (i.e., we are explicitly not in the identity context).
- let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
+ let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder();
if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
&& let Some(param_ty) = fn_sig.inputs().get(arg_index)
&& let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind()
// https://github.com/rust-lang/rust-clippy/issues/9504 and https://github.com/rust-lang/rust-clippy/issues/10021
- && (*param_index as usize) < call_substs.len()
+ && (*param_index as usize) < call_generic_args.len()
{
if fn_sig
.inputs()
@@ -422,8 +432,8 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
}
});
- let new_subst = cx.tcx.mk_substs_from_iter(
- call_substs.iter()
+ let new_subst = cx.tcx.mk_args_from_iter(
+ call_generic_args.iter()
.enumerate()
.map(|(i, t)|
if i == (*param_index as usize) {
@@ -433,7 +443,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
}));
if trait_predicates.any(|predicate| {
- let predicate = EarlyBinder::bind(predicate).subst(cx.tcx, new_subst);
+ let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, new_subst);
let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
!cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation)
}) {
@@ -500,8 +510,8 @@ fn is_to_string_on_string_like<'a>(
return false;
}
- if let Some(substs) = cx.typeck_results().node_substs_opt(call_expr.hir_id)
- && let [generic_arg] = substs.as_slice()
+ if let Some(args) = cx.typeck_results().node_args_opt(call_expr.hir_id)
+ && let [generic_arg] = args.as_slice()
&& let GenericArgKind::Type(ty) = generic_arg.unpack()
&& let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
&& let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
new file mode 100644
index 000000000..7bd16b473
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
@@ -0,0 +1,83 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::{is_never_like, is_type_diagnostic_item};
+use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, Lint};
+use rustc_middle::ty;
+use rustc_span::sym;
+
+use super::{EXPECT_USED, UNWRAP_USED};
+
+#[derive(Clone, Copy, Eq, PartialEq)]
+pub(super) enum Variant {
+ Unwrap,
+ Expect,
+}
+
+impl Variant {
+ fn method_name(self, is_err: bool) -> &'static str {
+ match (self, is_err) {
+ (Variant::Unwrap, true) => "unwrap_err",
+ (Variant::Unwrap, false) => "unwrap",
+ (Variant::Expect, true) => "expect_err",
+ (Variant::Expect, false) => "expect",
+ }
+ }
+
+ fn lint(self) -> &'static Lint {
+ match self {
+ Variant::Unwrap => UNWRAP_USED,
+ Variant::Expect => EXPECT_USED,
+ }
+ }
+}
+
+/// Lint usage of `unwrap` or `unwrap_err` for `Result` and `unwrap()` for `Option` (and their
+/// `expect` counterparts).
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ recv: &Expr<'_>,
+ is_err: bool,
+ allow_unwrap_in_tests: bool,
+ variant: Variant,
+) {
+ let ty = cx.typeck_results().expr_ty(recv).peel_refs();
+
+ let (kind, none_value, none_prefix) = if is_type_diagnostic_item(cx, ty, sym::Option) && !is_err {
+ ("an `Option`", "None", "")
+ } else if is_type_diagnostic_item(cx, ty, sym::Result)
+ && let ty::Adt(_, substs) = ty.kind()
+ && let Some(t_or_e_ty) = substs[usize::from(!is_err)].as_type()
+ {
+ if is_never_like(t_or_e_ty) {
+ return;
+ }
+
+ ("a `Result`", if is_err { "Ok" } else { "Err" }, "an ")
+ } else {
+ return;
+ };
+
+ let method_suffix = if is_err { "_err" } else { "" };
+
+ if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
+ return;
+ }
+
+ span_lint_and_then(
+ cx,
+ variant.lint(),
+ expr.span,
+ &format!("used `{}()` on {kind} value", variant.method_name(is_err)),
+ |diag| {
+ diag.note(format!("if this value is {none_prefix}`{none_value}`, it will panic"));
+
+ if variant == Variant::Unwrap && is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
+ diag.help(format!(
+ "consider using `expect{method_suffix}()` to provide a better panic message"
+ ));
+ }
+ },
+ );
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs
deleted file mode 100644
index 045f739e6..000000000
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-//! Lint for `some_result_or_option.unwrap_or_else(Default::default)`
-
-use super::UNWRAP_OR_ELSE_DEFAULT;
-use clippy_utils::{
- diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability,
- ty::is_type_diagnostic_item,
-};
-use rustc_ast::ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_lint::LateContext;
-use rustc_span::{sym, symbol};
-
-pub(super) fn check<'tcx>(
- cx: &LateContext<'tcx>,
- expr: &'tcx hir::Expr<'_>,
- recv: &'tcx hir::Expr<'_>,
- u_arg: &'tcx hir::Expr<'_>,
-) {
- // something.unwrap_or_else(Default::default)
- // ^^^^^^^^^- recv ^^^^^^^^^^^^^^^^- u_arg
- // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr
- let recv_ty = cx.typeck_results().expr_ty(recv);
- let is_option = is_type_diagnostic_item(cx, recv_ty, sym::Option);
- let is_result = is_type_diagnostic_item(cx, recv_ty, sym::Result);
-
- if_chain! {
- if is_option || is_result;
- if closure_body_returns_empty_to_string(cx, u_arg) || is_default_equivalent_call(cx, u_arg);
- then {
- let mut applicability = Applicability::MachineApplicable;
-
- span_lint_and_sugg(
- cx,
- UNWRAP_OR_ELSE_DEFAULT,
- expr.span,
- "use of `.unwrap_or_else(..)` to construct default value",
- "try",
- format!(
- "{}.unwrap_or_default()",
- snippet_with_applicability(cx, recv.span, "..", &mut applicability)
- ),
- applicability,
- );
- }
- }
-}
-
-fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
- if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
- let body = cx.tcx.hir().body(body);
-
- if body.params.is_empty()
- && let hir::Expr{ kind, .. } = &body.value
- && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind
- && ident == &symbol::Ident::from_str("to_string")
- && let hir::Expr{ kind, .. } = self_arg
- && let hir::ExprKind::Lit(lit) = kind
- && let LitKind::Str(symbol::kw::Empty, _) = lit.node
- {
- return true;
- }
- }
-
- false
-}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
deleted file mode 100644
index 5e4c3daee..000000000
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
-use rustc_hir as hir;
-use rustc_lint::LateContext;
-use rustc_span::sym;
-
-use super::{EXPECT_USED, UNWRAP_USED};
-
-/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`.
-pub(super) fn check(
- cx: &LateContext<'_>,
- expr: &hir::Expr<'_>,
- recv: &hir::Expr<'_>,
- is_err: bool,
- allow_unwrap_in_tests: bool,
-) {
- let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
-
- let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
- Some((UNWRAP_USED, "an `Option`", "None", ""))
- } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
- Some((UNWRAP_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
- } else {
- None
- };
-
- let method_suffix = if is_err { "_err" } else { "" };
-
- if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
- return;
- }
-
- if let Some((lint, kind, none_value, none_prefix)) = mess {
- let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
- format!(
- "if you don't want to handle the `{none_value}` case gracefully, consider \
- using `expect{method_suffix}()` to provide a better panic message"
- )
- } else {
- format!("if this value is {none_prefix}`{none_value}`, it will panic")
- };
-
- span_lint_and_help(
- cx,
- lint,
- expr.span,
- &format!("used `unwrap{method_suffix}()` on {kind} value"),
- None,
- &help,
- );
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index c1139d84e..b5f810edd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -37,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
USELESS_ASREF,
expr.span,
&format!("this call to `{call_name}` does nothing"),
- "try this",
+ "try",
snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(),
applicability,
);
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index c96d69226..9f1f73e60 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -143,7 +143,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
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).subst_identity();
+ 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 {
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 b0cfc163f..730727186 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
@@ -20,7 +20,7 @@ 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 is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Vec);
+ 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 {
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 d49bb0ca6..c79a1a7b9 100644
--- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
@@ -1,10 +1,9 @@
-use clippy_utils::{diagnostics::span_lint, is_from_proc_macro};
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::is_from_proc_macro;
use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::{
- def::{DefKind, Res},
- intravisit::{walk_item, Visitor},
- GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind,
-};
+use rustc_hir::def::{DefKind, Res};
+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};
@@ -25,7 +24,7 @@ declare_clippy_lint! {
/// ### Example
/// ```rust,ignore
/// for m in movies {
- /// let title = m.t;
+ /// let title = m.t;
/// }
/// ```
/// Use instead:
@@ -130,6 +129,14 @@ impl Visitor<'_> for IdentVisitor<'_, '_> {
return;
}
+ // `struct Array<T, const N: usize>([T; N])`
+ // ^
+ if let Node::GenericParam(generic_param) = node
+ && let GenericParamKind::Const { .. } = generic_param.kind
+ {
+ return;
+ }
+
if is_from_proc_macro(cx, &ident) {
return;
}
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 4dbb79334..c17f00c42 100644
--- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
@@ -46,7 +46,9 @@ declare_lint_pass!(MissingAssertMessage => [MISSING_ASSERT_MESSAGE]);
impl<'tcx> LateLintPass<'tcx> for MissingAssertMessage {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
+ let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
+ return;
+ };
let single_argument = match cx.tcx.get_diagnostic_name(macro_call.def_id) {
Some(sym::assert_macro | sym::debug_assert_macro) => true,
Some(
@@ -61,10 +63,14 @@ impl<'tcx> LateLintPass<'tcx> for MissingAssertMessage {
}
let panic_expn = if single_argument {
- let Some((_, panic_expn)) = find_assert_args(cx, expr, macro_call.expn) else { return };
+ let Some((_, panic_expn)) = find_assert_args(cx, expr, macro_call.expn) else {
+ return;
+ };
panic_expn
} else {
- let Some((_, _, panic_expn)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
+ let Some((_, _, panic_expn)) = find_assert_eq_args(cx, expr, macro_call.expn) else {
+ return;
+ };
panic_expn
};
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 773174679..96d83e114 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
@@ -1,8 +1,11 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_opt};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_opt;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
-use rustc_hir::{def::Res, def_id::DefId, Item, ItemKind, UseKind};
+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_span::Symbol;
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 497514fbc..2f63b9b9f 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
@@ -1,23 +1,17 @@
use std::ops::ControlFlow;
-use clippy_utils::{
- diagnostics::span_lint_and_then,
- is_path_lang_item, paths,
- ty::match_type,
- visitors::{for_each_expr, Visitable},
-};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::match_type;
+use clippy_utils::visitors::{for_each_expr, Visitable};
+use clippy_utils::{is_path_lang_item, paths};
use rustc_ast::LitKind;
use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::Block;
+use rustc_hir::def::{DefKind, Res};
use rustc_hir::{
- def::{DefKind, Res},
- Expr, ImplItemKind, LangItem, Node,
+ Block, Expr, ExprKind, Impl, ImplItem, ImplItemKind, Item, ItemKind, LangItem, Node, QPath, TyKind, VariantData,
};
-use rustc_hir::{ExprKind, Impl, ItemKind, QPath, TyKind};
-use rustc_hir::{ImplItem, Item, VariantData};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::Ty;
-use rustc_middle::ty::TypeckResults;
+use rustc_middle::ty::{Ty, TypeckResults};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span, Symbol};
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index a41d5a9ce..93f6025c7 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -74,7 +74,6 @@ fn is_executable_or_proc_macro(cx: &LateContext<'_>) -> bool {
use rustc_session::config::CrateType;
cx.tcx
- .sess
.crate_types()
.iter()
.any(|t: &CrateType| matches!(t, CrateType::Executable | CrateType::ProcMacro))
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 57ec3a1f1..367cd6bd4 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
@@ -239,7 +239,7 @@ fn check_expr<'tcx>(vis: &mut ReadVisitor<'_, 'tcx>, expr: &'tcx Expr<'_>) -> St
| ExprKind::MethodCall(..)
| ExprKind::Call(_, _)
| ExprKind::Assign(..)
- | ExprKind::Index(_, _)
+ | ExprKind::Index(..)
| ExprKind::Repeat(_, _)
| ExprKind::Struct(_, _, _) => {
walk_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 439cae812..efdc7560e 100644
--- a/src/tools/clippy/clippy_lints/src/module_style.rs
+++ b/src/tools/clippy/clippy_lints/src/module_style.rs
@@ -80,7 +80,9 @@ impl EarlyLintPass for ModStyle {
let files = cx.sess().source_map().files();
- let Some(trim_to_src) = cx.sess().opts.working_dir.local_path() else { return };
+ let Some(trim_to_src) = cx.sess().opts.working_dir.local_path() else {
+ return;
+ };
// `folder_segments` is all unique folder path segments `path/to/foo.rs` gives
// `[path, to]` but not foo
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 e6fd65f00..fe35126aa 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
@@ -1,12 +1,8 @@
-use clippy_utils::{
- diagnostics::span_lint_and_then,
- visitors::{for_each_expr_with_closures, Descend, Visitable},
-};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::visitors::{for_each_expr_with_closures, Descend, Visitable};
use core::ops::ControlFlow::Continue;
-use hir::{
- def::{DefKind, Res},
- BlockCheckMode, ExprKind, QPath, UnOp, Unsafety,
-};
+use hir::def::{DefKind, Res};
+use hir::{BlockCheckMode, ExprKind, QPath, UnOp, Unsafety};
use rustc_ast::Mutability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index 309f67521..5878f8995 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -139,7 +139,7 @@ impl MutableKeyType {
}
fn check_sig(&self, cx: &LateContext<'_>, fn_def_id: LocalDefId, decl: &hir::FnDecl<'_>) {
- let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity();
+ let fn_sig = cx.tcx.fn_sig(fn_def_id).instantiate_identity();
for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) {
self.check_ty_(cx, hir_ty.span, *ty);
}
@@ -150,7 +150,7 @@ impl MutableKeyType {
// generics (because the compiler cannot ensure immutability for unknown types).
fn check_ty_<'tcx>(&self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
let ty = ty.peel_refs();
- if let Adt(def, substs) = ty.kind() {
+ if let Adt(def, args) = ty.kind() {
let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet]
.iter()
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
@@ -158,7 +158,7 @@ impl MutableKeyType {
return;
}
- let subst_ty = substs.type_at(0);
+ let subst_ty = args.type_at(0);
// Determines if a type contains interior mutability which would affect its implementation of
// [`Hash`] or [`Ord`].
if is_interior_mut_ty(cx, subst_ty)
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index e91aac41b..e53e146ec 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -37,6 +37,11 @@ declare_lint_pass!(UnnecessaryMutPassed => [UNNECESSARY_MUT_PASSED]);
impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+ if e.span.from_expansion() {
+ // Issue #11268
+ return;
+ }
+
match e.kind {
ExprKind::Call(fn_expr, arguments) => {
if let ExprKind::Path(ref path) = fn_expr.kind {
@@ -51,8 +56,8 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
},
ExprKind::MethodCall(path, receiver, arguments, _) => {
let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
- let substs = cx.typeck_results().node_substs(e.hir_id);
- let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
+ let args = cx.typeck_results().node_args(e.hir_id);
+ let method_type = cx.tcx.type_of(def_id).instantiate(cx.tcx, args);
check_arguments(
cx,
std::iter::once(receiver).chain(arguments.iter()).collect(),
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 d8647a991..dea432fdb 100644
--- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
+++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
@@ -39,7 +39,9 @@ declare_lint_pass!(DebugAssertWithMutCall => [DEBUG_ASSERT_WITH_MUT_CALL]);
impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
- let Some(macro_call) = root_macro_call_first_node(cx, e) else { return };
+ let Some(macro_call) = root_macro_call_first_node(cx, e) else {
+ return;
+ };
let macro_name = cx.tcx.item_name(macro_call.def_id);
if !matches!(
macro_name.as_str(),
@@ -47,7 +49,9 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall {
) {
return;
}
- let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) else { return };
+ let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) else {
+ return;
+ };
for arg in [lhs, rhs] {
let mut visitor = MutArgVisitor::new(cx);
visitor.visit_expr(arg);
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index 62af42a39..f6b87b071 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -6,9 +6,9 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use clippy_utils::{
- get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt, span_extract_comment,
+ get_parent_node, higher, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt, span_extract_comment,
+ SpanlessEq,
};
-use clippy_utils::{higher, SpanlessEq};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp};
@@ -106,7 +106,7 @@ declare_clippy_lint! {
/// # let mut skip: bool;
/// skip = !must_keep(x, y);
/// ```
- #[clippy::version = "1.69.0"]
+ #[clippy::version = "1.71.0"]
pub NEEDLESS_BOOL_ASSIGN,
complexity,
"setting the same boolean variable in both branches of an if-statement"
@@ -119,7 +119,7 @@ fn condition_needs_parentheses(e: &Expr<'_>) -> bool {
| ExprKind::Call(i, _)
| ExprKind::Cast(i, _)
| ExprKind::Type(i, _)
- | ExprKind::Index(i, _) = inner.kind
+ | ExprKind::Index(i, _, _) = inner.kind
{
if matches!(
i.kind,
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 498e1408e..11bf9e9ca 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
@@ -52,7 +52,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
}
// Only lint immutable refs, because `&mut ref T` may be useful.
- let PatKind::Ref(pat, Mutability::Not) = ref_pat.kind else { return };
+ let PatKind::Ref(pat, Mutability::Not) = ref_pat.kind else {
+ return;
+ };
match pat.kind {
// Check sub_pat got a `ref` keyword (excluding `ref mut`).
diff --git a/src/tools/clippy/clippy_lints/src/needless_else.rs b/src/tools/clippy/clippy_lints/src/needless_else.rs
index 4ff1bf7ff..03bab86c6 100644
--- a/src/tools/clippy/clippy_lints/src/needless_else.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_else.rs
@@ -1,5 +1,5 @@
-use clippy_utils::source::snippet_opt;
-use clippy_utils::{diagnostics::span_lint_and_sugg, source::trim_span};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{snippet_opt, trim_span};
use rustc_ast::ast::{Expr, ExprKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
@@ -51,7 +51,7 @@ impl EarlyLintPass for NeedlessElse {
cx,
NEEDLESS_ELSE,
span,
- "this else branch is empty",
+ "this `else` branch is empty",
"you can remove it",
String::new(),
Applicability::MachineApplicable,
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 c3b633fd6..98bf122fa 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -1,11 +1,10 @@
use rustc_errors::Applicability;
-use rustc_hir::{
- intravisit::{walk_expr, Visitor},
- Closure, Expr, ExprKind, Stmt, StmtKind,
-};
+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_span::{source_map::Span, sym, Symbol};
+use rustc_span::source_map::Span;
+use rustc_span::{sym, Symbol};
use if_chain::if_chain;
@@ -50,7 +49,7 @@ declare_lint_pass!(NeedlessForEach => [NEEDLESS_FOR_EACH]);
impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
let (StmtKind::Expr(expr) | StmtKind::Semi(expr)) = stmt.kind else {
- return
+ return;
};
if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/needless_if.rs b/src/tools/clippy/clippy_lints/src/needless_if.rs
index ad5c3e1dc..1ed7ea6b3 100644
--- a/src/tools/clippy/clippy_lints/src/needless_if.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_if.rs
@@ -1,4 +1,7 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, higher::If, is_from_proc_macro, source::snippet_opt};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::higher::If;
+use clippy_utils::is_from_proc_macro;
+use clippy_utils::source::snippet_opt;
use rustc_errors::Applicability;
use rustc_hir::{ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
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 5a9387b34..948454d13 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -86,7 +86,9 @@ fn contains_let(cond: &Expr<'_>) -> bool {
}
fn stmt_needs_ordered_drop(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
- let StmtKind::Local(local) = stmt.kind else { return false };
+ let StmtKind::Local(local) = stmt.kind else {
+ return false;
+ };
!local.pat.walk_short(|pat| {
if let PatKind::Binding(.., None) = pat.kind {
!needs_ordered_drop(cx, cx.typeck_results().pat_ty(pat))
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 da1b9d999..d17a383e8 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
@@ -1,8 +1,6 @@
-use clippy_utils::{
- diagnostics::span_lint_and_then,
- higher,
- source::{snippet, snippet_with_applicability},
-};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::higher;
+use clippy_utils::source::{snippet, snippet_with_applicability};
use rustc_ast::ast;
use rustc_errors::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
new file mode 100644
index 000000000..7f0a5964a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -0,0 +1,441 @@
+use super::needless_pass_by_value::requires_exact_signature;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::source::snippet;
+use clippy_utils::{get_parent_node, inherits_cfg, is_from_proc_macro, is_self};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor};
+use rustc_hir::{
+ Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind, QPath,
+};
+use rustc_hir_typeck::expr_use_visitor as euv;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_lint::{LateContext, LateLintPass};
+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_span::def_id::LocalDefId;
+use rustc_span::symbol::kw;
+use rustc_span::Span;
+use rustc_target::spec::abi::Abi;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Check if a `&mut` function argument is actually used mutably.
+ ///
+ /// Be careful if the function is publicly reexported as it would break compatibility with
+ /// users of this function.
+ ///
+ /// ### Why is this bad?
+ /// Less `mut` means less fights with the borrow checker. It can also lead to more
+ /// opportunities for parallelization.
+ ///
+ /// ### Example
+ /// ```rust
+ /// fn foo(y: &mut i32) -> i32 {
+ /// 12 + *y
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// fn foo(y: &i32) -> i32 {
+ /// 12 + *y
+ /// }
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub NEEDLESS_PASS_BY_REF_MUT,
+ nursery,
+ "using a `&mut` argument when it's not mutated"
+}
+
+#[derive(Clone)]
+pub struct NeedlessPassByRefMut<'tcx> {
+ avoid_breaking_exported_api: bool,
+ used_fn_def_ids: FxHashSet<LocalDefId>,
+ fn_def_ids_to_maybe_unused_mut: FxIndexMap<LocalDefId, Vec<rustc_hir::Ty<'tcx>>>,
+}
+
+impl NeedlessPassByRefMut<'_> {
+ pub fn new(avoid_breaking_exported_api: bool) -> Self {
+ Self {
+ avoid_breaking_exported_api,
+ used_fn_def_ids: FxHashSet::default(),
+ fn_def_ids_to_maybe_unused_mut: FxIndexMap::default(),
+ }
+ }
+}
+
+impl_lint_pass!(NeedlessPassByRefMut<'_> => [NEEDLESS_PASS_BY_REF_MUT]);
+
+fn should_skip<'tcx>(
+ cx: &LateContext<'tcx>,
+ input: rustc_hir::Ty<'tcx>,
+ ty: Ty<'_>,
+ arg: &rustc_hir::Param<'_>,
+) -> bool {
+ // We check if this a `&mut`. `ref_mutability` returns `None` if it's not a reference.
+ if !matches!(ty.ref_mutability(), Some(Mutability::Mut)) {
+ return true;
+ }
+
+ if is_self(arg) {
+ return true;
+ }
+
+ if let PatKind::Binding(.., name, _) = arg.pat.kind {
+ // If it's a potentially unused variable, we don't check it.
+ if name.name == kw::Underscore || name.as_str().starts_with('_') {
+ return true;
+ }
+ }
+
+ // All spans generated from a proc-macro invocation are the same...
+ is_from_proc_macro(cx, &input)
+}
+
+impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
+ fn check_fn(
+ &mut self,
+ cx: &LateContext<'tcx>,
+ kind: FnKind<'tcx>,
+ decl: &'tcx FnDecl<'tcx>,
+ body: &'tcx Body<'_>,
+ span: Span,
+ fn_def_id: LocalDefId,
+ ) {
+ if span.from_expansion() {
+ return;
+ }
+
+ let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
+ let is_async = match kind {
+ FnKind::ItemFn(.., header) => {
+ let attrs = cx.tcx.hir().attrs(hir_id);
+ if header.abi != Abi::Rust || requires_exact_signature(attrs) {
+ return;
+ }
+ header.is_async()
+ },
+ FnKind::Method(.., sig) => sig.header.is_async(),
+ FnKind::Closure => return,
+ };
+
+ // Exclude non-inherent impls
+ if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
+ if matches!(
+ item.kind,
+ ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
+ ) {
+ return;
+ }
+ }
+
+ let fn_sig = cx.tcx.fn_sig(fn_def_id).instantiate_identity();
+ let fn_sig = cx.tcx.liberate_late_bound_regions(fn_def_id.to_def_id(), fn_sig);
+
+ // If there are no `&mut` argument, no need to go any further.
+ let mut it = decl
+ .inputs
+ .iter()
+ .zip(fn_sig.inputs())
+ .zip(body.params)
+ .filter(|((&input, &ty), arg)| !should_skip(cx, input, ty, arg))
+ .peekable();
+ if it.peek().is_none() {
+ return;
+ }
+ // Collect variables mutably used and spans which will need dereferencings from the
+ // function body.
+ let MutablyUsedVariablesCtxt { mutably_used_vars, .. } = {
+ let mut ctx = MutablyUsedVariablesCtxt {
+ mutably_used_vars: HirIdSet::default(),
+ prev_bind: None,
+ prev_move_to_closure: HirIdSet::default(),
+ aliases: HirIdMap::default(),
+ async_closures: FxHashSet::default(),
+ tcx: cx.tcx,
+ };
+ let infcx = cx.tcx.infer_ctxt().build();
+ euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
+ if is_async {
+ let mut checked_closures = FxHashSet::default();
+ while !ctx.async_closures.is_empty() {
+ let closures = ctx.async_closures.clone();
+ ctx.async_closures.clear();
+ let hir = cx.tcx.hir();
+ for closure in closures {
+ if !checked_closures.insert(closure) {
+ continue;
+ }
+ ctx.prev_bind = None;
+ ctx.prev_move_to_closure.clear();
+ if let Some(body) = hir
+ .find_by_def_id(closure)
+ .and_then(associated_body)
+ .map(|(_, body_id)| hir.body(body_id))
+ {
+ euv::ExprUseVisitor::new(&mut ctx, &infcx, closure, cx.param_env, cx.typeck_results())
+ .consume_body(body);
+ }
+ }
+ }
+ }
+ ctx
+ };
+ for ((&input, &_), arg) in it {
+ // Only take `&mut` arguments.
+ if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind
+ && !mutably_used_vars.contains(&canonical_id)
+ {
+ self.fn_def_ids_to_maybe_unused_mut.entry(fn_def_id).or_default().push(input);
+ }
+ }
+ }
+
+ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+ cx.tcx.hir().visit_all_item_likes_in_crate(&mut FnNeedsMutVisitor {
+ cx,
+ used_fn_def_ids: &mut self.used_fn_def_ids,
+ });
+
+ for (fn_def_id, unused) in self
+ .fn_def_ids_to_maybe_unused_mut
+ .iter()
+ .filter(|(def_id, _)| !self.used_fn_def_ids.contains(def_id))
+ {
+ let show_semver_warning =
+ self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(*fn_def_id);
+
+ let mut is_cfged = None;
+ for input in unused {
+ // If the argument is never used mutably, we emit the warning.
+ let sp = input.span;
+ if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind {
+ let is_cfged = is_cfged.get_or_insert_with(|| inherits_cfg(cx.tcx, *fn_def_id));
+ span_lint_hir_and_then(
+ cx,
+ NEEDLESS_PASS_BY_REF_MUT,
+ cx.tcx.hir().local_def_id_to_hir_id(*fn_def_id),
+ sp,
+ "this argument is a mutable reference, but not used mutably",
+ |diag| {
+ diag.span_suggestion(
+ sp,
+ "consider changing to".to_string(),
+ format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),),
+ Applicability::Unspecified,
+ );
+ if show_semver_warning {
+ diag.warn("changing this function will impact semver compatibility");
+ }
+ if *is_cfged {
+ diag.note("this is cfg-gated and may require further changes");
+ }
+ },
+ );
+ }
+ }
+ }
+ }
+}
+
+struct MutablyUsedVariablesCtxt<'tcx> {
+ mutably_used_vars: HirIdSet,
+ prev_bind: Option<HirId>,
+ prev_move_to_closure: HirIdSet,
+ aliases: HirIdMap<HirId>,
+ async_closures: FxHashSet<LocalDefId>,
+ tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> MutablyUsedVariablesCtxt<'tcx> {
+ fn add_mutably_used_var(&mut self, mut used_id: HirId) {
+ while let Some(id) = self.aliases.get(&used_id) {
+ self.mutably_used_vars.insert(used_id);
+ used_id = *id;
+ }
+ self.mutably_used_vars.insert(used_id);
+ }
+
+ fn would_be_alias_cycle(&self, alias: HirId, mut target: HirId) -> bool {
+ while let Some(id) = self.aliases.get(&target) {
+ if *id == alias {
+ return true;
+ }
+ target = *id;
+ }
+ false
+ }
+
+ fn add_alias(&mut self, alias: HirId, target: HirId) {
+ // This is to prevent alias loop.
+ if alias == target || self.would_be_alias_cycle(alias, target) {
+ return;
+ }
+ self.aliases.insert(alias, target);
+ }
+}
+
+impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
+ fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) {
+ if let euv::Place {
+ base:
+ euv::PlaceBase::Local(vid)
+ | euv::PlaceBase::Upvar(UpvarId {
+ var_path: UpvarPath { hir_id: vid },
+ ..
+ }),
+ base_ty,
+ ..
+ } = &cmt.place
+ {
+ if let Some(bind_id) = self.prev_bind.take() {
+ if bind_id != *vid {
+ self.add_alias(bind_id, *vid);
+ }
+ } else if !self.prev_move_to_closure.contains(vid)
+ && matches!(base_ty.ref_mutability(), Some(Mutability::Mut))
+ {
+ self.add_mutably_used_var(*vid);
+ }
+ self.prev_bind = None;
+ self.prev_move_to_closure.remove(vid);
+ }
+ }
+
+ fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId, borrow: ty::BorrowKind) {
+ self.prev_bind = None;
+ if let euv::Place {
+ base: euv::PlaceBase::Local(vid),
+ base_ty,
+ ..
+ } = &cmt.place
+ {
+ // If this is a mutable borrow, it was obviously used mutably so we add it. However
+ // for `UniqueImmBorrow`, it's interesting because if you do: `array[0] = value` inside
+ // a closure, it'll return this variant whereas if you have just an index access, it'll
+ // return `ImmBorrow`. So if there is "Unique" and it's a mutable reference, we add it
+ // to the mutably used variables set.
+ if borrow == ty::BorrowKind::MutBorrow
+ || (borrow == ty::BorrowKind::UniqueImmBorrow && base_ty.ref_mutability() == Some(Mutability::Mut))
+ {
+ self.add_mutably_used_var(*vid);
+ }
+ } else if borrow == ty::ImmBorrow {
+ // If there is an `async block`, it'll contain a call to a closure which we need to
+ // go into to ensure all "mutate" checks are found.
+ if let Node::Expr(Expr {
+ kind:
+ ExprKind::Call(
+ _,
+ [
+ Expr {
+ kind: ExprKind::Closure(Closure { def_id, .. }),
+ ..
+ },
+ ],
+ ),
+ ..
+ }) = self.tcx.hir().get(cmt.hir_id)
+ {
+ self.async_closures.insert(*def_id);
+ }
+ }
+ }
+
+ fn mutate(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) {
+ self.prev_bind = None;
+ if let euv::Place {
+ projections,
+ base:
+ euv::PlaceBase::Local(vid)
+ | euv::PlaceBase::Upvar(UpvarId {
+ var_path: UpvarPath { hir_id: vid },
+ ..
+ }),
+ ..
+ } = &cmt.place
+ {
+ if !projections.is_empty() {
+ self.add_mutably_used_var(*vid);
+ }
+ }
+ }
+
+ fn copy(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) {
+ self.prev_bind = None;
+ }
+
+ fn fake_read(
+ &mut self,
+ cmt: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
+ cause: FakeReadCause,
+ _id: HirId,
+ ) {
+ if let euv::Place {
+ base:
+ euv::PlaceBase::Upvar(UpvarId {
+ var_path: UpvarPath { hir_id: vid },
+ ..
+ }),
+ ..
+ } = &cmt.place
+ {
+ if let FakeReadCause::ForLet(Some(inner)) = cause {
+ // Seems like we are inside an async function. We need to store the closure `DefId`
+ // to go through it afterwards.
+ self.async_closures.insert(inner);
+ self.add_alias(cmt.hir_id, *vid);
+ self.prev_move_to_closure.insert(*vid);
+ self.prev_bind = None;
+ }
+ }
+ }
+
+ fn bind(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
+ self.prev_bind = Some(id);
+ }
+}
+
+/// A final pass to check for paths referencing this function that require the argument to be
+/// `&mut`, basically if the function is ever used as a `fn`-like argument.
+struct FnNeedsMutVisitor<'a, 'tcx> {
+ cx: &'a LateContext<'tcx>,
+ used_fn_def_ids: &'a mut FxHashSet<LocalDefId>,
+}
+
+impl<'tcx> Visitor<'tcx> for FnNeedsMutVisitor<'_, 'tcx> {
+ type NestedFilter = OnlyBodies;
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.cx.tcx.hir()
+ }
+
+ fn visit_qpath(&mut self, qpath: &'tcx QPath<'tcx>, hir_id: HirId, _: Span) {
+ walk_qpath(self, qpath, hir_id);
+
+ 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)
+ && let Some(parent) = get_parent_node(cx.tcx, expr.hir_id)
+ && let ty::FnDef(def_id, _) = cx.tcx.typeck(cx.tcx.hir().enclosing_body_owner(hir_id)).expr_ty(expr).kind()
+ && let Some(def_id) = def_id.as_local()
+ {
+ if let Node::Expr(e) = parent
+ && let ExprKind::Call(call, _) = e.kind
+ && call.hir_id == expr.hir_id
+ {
+ return;
+ }
+
+ // We don't need to check each argument individually as you cannot coerce a function
+ // taking `&mut` -> `&`, for some reason, so if we've gotten this far we know it's
+ // passed as a `fn`-like argument (or is unified) and should ignore every "unused"
+ // argument entirely
+ used_fn_def_ids.insert(def_id);
+ }
+ }
+}
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 f11d5773d..5ee26966f 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
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
use clippy_utils::ptr::get_spans;
use clippy_utils::source::{snippet, snippet_opt};
use clippy_utils::ty::{
- implements_trait, implements_trait_with_env, is_copy, is_type_diagnostic_item, is_type_lang_item,
+ implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item,
};
use clippy_utils::{get_trait_def_id, is_self, paths};
use if_chain::if_chain;
@@ -10,14 +10,14 @@ use rustc_ast::ast::Attribute;
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
- BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Mutability, Node, PatKind, QPath, TyKind,
+ BindingAnnotation, Body, FnDecl, GenericArg, HirId, HirIdSet, Impl, ItemKind, LangItem, Mutability, Node, PatKind,
+ QPath, TyKind,
};
-use rustc_hir::{HirIdSet, LangItem};
use rustc_hir_typeck::expr_use_visitor as euv;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::FakeReadCause;
-use rustc_middle::ty::{self, TypeVisitableExt, Ty};
+use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::kw;
@@ -140,7 +140,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
ctx
};
- let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity();
+ let fn_sig = cx.tcx.fn_sig(fn_def_id).instantiate_identity();
let fn_sig = cx.tcx.liberate_late_bound_regions(fn_def_id.to_def_id(), fn_sig);
for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params).enumerate() {
@@ -168,9 +168,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
(
preds.iter().any(|t| cx.tcx.is_diagnostic_item(sym::Borrow, t.def_id())),
!preds.is_empty() && {
- let ty_empty_region = Ty::new_imm_ref(cx.tcx,cx.tcx.lifetimes.re_erased, ty);
+ let ty_empty_region = Ty::new_imm_ref(cx.tcx, cx.tcx.lifetimes.re_erased, ty);
preds.iter().all(|t| {
- let ty_params = t.trait_ref.substs.iter().skip(1).collect::<Vec<_>>();
+ let ty_params = t.trait_ref.args.iter().skip(1).collect::<Vec<_>>();
implements_trait(cx, ty_empty_region, t.def_id(), &ty_params)
})
},
@@ -182,7 +182,13 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
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(cx.tcx, cx.param_env, ty, t, [None]));
+ 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;
@@ -289,7 +295,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
}
/// Functions marked with these attributes must have the exact signature.
-fn requires_exact_signature(attrs: &[Attribute]) -> bool {
+pub(crate) fn requires_exact_signature(attrs: &[Attribute]) -> bool {
attrs.iter().any(|attr| {
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
.iter()
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 e2a7ba02a..7b0f7eaf1 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -122,7 +122,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
} else {
return;
};
- if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &arg.kind;
+ 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.ctxt() == inner_expr.span.ctxt();
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 653b1a8a0..cf7cd671d 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -98,14 +98,14 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
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).subst_identity();
+ 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).subst_identity();
+ 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));
@@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
// generics
if_chain! {
if let Some(ref impling_types) = self.impling_types;
- let self_def = cx.tcx.type_of(self_def_id).subst_identity();
+ 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);
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index a4c7da7e4..5f2a324b0 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -1,8 +1,7 @@
use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
-use clippy_utils::peel_blocks;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::has_drop;
-use clippy_utils::{get_parent_node, is_lint_allowed};
+use clippy_utils::{get_parent_node, is_lint_allowed, peel_blocks};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{
@@ -161,7 +160,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
match peel_blocks(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),
+ ExprKind::Index(a, b, _) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b),
ExprKind::Array(v) | ExprKind::Tup(v) => v.iter().all(|val| has_no_effect(cx, val)),
ExprKind::Repeat(inner, _)
| ExprKind::Cast(inner, _)
@@ -264,7 +263,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
return None;
}
match expr.kind {
- ExprKind::Index(a, b) => Some(vec![a, b]),
+ ExprKind::Index(a, b, _) => Some(vec![a, b]),
ExprKind::Binary(ref binop, a, b) if binop.node != BinOpKind::And && binop.node != BinOpKind::Or => {
Some(vec![a, b])
},
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 75f1e9527..243192385 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -15,14 +15,12 @@ use rustc_hir::{
};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass, Lint};
-use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId};
use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, InnerSpan, Span};
use rustc_target::abi::VariantIdx;
-use rustc_middle::mir::interpret::EvalToValTreeResult;
-use rustc_middle::mir::interpret::GlobalId;
// FIXME: this is a correctness problem but there's no suitable
// warn-by-default category.
@@ -154,24 +152,32 @@ fn is_value_unfrozen_raw<'tcx>(
// As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the
// contained value.
ty::Adt(def, ..) if def.is_union() => false,
- ty::Array(ty, _) => {
- val.unwrap_branch().iter().any(|field| inner(cx, *field, ty))
- },
+ ty::Array(ty, _) => val.unwrap_branch().iter().any(|field| inner(cx, *field, ty)),
ty::Adt(def, _) if def.is_union() => false,
- ty::Adt(def, substs) if def.is_enum() => {
+ ty::Adt(def, args) if def.is_enum() => {
let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap();
- let variant_index =
- VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
- fields.iter().copied().zip(
- def.variants()[variant_index]
- .fields
- .iter()
- .map(|field| field.ty(cx.tcx, substs))).any(|(field, ty)| inner(cx, field, ty))
- }
- ty::Adt(def, substs) => {
- val.unwrap_branch().iter().zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, substs))).any(|(field, ty)| inner(cx, *field, ty))
- }
- ty::Tuple(tys) => val.unwrap_branch().iter().zip(tys).any(|(field, ty)| inner(cx, *field, ty)),
+ let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
+ fields
+ .iter()
+ .copied()
+ .zip(
+ def.variants()[variant_index]
+ .fields
+ .iter()
+ .map(|field| field.ty(cx.tcx, args)),
+ )
+ .any(|(field, ty)| inner(cx, field, ty))
+ },
+ ty::Adt(def, args) => val
+ .unwrap_branch()
+ .iter()
+ .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
+ .any(|(field, ty)| inner(cx, *field, ty)),
+ ty::Tuple(tys) => val
+ .unwrap_branch()
+ .iter()
+ .zip(tys)
+ .any(|(field, ty)| inner(cx, *field, ty)),
_ => false,
}
}
@@ -206,33 +212,38 @@ fn is_value_unfrozen_raw<'tcx>(
fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool {
let def_id = body_id.hir_id.owner.to_def_id();
- let substs = ty::InternalSubsts::identity_for_item(cx.tcx, def_id);
- let instance = ty::Instance::new(def_id, substs);
- let cid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None };
+ let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id);
+ let instance = ty::Instance::new(def_id, args);
+ let cid = rustc_middle::mir::interpret::GlobalId {
+ instance,
+ promoted: None,
+ };
let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx);
let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, None);
is_value_unfrozen_raw(cx, result, ty)
}
fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
- let substs = cx.typeck_results().node_substs(hir_id);
+ let args = cx.typeck_results().node_args(hir_id);
- let result = const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, substs), None);
+ let result = const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), None);
is_value_unfrozen_raw(cx, result, ty)
}
-
pub fn const_eval_resolve<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ct: ty::UnevaluatedConst<'tcx>,
span: Option<Span>,
) -> EvalToValTreeResult<'tcx> {
- match ty::Instance::resolve(tcx, param_env, ct.def, ct.substs) {
+ match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) {
Ok(Some(instance)) => {
- let cid = GlobalId { instance, promoted: None };
+ let cid = GlobalId {
+ instance,
+ promoted: None,
+ };
tcx.const_eval_global_id_for_typeck(param_env, cid, span)
- }
+ },
Ok(None) => Err(ErrorHandled::TooGeneric),
Err(err) => Err(ErrorHandled::Reported(err.into())),
}
@@ -286,7 +297,7 @@ declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTER
impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) {
- if let ItemKind::Const(hir_ty, body_id) = it.kind {
+ if let ItemKind::Const(hir_ty, _generics, body_id) = it.kind {
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
if !ignored_macro(cx, it) && is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) {
lint(cx, Source::Item { item: it.span });
@@ -347,7 +358,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
// and, in that case, the definition is *not* generic.
cx.tcx.normalize_erasing_regions(
cx.tcx.param_env(of_trait_def_id),
- cx.tcx.type_of(of_assoc_item).subst_identity(),
+ cx.tcx.type_of(of_assoc_item).instantiate_identity(),
),
))
.is_err();
@@ -392,7 +403,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
// Make sure it is a const item.
let Res::Def(DefKind::Const | DefKind::AssocConst, item_def_id) = cx.qpath_res(qpath, expr.hir_id) else {
- return
+ return;
};
// Climb up to resolve any field access and explicit referencing.
@@ -427,7 +438,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
dereferenced_expr = parent_expr;
},
- ExprKind::Index(e, _) if ptr::eq(&**e, cur_expr) => {
+ ExprKind::Index(e, _, _) if ptr::eq(&**e, cur_expr) => {
// `e[i]` => desugared to `*Index::index(&e, i)`,
// meaning `e` must be referenced.
// no need to go further up since a method call is involved now.
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 9f6917c14..d562047cb 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -91,7 +91,7 @@ struct ExistingName {
struct SimilarNamesLocalVisitor<'a, 'tcx> {
names: Vec<ExistingName>,
cx: &'a EarlyContext<'tcx>,
- lint: &'a NonExpressiveNames,
+ lint: NonExpressiveNames,
/// A stack of scopes containing the single-character bindings in each scope.
single_char_names: Vec<Vec<Ident>>,
@@ -365,7 +365,7 @@ impl EarlyLintPass for NonExpressiveNames {
..
}) = item.kind
{
- do_check(self, cx, &item.attrs, &sig.decl, blk);
+ do_check(*self, cx, &item.attrs, &sig.decl, blk);
}
}
@@ -380,12 +380,12 @@ impl EarlyLintPass for NonExpressiveNames {
..
}) = item.kind
{
- do_check(self, cx, &item.attrs, &sig.decl, blk);
+ do_check(*self, cx, &item.attrs, &sig.decl, blk);
}
}
}
-fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) {
+fn do_check(lint: NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) {
if !attrs.iter().any(|attr| attr.has_name(sym::test)) {
let mut visitor = SimilarNamesLocalVisitor {
names: Vec::new(),
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 7eaa7db78..c5e777c20 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
@@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::{FieldDef, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
+use rustc_middle::ty::{self, GenericArgKind, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::sym;
@@ -90,8 +90,8 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
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.subst_identity().self_ty();
- if let ty::Adt(adt_def, impl_trait_substs) = self_ty.kind();
+ 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();
@@ -104,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
.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_substs);
+ 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 {
@@ -206,10 +206,10 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t
.iter()
.all(|ty| ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait)),
ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, *ty, send_trait),
- ty::Adt(_, substs) => {
+ ty::Adt(_, args) => {
if contains_pointer_like(cx, ty) {
// descends only if ADT contains any raw pointers
- substs.iter().all(|generic_arg| match generic_arg.unpack() {
+ args.iter().all(|generic_arg| match generic_arg.unpack() {
GenericArgKind::Type(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
// Lifetimes and const generics are not solid part of ADT and ignored
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => true,
@@ -224,7 +224,7 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t
}
}
-/// Checks if the type contains any pointer-like types in substs (including nested ones)
+/// Checks if the type contains any pointer-like types in args (including nested ones)
fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> bool {
for ty_node in target_ty.walk() {
if let GenericArgKind::Type(inner_ty) = ty_node.unpack() {
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 2d79a5c90..bd194b935 100644
--- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
+++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
@@ -1,7 +1,5 @@
-use std::{
- fmt,
- hash::{Hash, Hasher},
-};
+use std::fmt;
+use std::hash::{Hash, Hasher};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt;
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 8b77a5c99..3dc652f9d 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
@@ -7,8 +7,7 @@ use rustc_hir::def_id::DefId;
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::subst::{EarlyBinder, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, ConstKind};
+use rustc_middle::ty::{self, ConstKind, EarlyBinder, GenericArgKind, GenericArgsRef};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::{kw, Ident};
use rustc_span::Span;
@@ -90,7 +89,7 @@ impl_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]);
enum FnKind {
Fn,
TraitFn,
- // This is a hack. Ideally we would store a `SubstsRef<'tcx>` type here, but a lint pass must be `'static`.
+ // This is a hack. Ideally we would store a `GenericArgsRef<'tcx>` type here, but a lint pass must be `'static`.
// Substitutions are, however, interned. This allows us to store the pointer as a `usize` when comparing for
// equality.
ImplTraitFn(usize),
@@ -244,12 +243,12 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
})) => {
#[allow(trivial_casts)]
if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into())
- && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::subst_identity)
+ && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::instantiate_identity)
&& let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id
{
(
trait_item_id,
- FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.substs) as *const _ as usize),
+ FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.args) as *const _ as usize),
usize::from(sig.decl.implicit_self.has_implicit_self()),
)
} else {
@@ -289,7 +288,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
ExprKind::Call(callee, args)
if path_def_id(cx, callee).map_or(false, |id| {
id == param.fn_id
- && has_matching_substs(param.fn_kind, typeck.node_substs(callee.hir_id))
+ && has_matching_args(param.fn_kind, typeck.node_args(callee.hir_id))
}) =>
{
if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) {
@@ -300,7 +299,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
ExprKind::MethodCall(_, receiver, args, _)
if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| {
id == param.fn_id
- && has_matching_substs(param.fn_kind, typeck.node_substs(parent.hir_id))
+ && has_matching_args(param.fn_kind, typeck.node_args(parent.hir_id))
}) =>
{
if let Some(idx) = iter::once(receiver).chain(args).position(|arg| arg.hir_id == child_id) {
@@ -381,15 +380,15 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
}
}
-fn has_matching_substs(kind: FnKind, substs: SubstsRef<'_>) -> bool {
+fn has_matching_args(kind: FnKind, args: GenericArgsRef<'_>) -> bool {
match kind {
FnKind::Fn => true,
- FnKind::TraitFn => substs.iter().enumerate().all(|(idx, subst)| match subst.unpack() {
+ FnKind::TraitFn => args.iter().enumerate().all(|(idx, subst)| match subst.unpack() {
GenericArgKind::Lifetime(_) => true,
GenericArgKind::Type(ty) => matches!(*ty.kind(), ty::Param(ty) if ty.index as usize == idx),
GenericArgKind::Const(c) => matches!(c.kind(), ConstKind::Param(c) if c.index as usize == idx),
}),
#[allow(trivial_casts)]
- FnKind::ImplTraitFn(expected_substs) => substs as *const _ as usize == expected_substs,
+ FnKind::ImplTraitFn(expected_args) => args as *const _ as usize == expected_args,
}
}
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 5c240276b..f9108145c 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
@@ -1,26 +1,20 @@
use super::ARITHMETIC_SIDE_EFFECTS;
-use clippy_utils::is_from_proc_macro;
-use clippy_utils::{
- consts::{constant, constant_simple, Constant},
- diagnostics::span_lint,
- is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary,
-};
-use rustc_ast as ast;
+use clippy_utils::consts::{constant, constant_simple, Constant};
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
use rustc_session::impl_lint_pass;
-use rustc_span::{
- source_map::{Span, Spanned},
- Symbol,
-};
+use rustc_span::source_map::{Span, Spanned};
+use rustc_span::Symbol;
+use {rustc_ast as ast, rustc_hir as hir};
const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[
["f32", "f32"],
["f64", "f64"],
- ["std::num::Saturating", "std::num::Saturating"],
- ["std::num::Wrapping", "std::num::Wrapping"],
+ ["std::num::Saturating", "*"],
+ ["std::num::Wrapping", "*"],
["std::string::String", "str"],
];
const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"];
@@ -144,8 +138,10 @@ impl ArithmeticSideEffects {
) {
return;
};
- let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
- let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
+ let (mut actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
+ let (mut actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
+ actual_lhs = expr_or_init(cx, actual_lhs);
+ actual_rhs = expr_or_init(cx, actual_rhs);
let lhs_ty = cx.typeck_results().expr_ty(actual_lhs).peel_refs();
let rhs_ty = cx.typeck_results().expr_ty(actual_rhs).peel_refs();
if self.has_allowed_binary(lhs_ty, rhs_ty) {
@@ -200,7 +196,9 @@ impl ArithmeticSideEffects {
ps: &hir::PathSegment<'tcx>,
receiver: &hir::Expr<'tcx>,
) {
- let Some(arg) = args.first() else { return; };
+ let Some(arg) = args.first() else {
+ return;
+ };
if constant_simple(cx, cx.typeck_results(), receiver).is_some() {
return;
}
@@ -225,7 +223,9 @@ impl ArithmeticSideEffects {
un_expr: &hir::Expr<'tcx>,
un_op: hir::UnOp,
) {
- let hir::UnOp::Neg = un_op else { return; };
+ let hir::UnOp::Neg = un_op else {
+ return;
+ };
if constant(cx, cx.typeck_results(), un_expr).is_some() {
return;
}
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 9bbf385fb..c4572a09d 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
@@ -1,9 +1,8 @@
-use clippy_utils::binop_traits;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::implements_trait;
use clippy_utils::visitors::for_each_expr;
-use clippy_utils::{eq_expr_value, trait_ref_of_method};
+use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method};
use core::ops::ControlFlow;
use if_chain::if_chain;
use rustc_errors::Applicability;
diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
index 1fddf0f50..c146f3ae9 100644
--- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
@@ -40,9 +40,9 @@ fn check_compare(cx: &LateContext<'_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp
if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr {
return;
}
- fetch_int_literal(cx, right)
- .or_else(|| fetch_int_literal(cx, left))
- .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span));
+ if let Some(mask) = fetch_int_literal(cx, right).or_else(|| fetch_int_literal(cx, left)) {
+ check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span);
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
new file mode 100644
index 000000000..abe8df195
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
@@ -0,0 +1,207 @@
+#![allow(clippy::match_same_arms)]
+
+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::source_map::{Span, Spanned};
+
+use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::source::snippet;
+use clippy_utils::SpanlessEq;
+
+use super::{IMPOSSIBLE_COMPARISONS, REDUNDANT_COMPARISONS};
+
+// Extract a comparison between a const and non-const
+// Flip yoda conditionals, turnings expressions like `42 < x` into `x > 42`
+fn comparison_to_const<'tcx>(
+ cx: &LateContext<'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
+ }
+ }
+}
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ and_op: Spanned<BinOpKind>,
+ left_cond: &'tcx Expr<'tcx>,
+ right_cond: &'tcx Expr<'tcx>,
+ span: Span,
+) {
+ if_chain! {
+ // 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 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);
+
+ if left_type == right_type;
+
+ // Check that the same expression is compared in both comparisons
+ if SpanlessEq::new(cx).eq_expr(left_expr, right_expr);
+
+ if !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);
+
+ // 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!(
+ (&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}`"),
+ };
+ span_lint_and_note(
+ cx,
+ IMPOSSIBLE_COMPARISONS,
+ span,
+ "boolean expression will never evaluate to 'true'",
+ None,
+ &note,
+ );
+ };
+ }
+ }
+}
+
+fn left_side_is_useless(left_cmp_op: CmpOp, ordering: Ordering) -> bool {
+ // Special-case for equal constants with an inclusive comparison
+ if ordering == Ordering::Equal {
+ match left_cmp_op {
+ CmpOp::Lt | CmpOp::Gt => false,
+ CmpOp::Le | CmpOp::Ge => true,
+ }
+ } else {
+ match (left_cmp_op.direction(), ordering) {
+ (CmpOpDirection::Lesser, Ordering::Less) => false,
+ (CmpOpDirection::Lesser, Ordering::Equal) => false,
+ (CmpOpDirection::Lesser, Ordering::Greater) => true,
+ (CmpOpDirection::Greater, Ordering::Less) => true,
+ (CmpOpDirection::Greater, Ordering::Equal) => false,
+ (CmpOpDirection::Greater, Ordering::Greater) => false,
+ }
+ }
+}
+
+fn comparison_is_possible(left_cmp_direction: CmpOpDirection, ordering: Ordering) -> bool {
+ match (left_cmp_direction, ordering) {
+ (CmpOpDirection::Lesser, Ordering::Less | Ordering::Equal) => false,
+ (CmpOpDirection::Lesser, Ordering::Greater) => true,
+ (CmpOpDirection::Greater, Ordering::Greater | Ordering::Equal) => false,
+ (CmpOpDirection::Greater, Ordering::Less) => true,
+ }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy)]
+enum CmpOpDirection {
+ Lesser,
+ Greater,
+}
+
+#[derive(Clone, Copy)]
+enum CmpOp {
+ Lt,
+ Le,
+ Ge,
+ Gt,
+}
+
+impl CmpOp {
+ fn reverse(self) -> Self {
+ match self {
+ CmpOp::Lt => CmpOp::Gt,
+ CmpOp::Le => CmpOp::Ge,
+ CmpOp::Ge => CmpOp::Le,
+ CmpOp::Gt => CmpOp::Lt,
+ }
+ }
+
+ fn direction(self) -> CmpOpDirection {
+ match self {
+ CmpOp::Lt => CmpOpDirection::Lesser,
+ CmpOp::Le => CmpOpDirection::Lesser,
+ CmpOp::Ge => CmpOpDirection::Greater,
+ CmpOp::Gt => CmpOpDirection::Greater,
+ }
+ }
+}
+
+impl TryFrom<BinOpKind> for CmpOp {
+ type Error = ();
+
+ fn try_from(bin_op: BinOpKind) -> Result<Self, Self::Error> {
+ match bin_op {
+ BinOpKind::Lt => Ok(CmpOp::Lt),
+ BinOpKind::Le => Ok(CmpOp::Le),
+ BinOpKind::Ge => Ok(CmpOp::Ge),
+ BinOpKind::Gt => Ok(CmpOp::Gt),
+ _ => Err(()),
+ }
+ }
+}
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 78965b7d6..88d566318 100644
--- a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
@@ -1,6 +1,7 @@
+use clippy_utils::ast_utils::is_useless_with_eq_exprs;
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace};
-use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function};
+use clippy_utils::{eq_expr_value, is_in_test_function};
use rustc_hir::{BinOpKind, Expr};
use rustc_lint::LateContext;
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 015f6c14e..5eabb349e 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
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::eq_expr_value;
use clippy_utils::source::snippet_opt;
-use clippy_utils::sugg;
+use clippy_utils::{eq_expr_value, sugg};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index 2cf15adda..4635e1164 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -2,6 +2,7 @@ mod absurd_extreme_comparisons;
mod assign_op_pattern;
mod bit_mask;
mod cmp_owned;
+mod const_comparisons;
mod double_comparison;
mod duration_subsec;
mod eq_op;
@@ -300,6 +301,45 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
+ /// Checks for double comparisons that can never succeed
+ ///
+ /// ### Why is this bad?
+ /// The whole expression can be replaced by `false`,
+ /// which is probably not the programmer's intention
+ ///
+ /// ### Example
+ /// ```rust
+ /// # let status_code = 200;
+ /// if status_code <= 400 && status_code > 500 {}
+ /// ```
+ #[clippy::version = "1.71.0"]
+ pub IMPOSSIBLE_COMPARISONS,
+ correctness,
+ "double comparisons that will never evaluate to `true`"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for ineffective double comparisons against constants.
+ ///
+ /// ### Why is this bad?
+ /// Only one of the comparisons has any effect on the result, the programmer
+ /// probably intended to flip one of the comparison operators, or compare a
+ /// different value entirely.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # let status_code = 200;
+ /// if status_code <= 400 && status_code < 500 {}
+ /// ```
+ #[clippy::version = "1.71.0"]
+ pub REDUNDANT_COMPARISONS,
+ correctness,
+ "double comparisons where one of them can be removed"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
/// Checks for calculation of subsecond microseconds or milliseconds
/// from other `Duration` methods.
///
@@ -742,6 +782,8 @@ impl_lint_pass!(Operators => [
INEFFECTIVE_BIT_MASK,
VERBOSE_BIT_MASK,
DOUBLE_COMPARISONS,
+ IMPOSSIBLE_COMPARISONS,
+ REDUNDANT_COMPARISONS,
DURATION_SUBSEC,
EQ_OP,
OP_REF,
@@ -786,6 +828,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
bit_mask::check(cx, e, op.node, lhs, rhs);
verbose_bit_mask::check(cx, e, op.node, lhs, rhs, self.verbose_bit_mask_threshold);
double_comparison::check(cx, op.node, lhs, rhs, e.span);
+ const_comparisons::check(cx, op, lhs, rhs, e.span);
duration_subsec::check(cx, e, op.node, lhs, rhs);
float_equality_without_abs::check(cx, e, op.node, lhs, rhs);
integer_division::check(cx, e, op.node, lhs, rhs);
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 d7917e86a..932dd470f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
@@ -4,7 +4,9 @@ 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, def_id::DefId, BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, TyKind};
+use rustc_hir::def::Res;
+use rustc_hir::def_id::DefId;
+use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, TyKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
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 377bddeaa..9c7f7e1cd 100644
--- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_direct_expn_of;
-use if_chain::if_chain;
use rustc_ast::ast::{Expr, ExprKind, MethodCall};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
+use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
@@ -36,21 +35,27 @@ declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]);
impl EarlyLintPass for OptionEnvUnwrap {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
- if_chain! {
- if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind;
- if matches!(seg.ident.name, sym::expect | sym::unwrap);
- if let ExprKind::Call(caller, _) = &receiver.kind;
- if is_direct_expn_of(caller.span, "option_env").is_some();
- then {
- span_lint_and_help(
- cx,
- OPTION_ENV_UNWRAP,
- expr.span,
- "this will panic at run-time if the environment variable doesn't exist at compile-time",
- None,
- "consider using the `env!` macro instead"
- );
- }
+ fn lint(cx: &EarlyContext<'_>, span: Span) {
+ span_lint_and_help(
+ cx,
+ OPTION_ENV_UNWRAP,
+ span,
+ "this will panic at run-time if the environment variable doesn't exist at compile-time",
+ None,
+ "consider using the `env!` macro instead",
+ );
}
+
+ if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind &&
+ matches!(seg.ident.name, sym::expect | sym::unwrap) {
+ if let ExprKind::Call(caller, _) = &receiver.kind &&
+ // If it exists, it will be ::core::option::Option::Some("<env var>").unwrap() (A method call in the HIR)
+ is_direct_expn_of(caller.span, "option_env").is_some() {
+ lint(cx, expr.span);
+ } else if let ExprKind::Path(_, caller) = &receiver.kind && // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR)
+ is_direct_expn_of(caller.span, "option_env").is_some() {
+ lint(cx, expr.span);
+ }
+ }
}
}
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 abdccc47f..a7a7f4fd8 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
@@ -6,10 +6,9 @@ use clippy_utils::{
};
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::{
- def::Res, Arm, BindingAnnotation, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp,
-};
+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_span::SyntaxContext;
@@ -156,7 +155,7 @@ fn try_get_option_occurrence<'tcx>(
});
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)))
+ .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,
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 849cd03dd..a049427d8 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
@@ -13,7 +13,7 @@ use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
- /// Checks for usage of `panic!`, `unimplemented!`, `todo!`, `unreachable!` or assertions in a function of type result.
+ /// Checks for usage of `panic!` or assertions in a function of type result.
///
/// ### Why is this bad?
/// For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence panicking macros should be avoided.
@@ -37,7 +37,7 @@ declare_clippy_lint! {
#[clippy::version = "1.48.0"]
pub PANIC_IN_RESULT_FN,
restriction,
- "functions of type `Result<..>` that contain `panic!()`, `todo!()`, `unreachable()`, `unimplemented()` or assertion"
+ "functions of type `Result<..>` that contain `panic!()` or assertion"
}
declare_lint_pass!(PanicInResultFn => [PANIC_IN_RESULT_FN]);
@@ -70,7 +70,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir
};
if matches!(
cx.tcx.item_name(macro_call.def_id).as_str(),
- "unimplemented" | "unreachable" | "panic" | "todo" | "assert" | "assert_eq" | "assert_ne"
+ "panic" | "assert" | "assert_eq" | "assert_ne"
) {
panics.push(macro_call.span);
ControlFlow::Continue(Descend::No)
@@ -83,10 +83,10 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir
cx,
PANIC_IN_RESULT_FN,
impl_span,
- "used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`",
+ "used `panic!()` or assertion in a function that returns `Result`",
move |diag| {
diag.help(
- "`unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing",
+ "`panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing",
);
diag.span_note(panics, "return Err() instead of panicking");
},
diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
index 2f3007658..a72aefe91 100644
--- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
@@ -76,7 +76,9 @@ declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANI
impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
+ let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
+ return;
+ };
if is_panic(cx, macro_call.def_id) {
if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
return;
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 456ded3fc..d9f5d1642 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
@@ -1,7 +1,6 @@
-use clippy_utils::{
- diagnostics::span_lint_and_sugg, is_res_lang_ctor, path_res, peel_hir_expr_refs, peel_ref_operators, sugg,
- ty::is_type_diagnostic_item,
-};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_res_lang_ctor, path_res, peel_hir_expr_refs, peel_ref_operators, sugg};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem};
use rustc_lint::{LateContext, LateLintPass};
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 eab725de1..41513647f 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
@@ -1,5 +1,4 @@
-use std::cmp;
-use std::iter;
+use std::{cmp, iter};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
@@ -143,7 +142,7 @@ impl<'tcx> PassByRefOrValue {
return;
}
- let fn_sig = cx.tcx.fn_sig(def_id).subst_identity();
+ let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity();
let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id));
// Gather all the lifetimes found in the output type which may affect whether
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 32213718b..8009b00b4 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -26,10 +26,10 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::sym;
use rustc_span::symbol::Symbol;
+use rustc_target::spec::abi::Abi;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
-use std::fmt;
-use std::iter;
+use std::{fmt, iter};
declare_clippy_lint! {
/// ### What it does
@@ -164,9 +164,19 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
}
check_mut_from_ref(cx, sig, None);
+
+ if !matches!(sig.header.abi, Abi::Rust) {
+ // Ignore `extern` functions with non-Rust calling conventions
+ return;
+ }
+
for arg in check_fn_args(
cx,
- cx.tcx.fn_sig(item.owner_id).subst_identity().skip_binder().inputs(),
+ cx.tcx
+ .fn_sig(item.owner_id)
+ .instantiate_identity()
+ .skip_binder()
+ .inputs(),
sig.decl.inputs,
&sig.decl.output,
&[],
@@ -219,8 +229,14 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
};
check_mut_from_ref(cx, sig, Some(body));
+
+ if !matches!(sig.header.abi, Abi::Rust) {
+ // Ignore `extern` functions with non-Rust calling conventions
+ return;
+ }
+
let decl = sig.decl;
- let sig = cx.tcx.fn_sig(item_id).subst_identity().skip_binder();
+ let sig = cx.tcx.fn_sig(item_id).instantiate_identity().skip_binder();
let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, &decl.output, body.params)
.filter(|arg| !is_trait_item || arg.mutability() == Mutability::Not)
.collect();
@@ -389,11 +405,12 @@ impl<'tcx> DerefTy<'tcx> {
fn ty(&self, cx: &LateContext<'tcx>) -> Ty<'tcx> {
match *self {
Self::Str => cx.tcx.types.str_,
- Self::Path => Ty::new_adt(cx.tcx,
+ Self::Path => Ty::new_adt(
+ cx.tcx,
cx.tcx.adt_def(cx.tcx.get_diagnostic_item(sym::Path).unwrap()),
List::empty(),
),
- Self::Slice(_, ty) => Ty::new_slice(cx.tcx,ty),
+ Self::Slice(_, ty) => Ty::new_slice(cx.tcx, ty),
}
}
@@ -423,7 +440,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
.enumerate()
.filter_map(move |(i, (ty, hir_ty))| {
if let ty::Ref(_, ty, mutability) = *ty.kind()
- && let ty::Adt(adt, substs) = *ty.kind()
+ && let ty::Adt(adt, args) = *ty.kind()
&& let TyKind::Ref(lt, ref ty) = hir_ty.kind
&& let TyKind::Path(QPath::Resolved(None, path)) = ty.ty.kind
// Check that the name as typed matches the actual name of the type.
@@ -443,7 +460,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
} else {
None
}),
- substs.type_at(0),
+ args.type_at(0),
),
),
_ if Some(adt.did()) == cx.tcx.lang_items().string() => (
@@ -496,7 +513,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
}
let ty_name =
- snippet_opt(cx, ty.span()).unwrap_or_else(|| substs.type_at(1).to_string());
+ snippet_opt(cx, ty.span()).unwrap_or_else(|| args.type_at(1).to_string());
span_lint_hir_and_then(
cx,
@@ -659,7 +676,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
return;
};
- match *self.cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i]
+ match *self.cx.tcx.fn_sig(id).instantiate_identity().skip_binder().inputs()[i]
.peel_refs()
.kind()
{
@@ -678,7 +695,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
}
},
// Indexing is fine for currently supported types.
- ExprKind::Index(e, _) if e.hir_id == child_id => (),
+ ExprKind::Index(e, _, _) if e.hir_id == child_id => (),
_ => set_skip_flag(),
},
_ => set_skip_flag(),
@@ -725,7 +742,7 @@ fn matches_preds<'tcx>(
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.substs.iter()), cx.param_env)
+ .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,
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 47b8891e1..20e032d4b 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
@@ -50,12 +50,12 @@ impl<'tcx> LateLintPass<'tcx> for PtrOffsetWithCast {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// Check if the expressions is a ptr.offset or ptr.wrapping_offset method call
let Some((receiver_expr, arg_expr, method)) = expr_as_ptr_offset_call(cx, expr) else {
- return
+ return;
};
// Check if the argument to the method call is a cast from usize
let Some(cast_lhs_expr) = expr_as_cast_from_usize(cx, arg_expr) else {
- return
+ return;
};
let msg = format!("use of `{method}` with a `usize` casted to an `isize`");
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index e3d940ad2..734ca2914 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -1,21 +1,26 @@
+use crate::manual_let_else::{MatchLintBehaviour, MANUAL_LET_ELSE};
+use crate::question_mark_used::QUESTION_MARK_USED;
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::Msrv;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{
- eq_expr_value, get_parent_node, in_constant, is_else_clause, is_res_lang_ctor, path_to_local, path_to_local_id,
- peel_blocks, peel_blocks_with_stmt,
+ eq_expr_value, get_parent_node, higher, in_constant, is_else_clause, is_lint_allowed, is_path_lang_item,
+ 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 clippy_utils::{higher, is_path_lang_item};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
-use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, Node, PatKind, PathSegment, QPath};
+use rustc_hir::{
+ BindingAnnotation, Block, ByRef, Expr, ExprKind, Local, Node, PatKind, PathSegment, QPath, Stmt, StmtKind,
+};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
-use rustc_session::declare_tool_lint;
-use rustc_session::impl_lint_pass;
-use rustc_span::{sym, symbol::Symbol};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::sym;
+use rustc_span::symbol::Symbol;
declare_clippy_lint! {
/// ### What it does
@@ -42,8 +47,9 @@ declare_clippy_lint! {
"checks for expressions that could be replaced by the question mark operator"
}
-#[derive(Default)]
pub struct QuestionMark {
+ pub(crate) msrv: Msrv,
+ pub(crate) matches_behaviour: MatchLintBehaviour,
/// Keeps track of how many try blocks we are in at any point during linting.
/// This allows us to answer the question "are we inside of a try block"
/// very quickly, without having to walk up the parent chain, by simply checking
@@ -51,7 +57,19 @@ pub struct QuestionMark {
/// As for why we need this in the first place: <https://github.com/rust-lang/rust-clippy/issues/8628>
try_block_depth_stack: Vec<u32>,
}
-impl_lint_pass!(QuestionMark => [QUESTION_MARK]);
+
+impl_lint_pass!(QuestionMark => [QUESTION_MARK, MANUAL_LET_ELSE]);
+
+impl QuestionMark {
+ #[must_use]
+ pub fn new(msrv: Msrv, matches_behaviour: MatchLintBehaviour) -> Self {
+ Self {
+ msrv,
+ matches_behaviour,
+ try_block_depth_stack: Vec::new(),
+ }
+ }
+}
enum IfBlockType<'hir> {
/// An `if x.is_xxx() { a } else { b } ` expression.
@@ -78,6 +96,29 @@ enum IfBlockType<'hir> {
),
}
+fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
+ if let StmtKind::Local(Local { pat, init: Some(init_expr), els: Some(els), .. }) = stmt.kind &&
+ let Block { stmts: &[], expr: Some(els), .. } = els &&
+ let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, els)
+ {
+ let mut applicability = Applicability::MaybeIncorrect;
+ let init_expr_str = snippet_with_applicability(cx, init_expr.span, "..", &mut applicability);
+ let receiver_str = snippet_with_applicability(cx, inner_pat.span, "..", &mut applicability);
+ let sugg = format!(
+ "let {receiver_str} = {init_expr_str}?;",
+ );
+ span_lint_and_sugg(
+ cx,
+ QUESTION_MARK,
+ stmt.span,
+ "this `let...else` may be rewritten with the `?` operator",
+ "replace it with",
+ sugg,
+ applicability,
+ );
+ }
+}
+
fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_>) -> bool {
match *if_block {
IfBlockType::IfIs(caller, caller_ty, call_sym, if_then, _) => {
@@ -259,8 +300,18 @@ fn is_try_block(cx: &LateContext<'_>, bl: &rustc_hir::Block<'_>) -> bool {
}
impl<'tcx> LateLintPass<'tcx> for QuestionMark {
+ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+ if !is_lint_allowed(cx, QUESTION_MARK_USED, stmt.hir_id) {
+ return;
+ }
+
+ if !in_constant(cx, stmt.hir_id) {
+ check_let_some_else_return_none(cx, stmt);
+ }
+ self.check_manual_let_else(cx, stmt);
+ }
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if !in_constant(cx, expr.hir_id) {
+ if !in_constant(cx, expr.hir_id) && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id) {
self.check_is_none_or_err_and_early_return(cx, expr);
self.check_if_let_some_or_err_and_early_return(cx, expr);
}
@@ -291,4 +342,5 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark {
.expect("blocks are always part of bodies and must have a depth") -= 1;
}
}
+ extract_msrv_attr!(LateContext);
}
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 ff66b8a00..d0de33e3c 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark_used.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
@@ -34,7 +34,7 @@ declare_lint_pass!(QuestionMarkUsed => [QUESTION_MARK_USED]);
impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if let ExprKind::Match(_, _, MatchSource::TryDesugar) = expr.kind {
+ if let ExprKind::Match(_, _, MatchSource::TryDesugar(_)) = expr.kind {
if !span_is_local(expr.span) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index d2018aba9..3287675a8 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -1,10 +1,9 @@
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::higher;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
-use clippy_utils::{get_parent_expr, in_constant, is_integer_const, path_to_local};
+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;
diff --git a/src/tools/clippy/clippy_lints/src/raw_strings.rs b/src/tools/clippy/clippy_lints/src/raw_strings.rs
index f45bb1ef3..ccabb577c 100644
--- a/src/tools/clippy/clippy_lints/src/raw_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/raw_strings.rs
@@ -1,10 +1,10 @@
-use std::{iter::once, ops::ControlFlow};
+use std::iter::once;
+use std::ops::ControlFlow;
-use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet};
-use rustc_ast::{
- ast::{Expr, ExprKind},
- token::LitKind,
-};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use rustc_ast::ast::{Expr, ExprKind};
+use rustc_ast::token::LitKind;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
@@ -95,7 +95,7 @@ impl EarlyLintPass for RawStrings {
// `once` so a raw string ending in hashes is still checked
let num = str.as_bytes().iter().chain(once(&0)).try_fold(0u8, |acc, &b| {
match b {
- b'"' => (following_quote, req) = (true, 1),
+ b'"' if !following_quote => (following_quote, req) = (true, 1),
// I'm a bit surprised the compiler didn't optimize this out, there's no
// branch but it still ends up doing an unnecessary comparison, it's:
// - cmp r9b,1h
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 e82aa3a7b..8e85c55e7 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
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::VecArgs;
-use clippy_utils::last_path_segment;
use clippy_utils::macros::root_macro_call_first_node;
-use clippy_utils::paths;
use clippy_utils::source::{indent_of, snippet};
use clippy_utils::ty::match_type;
+use clippy_utils::{last_path_segment, paths};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -50,9 +49,15 @@ declare_lint_pass!(RcCloneInVecInit => [RC_CLONE_IN_VEC_INIT]);
impl LateLintPass<'_> for RcCloneInVecInit {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return; };
- let Some(VecArgs::Repeat(elem, len)) = VecArgs::hir(cx, expr) else { return; };
- let Some((symbol, func_span)) = ref_init(cx, elem) else { return; };
+ let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
+ return;
+ };
+ let Some(VecArgs::Repeat(elem, len)) = VecArgs::hir(cx, expr) else {
+ return;
+ };
+ let Some((symbol, func_span)) = ref_init(cx, elem) else {
+ return;
+ };
emit_lint(cx, symbol, macro_call.span, elem, len, 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 fa1078588..2bf90815c 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
@@ -1,9 +1,7 @@
-use clippy_utils::{
- diagnostics::{span_lint, span_lint_and_sugg},
- higher::{get_vec_init_kind, VecInitKind},
- source::snippet,
- visitors::for_each_expr,
-};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
+use clippy_utils::source::snippet;
+use clippy_utils::visitors::for_each_expr;
use core::ops::ControlFlow;
use hir::{Expr, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind};
use rustc_errors::Applicability;
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 05e52e6b3..534b2762b 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
@@ -1,15 +1,14 @@
use std::ops::ControlFlow;
-use clippy_utils::{
- diagnostics::span_lint_and_sugg,
- peel_blocks,
- source::{snippet, walk_span_to_context},
- visitors::for_each_expr,
-};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::peel_blocks;
+use clippy_utils::source::{snippet, walk_span_to_context};
+use clippy_utils::visitors::for_each_expr;
use rustc_errors::Applicability;
use rustc_hir::{AsyncGeneratorKind, Closure, Expr, ExprKind, GeneratorKind, MatchSource};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::{lint::in_external_macro, ty::UpvarCapture};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::UpvarCapture;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
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 b6ce4ebc2..fc49b58e0 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -6,8 +6,7 @@ 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;
-use rustc_hir::intravisit::Visitor;
+use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro;
@@ -53,7 +52,7 @@ impl ReturnVisitor {
impl<'tcx> Visitor<'tcx> for ReturnVisitor {
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
- if let hir::ExprKind::Ret(_) | hir::ExprKind::Match(.., hir::MatchSource::TryDesugar) = ex.kind {
+ if let hir::ExprKind::Ret(_) | hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_)) = ex.kind {
self.found_return = true;
} else {
hir_visit::walk_expr(self, ex);
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
new file mode 100644
index 000000000..0c89c7ee4
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -0,0 +1,126 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_from_proc_macro;
+use clippy_utils::ty::needs_ordered_drop;
+use rustc_ast::Mutability;
+use rustc_hir::def::Res;
+use rustc_hir::{
+ BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath,
+};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::{in_external_macro, is_from_async_await};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::Ident;
+use rustc_span::DesugaringKind;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for redundant redefinitions of local bindings.
+ ///
+ /// ### Why is this bad?
+ /// Redundant redefinitions of local bindings do not change behavior and are likely to be unintended.
+ ///
+ /// Note that although these bindings do not affect your code's meaning, they _may_ affect `rustc`'s stack allocation.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let a = 0;
+ /// let a = a;
+ ///
+ /// fn foo(b: i32) {
+ /// let b = b;
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let a = 0;
+ /// // no redefinition with the same name
+ ///
+ /// fn foo(b: i32) {
+ /// // no redefinition with the same name
+ /// }
+ /// ```
+ #[clippy::version = "1.72.0"]
+ pub REDUNDANT_LOCALS,
+ correctness,
+ "redundant redefinition of a local binding"
+}
+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);
+ // the pattern is a single by-value binding
+ if let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind;
+ // the binding is not type-ascribed
+ if 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;
+ // the path is a single segment equal to the local's name
+ if let [last_segment] = path.segments;
+ if 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);
+ // the previous binding has the same mutability
+ if find_binding(binding_pat, ident).unwrap().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);
+ // the local does not affect the code's drop behavior
+ if !affects_drop_behavior(cx, binding_id, local.hir_id, expr);
+ // the local is user-controlled
+ if !in_external_macro(cx.sess(), local.span);
+ if !is_from_proc_macro(cx, expr);
+ // Async function parameters are lowered into the closure body, so we can't lint them.
+ // see `lower_maybe_async_body` in `rust_ast_lowering`
+ if !is_from_async_await(local.span);
+ then {
+ span_lint_and_help(
+ cx,
+ REDUNDANT_LOCALS,
+ vec![binding_pat.span, local.span],
+ "redundant redefinition of a binding",
+ None,
+ &format!("remove the redefinition of `{ident}`"),
+ );
+ }
+ }
+ }
+}
+
+/// Find the annotation of a binding introduced by a pattern, or `None` if it's not introduced.
+fn find_binding(pat: &Pat<'_>, name: Ident) -> Option<BindingAnnotation> {
+ let mut ret = None;
+
+ pat.each_binding_or_first(&mut |annotation, _, _, ident| {
+ if ident == name {
+ ret = Some(annotation);
+ }
+ });
+
+ ret
+}
+
+/// Check if a rebinding of a local changes the effect of assignments to the binding.
+fn affects_assignments(cx: &LateContext<'_>, mutability: Mutability, bind: HirId, rebind: HirId) -> bool {
+ let hir = cx.tcx.hir();
+
+ // the binding is mutable and the rebinding is in a different scope than the original binding
+ mutability == Mutability::Mut && hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
+}
+
+/// Check if a rebinding of a local affects the code's drop behavior.
+fn affects_drop_behavior<'tcx>(
+ cx: &LateContext<'tcx>,
+ bind: HirId,
+ rebind: HirId,
+ rebind_expr: &Expr<'tcx>,
+) -> bool {
+ let hir = cx.tcx.hir();
+
+ // the rebinding is in a different scope than the original binding
+ // and the type of the binding cares about drop order
+ hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
+ && needs_ordered_drop(cx, cx.typeck_results().expr_ty(rebind_expr))
+}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index c70ce83a9..4abfa0fc3 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -7,9 +7,8 @@ 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::Ty;
use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability};
-use rustc_middle::ty::subst::GenericArg;
+use rustc_middle::ty::{GenericArg, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
@@ -82,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
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 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));
@@ -135,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
} 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_substs(&[GenericArg::from(indexed_ty)])),
+ 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;
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 038dfe8e4..ed42a422b 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
@@ -5,6 +5,7 @@ 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_span::symbol::kw;
declare_clippy_lint! {
/// ### What it does
@@ -64,7 +65,7 @@ impl RedundantStaticLifetimes {
if let Some(lifetime) = *optional_lifetime {
match borrow_type.ty.kind {
TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
- if lifetime.ident.name == rustc_span::symbol::kw::StaticLifetime {
+ if lifetime.ident.name == kw::StaticLifetime {
let snip = snippet(cx, borrow_type.ty.span, "<type>");
let sugg = format!("&{}{snip}", borrow_type.mutbl.prefix_str());
span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs
index a642e2da3..db870ec4c 100644
--- a/src/tools/clippy/clippy_lints/src/reference.rs
+++ b/src/tools/clippy/clippy_lints/src/reference.rs
@@ -94,7 +94,7 @@ impl EarlyLintPass for DerefAddrOf {
DEREF_ADDROF,
e.span,
"immediately dereferencing a reference",
- "try this",
+ "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 674f8bf4c..b795e4b15 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -3,12 +3,12 @@ use std::fmt::Display;
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::source::snippet_opt;
-use clippy_utils::{match_def_path, paths};
-use if_chain::if_chain;
+use clippy_utils::{def_path_def_ids, path_def_id, paths};
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_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::{BytePos, Span};
declare_clippy_lint! {
@@ -55,26 +55,52 @@ declare_clippy_lint! {
"trivial regular expressions"
}
-declare_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]);
+#[derive(Copy, Clone)]
+enum RegexKind {
+ Unicode,
+ UnicodeSet,
+ Bytes,
+ BytesSet,
+}
+
+#[derive(Default)]
+pub struct Regex {
+ definitions: DefIdMap<RegexKind>,
+}
+
+impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]);
impl<'tcx> LateLintPass<'tcx> for Regex {
+ fn check_crate(&mut self, cx: &LateContext<'tcx>) {
+ // We don't use `match_def_path` here because that relies on matching the exact path, which changed
+ // between regex 1.8 and 1.9
+ //
+ // `def_path_def_ids` will resolve through re-exports but is relatively heavy, so we only perform
+ // the operation once and store the results
+ let mut resolve = |path, kind| {
+ for id in def_path_def_ids(cx, path) {
+ self.definitions.insert(id, kind);
+ }
+ };
+
+ resolve(&paths::REGEX_NEW, RegexKind::Unicode);
+ resolve(&paths::REGEX_BUILDER_NEW, RegexKind::Unicode);
+ resolve(&paths::REGEX_SET_NEW, RegexKind::UnicodeSet);
+ resolve(&paths::REGEX_BYTES_NEW, RegexKind::Bytes);
+ resolve(&paths::REGEX_BYTES_BUILDER_NEW, RegexKind::Bytes);
+ resolve(&paths::REGEX_BYTES_SET_NEW, RegexKind::BytesSet);
+ }
+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if_chain! {
- if let ExprKind::Call(fun, [arg]) = expr.kind;
- if let ExprKind::Path(ref qpath) = fun.kind;
- if let Some(def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
- then {
- if match_def_path(cx, def_id, &paths::REGEX_NEW) ||
- match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) {
- check_regex(cx, arg, true);
- } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) ||
- match_def_path(cx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) {
- check_regex(cx, arg, false);
- } else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) {
- check_set(cx, arg, true);
- } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) {
- check_set(cx, arg, false);
- }
+ if let ExprKind::Call(fun, [arg]) = expr.kind
+ && let Some(def_id) = path_def_id(cx, fun)
+ && let Some(regex_kind) = self.definitions.get(&def_id)
+ {
+ match regex_kind {
+ RegexKind::Unicode => check_regex(cx, arg, true),
+ RegexKind::UnicodeSet => check_set(cx, arg, true),
+ RegexKind::Bytes => check_regex(cx, arg, false),
+ RegexKind::BytesSet => check_set(cx, arg, false),
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index 44e7cbfba..fc1fabcc0 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -30,6 +30,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
("clippy::single_char_push_str", "clippy::single_char_add_str"),
("clippy::stutter", "clippy::module_name_repetitions"),
("clippy::to_string_in_display", "clippy::recursive_format_impl"),
+ ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"),
("clippy::zero_width_space", "clippy::invisible_characters"),
("clippy::cast_ref_to_mut", "invalid_reference_casting"),
("clippy::clone_double_ref", "suspicious_double_ref_op"),
@@ -42,6 +43,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
("clippy::forget_copy", "forgetting_copy_types"),
("clippy::forget_ref", "forgetting_references"),
+ ("clippy::fn_null_check", "useless_ptr_null_checks"),
("clippy::into_iter_on_array", "array_into_iter"),
("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
("clippy::invalid_ref", "invalid_value"),
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 958351ad8..d6b9a49d2 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -1,15 +1,17 @@
-use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::source::{snippet_opt, snippet_with_context};
-use clippy_utils::visitors::{for_each_expr, Descend};
-use clippy_utils::{fn_def_id, path_to_local_id, span_find_starting_semi};
+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 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, LangItem, MatchSource, PatKind, QPath, StmtKind};
+use rustc_hir::{
+ Block, Body, Expr, ExprKind, FnDecl, ItemKind, LangItem, MatchSource, OwnerNode, PatKind, QPath, Stmt, StmtKind,
+};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
+use rustc_middle::ty::{self, GenericArgKind, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::Span;
@@ -76,6 +78,46 @@ declare_clippy_lint! {
"using a return statement like `return expr;` where an expression would suffice"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for return statements on `Err` paired with the `?` operator.
+ ///
+ /// ### Why is this bad?
+ /// The `return` is unnecessary.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+ /// if x == 0 {
+ /// return Err(...)?;
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ /// simplify to
+ /// ```rust,ignore
+ /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+ /// if x == 0 {
+ /// Err(...)?;
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ /// if paired with `try_err`, use instead:
+ /// ```rust,ignore
+ /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+ /// if x == 0 {
+ /// return Err(...);
+ /// }
+ /// Ok(())
+ /// }
+ /// ```
+ #[clippy::version = "1.73.0"]
+ pub NEEDLESS_RETURN_WITH_QUESTION_MARK,
+ style,
+ "using a return statement like `return Err(expr)?;` where removing it would suffice"
+}
+
#[derive(PartialEq, Eq)]
enum RetReplacement<'tcx> {
Empty,
@@ -115,9 +157,35 @@ impl<'tcx> ToString for RetReplacement<'tcx> {
}
}
-declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN]);
+declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN, NEEDLESS_RETURN_WITH_QUESTION_MARK]);
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)
+ && let StmtKind::Semi(expr) = stmt.kind
+ && let ExprKind::Ret(Some(ret)) = expr.kind
+ && let ExprKind::Match(.., MatchSource::TryDesugar(_)) = ret.kind
+ // Ensure this is not the final stmt, otherwise removing it would cause a compile error
+ && let OwnerNode::Item(item) = cx.tcx.hir().owner(cx.tcx.hir().get_parent_item(expr.hir_id))
+ && let ItemKind::Fn(_, _, body) = item.kind
+ && let block = cx.tcx.hir().body(body).value
+ && let ExprKind::Block(block, _) = block.kind
+ && let [.., final_stmt] = block.stmts
+ && final_stmt.hir_id != stmt.hir_id
+ && !is_from_proc_macro(cx, expr)
+ {
+ span_lint_and_sugg(
+ cx,
+ NEEDLESS_RETURN_WITH_QUESTION_MARK,
+ expr.span.until(ret.span),
+ "unneeded `return` statement with `?` operator",
+ "remove it",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
// we need both a let-binding stmt and an expr
if_chain! {
@@ -173,6 +241,10 @@ impl<'tcx> LateLintPass<'tcx> for Return {
sp: Span,
_: LocalDefId,
) {
+ if sp.from_expansion() {
+ return;
+ }
+
match kind {
FnKind::Closure => {
// when returning without value in closure, replace this `return`
@@ -328,16 +400,16 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec<Span>,
}
fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
- for_each_expr(expr, |e| {
+ for_each_expr_with_closures(cx, expr, |e| {
if let Some(def_id) = fn_def_id(cx, e)
&& cx
.tcx
.fn_sig(def_id)
- .subst_identity()
+ .instantiate_identity()
.skip_binder()
.output()
.walk()
- .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
+ .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if !re.is_static()))
{
ControlFlow::Break(())
} else {
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 beca203c8..b92014f68 100644
--- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
+++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
@@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
let item = cx.tcx.hir().expect_item(parent);
- let self_ty = cx.tcx.type_of(item.owner_id).subst_identity();
+ let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
let ret_ty = return_ty(cx, impl_item.owner_id);
// Do not check trait impls
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index 419d7991f..88f295c72 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -148,12 +148,18 @@ impl LateLintPass<'_> for SemicolonBlock {
expr: None,
stmts: [.., stmt],
..
- } = block else { return };
+ } = block
+ else {
+ return;
+ };
let &Stmt {
kind: StmtKind::Semi(expr),
span,
..
- } = stmt else { return };
+ } = stmt
+ else {
+ return;
+ };
self.semicolon_outside_block(cx, block, expr, span);
},
StmtKind::Semi(Expr {
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 355f907e2..c9547cd95 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
@@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned {
if let Some(expr) = block.expr;
let t_expr = cx.typeck_results().expr_ty(expr);
if t_expr.is_unit();
- let mut app = Applicability::MaybeIncorrect;
+ 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);
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 993f9373d..78418b223 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -106,7 +106,9 @@ impl_lint_pass!(Shadow => [SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED]);
impl<'tcx> LateLintPass<'tcx> for Shadow {
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
- let PatKind::Binding(_, id, ident, _) = pat.kind else { return };
+ let PatKind::Binding(_, id, ident, _) = pat.kind else {
+ return;
+ };
if pat.span.desugaring_kind().is_some() || pat.span.from_expansion() {
return;
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 fffa8a380..4b248c9c7 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -1,18 +1,16 @@
-use clippy_utils::{
- diagnostics::span_lint_and_then,
- expr_or_init, get_attr, path_to_local,
- source::{indent_of, snippet},
-};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::{indent_of, snippet};
+use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_errors::Applicability;
-use rustc_hir::{
- self as hir,
- intravisit::{walk_expr, Visitor},
-};
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::intravisit::{walk_expr, Visitor};
+use rustc_hir::{self as hir};
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::{subst::GenericArgKind, Ty, TypeAndMut};
+use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{symbol::Ident, Span, DUMMY_SP};
+use rustc_span::symbol::Ident;
+use rustc_span::{sym, Span, DUMMY_SP};
use std::borrow::Cow;
declare_clippy_lint! {
@@ -237,7 +235,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx
fn manage_has_expensive_expr_after_last_attr(&mut self) {
let has_expensive_stmt = match self.ap.curr_stmt.kind {
- hir::StmtKind::Expr(expr) if !is_expensive_expr(expr) => false,
+ hir::StmtKind::Expr(expr) if is_inexpensive_expr(expr) => false,
hir::StmtKind::Local(local) if let Some(expr) = local.init
&& let hir::ExprKind::Path(_) = expr.kind => false,
_ => true
@@ -332,13 +330,13 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o
apa.last_method_span = span;
}
},
- hir::StmtKind::Semi(expr) => {
- if has_drop(expr, &apa.first_bind_ident) {
+ hir::StmtKind::Semi(semi_expr) => {
+ if has_drop(semi_expr, &apa.first_bind_ident, self.cx) {
apa.has_expensive_expr_after_last_attr = false;
apa.last_stmt_span = DUMMY_SP;
return;
}
- if let hir::ExprKind::MethodCall(_, _, _, span) = expr.kind {
+ if let hir::ExprKind::MethodCall(_, _, _, span) = semi_expr.kind {
apa.last_method_span = span;
}
},
@@ -430,22 +428,37 @@ fn dummy_stmt_expr<'any>(expr: &'any hir::Expr<'any>) -> hir::Stmt<'any> {
}
}
-fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident) -> bool {
+fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident, lcx: &LateContext<'_>) -> bool {
if let hir::ExprKind::Call(fun, args) = expr.kind
&& let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind
- && let [fun_ident, ..] = fun_path.segments
- && fun_ident.ident.name == rustc_span::sym::drop
+ && let Res::Def(DefKind::Fn, did) = fun_path.res
+ && lcx.tcx.is_diagnostic_item(sym::mem_drop, did)
&& let [first_arg, ..] = args
- && let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &first_arg.kind
- && let [first_arg_ps, .. ] = arg_path.segments
{
- &first_arg_ps.ident == first_bind_ident
- }
- else {
- false
+ let has_ident = |local_expr: &hir::Expr<'_>| {
+ if let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &local_expr.kind
+ && let [first_arg_ps, .. ] = arg_path.segments
+ && &first_arg_ps.ident == first_bind_ident
+ {
+ true
+ }
+ else {
+ false
+ }
+ };
+ if has_ident(first_arg) {
+ return true;
+ }
+ if let hir::ExprKind::Tup(value) = &first_arg.kind && value.iter().any(has_ident) {
+ return true;
+ }
}
+ false
}
-fn is_expensive_expr(expr: &hir::Expr<'_>) -> bool {
- !matches!(expr.kind, hir::ExprKind::Path(_))
+fn is_inexpensive_expr(expr: &hir::Expr<'_>) -> bool {
+ let actual = peel_hir_expr_unary(expr).0;
+ let is_path = matches!(actual.kind, hir::ExprKind::Path(_));
+ let is_lit = matches!(actual.kind, hir::ExprKind::Lit(_));
+ is_path || is_lit
}
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 42753d2e9..7bbe98e0a 100644
--- a/src/tools/clippy/clippy_lints/src/single_call_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/single_call_fn.rs
@@ -2,8 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{is_from_proc_macro, is_in_test_function};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{intravisit::FnKind, Body, Expr, ExprKind, FnDecl};
+use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
+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;
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 5743dd21c..9c21d70c8 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
@@ -1,11 +1,14 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
use rustc_ast::node_id::{NodeId, NodeMap};
+use rustc_ast::ptr::P;
use rustc_ast::visit::{walk_expr, Visitor};
-use rustc_ast::{ptr::P, Crate, Expr, ExprKind, Item, ItemKind, MacroDef, ModKind, Ty, TyKind, UseTreeKind};
+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_span::{edition::Edition, symbol::kw, Span, Symbol};
+use rustc_span::edition::Edition;
+use rustc_span::symbol::kw;
+use rustc_span::{Span, Symbol};
declare_clippy_lint! {
/// ### What it does
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 dfe8be7a6..321c89889 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
@@ -1,7 +1,9 @@
-use clippy_utils::{
- diagnostics::span_lint_and_then, get_trait_def_id, higher::VecArgs, macros::root_macro_call_first_node,
- source::snippet_opt, ty::implements_trait,
-};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::get_trait_def_id;
+use clippy_utils::higher::VecArgs;
+use clippy_utils::macros::root_macro_call_first_node;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::implements_trait;
use rustc_ast::{LitIntType, LitKind, UintTy};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem, QPath};
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 ac4e29e9d..bd783b4e0 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
@@ -4,8 +4,7 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
-use rustc_hir::BinOpKind;
-use rustc_hir::{Expr, ExprKind};
+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};
@@ -47,7 +46,7 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted:
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_substs(count_func.hir_id).types().next()
+ cx.typeck_results().node_args(count_func.hir_id).types().next()
} else {
None
}
@@ -101,7 +100,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
if FUNCTIONS.iter().any(|func_path| match_def_path(cx, def_id, func_path));
// Get the pointee type
- if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next();
+ if let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).types().next();
then {
return Some((pointee_ty, count));
}
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 8abec06c6..89ac8cd8c 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
@@ -1,4 +1,6 @@
-use clippy_utils::{diagnostics::span_lint_and_help, path_def_id, ty::peel_mid_ty_refs};
+use clippy_utils::diagnostics::span_lint_and_help;
+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};
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 858135c8d..c9ab622ad 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -1,13 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{
- get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, SpanlessEq,
+ 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, QPath, Stmt, StmtKind};
+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_span::symbol::sym;
@@ -20,18 +20,27 @@ declare_clippy_lint! {
/// These structures are non-idiomatic and less efficient than simply using
/// `vec![0; len]`.
///
+ /// Specifically, for `vec![0; len]`, the compiler can use a specialized type of allocation
+ /// that also zero-initializes the allocated memory in the same call
+ /// (see: [alloc_zeroed](https://doc.rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html#method.alloc_zeroed)).
+ ///
+ /// Writing `Vec::new()` followed by `vec.resize(len, 0)` is suboptimal because,
+ /// while it does do the same number of allocations,
+ /// it involves two operations for allocating and initializing.
+ /// The `resize` call first allocates memory (since `Vec::new()` did not), and only *then* zero-initializes it.
+ ///
/// ### Example
/// ```rust
/// # use core::iter::repeat;
/// # let len = 4;
- /// let mut vec1 = Vec::with_capacity(len);
+ /// let mut vec1 = Vec::new();
/// vec1.resize(len, 0);
///
- /// let mut vec1 = Vec::with_capacity(len);
- /// vec1.resize(vec1.capacity(), 0);
- ///
/// let mut vec2 = Vec::with_capacity(len);
- /// vec2.extend(repeat(0).take(len));
+ /// vec2.resize(len, 0);
+ ///
+ /// let mut vec3 = Vec::with_capacity(len);
+ /// vec3.extend(repeat(0).take(len));
/// ```
///
/// Use instead:
@@ -39,6 +48,7 @@ declare_clippy_lint! {
/// # let len = 4;
/// let mut vec1 = vec![0; len];
/// let mut vec2 = vec![0; len];
+ /// let mut vec3 = vec![0; len];
/// ```
#[clippy::version = "1.32.0"]
pub SLOW_VECTOR_INITIALIZATION,
@@ -60,7 +70,24 @@ struct VecAllocation<'tcx> {
/// Reference to the expression used as argument on `with_capacity` call. This is used
/// to only match slow zero-filling idioms of the same length than vector initialization.
- len_expr: &'tcx Expr<'tcx>,
+ size_expr: InitializedSize<'tcx>,
+}
+
+/// Initializer for the creation of the vector.
+///
+/// When `Vec::with_capacity(size)` is found, the `size` expression will be in
+/// `InitializedSize::Initialized`.
+///
+/// Otherwise, for `Vec::new()` calls, there is no allocation initializer yet, so
+/// `InitializedSize::Uninitialized` is used.
+/// Later, when a call to `.resize(size, 0)` or similar is found, it's set
+/// to `InitializedSize::Initialized(size)`.
+///
+/// Since it will be set to `InitializedSize::Initialized(size)` when a slow initialization is
+/// found, it is always safe to "unwrap" it at lint time.
+enum InitializedSize<'tcx> {
+ Initialized(&'tcx Expr<'tcx>),
+ Uninitialized,
}
/// Type of slow initialization
@@ -77,18 +104,14 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
// Matches initialization on reassignments. For example: `vec = Vec::with_capacity(100)`
if_chain! {
if let ExprKind::Assign(left, right, _) = expr.kind;
-
- // Extract variable
if let Some(local_id) = path_to_local(left);
-
- // Extract len argument
- if let Some(len_arg) = Self::is_vec_with_capacity(cx, right);
+ if let Some(size_expr) = Self::as_vec_initializer(cx, right);
then {
let vi = VecAllocation {
local_id,
allocation_expr: right,
- len_expr: len_arg,
+ size_expr,
};
Self::search_initialization(cx, vi, expr.hir_id);
@@ -98,17 +121,18 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
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(len_arg) = Self::is_vec_with_capacity(cx, init);
+ if let Some(size_expr) = Self::as_vec_initializer(cx, init);
then {
let vi = VecAllocation {
local_id,
allocation_expr: init,
- len_expr: len_arg,
+ size_expr,
};
Self::search_initialization(cx, vi, stmt.hir_id);
@@ -118,19 +142,20 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
}
impl SlowVectorInit {
- /// Checks if the given expression is `Vec::with_capacity(..)`. It will return the expression
- /// of the first argument of `with_capacity` call if it matches or `None` if it does not.
- fn is_vec_with_capacity<'tcx>(cx: &LateContext<'_>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
- if_chain! {
- if let ExprKind::Call(func, [arg]) = expr.kind;
- if let ExprKind::Path(QPath::TypeRelative(ty, name)) = func.kind;
- if name.ident.as_str() == "with_capacity";
- if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec);
- then {
- Some(arg)
- } else {
- None
- }
+ /// Looks for `Vec::with_capacity(size)` or `Vec::new()` calls and returns the initialized size,
+ /// if any. More specifically, it returns:
+ /// - `Some(InitializedSize::Initialized(size))` for `Vec::with_capacity(size)`
+ /// - `Some(InitializedSize::Uninitialized)` for `Vec::new()`
+ /// - `None` for other, unrelated kinds of expressions
+ fn as_vec_initializer<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<InitializedSize<'tcx>> {
+ if let ExprKind::Call(func, [len_expr]) = expr.kind
+ && is_expr_path_def_path(cx, func, &paths::VEC_WITH_CAPACITY)
+ {
+ Some(InitializedSize::Initialized(len_expr))
+ } else if matches!(expr.kind, ExprKind::Call(func, _) if is_expr_path_def_path(cx, func, &paths::VEC_NEW)) {
+ Some(InitializedSize::Uninitialized)
+ } else {
+ None
}
}
@@ -169,12 +194,19 @@ impl SlowVectorInit {
}
fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &str) {
- let len_expr = Sugg::hir(cx, vec_alloc.len_expr, "len");
+ let len_expr = Sugg::hir(
+ cx,
+ match vec_alloc.size_expr {
+ InitializedSize::Initialized(expr) => expr,
+ InitializedSize::Uninitialized => unreachable!("size expression must be set by this point"),
+ },
+ "len",
+ );
span_lint_and_then(cx, SLOW_VECTOR_INITIALIZATION, slow_fill.span, msg, |diag| {
diag.span_suggestion(
vec_alloc.allocation_expr.span,
- "consider replace allocation with",
+ "consider replacing this with",
format!("vec![0; {len_expr}]"),
Applicability::Unspecified,
);
@@ -214,36 +246,45 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
}
/// Checks if the given expression is resizing a vector with 0
- fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) {
+ fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'tcx>) {
if self.initialization_found
&& let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind
&& path_to_local_id(self_arg, self.vec_alloc.local_id)
&& path.ident.name == sym!(resize)
// Check that is filled with 0
- && is_integer_literal(fill_arg, 0) {
- // Check that len expression is equals to `with_capacity` expression
- if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
- self.slow_expression = Some(InitializationType::Resize(expr));
- } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
- self.slow_expression = Some(InitializationType::Resize(expr));
- }
+ && is_integer_literal(fill_arg, 0)
+ {
+ let is_matching_resize = if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
+ // If we have a size expression, check that it is equal to what's passed to `resize`
+ SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
+ || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity")
+ } else {
+ self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);
+ true
+ };
+
+ if is_matching_resize {
+ self.slow_expression = Some(InitializationType::Resize(expr));
}
+ }
}
/// Returns `true` if give expression is `repeat(0).take(...)`
- fn is_repeat_take(&self, expr: &Expr<'_>) -> bool {
+ 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);
// Check that take is applied to `repeat(0)`
if self.is_repeat_zero(recv);
then {
- // Check that len expression is equals to `with_capacity` expression
- if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
- return true;
- } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
- return true;
+ 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;
}
}
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 a13bc7a51..f23916527 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -1,9 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
-use rustc_hir::{def::Res, HirId, Path, PathSegment};
+use rustc_hir::{HirId, Path, PathSegment};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{sym, symbol::kw, Span};
+use rustc_span::symbol::kw;
+use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 8658009eb..76f463fff 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -1,8 +1,10 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::ty::is_type_lang_item;
-use clippy_utils::{get_expr_use_or_unification_node, peel_blocks, SpanlessEq};
-use clippy_utils::{get_parent_expr, is_lint_allowed, is_path_diagnostic_item, method_calls};
+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;
@@ -188,7 +190,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd {
);
}
},
- ExprKind::Index(target, _idx) => {
+ ExprKind::Index(target, _idx, _) => {
let e_ty = cx.typeck_results().expr_ty(target).peel_refs();
if e_ty.is_str() || is_type_lang_item(cx, e_ty, LangItem::String) {
span_lint(
@@ -260,7 +262,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
// Find string::as_bytes
if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args[0].kind;
- if let ExprKind::Index(left, right) = args.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;
@@ -326,7 +328,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
{
// Don't lint. Byte strings produce `&[u8; N]` whereas `as_bytes()` produces
// `&[u8]`. This change would prevent matching with different sized slices.
- } else {
+ } else if !callsite.starts_with("env!") {
span_lint_and_sugg(
cx,
STRING_LIT_AS_BYTES,
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 2f2e84fa3..b3db5e9a4 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
@@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
STRLEN_ON_C_STRINGS,
span,
"using `libc::strlen` on a `CString` or `CStr` value",
- "try this",
+ "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
index e5746ca99..8be4ec3dc 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
use if_chain::if_chain;
-use rustc_ast::{token::CommentKind, AttrKind, AttrStyle, Attribute, Item};
+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};
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 e2cdc48b5..23d6e2a84 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -572,7 +572,7 @@ fn ident_difference_expr_with_base_location(
| (AddrOf(_, _, _), AddrOf(_, _, _))
| (Path(_, _), Path(_, _))
| (Range(_, _, _), Range(_, _, _))
- | (Index(_, _), Index(_, _))
+ | (Index(_, _, _), Index(_, _, _))
| (Field(_, _), Field(_, _))
| (AssignOp(_, _, _), AssignOp(_, _, _))
| (Assign(_, _, _), Assign(_, _, _))
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 9c0dc8096..8e156b882 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
@@ -1,4 +1,7 @@
-use clippy_utils::{numeric_literal::NumericLiteral, source::snippet_with_context};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::numeric_literal::NumericLiteral;
+use clippy_utils::source::snippet;
+use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -27,27 +30,29 @@ declare_lint_pass!(ConfusingXorAndPow => [SUSPICIOUS_XOR_USED_AS_POW]);
impl LateLintPass<'_> for ConfusingXorAndPow {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- if !in_external_macro(cx.sess(), expr.span) &&
- let ExprKind::Binary(op, left, right) = &expr.kind &&
- op.node == BinOpKind::BitXor &&
- left.span.ctxt() == right.span.ctxt() &&
- let ExprKind::Lit(lit_left) = &left.kind &&
- let ExprKind::Lit(lit_right) = &right.kind &&
- let snip_left = snippet_with_context(cx, lit_left.span, lit_left.span.ctxt(), "..", &mut Applicability::MaybeIncorrect) &&
- let snip_right = snippet_with_context(cx, lit_right.span, lit_right.span.ctxt(), "..", &mut Applicability::MaybeIncorrect) &&
- let Some(left_val) = NumericLiteral::from_lit_kind(&snip_left.0, &lit_left.node) &&
- let Some(right_val) = NumericLiteral::from_lit_kind(&snip_right.0, &lit_right.node) &&
- left_val.is_decimal() &&
- right_val.is_decimal() {
- clippy_utils::diagnostics::span_lint_and_sugg(
- cx,
- SUSPICIOUS_XOR_USED_AS_POW,
- expr.span,
- "`^` is not the exponentiation operator",
- "did you mean to write",
- format!("{}.pow({})", left_val.format(), right_val.format()),
- Applicability::MaybeIncorrect,
- );
+ if !in_external_macro(cx.sess(), expr.span)
+ && let ExprKind::Binary(op, left, right) = &expr.kind
+ && op.node == BinOpKind::BitXor
+ && left.span.ctxt() == right.span.ctxt()
+ && let ExprKind::Lit(lit_left) = &left.kind
+ && let ExprKind::Lit(lit_right) = &right.kind
+ && matches!(lit_right.node, LitKind::Int(..) | LitKind::Float(..))
+ && matches!(lit_left.node, LitKind::Int(..) | LitKind::Float(..))
+ && NumericLiteral::from_lit_kind(&snippet(cx, lit_right.span, ".."), &lit_right.node).is_some_and(|x| x.is_decimal())
+ {
+ span_lint_and_sugg(
+ cx,
+ SUSPICIOUS_XOR_USED_AS_POW,
+ expr.span,
+ "`^` is not the exponentiation operator",
+ "did you mean to write",
+ format!(
+ "{}.pow({})",
+ lit_left.node,
+ lit_right.node
+ ),
+ Applicability::MaybeIncorrect,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index f7eef03d1..548fabb8b 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -11,8 +11,8 @@ use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;
-use rustc_span::SyntaxContext;
-use rustc_span::{sym, symbol::Ident, Span};
+use rustc_span::symbol::Ident;
+use rustc_span::{sym, Span, SyntaxContext};
declare_clippy_lint! {
/// ### What it does
@@ -86,8 +86,8 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
let mut applicability = Applicability::MachineApplicable;
if !can_mut_borrow_both(cx, e1, e2) {
- if let ExprKind::Index(lhs1, idx1) = e1.kind
- && let ExprKind::Index(lhs2, idx2) = e2.kind
+ if let ExprKind::Index(lhs1, idx1, _) = e1.kind
+ && let ExprKind::Index(lhs2, idx2, _) = e2.kind
&& eq_expr_value(cx, lhs1, lhs2)
&& e1.span.ctxt() == ctxt
&& e2.span.ctxt() == ctxt
diff --git a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
index 3766b8f8e..b6b653f66 100644
--- a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
+++ b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
@@ -33,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryAssignment {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Assign(target, ..) = &expr.kind {
let mut base = target;
- while let ExprKind::Field(f, _) | ExprKind::Index(f, _) = &base.kind {
+ while let ExprKind::Field(f, _) | ExprKind::Index(f, _, _) = &base.kind {
base = f;
}
if is_temporary(base) && !is_adjusted(cx, base) {
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 0a0a77082..b356666d8 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
@@ -1,8 +1,11 @@
-use clippy_utils::{diagnostics::span_lint_and_note, is_in_cfg_test, is_in_test_function};
-use rustc_hir::{intravisit::FnKind, Body, FnDecl};
+use clippy_utils::diagnostics::span_lint_and_note;
+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_span::{def_id::LocalDefId, Span};
+use rustc_span::def_id::LocalDefId;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
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 2512500a6..f1b703fde 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
@@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
TO_DIGIT_IS_SOME,
expr.span,
"use of `.to_digit(..).is_some()`",
- "try this",
+ "try",
if is_method_call {
format!("{char_arg_snip}.is_digit({radix_snip})")
} else {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
index 550365325..c0d0d2b93 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
@@ -4,10 +4,8 @@ use clippy_utils::sugg;
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
-use rustc_middle::{
- query::Key,
- ty::{self, Ty},
-};
+use rustc_middle::query::Key;
+use rustc_middle::ty::{self, Ty};
use rustc_span::symbol::sym;
/// Checks for `transmute_int_to_non_zero` lint.
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
index 857d2ad82..4ae4359ee 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
"transmute from a pointer to a pointer",
|diag| {
if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
- let sugg = arg.as_ty(Ty::new_ptr(cx.tcx,*to_ty));
+ let sugg = arg.as_ty(Ty::new_ptr(cx.tcx, *to_ty));
diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified);
}
},
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 5e24213d0..c61eb0a93 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -3,8 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::is_c_void;
use rustc_hir::Expr;
use rustc_lint::LateContext;
-use rustc_middle::ty::SubstsRef;
-use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy};
+use rustc_middle::ty::{self, GenericArgsRef, IntTy, Ty, TypeAndMut, UintTy};
#[expect(clippy::too_many_lines)]
pub(super) fn check<'tcx>(
@@ -268,12 +267,12 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
}
ReducedTy::UnorderedFields(ty)
},
- ty::Adt(def, substs) if def.is_struct() => {
+ ty::Adt(def, args) if def.is_struct() => {
let mut iter = def
.non_enum_variant()
.fields
.iter()
- .map(|f| cx.tcx.type_of(f.did).subst(cx.tcx, substs));
+ .map(|f| cx.tcx.type_of(f.did).instantiate(cx.tcx, args));
let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
return ReducedTy::TypeErasure { raw_ptr_only: false };
};
@@ -322,7 +321,7 @@ fn is_size_pair(ty: Ty<'_>) -> bool {
}
}
-fn same_except_params<'tcx>(subs1: SubstsRef<'tcx>, subs2: SubstsRef<'tcx>) -> bool {
+fn same_except_params<'tcx>(subs1: GenericArgsRef<'tcx>, subs2: GenericArgsRef<'tcx>) -> bool {
// TODO: check const parameters as well. Currently this will consider `Array<5>` the same as
// `Array<6>`
for (ty1, ty2) in subs1.types().zip(subs2.types()).filter(|(ty1, ty2)| ty1 != ty2) {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
index 85cd74f23..513a913f5 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
@@ -6,7 +6,8 @@ use rustc_ast::ExprPrecedence;
use rustc_errors::Applicability;
use rustc_hir::{Expr, Node};
use rustc_lint::LateContext;
-use rustc_middle::ty::{cast::CastKind, Ty};
+use rustc_middle::ty::cast::CastKind;
+use rustc_middle::ty::Ty;
/// Checks for `transmutes_expressible_as_ptr_casts` lint.
/// Returns `true` if it's triggered, otherwise returns `false`.
diff --git a/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs
index b1445311b..891fefc17 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs
@@ -10,7 +10,7 @@ use rustc_span::symbol::sym;
/// Returns `true` if it's triggered, otherwise returns `false`.
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> bool {
match (&from_ty.kind(), &to_ty.kind()) {
- (ty::Adt(from_adt, from_substs), ty::Adt(to_adt, to_substs)) => {
+ (ty::Adt(from_adt, from_args), ty::Adt(to_adt, to_args)) => {
if from_adt.did() != to_adt.did() {
return false;
}
@@ -28,9 +28,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty
) {
return false;
}
- if from_substs
+ if from_args
.types()
- .zip(to_substs.types())
+ .zip(to_args.types())
.any(|(from_ty, to_ty)| is_layout_incompatible(cx, from_ty, to_ty))
{
span_lint(
diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
index b6615410e..088c8fda8 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
@@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(
let sugg = if *ptr_ty == rty_and_mut {
arg.as_ty(to_ty)
} else {
- arg.as_ty(Ty::new_ptr(cx.tcx,rty_and_mut)).as_ty(to_ty)
+ arg.as_ty(Ty::new_ptr(cx.tcx, rty_and_mut)).as_ty(to_ty)
};
diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified);
diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
index 62efd13b8..1cf6cf854 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
@@ -2,7 +2,8 @@ use rustc_hir as hir;
use rustc_hir::Expr;
use rustc_hir_typeck::{cast, FnCtxt, Inherited};
use rustc_lint::LateContext;
-use rustc_middle::ty::{cast::CastKind, Ty};
+use rustc_middle::ty::cast::CastKind;
+use rustc_middle::ty::Ty;
use rustc_span::DUMMY_SP;
// check if the component types of the transmuted collection and the result have different ABI,
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 90eb45a09..78ad52d8a 100644
--- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
@@ -1,23 +1,29 @@
-use clippy_utils::{
- diagnostics::span_lint_and_help,
- is_from_proc_macro,
- msrvs::{self, Msrv},
- path_to_local,
-};
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::visitors::for_each_local_use_after_expr;
+use clippy_utils::{is_from_proc_macro, path_to_local};
+use itertools::Itertools;
use rustc_ast::LitKind;
-use rustc_hir::{Expr, ExprKind, HirId, Node, Pat};
+use rustc_hir::{Expr, ExprKind, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::{lint::in_external_macro, ty};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use std::iter::once;
+use std::ops::ControlFlow;
declare_clippy_lint! {
/// ### What it does
/// Checks for tuple<=>array conversions that are not done with `.into()`.
///
/// ### Why is this bad?
- /// It's unnecessary complexity. `.into()` works for tuples<=>arrays at or below 12 elements and
- /// conveys the intent a lot better, while also leaving less room for hard to spot bugs!
+ /// It may be unnecessary complexity. `.into()` works for converting tuples<=> arrays of up to
+ /// 12 elements and conveys the intent more clearly, while also leaving less room for hard to
+ /// spot bugs!
+ ///
+ /// ### Known issues
+ /// The suggested code may hide potential asymmetry in some cases. See
+ /// [#11085](https://github.com/rust-lang/rust-clippy/issues/11085) for more info.
///
/// ### Example
/// ```rust,ignore
@@ -43,130 +49,152 @@ pub struct TupleArrayConversions {
impl LateLintPass<'_> for TupleArrayConversions {
fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if !in_external_macro(cx.sess(), expr.span) && self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) {
- match expr.kind {
- ExprKind::Array(elements) if (1..=12).contains(&elements.len()) => check_array(cx, expr, elements),
- ExprKind::Tup(elements) if (1..=12).contains(&elements.len()) => check_tuple(cx, expr, elements),
- _ => {},
- }
+ if in_external_macro(cx.sess(), expr.span) || !self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) {
+ return;
+ }
+
+ match expr.kind {
+ ExprKind::Array(elements) if (1..=12).contains(&elements.len()) => check_array(cx, expr, elements),
+ ExprKind::Tup(elements) if (1..=12).contains(&elements.len()) => check_tuple(cx, expr, elements),
+ _ => {},
}
}
extract_msrv_attr!(LateContext);
}
-#[expect(
- clippy::blocks_in_if_conditions,
- reason = "not a FP, but this is much easier to understand"
-)]
fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) {
- if should_lint(
- cx,
- elements,
- // This is cursed.
- Some,
- |(first_id, local)| {
- if let Node::Pat(pat) = local
- && let parent = parent_pat(cx, pat)
- && parent.hir_id == first_id
- {
- return matches!(
- cx.typeck_results().pat_ty(parent).peel_refs().kind(),
- ty::Tuple(len) if len.len() == elements.len()
- );
- }
-
- false
- },
- ) || should_lint(
- cx,
- elements,
- |(i, expr)| {
- if let ExprKind::Field(path, field) = expr.kind && field.as_str() == i.to_string() {
- return Some((i, path));
- };
-
- None
- },
- |(first_id, local)| {
- if let Node::Pat(pat) = local
- && let parent = parent_pat(cx, pat)
- && parent.hir_id == first_id
- {
- return matches!(
- cx.typeck_results().pat_ty(parent).peel_refs().kind(),
- ty::Tuple(len) if len.len() == elements.len()
- );
- }
+ let (ty::Array(ty, _) | ty::Slice(ty)) = cx.typeck_results().expr_ty(expr).kind() else {
+ unreachable!("`expr` must be an array or slice due to `ExprKind::Array`");
+ };
+
+ if let [first, ..] = elements
+ && let Some(locals) = (match first.kind {
+ ExprKind::Field(_, _) => elements
+ .iter()
+ .enumerate()
+ .map(|(i, f)| -> Option<&'tcx Expr<'tcx>> {
+ let ExprKind::Field(lhs, ident) = f.kind else {
+ return None;
+ };
+ (ident.name.as_str() == i.to_string()).then_some(lhs)
+ })
+ .collect::<Option<Vec<_>>>(),
+ ExprKind::Path(_) => Some(elements.iter().collect()),
+ _ => None,
+ })
+ && all_bindings_are_for_conv(cx, &[*ty], expr, elements, &locals, ToType::Array)
+ && !is_from_proc_macro(cx, expr)
+ {
+ span_lint_and_help(
+ cx,
+ TUPLE_ARRAY_CONVERSIONS,
+ expr.span,
+ "it looks like you're trying to convert a tuple to an array",
+ None,
+ "use `.into()` instead, or `<[T; N]>::from` if type annotations are needed",
+ );
+ }
+}
- false
- },
- ) {
- emit_lint(cx, expr, ToType::Array);
+fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) {
+ if let ty::Tuple(tys) = cx.typeck_results().expr_ty(expr).kind()
+ && let [first, ..] = elements
+ // Fix #11100
+ && tys.iter().all_equal()
+ && let Some(locals) = (match first.kind {
+ ExprKind::Index(..) => elements
+ .iter()
+ .enumerate()
+ .map(|(i, i_expr)| -> Option<&'tcx Expr<'tcx>> {
+ if let ExprKind::Index(lhs, index, _) = i_expr.kind
+ && let ExprKind::Lit(lit) = index.kind
+ && let LitKind::Int(val, _) = lit.node
+ {
+ return (val == i as u128).then_some(lhs);
+ };
+
+ None
+ })
+ .collect::<Option<Vec<_>>>(),
+ ExprKind::Path(_) => Some(elements.iter().collect()),
+ _ => None,
+ })
+ && all_bindings_are_for_conv(cx, tys, expr, elements, &locals, ToType::Tuple)
+ && !is_from_proc_macro(cx, expr)
+ {
+ span_lint_and_help(
+ cx,
+ TUPLE_ARRAY_CONVERSIONS,
+ expr.span,
+ "it looks like you're trying to convert an array to a tuple",
+ None,
+ "use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed",
+ );
}
}
-#[expect(
- clippy::blocks_in_if_conditions,
- reason = "not a FP, but this is much easier to understand"
-)]
+/// Checks that every binding in `elements` comes from the same parent `Pat` with the kind if there
+/// is a parent `Pat`. Returns false in any of the following cases:
+/// * `kind` does not match `pat.kind`
+/// * one or more elements in `elements` is not a binding
+/// * one or more bindings does not have the same parent `Pat`
+/// * one or more bindings are used after `expr`
+/// * the bindings do not all have the same type
#[expect(clippy::cast_possible_truncation)]
-fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) {
- if should_lint(cx, elements, Some, |(first_id, local)| {
- if let Node::Pat(pat) = local
- && let parent = parent_pat(cx, pat)
- && parent.hir_id == first_id
- {
- return matches!(
- cx.typeck_results().pat_ty(parent).peel_refs().kind(),
- ty::Array(_, len) if len.eval_target_usize(cx.tcx, cx.param_env) as usize == elements.len()
- );
+fn all_bindings_are_for_conv<'tcx>(
+ cx: &LateContext<'tcx>,
+ final_tys: &[Ty<'tcx>],
+ expr: &Expr<'_>,
+ elements: &[Expr<'_>],
+ locals: &[&Expr<'_>],
+ kind: ToType,
+) -> bool {
+ let Some(locals) = locals.iter().map(|e| path_to_local(e)).collect::<Option<Vec<_>>>() else {
+ return false;
+ };
+ let Some(local_parents) = locals
+ .iter()
+ .map(|&l| cx.tcx.hir().find_parent(l))
+ .collect::<Option<Vec<_>>>()
+ else {
+ return false;
+ };
+
+ local_parents
+ .iter()
+ .map(|node| match node {
+ Node::Pat(pat) => kind.eq(&pat.kind).then_some(pat.hir_id),
+ Node::Local(l) => Some(l.hir_id),
+ _ => None,
+ })
+ .all_equal()
+ // Fix #11124, very convenient utils function! ❤️
+ && locals
+ .iter()
+ .all(|&l| for_each_local_use_after_expr(cx, l, expr.hir_id, |_| ControlFlow::Break::<()>(())).is_continue())
+ && local_parents.first().is_some_and(|node| {
+ let Some(ty) = match node {
+ Node::Pat(pat) => Some(pat.hir_id),
+ Node::Local(l) => Some(l.hir_id),
+ _ => None,
}
-
- false
- }) || should_lint(
- cx,
- elements,
- |(i, expr)| {
- if let ExprKind::Index(path, index) = expr.kind
- && let ExprKind::Lit(lit) = index.kind
- && let LitKind::Int(val, _) = lit.node
- && val as usize == i
- {
- return Some((i, path));
+ .map(|hir_id| cx.typeck_results().node_type(hir_id)) else {
+ return false;
};
-
- None
- },
- |(first_id, local)| {
- if let Node::Pat(pat) = local
- && let parent = parent_pat(cx, pat)
- && parent.hir_id == first_id
- {
- return matches!(
- cx.typeck_results().pat_ty(parent).peel_refs().kind(),
- ty::Array(_, len) if len.eval_target_usize(cx.tcx, cx.param_env) as usize == elements.len()
- );
+ match (kind, ty.kind()) {
+ // Ensure the final type and the original type have the same length, and that there
+ // is no implicit `&mut`<=>`&` anywhere (#11100). Bit ugly, I know, but it works.
+ (ToType::Array, ty::Tuple(tys)) => {
+ tys.len() == elements.len() && tys.iter().chain(final_tys.iter().copied()).all_equal()
+ },
+ (ToType::Tuple, ty::Array(ty, len)) => {
+ len.eval_target_usize(cx.tcx, cx.param_env) as usize == elements.len()
+ && final_tys.iter().chain(once(ty)).all_equal()
+ },
+ _ => false,
}
-
- false
- },
- ) {
- emit_lint(cx, expr, ToType::Tuple);
- }
-}
-
-/// Walks up the `Pat` until it's reached the final containing `Pat`.
-fn parent_pat<'tcx>(cx: &LateContext<'tcx>, start: &'tcx Pat<'tcx>) -> &'tcx Pat<'tcx> {
- let mut end = start;
- for (_, node) in cx.tcx.hir().parent_iter(start.hir_id) {
- if let Node::Pat(pat) = node {
- end = pat;
- } else {
- break;
- }
- }
- end
+ })
}
#[derive(Clone, Copy)]
@@ -175,61 +203,11 @@ enum ToType {
Tuple,
}
-impl ToType {
- fn msg(self) -> &'static str {
- match self {
- ToType::Array => "it looks like you're trying to convert a tuple to an array",
- ToType::Tuple => "it looks like you're trying to convert an array to a tuple",
- }
- }
-
- fn help(self) -> &'static str {
+impl PartialEq<PatKind<'_>> for ToType {
+ fn eq(&self, other: &PatKind<'_>) -> bool {
match self {
- ToType::Array => "use `.into()` instead, or `<[T; N]>::from` if type annotations are needed",
- ToType::Tuple => "use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed",
+ ToType::Array => matches!(other, PatKind::Tuple(_, _)),
+ ToType::Tuple => matches!(other, PatKind::Slice(_, _, _)),
}
}
}
-
-fn emit_lint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, to_type: ToType) -> bool {
- if !is_from_proc_macro(cx, expr) {
- span_lint_and_help(
- cx,
- TUPLE_ARRAY_CONVERSIONS,
- expr.span,
- to_type.msg(),
- None,
- to_type.help(),
- );
-
- return true;
- }
-
- false
-}
-
-fn should_lint<'tcx>(
- cx: &LateContext<'tcx>,
- elements: &'tcx [Expr<'tcx>],
- map: impl FnMut((usize, &'tcx Expr<'tcx>)) -> Option<(usize, &Expr<'_>)>,
- predicate: impl FnMut((HirId, &Node<'tcx>)) -> bool,
-) -> bool {
- if let Some(elements) = elements
- .iter()
- .enumerate()
- .map(map)
- .collect::<Option<Vec<_>>>()
- && let Some(locals) = elements
- .iter()
- .map(|(_, element)| path_to_local(element).and_then(|local| cx.tcx.hir().find(local)))
- .collect::<Option<Vec<_>>>()
- && let [first, rest @ ..] = &*locals
- && let Node::Pat(first_pat) = first
- && let parent = parent_pat(cx, first_pat).hir_id
- && rest.iter().chain(once(first)).map(|i| (parent, i)).all(predicate)
- {
- return true;
- }
-
- false
-}
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 acdf54710..306ca5724 100644
--- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -2,8 +2,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::{self as hir, GenericArg, GenericBounds, GenericParamKind};
-use rustc_hir::{HirId, Lifetime, MutTy, Mutability, Node, QPath, TyKind};
+use rustc_hir::{
+ self as hir, GenericArg, GenericBounds, GenericParamKind, HirId, Lifetime, MutTy, Mutability, Node, QPath, TyKind,
+};
use rustc_lint::LateContext;
use rustc_span::sym;
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 43665a922..4a5a94f26 100644
--- a/src/tools/clippy/clippy_lints/src/types/box_collection.rs
+++ b/src/tools/clippy/clippy_lints/src/types/box_collection.rs
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{path_def_id, qpath_generic_tys};
-use rustc_hir::{self as hir, def_id::DefId, QPath};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, QPath};
use rustc_lint::LateContext;
use rustc_span::{sym, Symbol};
diff --git a/src/tools/clippy/clippy_lints/src/types/linked_list.rs b/src/tools/clippy/clippy_lints/src/types/linked_list.rs
index 5fb708741..fba804bbe 100644
--- a/src/tools/clippy/clippy_lints/src/types/linked_list.rs
+++ b/src/tools/clippy/clippy_lints/src/types/linked_list.rs
@@ -1,5 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_hir::{self as hir, def_id::DefId};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir};
use rustc_lint::LateContext;
use rustc_span::symbol::sym;
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 3c873a590..79f9d45d5 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -349,7 +349,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
match item.kind {
- ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => self.check_ty(
+ ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty(
cx,
ty,
CheckTyContext {
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 8767e3c30..60622903a 100644
--- a/src/tools/clippy/clippy_lints/src/types/option_option.rs
+++ b/src/tools/clippy/clippy_lints/src/types/option_option.rs
@@ -1,7 +1,8 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{path_def_id, qpath_generic_tys};
use if_chain::if_chain;
-use rustc_hir::{self as hir, def_id::DefId, QPath};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, QPath};
use rustc_lint::LateContext;
use rustc_span::symbol::sym;
diff --git a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
index 855137b14..f6c2d8d5a 100644
--- a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
+++ b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
@@ -2,7 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{path_def_id, qpath_generic_tys};
use rustc_errors::Applicability;
-use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, QPath, TyKind};
use rustc_lint::LateContext;
use rustc_span::symbol::sym;
@@ -22,7 +23,9 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
app,
);
} else {
- let Some(ty) = qpath_generic_tys(qpath).next() else { return false };
+ let Some(ty) = qpath_generic_tys(qpath).next() else {
+ return false;
+ };
let Some(id) = path_def_id(cx, ty) else { return false };
if !cx.tcx.is_diagnostic_item(sym::Vec, id) {
return 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 a75972cf3..a616c3e4e 100644
--- a/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
@@ -1,7 +1,8 @@
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::{self as hir, def_id::DefId, QPath};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, QPath};
use rustc_lint::LateContext;
use rustc_span::symbol::sym;
diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
index f7adc9d35..5a986254f 100644
--- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
+++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
@@ -2,7 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::{path_def_id, qpath_generic_tys};
use rustc_errors::Applicability;
-use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, QPath, TyKind};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::LateContext;
use rustc_middle::ty::TypeVisitableExt;
@@ -39,7 +40,9 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
return true;
}
- let Some(ty) = qpath_generic_tys(qpath).next() else { return false };
+ let Some(ty) = qpath_generic_tys(qpath).next() else {
+ return false;
+ };
let Some(id) = path_def_id(cx, ty) else { return false };
let (inner_sym, ty) = match cx.tcx.get_diagnostic_name(id) {
Some(sym::Arc) => ("Arc", ty),
@@ -49,7 +52,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
};
let TyKind::Path(inner_qpath) = &ty.kind else {
- return false
+ return false;
};
let inner_span = match qpath_generic_tys(inner_qpath).next() {
Some(hir_ty) => {
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 d3062f3d2..decc183ad 100644
--- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
@@ -3,7 +3,8 @@ use clippy_utils::last_path_segment;
use clippy_utils::source::snippet;
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::{self as hir, def_id::DefId, GenericArg, QPath, TyKind};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, GenericArg, QPath, TyKind};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::LateContext;
use rustc_middle::ty::layout::LayoutOf;
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 a9deee967..f2ef60201 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -158,11 +158,12 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
}
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &hir::Stmt<'tcx>) {
- let (
- hir::StmtKind::Local(&hir::Local { init: Some(expr), .. })
- | hir::StmtKind::Expr(expr)
- | hir::StmtKind::Semi(expr)
- ) = stmt.kind else { return };
+ let (hir::StmtKind::Local(&hir::Local { init: Some(expr), .. })
+ | hir::StmtKind::Expr(expr)
+ | hir::StmtKind::Semi(expr)) = stmt.kind
+ else {
+ return;
+ };
if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, stmt.hir_id)
&& !in_external_macro(cx.tcx.sess, stmt.span)
&& let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, stmt.span, stmt.hir_id)
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index 1ab0162a8..6756df8e7 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -88,7 +88,7 @@ fn handle_uninit_vec_pair<'tcx>(
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(_, substs) = vec_ty.kind();
+ if 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 {
@@ -96,7 +96,7 @@ fn handle_uninit_vec_pair<'tcx>(
// with_capacity / reserve -> set_len
// Check T of Vec<T>
- if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)) {
+ 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(
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 99a1d1976..dd829ded0 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
@@ -65,7 +65,7 @@ fn get_projection_pred<'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));
- if projection_pred.projection_ty.substs == trait_pred.trait_ref.substs {
+ if projection_pred.projection_ty.args == trait_pred.trait_ref.args {
return Some(projection_pred);
}
}
@@ -76,7 +76,7 @@ fn get_projection_pred<'tcx>(
fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Vec<(usize, String)> {
let mut args_to_check = Vec::new();
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
- let fn_sig = cx.tcx.fn_sig(def_id).subst_identity();
+ let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity();
let generics = cx.tcx.predicates_of(def_id);
let fn_mut_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().fn_mut_trait());
let ord_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.get_diagnostic_item(sym::Ord));
@@ -120,8 +120,8 @@ 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, substs) = &cx.typeck_results().node_type(arg.hir_id).kind();
- let ret_ty = substs.as_closure().sig().output();
+ 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 {
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index cc7c2b039..704d7abd7 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -161,7 +161,7 @@ fn needs_inferred_result_ty(
},
_ => return false,
};
- let sig = cx.tcx.fn_sig(id).subst_identity().skip_binder();
+ let sig = cx.tcx.fn_sig(id).instantiate_identity().skip_binder();
if let ty::Param(output_ty) = *sig.output().kind() {
let args: Vec<&Expr<'_>> = if let Some(receiver) = receiver {
std::iter::once(receiver).chain(args.iter()).collect()
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 dd120599c..462b1aa81 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
@@ -42,7 +42,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) {
!matches!(
&arg.kind,
- ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..)
+ ExprKind::Match(.., MatchSource::TryDesugar(_)) | ExprKind::Path(..)
)
} else {
false
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
index 226495dcb..d4342ec51 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
@@ -14,7 +14,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
"assert_ne" | "debug_assert_ne" => "fail",
_ => return,
};
- let Some ((left, _, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
+ let Some((left, _, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else {
+ return;
+ };
if !cx.typeck_results().expr_ty(left).is_unit() {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/unnamed_address.rs b/src/tools/clippy/clippy_lints/src/unnamed_address.rs
index 0f5cdb6aa..dea8a1e35 100644
--- a/src/tools/clippy/clippy_lints/src/unnamed_address.rs
+++ b/src/tools/clippy/clippy_lints/src/unnamed_address.rs
@@ -97,7 +97,7 @@ impl LateLintPass<'_> for UnnamedAddress {
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 match_def_path(cx, def_id, &paths::PTR_EQ);
- let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0);
+ let ty_param = cx.typeck_results().node_args(func.hir_id).type_at(0);
if ty_param.is_trait();
then {
span_lint_and_help(
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 e7449639f..ed2ef5063 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
@@ -1,6 +1,8 @@
-use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::approx_ty_size;
use rustc_errors::Applicability;
-use rustc_hir::{def_id::LocalDefId, FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
+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_span::Symbol;
@@ -63,7 +65,9 @@ impl UnnecessaryBoxReturns {
return;
}
- let FnRetTy::Return(return_ty_hir) = &decl.output else { return };
+ let FnRetTy::Return(return_ty_hir) = &decl.output else {
+ return;
+ };
let return_ty = cx
.tcx
@@ -103,25 +107,33 @@ impl UnnecessaryBoxReturns {
impl LateLintPass<'_> for UnnecessaryBoxReturns {
fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
- let TraitItemKind::Fn(signature, _) = &item.kind else { return };
+ let TraitItemKind::Fn(signature, _) = &item.kind else {
+ return;
+ };
self.check_fn_item(cx, signature.decl, item.owner_id.def_id, item.ident.name);
}
fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
// Ignore implementations of traits, because the lint should be on the
// trait, not on the implementation of it.
- let Node::Item(parent) = cx.tcx.hir().get_parent(item.hir_id()) else { return };
+ let Node::Item(parent) = cx.tcx.hir().get_parent(item.hir_id()) else {
+ return;
+ };
let ItemKind::Impl(parent) = parent.kind else { return };
if parent.of_trait.is_some() {
return;
}
- let ImplItemKind::Fn(signature, ..) = &item.kind else { return };
+ let ImplItemKind::Fn(signature, ..) = &item.kind else {
+ return;
+ };
self.check_fn_item(cx, signature.decl, item.owner_id.def_id, item.ident.name);
}
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
- let ItemKind::Fn(signature, ..) = &item.kind else { return };
+ let ItemKind::Fn(signature, ..) = &item.kind else {
+ return;
+ };
self.check_fn_item(cx, signature.decl, item.owner_id.def_id, item.ident.name);
}
}
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 6e802794f..57a4a429e 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,4 +1,5 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, ty::is_type_lang_item};
+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;
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 084b03198..f4111186c 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs
@@ -1,4 +1,7 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_expr, path_to_local, source::snippet, ty::is_copy};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+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};
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index 5073eb02b..f34f8d0e3 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
-use clippy_utils::{contains_return, is_res_lang_ctor, path_res, return_ty, visitors::find_all_ret_expressions};
+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;
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 a57bf7ee8..9cf595772 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -6,7 +6,8 @@ use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::over;
use rustc_ast::mut_visit::*;
use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, Mutability, Pat, PatKind, PatKind::*, DUMMY_NODE_ID};
+use rustc_ast::PatKind::*;
+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};
@@ -162,9 +163,7 @@ fn unnest_or_patterns(pat: &mut P<Pat>) -> bool {
noop_visit_pat(p, self);
// Don't have an or-pattern? Just quit early on.
- let Or(alternatives) = &mut p.kind else {
- return
- };
+ let Or(alternatives) = &mut p.kind else { return };
// Collapse or-patterns directly nested in or-patterns.
let mut idx = 0;
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index 5e42cf7e4..bc7c3897a 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -1,11 +1,12 @@
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::is_def_id_trait_method;
+use rustc_hir::def::DefKind;
use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnDecl, YieldSource};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::def_id::LocalDefId;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::{LocalDefId, LocalDefIdSet};
use rustc_span::Span;
declare_clippy_lint! {
@@ -38,7 +39,24 @@ declare_clippy_lint! {
"finds async functions with no await statements"
}
-declare_lint_pass!(UnusedAsync => [UNUSED_ASYNC]);
+#[derive(Default)]
+pub struct UnusedAsync {
+ /// Keeps track of async functions used as values (i.e. path expressions to async functions that
+ /// are not immediately called)
+ async_fns_as_value: LocalDefIdSet,
+ /// Functions with unused `async`, linted post-crate after we've found all uses of local async
+ /// functions
+ unused_async_fns: Vec<UnusedAsyncFn>,
+}
+
+#[derive(Copy, Clone)]
+struct UnusedAsyncFn {
+ def_id: LocalDefId,
+ fn_span: Span,
+ await_in_async_block: Option<Span>,
+}
+
+impl_lint_pass!(UnusedAsync => [UNUSED_ASYNC]);
struct AsyncFnVisitor<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
@@ -101,24 +119,70 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
};
walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id);
if !visitor.found_await {
- span_lint_and_then(
- cx,
- UNUSED_ASYNC,
- span,
- "unused `async` for function with no await statements",
- |diag| {
- diag.help("consider removing the `async` from this function");
-
- if let Some(span) = visitor.await_in_async_block {
- diag.span_note(
- span,
- "`await` used in an async block, which does not require \
- the enclosing function to be `async`",
- );
- }
- },
- );
+ // Don't lint just yet, but store the necessary information for later.
+ // The actual linting happens in `check_crate_post`, once we've found all
+ // uses of local async functions that do require asyncness to pass typeck
+ self.unused_async_fns.push(UnusedAsyncFn {
+ await_in_async_block: visitor.await_in_async_block,
+ fn_span: span,
+ def_id,
+ });
}
}
}
+
+ fn check_path(&mut self, cx: &LateContext<'tcx>, path: &rustc_hir::Path<'tcx>, hir_id: rustc_hir::HirId) {
+ fn is_node_func_call(node: Node<'_>, expected_receiver: Span) -> bool {
+ matches!(
+ node,
+ Node::Expr(Expr {
+ kind: ExprKind::Call(Expr { span, .. }, _) | ExprKind::MethodCall(_, Expr { span, .. }, ..),
+ ..
+ }) if *span == expected_receiver
+ )
+ }
+
+ // Find paths to local async functions that aren't immediately called.
+ // E.g. `async fn f() {}; let x = f;`
+ // Depending on how `x` is used, f's asyncness might be required despite not having any `await`
+ // 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.asyncness(def_id).is_async()
+ && !is_node_func_call(cx.tcx.hir().get_parent(hir_id), path.span)
+ {
+ self.async_fns_as_value.insert(local_def_id);
+ }
+ }
+
+ // After collecting all unused `async` and problematic paths to such functions,
+ // lint those unused ones that didn't have any path expressions to them.
+ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+ let iter = self
+ .unused_async_fns
+ .iter()
+ .filter(|UnusedAsyncFn { def_id, .. }| (!self.async_fns_as_value.contains(def_id)));
+
+ for fun in iter {
+ span_lint_hir_and_then(
+ cx,
+ UNUSED_ASYNC,
+ cx.tcx.local_def_id_to_hir_id(fun.def_id),
+ fun.fn_span,
+ "unused `async` for function with no await statements",
+ |diag| {
+ diag.help("consider removing the `async` from this function");
+
+ if let Some(span) = fun.await_in_async_block {
+ diag.span_note(
+ span,
+ "`await` used in an async block, which does not require \
+ the enclosing function to be `async`",
+ );
+ }
+ },
+ );
+ }
+ }
}
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 0e526c216..0fcb62017 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -48,7 +48,7 @@ declare_lint_pass!(UnusedIoAmount => [UNUSED_IO_AMOUNT]);
impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
let (hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr)) = s.kind else {
- return
+ return;
};
match expr.kind {
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs
index cad8da18c..95e74718d 100644
--- a/src/tools/clippy/clippy_lints/src/unused_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -1,7 +1,8 @@
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::{ast, visit::FnKind, ClosureBinder};
+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};
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 377d3fb6f..c99b0290c 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::higher;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{path_to_local, usage::is_potentially_mutated};
+use clippy_utils::usage::is_potentially_mutated;
+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};
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 5a0298745..50231d930 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -5,13 +5,12 @@ 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};
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::{walk_inf, walk_ty, Visitor};
use rustc_hir::{
- self as hir,
- def::{CtorOf, DefKind, Res},
- def_id::LocalDefId,
- intravisit::{walk_inf, walk_ty, Visitor},
- Expr, ExprKind, FnRetTy, FnSig, GenericArg, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl,
- ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind,
+ self as hir, Expr, ExprKind, FnRetTy, FnSig, GenericArg, GenericArgsParentheses, GenericParam, GenericParamKind,
+ HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind,
};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
@@ -145,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
then {
// `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
// `Self`.
- let self_ty = impl_trait_ref.subst_identity().self_ty();
+ 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.
@@ -154,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
.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).subst_identity();
+ 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);
// `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the
@@ -226,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
} else {
hir_ty_to_ty(cx.tcx, hir_ty)
};
- if same_type_and_consts(ty, cx.tcx.type_of(impl_id).subst_identity());
+ if same_type_and_consts(ty, cx.tcx.type_of(impl_id).instantiate_identity());
then {
span_lint(cx, hir_ty.span);
}
@@ -238,7 +237,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
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).subst_identity();
+ if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id).instantiate_identity();
then {} else { return; }
}
match expr.kind {
@@ -262,7 +261,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
if 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).subst_identity();
+ if cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id).instantiate_identity();
then {
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 22de383ea..5ac4f0aa4 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -1,9 +1,8 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::is_ty_alias;
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
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, match_def_path, path_to_local, paths};
+use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, match_def_path, path_to_local, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::DefKind;
@@ -117,9 +116,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
}
match e.kind {
- ExprKind::Match(_, arms, MatchSource::TryDesugar) => {
+ ExprKind::Match(_, arms, MatchSource::TryDesugar(_)) => {
let (ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e))) = arms[0].body.kind else {
- return
+ return;
};
if let ExprKind::Call(_, [arg, ..]) = e.kind {
self.try_desugar_arm.push(arg.hir_id);
@@ -236,8 +235,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
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(_, substs) = a.kind();
- if let Some(a_type) = substs.types().next();
+ if let ty::Adt(_, args) = a.kind();
+ if let Some(a_type) = args.types().next();
if same_type_and_consts(a_type, b);
then {
@@ -264,8 +263,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
if_chain! {
if match_def_path(cx, def_id, &paths::TRY_FROM);
if is_type_diagnostic_item(cx, a, sym::Result);
- if let ty::Adt(_, substs) = a.kind();
- if let Some(a_type) = substs.types().next();
+ if let ty::Adt(_, args) = a.kind();
+ if let Some(a_type) = args.types().next();
if same_type_and_consts(a_type, b);
then {
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 6b51974d7..f02c33cc6 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -526,7 +526,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
self.ident(field_name);
self.expr(object);
},
- ExprKind::Index(object, index) => {
+ ExprKind::Index(object, index, _) => {
bind!(self, object, index);
kind!("Index({object}, {index})");
self.expr(object);
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index f1d05c752..58ae0656d 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -319,7 +319,7 @@ define_Conf! {
/// Lint: DISALLOWED_NAMES.
///
/// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
- /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
+ /// `".."` can be used as part of the list to indicate that the configured values should be appended to the
/// default configuration of Clippy. By default, any configuration will replace the default value.
(disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
/// Lint: SEMICOLON_INSIDE_BLOCK.
@@ -551,6 +551,16 @@ define_Conf! {
///
/// Whether to allow `r#""#` when `r""` can be used
(allow_one_hash_in_raw_strings: bool = false),
+ /// Lint: ABSOLUTE_PATHS.
+ ///
+ /// The maximum number of segments a path can have before being linted, anything above this will
+ /// be linted.
+ (absolute_paths_max_segments: u64 = 2),
+ /// Lint: ABSOLUTE_PATHS.
+ ///
+ /// Which crates to allow absolute paths from
+ (absolute_paths_allowed_crates: rustc_data_structures::fx::FxHashSet<String> =
+ rustc_data_structures::fx::FxHashSet::default()),
}
/// Search for the configuration file.
diff --git a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs
index 09fcb82c3..6d3493523 100644
--- a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs
@@ -71,7 +71,9 @@ fn has_span_from_proc_macro(cx: &EarlyContext<'_>, args: &FormatArgs) -> bool {
for between_span in between_spans {
let mut seen_comma = false;
- let Some(snippet) = snippet_opt(cx, between_span) else { return true };
+ let Some(snippet) = snippet_opt(cx, between_span) else {
+ return true;
+ };
for token in tokenize(&snippet) {
match token.kind {
TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {},
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
index 883a5c08e..fe2f12fe8 100644
--- 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
@@ -46,7 +46,9 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
} else {
return;
};
- let ExprKind::Block(then_block, _) = then.kind 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);
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 dced9fcf9..da8654d93 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
@@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
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).subst_identity();
+ 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();
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 9afe02c1e..4ed985f54 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
@@ -7,7 +7,8 @@ use rustc_hir::def::DefKind;
use rustc_hir::Item;
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, fast_reject::SimplifiedType, FloatTy};
+use rustc_middle::ty::fast_reject::SimplifiedType;
+use rustc_middle::ty::{self, FloatTy};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::Symbol;
@@ -33,7 +34,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
if_chain! {
if mod_name.as_str() == "paths";
- if let hir::ItemKind::Const(ty, body_id) = item.kind;
+ if let hir::ItemKind::Const(ty, _, body_id) = item.kind;
let ty = hir_ty_to_ty(cx.tcx, ty);
if let ty::Array(el_ty, _) = &ty.kind();
if let ty::Ref(_, el_ty, _) = &el_ty.kind();
@@ -73,10 +74,10 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
let lang_items = cx.tcx.lang_items();
// This list isn't complete, but good enough for our current list of paths.
let incoherent_impls = [
- SimplifiedType::FloatSimplifiedType(FloatTy::F32),
- SimplifiedType::FloatSimplifiedType(FloatTy::F64),
- SimplifiedType::SliceSimplifiedType,
- SimplifiedType::StrSimplifiedType,
+ SimplifiedType::Float(FloatTy::F32),
+ SimplifiedType::Float(FloatTy::F64),
+ SimplifiedType::Slice,
+ SimplifiedType::Str,
]
.iter()
.flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter().copied());
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 f71820765..87380f14f 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
@@ -3,10 +3,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::{is_lint_allowed, match_def_path, paths};
use if_chain::if_chain;
-use rustc_ast as ast;
use rustc_ast::ast::LitKind;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::Visitor;
@@ -18,6 +16,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::Symbol;
use rustc_span::{sym, Span};
+use {rustc_ast as ast, rustc_hir as hir};
declare_clippy_lint! {
/// ### What it does
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 107a62806..f49c3fadb 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -8,11 +8,8 @@
//! a simple mistake)
use crate::renamed_lints::RENAMED_LINTS;
-use crate::utils::{
- collect_configs,
- internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type},
- ClippyConfiguration,
-};
+use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type};
+use crate::utils::{collect_configs, ClippyConfiguration};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
@@ -21,22 +18,22 @@ use if_chain::if_chain;
use itertools::Itertools;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::{
- self as hir, def::DefKind, intravisit, intravisit::Visitor, Closure, ExprKind, Item, ItemKind, Mutability, QPath,
-};
+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_middle::hir::nested_filter;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::Ident;
use rustc_span::{sym, Loc, Span, Symbol};
-use serde::{ser::SerializeStruct, Serialize, Serializer};
+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, OpenOptions};
use std::io::prelude::*;
-use std::path::Path;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use std::process::Command;
/// This is the json output file of the lint collector.
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 09f0f0d0a..bf835f89c 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
@@ -7,7 +7,7 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::{self, subst::GenericArgKind};
+use rustc_middle::ty::{self, GenericArgKind};
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
@@ -39,7 +39,7 @@ impl LateLintPass<'_> for MsrvAttrImpl {
if self_ty_def.all_fields().any(|f| {
cx.tcx
.type_of(f.did)
- .subst_identity()
+ .instantiate_identity()
.walk()
.filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
.any(|t| match_type(cx, t.expect_ty(), &paths::MSRV))
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 008423766..f66f33fee 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
@@ -229,11 +229,11 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
Res::Def(DefKind::Static(_), def_id) => read_mir_alloc_def_path(
cx,
cx.tcx.eval_static_initializer(def_id).ok()?.inner(),
- cx.tcx.type_of(def_id).subst_identity(),
+ cx.tcx.type_of(def_id).instantiate_identity(),
),
Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? {
ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => {
- read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id).subst_identity())
+ read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id).instantiate_identity())
},
_ => None,
},
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index fb0825693..4fef8c071 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -18,7 +18,7 @@ const BOOK_CONFIGS_PATH: &str = "https://doc.rust-lang.org/clippy/lint_configura
// ==================================================================
// Configuration
// ==================================================================
-#[derive(Debug, Clone, Default)] //~ ERROR no such field
+#[derive(Debug, Clone, Default)]
pub struct ClippyConfiguration {
pub name: String,
#[allow(dead_code)]
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index 2a594e750..fc17e7c6d 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -154,6 +154,10 @@ impl UselessVec {
span: Span,
suggest_slice: SuggestedType,
) {
+ if span.from_expansion() {
+ return;
+ }
+
let mut applicability = Applicability::MachineApplicable;
let snippet = match *vec_args {
@@ -181,7 +185,7 @@ impl UselessVec {
if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack {
return;
}
- let span = args[0].span.to(last.span);
+ let span = args[0].span.source_callsite().to(last.span.source_callsite());
let args = snippet_with_applicability(cx, span, "..", &mut applicability);
match suggest_slice {
@@ -230,8 +234,8 @@ fn size_of(cx: &LateContext<'_>, expr: &Expr<'_>) -> u64 {
/// Returns the item type of the vector (i.e., the `T` in `Vec<T>`).
fn vec_type(ty: Ty<'_>) -> Ty<'_> {
- if let ty::Adt(_, substs) = ty.kind() {
- substs.type_at(0)
+ if let ty::Adt(_, args) = ty.kind() {
+ args.type_at(0)
} else {
panic!("The type of `vec!` is a not a struct?");
}
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 bd5be0c9d..3fa51216c 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
@@ -74,7 +74,7 @@ impl VecPushSearcher {
let mut needs_mut = false;
let res = for_each_local_use_after_expr(cx, self.local_id, self.last_push_expr, |e| {
let Some(parent) = get_parent_expr(cx, e) else {
- return ControlFlow::Continue(())
+ return ControlFlow::Continue(());
};
let adjusted_ty = cx.typeck_results().expr_ty_adjusted(e);
let adjusted_mut = adjusted_ty.ref_mutability().unwrap_or(Mutability::Not);
@@ -88,7 +88,7 @@ impl VecPushSearcher {
let mut last_place = parent;
while let Some(parent) = get_parent_expr(cx, last_place) {
if matches!(parent.kind, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Field(..))
- || matches!(parent.kind, ExprKind::Index(e, _) if e.hir_id == last_place.hir_id)
+ || matches!(parent.kind, ExprKind::Index(e, _, _) if e.hir_id == last_place.hir_id)
{
last_place = parent;
} else {
diff --git a/src/tools/clippy/clippy_lints/src/visibility.rs b/src/tools/clippy/clippy_lints/src/visibility.rs
index 43248bccc..496376520 100644
--- a/src/tools/clippy/clippy_lints/src/visibility.rs
+++ b/src/tools/clippy/clippy_lints/src/visibility.rs
@@ -1,10 +1,12 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_opt};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_opt;
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_span::{symbol::kw, Span};
+use rustc_span::symbol::kw;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 2a3d86988..d09d02a7d 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -3,10 +3,8 @@ 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},
- Item, ItemKind, PathSegment, UseKind,
-};
+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};
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index f194dc5d4..a9957b18a 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -272,9 +272,15 @@ impl<'tcx> LateLintPass<'tcx> for Write {
}
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
- let Some(diag_name) = cx.tcx.get_diagnostic_name(macro_call.def_id) else { return };
- let Some(name) = diag_name.as_str().strip_suffix("_macro") else { return };
+ let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
+ return;
+ };
+ let Some(diag_name) = cx.tcx.get_diagnostic_name(macro_call.def_id) else {
+ return;
+ };
+ let Some(name) = diag_name.as_str().strip_suffix("_macro") else {
+ return;
+ };
let is_build_script = cx
.sess()
@@ -343,7 +349,9 @@ fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
}
fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) {
- let Some(FormatArgsPiece::Literal(last)) = format_args.template.last() else { return };
+ let Some(FormatArgsPiece::Literal(last)) = format_args.template.last() else {
+ return;
+ };
let count_vertical_whitespace = || {
format_args
@@ -379,7 +387,9 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma
&format!("using `{name}!()` with a format string that ends in a single newline"),
|diag| {
let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!');
- let Some(format_snippet) = snippet_opt(cx, format_string_span) else { return };
+ let Some(format_snippet) = snippet_opt(cx, format_string_span) else {
+ return;
+ };
if format_args.template.len() == 1 && last.as_str() == "\n" {
// print!("\n"), write!(f, "\n")
@@ -522,7 +532,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
{
let replacement = replacement.replace('{', "{{").replace('}', "}}");
diag.multipart_suggestion(
- "try this",
+ "try",
vec![(*placeholder_span, replacement), (removal_span, String::new())],
Applicability::MachineApplicable,
);
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 93e4b023c..002304f88 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
@@ -51,8 +51,8 @@ impl LateLintPass<'_> for ZeroSizedMapValues {
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(_, substs) = ty.kind();
- let ty = substs.type_at(1);
+ if 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();
diff --git a/src/tools/clippy/clippy_test_deps/Cargo.toml b/src/tools/clippy/clippy_test_deps/Cargo.toml
deleted file mode 100644
index 362c08e0d..000000000
--- a/src/tools/clippy/clippy_test_deps/Cargo.toml
+++ /dev/null
@@ -1,23 +0,0 @@
-[package]
-name = "clippy_test_deps"
-version = "0.1.0"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-clippy_utils = { path = "../clippy_utils" }
-derive-new = "0.5"
-if_chain = "1.0"
-itertools = "0.10.1"
-quote = "1.0"
-serde = { version = "1.0.125", features = ["derive"] }
-syn = { version = "2.0", features = ["full"] }
-futures = "0.3"
-parking_lot = "0.12"
-tokio = { version = "1", features = ["io-util"] }
-regex = "1.5"
-clippy_lints = { path = "../clippy_lints" }
-
-[features]
-internal = ["clippy_lints/internal"]
diff --git a/src/tools/clippy/clippy_test_deps/src/lib.rs b/src/tools/clippy/clippy_test_deps/src/lib.rs
deleted file mode 100644
index 7d12d9af8..000000000
--- a/src/tools/clippy/clippy_test_deps/src/lib.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-pub fn add(left: usize, right: usize) -> usize {
- left + right
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn it_works() {
- let result = add(2, 2);
- assert_eq!(result, 4);
- }
-}
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index cfe686eb9..3926b954e 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy_utils"
-version = "0.1.72"
+version = "0.1.73"
edition = "2021"
publish = false
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 8cc01f1ef..140cfa219 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -178,7 +178,9 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
(Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r),
(Break(ll, le), Break(rl, re)) => eq_label(ll, rl) && eq_expr_opt(le, re),
(Continue(ll), Continue(rl)) => eq_label(ll, rl),
- (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2), Index(r1, r2)) => eq_expr(l1, r1) && eq_expr(l2, r2),
+ (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => {
+ eq_expr(l1, r1) && eq_expr(l2, r2)
+ },
(AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv),
(Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp),
(Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, eq_arm),
@@ -301,15 +303,17 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
(
Const(box ast::ConstItem {
defaultness: ld,
+ generics: lg,
ty: lt,
expr: le,
}),
Const(box ast::ConstItem {
defaultness: rd,
+ generics: rg,
ty: rt,
expr: re,
}),
- ) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
+ ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le, re),
(
Fn(box ast::Fn {
defaultness: ld,
@@ -476,15 +480,17 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
(
Const(box ast::ConstItem {
defaultness: ld,
+ generics: lg,
ty: lt,
expr: le,
}),
Const(box ast::ConstItem {
defaultness: rd,
+ generics: rg,
ty: rt,
expr: re,
}),
- ) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
+ ) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le, re),
(
Fn(box ast::Fn {
defaultness: ld,
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index 49cb9718e..51771f78d 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -1,5 +1,4 @@
-use rustc_ast::ast;
-use rustc_ast::attr;
+use rustc_ast::{ast, attr};
use rustc_errors::Applicability;
use rustc_session::Session;
use rustc_span::sym;
@@ -143,13 +142,13 @@ pub fn get_unique_attr<'a>(
unique_attr
}
-/// Return true if the attributes contain any of `proc_macro`,
+/// Returns true if the attributes contain any of `proc_macro`,
/// `proc_macro_derive` or `proc_macro_attribute`, false otherwise
pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool {
attrs.iter().any(rustc_ast::Attribute::is_proc_macro_attr)
}
-/// Return true if the attributes contain `#[doc(hidden)]`
+/// Returns true if the attributes contain `#[doc(hidden)]`
pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool {
attrs
.iter()
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index c6d0b654f..6be8b8bb9 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -12,20 +12,20 @@
//! code was written, and check if the span contains that text. Note this will only work correctly
//! if the span is not from a `macro_rules` based macro.
-use rustc_ast::{
- ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, UintTy},
- token::CommentKind,
- AttrStyle,
-};
+use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, UintTy};
+use rustc_ast::token::CommentKind;
+use rustc_ast::AttrStyle;
+use rustc_hir::intravisit::FnKind;
use rustc_hir::{
- intravisit::FnKind, Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId,
- Impl, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem,
- TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource,
+ Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId, Impl, ImplItem,
+ ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem, TraitItemKind, Ty,
+ TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource,
};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
-use rustc_span::{symbol::Ident, Span, Symbol};
+use rustc_span::symbol::Ident;
+use rustc_span::{Span, Symbol};
use rustc_target::spec::abi::Abi;
/// The search pattern to look for. Used by `span_matches_pat`
@@ -149,7 +149,7 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
(Pat::Str("for"), Pat::Str("}"))
},
ExprKind::Match(_, _, MatchSource::Normal) => (Pat::Str("match"), Pat::Str("}")),
- ExprKind::Match(e, _, MatchSource::TryDesugar) => (expr_search_pat(tcx, e).0, Pat::Str("?")),
+ ExprKind::Match(e, _, MatchSource::TryDesugar(_)) => (expr_search_pat(tcx, e).0, Pat::Str("?")),
ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => {
(expr_search_pat(tcx, e).0, Pat::Str("await"))
},
@@ -163,7 +163,7 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
) => (Pat::Str("unsafe"), Pat::Str("}")),
ExprKind::Block(_, None) => (Pat::Str("{"), Pat::Str("}")),
ExprKind::Field(e, name) => (expr_search_pat(tcx, e).0, Pat::Sym(name.name)),
- ExprKind::Index(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")),
+ ExprKind::Index(e, _, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")),
ExprKind::Path(ref path) => qpath_search_pat(path),
ExprKind::AddrOf(_, _, e) => (Pat::Str("&"), expr_search_pat(tcx, e).1),
ExprKind::Break(Destination { label: None, .. }, None) => (Pat::Str("break"), Pat::Str("break")),
@@ -339,7 +339,7 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
TyKind::Tup(..) => (Pat::Str("("), Pat::Str(")")),
TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")),
TyKind::Path(qpath) => qpath_search_pat(&qpath),
- // NOTE: This is missing `TraitObject`. It always return true then.
+ // NOTE: This is missing `TraitObject`. It will always return true then.
_ => (Pat::Str(""), Pat::Str("")),
}
}
diff --git a/src/tools/clippy/clippy_utils/src/comparisons.rs b/src/tools/clippy/clippy_utils/src/comparisons.rs
index 7a18d5e81..5e6bf2278 100644
--- a/src/tools/clippy/clippy_utils/src/comparisons.rs
+++ b/src/tools/clippy/clippy_utils/src/comparisons.rs
@@ -1,11 +1,11 @@
-//! Utility functions about comparison operators.
+//! Utility functions for comparison operators.
#![deny(clippy::missing_docs_in_private_items)]
use rustc_hir::{BinOpKind, Expr};
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
-/// Represent a normalized comparison operator.
+/// Represents a normalized comparison operator.
pub enum Rel {
/// `<`
Lt,
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index d1cfdc496..6d57af325 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -9,11 +9,9 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
use rustc_lexer::tokenize;
use rustc_lint::LateContext;
-use rustc_middle::mir;
use rustc_middle::mir::interpret::Scalar;
-use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt};
-use rustc_middle::ty::{List, SubstsRef};
-use rustc_middle::{bug, span_bug};
+use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, List, ScalarInt, Ty, TyCtxt};
+use rustc_middle::{bug, mir, span_bug};
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::SyntaxContext;
use std::cmp::Ordering::{self, Equal};
@@ -155,7 +153,7 @@ impl<'tcx> Constant<'tcx> {
},
(Self::Vec(l), Self::Vec(r)) => {
let (ty::Array(cmp_type, _) | ty::Slice(cmp_type)) = *cmp_type.kind() else {
- return None
+ return None;
};
iter::zip(l, r)
.map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri))
@@ -267,7 +265,7 @@ pub fn constant_with_source<'tcx>(
res.map(|x| (x, ctxt.source))
}
-/// Attempts to evaluate an expression only if it's value is not dependent on other items.
+/// Attempts to evaluate an expression only if its value is not dependent on other items.
pub fn constant_simple<'tcx>(
lcx: &LateContext<'tcx>,
typeck_results: &ty::TypeckResults<'tcx>,
@@ -327,17 +325,17 @@ pub struct ConstEvalLateContext<'a, 'tcx> {
typeck_results: &'a ty::TypeckResults<'tcx>,
param_env: ty::ParamEnv<'tcx>,
source: ConstantSource,
- substs: SubstsRef<'tcx>,
+ args: GenericArgsRef<'tcx>,
}
impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
- fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self {
+ pub fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self {
Self {
lcx,
typeck_results,
param_env: lcx.param_env,
source: ConstantSource::Local,
- substs: List::empty(),
+ args: List::empty(),
}
}
@@ -396,7 +394,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
}
}
},
- ExprKind::Index(arr, index) => self.index(arr, index),
+ ExprKind::Index(arr, index, _) => self.index(arr, index),
ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
ExprKind::Field(local_expr, ref field) => {
let result = self.expr(local_expr);
@@ -463,7 +461,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
// Check if this constant is based on `cfg!(..)`,
// which is NOT constant for our purposes.
if let Some(node) = self.lcx.tcx.hir().get_if_local(def_id)
- && let Node::Item(Item { kind: ItemKind::Const(_, body_id), .. }) = node
+ && let Node::Item(Item { kind: ItemKind::Const(.., body_id), .. }) = node
&& let Node::Expr(Expr { kind: ExprKind::Lit(_), span, .. }) = self.lcx
.tcx
.hir()
@@ -473,16 +471,16 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
return None;
}
- let substs = self.typeck_results.node_substs(id);
- let substs = if self.substs.is_empty() {
- substs
+ let args = self.typeck_results.node_args(id);
+ let args = if self.args.is_empty() {
+ args
} else {
- EarlyBinder::bind(substs).subst(self.lcx.tcx, self.substs)
+ EarlyBinder::bind(args).instantiate(self.lcx.tcx, self.args)
};
let result = self
.lcx
.tcx
- .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, substs), None)
+ .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None)
.ok()
.map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?;
let result = miri_to_const(self.lcx, result)?;
@@ -726,7 +724,7 @@ fn field_of_struct<'tcx>(
field: &Ident,
) -> Option<mir::ConstantKind<'tcx>> {
if let mir::ConstantKind::Val(result, ty) = result
- && let Some(dc) = lcx.tcx.try_destructure_mir_constant_for_diagnostics((result, ty))
+ && let Some(dc) = rustc_const_eval::const_eval::try_destructure_mir_constant_for_diagnostics(lcx.tcx, result, ty)
&& let Some(dc_variant) = dc.variant
&& let Some(variant) = adt_def.variants().get(dc_variant)
&& let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name)
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 4a845ca63..0bcefba75 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -1,7 +1,7 @@
//! Utilities for evaluating whether eagerly evaluated expressions can be made lazy and vice versa.
//!
//! Things to consider:
-//! - has the expression side-effects?
+//! - does the expression have side-effects?
//! - is the expression computationally expensive?
//!
//! See lints:
@@ -12,14 +12,14 @@
use crate::ty::{all_predicates_of, is_copy};
use crate::visitors::is_const_evaluatable;
use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{def_id::DefId, Block, Expr, ExprKind, QPath, UnOp};
+use rustc_hir::{Block, Expr, ExprKind, QPath, UnOp};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_middle::ty::adjustment::Adjust;
use rustc_span::{sym, Symbol};
-use std::cmp;
-use std::ops;
+use std::{cmp, ops};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
enum EagernessSuggestion {
@@ -51,7 +51,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
let name = name.as_str();
let ty = match cx.tcx.impl_of_method(fn_id) {
- Some(id) => cx.tcx.type_of(id).subst_identity(),
+ Some(id) => cx.tcx.type_of(id).instantiate_identity(),
None => return Lazy,
};
@@ -68,19 +68,24 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
// Types where the only fields are generic types (or references to) with no trait bounds other
// than marker traits.
// Due to the limited operations on these types functions should be fairly cheap.
- if def
- .variants()
- .iter()
- .flat_map(|v| v.fields.iter())
- .any(|x| matches!(cx.tcx.type_of(x.did).subst_identity().peel_refs().kind(), ty::Param(_)))
- && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() {
- ty::ClauseKind::Trait(pred) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker,
- _ => true,
- })
- && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_)))
+ if def.variants().iter().flat_map(|v| v.fields.iter()).any(|x| {
+ matches!(
+ cx.tcx.type_of(x.did).instantiate_identity().peel_refs().kind(),
+ ty::Param(_)
+ )
+ }) && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() {
+ ty::ClauseKind::Trait(pred) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker,
+ _ => true,
+ }) && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_)))
{
// Limit the function to either `(self) -> bool` or `(&self) -> bool`
- match &**cx.tcx.fn_sig(fn_id).subst_identity().skip_binder().inputs_and_output {
+ match &**cx
+ .tcx
+ .fn_sig(fn_id)
+ .instantiate_identity()
+ .skip_binder()
+ .inputs_and_output
+ {
[arg, res] if !arg.is_mutable_ptr() && arg.peel_refs() == ty && res.is_bool() => NoChange,
_ => Lazy,
}
@@ -180,7 +185,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
.type_dependent_def_id(e.hir_id)
.map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, true));
},
- ExprKind::Index(_, e) => {
+ ExprKind::Index(_, e, _) => {
let ty = self.cx.typeck_results().expr_ty_adjusted(e);
if is_copy(self.cx, ty) && !ty.is_ref() {
self.eagerness |= NoChange;
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index a61e4c380..802adbd4d 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -13,7 +13,7 @@ use rustc_lint::LateContext;
use rustc_span::{sym, symbol, Span};
/// The essential nodes of a desugared for loop as well as the entire span:
-/// `for pat in arg { body }` becomes `(pat, arg, body)`. Return `(pat, arg, body, span)`.
+/// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`.
pub struct ForLoop<'tcx> {
/// `for` loop item
pub pat: &'tcx hir::Pat<'tcx>,
@@ -138,6 +138,7 @@ impl<'hir> IfLet<'hir> {
}
/// An `if let` or `match` expression. Useful for lints that trigger on one or the other.
+#[derive(Debug)]
pub enum IfLetOrMatch<'hir> {
/// Any `match` expression
Match(&'hir Expr<'hir>, &'hir [Arm<'hir>], MatchSource),
@@ -264,7 +265,7 @@ impl<'a> Range<'a> {
}
}
-/// Represent the pre-expansion arguments of a `vec!` invocation.
+/// Represents the pre-expansion arguments of a `vec!` invocation.
pub enum VecArgs<'a> {
/// `vec![elem; len]`
Repeat(&'a hir::Expr<'a>, &'a hir::Expr<'a>),
@@ -398,7 +399,7 @@ impl<'hir> WhileLet<'hir> {
}
}
-/// Converts a hir binary operator to the corresponding `ast` type.
+/// Converts a `hir` binary operator to the corresponding `ast` type.
#[must_use]
pub fn binop(op: hir::BinOpKind) -> ast::BinOpKind {
match op {
@@ -436,7 +437,7 @@ pub enum VecInitKind {
WithExprCapacity(HirId),
}
-/// Checks if given expression is an initialization of `Vec` and returns its kind.
+/// Checks if the given expression is an initialization of `Vec` and returns its kind.
pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<VecInitKind> {
if let ExprKind::Call(func, args) = expr.kind {
match func.kind {
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 3e1d73564..fdc35cd4d 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -5,10 +5,9 @@ use crate::tokenize_with_text;
use rustc_ast::ast::InlineAsmTemplatePiece;
use rustc_data_structures::fx::FxHasher;
use rustc_hir::def::Res;
-use rustc_hir::HirIdMap;
use rustc_hir::{
ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
- GenericArgs, Guard, HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, Pat, PatField, PatKind, Path,
+ GenericArgs, Guard, HirId, HirIdMap, InlineAsmOperand, Let, Lifetime, LifetimeName, Pat, PatField, PatKind, Path,
PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
};
use rustc_lexer::{tokenize, TokenKind};
@@ -253,15 +252,15 @@ impl HirEqInterExpr<'_, '_, '_> {
return false;
}
- if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results {
- if let (Some(l), Some(r)) = (
+ if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results
+ && typeck_lhs.expr_ty(left) == typeck_rhs.expr_ty(right)
+ && let (Some(l), Some(r)) = (
constant_simple(self.inner.cx, typeck_lhs, left),
constant_simple(self.inner.cx, typeck_rhs, right),
- ) {
- if l == r {
- return true;
- }
- }
+ )
+ && l == r
+ {
+ return true;
}
let is_eq = match (
@@ -300,7 +299,7 @@ impl HirEqInterExpr<'_, '_, '_> {
(&ExprKind::Field(l_f_exp, ref l_f_ident), &ExprKind::Field(r_f_exp, ref r_f_ident)) => {
l_f_ident.name == r_f_ident.name && self.eq_expr(l_f_exp, r_f_exp)
},
- (&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
+ (&ExprKind::Index(la, li, _), &ExprKind::Index(ra, ri, _)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
(&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
self.eq_expr(lc, rc) && self.eq_expr(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r))
},
@@ -495,10 +494,13 @@ impl HirEqInterExpr<'_, '_, '_> {
loop {
use TokenKind::{BlockComment, LineComment, Whitespace};
if left_data.macro_def_id != right_data.macro_def_id
- || (matches!(left_data.kind, ExpnKind::Macro(MacroKind::Bang, name) if name == sym::cfg)
- && !eq_span_tokens(self.inner.cx, left_data.call_site, right_data.call_site, |t| {
- !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. })
- }))
+ || (matches!(
+ left_data.kind,
+ ExpnKind::Macro(MacroKind::Bang, name)
+ if name == sym::cfg || name == sym::option_env
+ ) && !eq_span_tokens(self.inner.cx, left_data.call_site, right_data.call_site, |t| {
+ !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. })
+ }))
{
// Either a different chain of macro calls, or different arguments to the `cfg` macro.
return false;
@@ -728,7 +730,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
self.hash_expr(e);
self.hash_name(f.name);
},
- ExprKind::Index(a, i) => {
+ ExprKind::Index(a, i, _) => {
self.hash_expr(a);
self.hash_expr(i);
},
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 727b59f1f..6c4cec595 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -74,8 +74,7 @@ pub use self::hir_utils::{
use core::ops::ControlFlow;
use std::collections::hash_map::Entry;
use std::hash::BuildHasherDefault;
-use std::sync::OnceLock;
-use std::sync::{Mutex, MutexGuard};
+use std::sync::{Mutex, MutexGuard, OnceLock};
use if_chain::if_chain;
use itertools::Itertools;
@@ -84,41 +83,40 @@ use rustc_ast::Attribute;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unhash::UnhashMap;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalModDefId, LOCAL_CRATE};
use rustc_hir::hir_id::{HirIdMap, HirIdSet};
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
-use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
+use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
use rustc_hir::{
self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
- ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
- MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
- TraitItem, TraitItemRef, TraitRef, TyKind, UnOp,
+ ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item,
+ ItemKind, LangItem, Local, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy,
+ QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, Level, Lint, LintContext};
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::mir::ConstantKind;
-use rustc_middle::ty as rustc_ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::fast_reject::SimplifiedType::{
- ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType,
- PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType,
-};
+use rustc_middle::ty::fast_reject::SimplifiedType;
+use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{
- layout::IntegerExt, BorrowKind, ClosureKind, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UpvarCapture,
+ self as rustc_ty, Binder, BorrowKind, ClosureKind, FloatTy, IntTy, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeAndMut,
+ TypeVisitableExt, UintTy, UpvarCapture,
};
-use rustc_middle::ty::{FloatTy, IntTy, UintTy};
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::source_map::SourceMap;
-use rustc_span::sym;
use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
use rustc_target::abi::Integer;
use crate::consts::{constant, miri_to_const, Constant};
use crate::higher::Range;
-use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param};
+use crate::ty::{
+ adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type,
+ ty_is_fn_once_param,
+};
use crate::visitors::for_each_expr;
use rustc_middle::hir::nested_filter;
@@ -288,7 +286,7 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
/// Checks if the given `QPath` belongs to a type alias.
pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
match *qpath {
- QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias | DefKind::AssocTy, ..)),
+ QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias { .. } | DefKind::AssocTy, ..)),
QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => { is_ty_alias(&qpath) },
_ => false,
}
@@ -305,7 +303,7 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str])
/// Checks if a method is defined in an impl of a diagnostic item
pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
- if let Some(adt) = cx.tcx.type_of(impl_did).subst_identity().ty_adt_def() {
+ if let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def() {
return cx.tcx.is_diagnostic_item(diag_item, adt.did());
}
}
@@ -514,30 +512,30 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
let ty = match name {
- "bool" => BoolSimplifiedType,
- "char" => CharSimplifiedType,
- "str" => StrSimplifiedType,
- "array" => ArraySimplifiedType,
- "slice" => SliceSimplifiedType,
+ "bool" => SimplifiedType::Bool,
+ "char" => SimplifiedType::Char,
+ "str" => SimplifiedType::Str,
+ "array" => SimplifiedType::Array,
+ "slice" => SimplifiedType::Slice,
// FIXME: rustdoc documents these two using just `pointer`.
//
// Maybe this is something we should do here too.
- "const_ptr" => PtrSimplifiedType(Mutability::Not),
- "mut_ptr" => PtrSimplifiedType(Mutability::Mut),
- "isize" => IntSimplifiedType(IntTy::Isize),
- "i8" => IntSimplifiedType(IntTy::I8),
- "i16" => IntSimplifiedType(IntTy::I16),
- "i32" => IntSimplifiedType(IntTy::I32),
- "i64" => IntSimplifiedType(IntTy::I64),
- "i128" => IntSimplifiedType(IntTy::I128),
- "usize" => UintSimplifiedType(UintTy::Usize),
- "u8" => UintSimplifiedType(UintTy::U8),
- "u16" => UintSimplifiedType(UintTy::U16),
- "u32" => UintSimplifiedType(UintTy::U32),
- "u64" => UintSimplifiedType(UintTy::U64),
- "u128" => UintSimplifiedType(UintTy::U128),
- "f32" => FloatSimplifiedType(FloatTy::F32),
- "f64" => FloatSimplifiedType(FloatTy::F64),
+ "const_ptr" => SimplifiedType::Ptr(Mutability::Not),
+ "mut_ptr" => SimplifiedType::Ptr(Mutability::Mut),
+ "isize" => SimplifiedType::Int(IntTy::Isize),
+ "i8" => SimplifiedType::Int(IntTy::I8),
+ "i16" => SimplifiedType::Int(IntTy::I16),
+ "i32" => SimplifiedType::Int(IntTy::I32),
+ "i64" => SimplifiedType::Int(IntTy::I64),
+ "i128" => SimplifiedType::Int(IntTy::I128),
+ "usize" => SimplifiedType::Uint(UintTy::Usize),
+ "u8" => SimplifiedType::Uint(UintTy::U8),
+ "u16" => SimplifiedType::Uint(UintTy::U16),
+ "u32" => SimplifiedType::Uint(UintTy::U32),
+ "u64" => SimplifiedType::Uint(UintTy::U64),
+ "u128" => SimplifiedType::Uint(UintTy::U128),
+ "f32" => SimplifiedType::Float(FloatTy::F32),
+ "f64" => SimplifiedType::Float(FloatTy::F64),
_ => return [].iter().copied(),
};
@@ -737,7 +735,7 @@ fn projection_stack<'a, 'hir>(mut e: &'a Expr<'hir>) -> (Vec<&'a Expr<'hir>>, &'
let mut result = vec![];
let root = loop {
match e.kind {
- ExprKind::Index(ep, _) | ExprKind::Field(ep, _) => {
+ ExprKind::Index(ep, _, _) | ExprKind::Field(ep, _) => {
result.push(e);
e = ep;
},
@@ -784,7 +782,7 @@ pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) -
return true;
}
},
- (ExprKind::Index(_, i1), ExprKind::Index(_, i2)) => {
+ (ExprKind::Index(_, i1, _), ExprKind::Index(_, i2, _)) => {
if !eq_expr_value(cx, i1, i2) {
return false;
}
@@ -812,7 +810,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<
if let QPath::TypeRelative(_, method) = path {
if method.ident.name == sym::new {
if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
- if let Some(adt) = cx.tcx.type_of(impl_did).subst_identity().ty_adt_def() {
+ if let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def() {
return std_types_symbols.iter().any(|&symbol| {
cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string()
});
@@ -823,7 +821,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<
false
}
-/// Return true if the expr is equal to `Default::default` when evaluated.
+/// Returns true if the expr is equal to `Default::default` when evaluated.
pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> bool {
if_chain! {
if let hir::ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
@@ -1377,7 +1375,7 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
.chain(args.iter())
.position(|arg| arg.hir_id == id)?;
let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
- let ty = cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i];
+ let ty = cx.tcx.fn_sig(id).instantiate_identity().skip_binder().inputs()[i];
ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
},
_ => None,
@@ -1639,13 +1637,13 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
/// Convenience function to get the return type of a function.
pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId) -> Ty<'tcx> {
- let ret_ty = cx.tcx.fn_sig(fn_def_id).subst_identity().output();
+ let ret_ty = cx.tcx.fn_sig(fn_def_id).instantiate_identity().output();
cx.tcx.erase_late_bound_regions(ret_ty)
}
/// Convenience function to get the nth argument type of a function.
pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId, nth: usize) -> Ty<'tcx> {
- let arg = cx.tcx.fn_sig(fn_def_id).subst_identity().input(nth);
+ let arg = cx.tcx.fn_sig(fn_def_id).instantiate_identity().input(nth);
cx.tcx.erase_late_bound_regions(arg)
}
@@ -1767,7 +1765,7 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc
if let ExprKind::Match(_, arms, ref source) = expr.kind {
// desugared from a `?` operator
- if *source == MatchSource::TryDesugar {
+ if let MatchSource::TryDesugar(_) = *source {
return Some(expr);
}
@@ -2372,11 +2370,11 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
false
}
-static TEST_ITEM_NAMES_CACHE: OnceLock<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = OnceLock::new();
+static TEST_ITEM_NAMES_CACHE: OnceLock<Mutex<FxHashMap<LocalModDefId, Vec<Symbol>>>> = OnceLock::new();
-fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool {
+fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Symbol]) -> bool) -> bool {
let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
- let mut map: MutexGuard<'_, FxHashMap<LocalDefId, Vec<Symbol>>> = cache.lock().unwrap();
+ let mut map: MutexGuard<'_, FxHashMap<LocalModDefId, Vec<Symbol>>> = cache.lock().unwrap();
let value = map.entry(module);
match value {
Entry::Occupied(entry) => f(entry.get()),
@@ -2385,7 +2383,7 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalDefId, f: impl Fn(&[Symbol
for id in tcx.hir().module_items(module) {
if matches!(tcx.def_kind(id.owner_id), DefKind::Const)
&& let item = tcx.hir().item(id)
- && let ItemKind::Const(ty, _body) = item.kind {
+ && let ItemKind::Const(ty, _generics, _body) = item.kind {
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
// We could also check for the type name `test::TestDescAndFn`
if let Res::Def(DefKind::Struct, _) = path.res {
@@ -2450,6 +2448,17 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
.any(is_cfg_test)
}
+/// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
+pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+ let hir = tcx.hir();
+
+ tcx.has_attr(def_id, sym::cfg)
+ || hir
+ .parent_iter(hir.local_def_id_to_hir_id(def_id))
+ .flat_map(|(parent_id, _)| hir.attrs(parent_id))
+ .any(|attr| attr.has_name(sym::cfg))
+}
+
/// Checks whether item either has `test` attribute applied, or
/// is a module with `test` in its name.
///
@@ -2504,6 +2513,262 @@ pub fn walk_to_expr_usage<'tcx, T>(
None
}
+/// A type definition as it would be viewed from within a function.
+#[derive(Clone, Copy)]
+pub enum DefinedTy<'tcx> {
+ // Used for locals and closures defined within the function.
+ Hir(&'tcx hir::Ty<'tcx>),
+ /// Used for function signatures, and constant and static values. This includes the `ParamEnv`
+ /// from the definition site.
+ Mir(ParamEnvAnd<'tcx, Binder<'tcx, Ty<'tcx>>>),
+}
+
+/// The context an expressions value is used in.
+pub struct ExprUseCtxt<'tcx> {
+ /// The parent node which consumes the value.
+ pub node: ExprUseNode<'tcx>,
+ /// Any adjustments applied to the type.
+ pub adjustments: &'tcx [Adjustment<'tcx>],
+ /// Whether or not the type must unify with another code path.
+ pub is_ty_unified: bool,
+ /// Whether or not the value will be moved before it's used.
+ pub moved_before_use: bool,
+}
+
+/// The node which consumes a value.
+pub enum ExprUseNode<'tcx> {
+ /// Assignment to, or initializer for, a local
+ Local(&'tcx Local<'tcx>),
+ /// Initializer for a const or static item.
+ ConstStatic(OwnerId),
+ /// Implicit or explicit return from a function.
+ Return(OwnerId),
+ /// Initialization of a struct field.
+ Field(&'tcx ExprField<'tcx>),
+ /// An argument to a function.
+ FnArg(&'tcx Expr<'tcx>, usize),
+ /// An argument to a method.
+ MethodArg(HirId, Option<&'tcx GenericArgs<'tcx>>, usize),
+ /// The callee of a function call.
+ Callee,
+ /// Access of a field.
+ FieldAccess(Ident),
+}
+impl<'tcx> ExprUseNode<'tcx> {
+ /// Checks if the value is returned from the function.
+ pub fn is_return(&self) -> bool {
+ matches!(self, Self::Return(_))
+ }
+
+ /// Checks if the value is used as a method call receiver.
+ pub fn is_recv(&self) -> bool {
+ matches!(self, Self::MethodArg(_, _, 0))
+ }
+
+ /// Gets the needed type as it's defined without any type inference.
+ pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option<DefinedTy<'tcx>> {
+ match *self {
+ Self::Local(Local { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)),
+ Self::ConstStatic(id) => Some(DefinedTy::Mir(
+ cx.param_env
+ .and(Binder::dummy(cx.tcx.type_of(id).instantiate_identity())),
+ )),
+ Self::Return(id) => {
+ let hir_id = cx.tcx.hir().local_def_id_to_hir_id(id.def_id);
+ if let Some(Node::Expr(Expr {
+ kind: ExprKind::Closure(c),
+ ..
+ })) = cx.tcx.hir().find(hir_id)
+ {
+ match c.fn_decl.output {
+ FnRetTy::DefaultReturn(_) => None,
+ FnRetTy::Return(ty) => Some(DefinedTy::Hir(ty)),
+ }
+ } else {
+ Some(DefinedTy::Mir(
+ cx.param_env.and(cx.tcx.fn_sig(id).instantiate_identity().output()),
+ ))
+ }
+ },
+ Self::Field(field) => match get_parent_expr_for_hir(cx, field.hir_id) {
+ Some(Expr {
+ hir_id,
+ kind: ExprKind::Struct(path, ..),
+ ..
+ }) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
+ .and_then(|(adt, variant)| {
+ variant
+ .fields
+ .iter()
+ .find(|f| f.name == field.ident.name)
+ .map(|f| (adt, f))
+ })
+ .map(|(adt, field_def)| {
+ DefinedTy::Mir(
+ cx.tcx
+ .param_env(adt.did())
+ .and(Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity())),
+ )
+ }),
+ _ => None,
+ },
+ Self::FnArg(callee, i) => {
+ let sig = expr_sig(cx, callee)?;
+ let (hir_ty, ty) = sig.input_with_hir(i)?;
+ Some(match hir_ty {
+ Some(hir_ty) => DefinedTy::Hir(hir_ty),
+ None => DefinedTy::Mir(
+ sig.predicates_id()
+ .map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id))
+ .and(ty),
+ ),
+ })
+ },
+ Self::MethodArg(id, _, i) => {
+ let id = cx.typeck_results().type_dependent_def_id(id)?;
+ let sig = cx.tcx.fn_sig(id).skip_binder();
+ Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i))))
+ },
+ Self::Local(_) | Self::FieldAccess(..) | Self::Callee => None,
+ }
+ }
+}
+
+/// Gets the context an expression's value is used in.
+#[expect(clippy::too_many_lines)]
+pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option<ExprUseCtxt<'tcx>> {
+ let mut adjustments = [].as_slice();
+ let mut is_ty_unified = false;
+ let mut moved_before_use = false;
+ let ctxt = e.span.ctxt();
+ walk_to_expr_usage(cx, e, &mut |parent, child_id| {
+ // LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead.
+ if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir().get(child_id) {
+ adjustments = cx.typeck_results().expr_adjustments(e);
+ }
+ match parent {
+ Node::Local(l) if l.span.ctxt() == ctxt => Some(ExprUseCtxt {
+ node: ExprUseNode::Local(l),
+ adjustments,
+ is_ty_unified,
+ moved_before_use,
+ }),
+ Node::Item(&Item {
+ kind: ItemKind::Static(..) | ItemKind::Const(..),
+ owner_id,
+ span,
+ ..
+ })
+ | Node::TraitItem(&TraitItem {
+ kind: TraitItemKind::Const(..),
+ owner_id,
+ span,
+ ..
+ })
+ | Node::ImplItem(&ImplItem {
+ kind: ImplItemKind::Const(..),
+ owner_id,
+ span,
+ ..
+ }) if span.ctxt() == ctxt => Some(ExprUseCtxt {
+ node: ExprUseNode::ConstStatic(owner_id),
+ adjustments,
+ is_ty_unified,
+ moved_before_use,
+ }),
+
+ Node::Item(&Item {
+ kind: ItemKind::Fn(..),
+ owner_id,
+ span,
+ ..
+ })
+ | Node::TraitItem(&TraitItem {
+ kind: TraitItemKind::Fn(..),
+ owner_id,
+ span,
+ ..
+ })
+ | Node::ImplItem(&ImplItem {
+ kind: ImplItemKind::Fn(..),
+ owner_id,
+ span,
+ ..
+ }) if span.ctxt() == ctxt => Some(ExprUseCtxt {
+ node: ExprUseNode::Return(owner_id),
+ adjustments,
+ is_ty_unified,
+ moved_before_use,
+ }),
+
+ Node::ExprField(field) if field.span.ctxt() == ctxt => Some(ExprUseCtxt {
+ node: ExprUseNode::Field(field),
+ adjustments,
+ is_ty_unified,
+ moved_before_use,
+ }),
+
+ Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
+ ExprKind::Ret(_) => Some(ExprUseCtxt {
+ node: ExprUseNode::Return(OwnerId {
+ def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
+ }),
+ adjustments,
+ is_ty_unified,
+ moved_before_use,
+ }),
+ ExprKind::Closure(closure) => Some(ExprUseCtxt {
+ node: ExprUseNode::Return(OwnerId { def_id: closure.def_id }),
+ adjustments,
+ is_ty_unified,
+ moved_before_use,
+ }),
+ ExprKind::Call(func, args) => Some(ExprUseCtxt {
+ node: match args.iter().position(|arg| arg.hir_id == child_id) {
+ Some(i) => ExprUseNode::FnArg(func, i),
+ None => ExprUseNode::Callee,
+ },
+ adjustments,
+ is_ty_unified,
+ moved_before_use,
+ }),
+ ExprKind::MethodCall(name, _, args, _) => Some(ExprUseCtxt {
+ node: ExprUseNode::MethodArg(
+ parent.hir_id,
+ name.args,
+ args.iter().position(|arg| arg.hir_id == child_id).map_or(0, |i| i + 1),
+ ),
+ adjustments,
+ is_ty_unified,
+ moved_before_use,
+ }),
+ ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(ExprUseCtxt {
+ node: ExprUseNode::FieldAccess(name),
+ adjustments,
+ is_ty_unified,
+ moved_before_use,
+ }),
+ ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id != child_id => {
+ is_ty_unified = true;
+ moved_before_use = true;
+ None
+ },
+ ExprKind::Block(_, Some(_)) | ExprKind::Break(..) => {
+ is_ty_unified = true;
+ moved_before_use = true;
+ None
+ },
+ ExprKind::Block(..) => {
+ moved_before_use = true;
+ None
+ },
+ _ => None,
+ },
+ _ => None,
+ }
+ })
+}
+
/// Tokenizes the input while keeping the text associated with each token.
pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str)> {
let mut pos = 0;
@@ -2518,7 +2783,9 @@ pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str)> {
/// Checks whether a given span has any comment token
/// This checks for all types of comment: line "//", block "/**", doc "///" "//!"
pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
- let Ok(snippet) = sm.span_to_snippet(span) else { return false };
+ let Ok(snippet) = sm.span_to_snippet(span) else {
+ return false;
+ };
return tokenize(&snippet).any(|token| {
matches!(
token.kind,
@@ -2527,7 +2794,8 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
});
}
-/// Return all the comments a given span contains
+/// Returns all the comments a given span contains
+///
/// Comments are returned wrapped with their relevant delimiters
pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String {
let snippet = sm.span_to_snippet(span).unwrap_or_default();
@@ -2542,6 +2810,50 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
sm.span_take_while(span, |&ch| ch == ' ' || ch == ';')
}
+/// Returns whether the given let pattern and else body can be turned into a question mark
+///
+/// For this example:
+/// ```ignore
+/// let FooBar { a, b } = if let Some(a) = ex { a } else { return None };
+/// ```
+/// We get as parameters:
+/// ```ignore
+/// pat: Some(a)
+/// else_body: return None
+/// ```
+
+/// And for this example:
+/// ```ignore
+/// let Some(FooBar { a, b }) = ex else { return None };
+/// ```
+/// We get as parameters:
+/// ```ignore
+/// pat: Some(FooBar { a, b })
+/// else_body: return None
+/// ```
+
+/// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because
+/// the question mark operator is applicable here. Callers have to check whether we are in a
+/// constant or not.
+pub fn pat_and_expr_can_be_question_mark<'a, 'hir>(
+ cx: &LateContext<'_>,
+ pat: &'a Pat<'hir>,
+ else_body: &Expr<'_>,
+) -> Option<&'a Pat<'hir>> {
+ if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind &&
+ is_res_lang_ctor(cx, cx.qpath_res(&pat_path, pat.hir_id), OptionSome) &&
+ !is_refutable(cx, inner_pat) &&
+ let else_body = peel_blocks(else_body) &&
+ let ExprKind::Ret(Some(ret_val)) = else_body.kind &&
+ let ExprKind::Path(ret_path) = ret_val.kind &&
+ is_res_lang_ctor(cx, cx.qpath_res(&ret_path, ret_val.hir_id), OptionNone)
+ {
+ Some(inner_pat)
+ } else {
+ None
+ }
+}
+
macro_rules! op_utils {
($($name:ident $assign:ident)*) => {
/// Binary operation traits like `LangItem::Add`
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index 00f3abaec..173f9841d 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -192,7 +192,9 @@ pub fn first_node_in_macro(cx: &LateContext<'_>, node: &impl HirNode) -> Option<
/// Is `def_id` of `std::panic`, `core::panic` or any inner implementation macros
pub fn is_panic(cx: &LateContext<'_>, def_id: DefId) -> bool {
- let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return false };
+ let Some(name) = cx.tcx.get_diagnostic_name(def_id) else {
+ return false;
+ };
matches!(
name,
sym::core_panic_macro
@@ -205,7 +207,9 @@ pub fn is_panic(cx: &LateContext<'_>, def_id: DefId) -> bool {
/// Is `def_id` of `assert!` or `debug_assert!`
pub fn is_assert_macro(cx: &LateContext<'_>, def_id: DefId) -> bool {
- let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return false };
+ let Some(name) = cx.tcx.get_diagnostic_name(def_id) else {
+ return false;
+ };
matches!(name, sym::assert_macro | sym::debug_assert_macro)
}
@@ -223,13 +227,19 @@ pub enum PanicExpn<'a> {
impl<'a> PanicExpn<'a> {
pub fn parse(expr: &'a Expr<'a>) -> Option<Self> {
- let ExprKind::Call(callee, [arg, rest @ ..]) = &expr.kind else { return None };
- let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else { return None };
+ let ExprKind::Call(callee, [arg, rest @ ..]) = &expr.kind else {
+ return None;
+ };
+ let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else {
+ return None;
+ };
let result = match path.segments.last().unwrap().ident.as_str() {
"panic" if arg.span.ctxt() == expr.span.ctxt() => Self::Empty,
"panic" | "panic_str" => Self::Str(arg),
"panic_display" => {
- let ExprKind::AddrOf(_, _, e) = &arg.kind else { return None };
+ let ExprKind::AddrOf(_, _, e) = &arg.kind else {
+ return None;
+ };
Self::Display(e)
},
"panic_fmt" => Self::Format(arg),
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
index 920ce8e65..703985b9d 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -1,11 +1,15 @@
-use super::{possible_origin::PossibleOriginVisitor, transitive_relation::TransitiveRelation};
+use super::possible_origin::PossibleOriginVisitor;
+use super::transitive_relation::TransitiveRelation;
use crate::ty::is_copy;
use rustc_data_structures::fx::FxHashMap;
use rustc_index::bit_set::{BitSet, HybridBitSet};
use rustc_lint::LateContext;
-use rustc_middle::mir::{self, visit::Visitor as _, Mutability};
-use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt};
-use rustc_mir_dataflow::{impls::MaybeStorageLive, Analysis, ResultsCursor};
+use rustc_middle::mir::visit::Visitor as _;
+use rustc_middle::mir::{self, Mutability};
+use rustc_middle::ty::visit::TypeVisitor;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_mir_dataflow::impls::MaybeStorageLive;
+use rustc_mir_dataflow::{Analysis, ResultsCursor};
use std::borrow::Cow;
use std::ops::ControlFlow;
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
index 8e7513d74..da0426686 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
@@ -44,7 +44,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'a, 'tcx> {
let lhs = place.local;
match rvalue {
// Only consider `&mut`, which can modify origin place
- mir::Rvalue::Ref(_, rustc_middle::mir::BorrowKind::Mut { .. }, borrowed) |
+ mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, borrowed) |
// _2: &mut _;
// _3 = move _2
mir::Rvalue::Use(mir::Operand::Move(borrowed)) |
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 0e6f01287..914ea85ac 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -94,12 +94,12 @@ pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"];
pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"];
-pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
-pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
-pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
-pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
-pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
-pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
+pub const REGEX_BUILDER_NEW: [&str; 3] = ["regex", "RegexBuilder", "new"];
+pub const REGEX_BYTES_BUILDER_NEW: [&str; 4] = ["regex", "bytes", "RegexBuilder", "new"];
+pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "bytes", "Regex", "new"];
+pub const REGEX_BYTES_SET_NEW: [&str; 4] = ["regex", "bytes", "RegexSet", "new"];
+pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"];
+pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"];
pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];
@@ -149,6 +149,7 @@ pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "VecDeque", "iter"];
pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
+pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"];
pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
@@ -161,3 +162,6 @@ pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"];
pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"];
pub const FORMATTER: [&str; 3] = ["core", "fmt", "Formatter"];
pub const DEBUG_STRUCT: [&str; 4] = ["core", "fmt", "builders", "DebugStruct"];
+pub const ORD_CMP: [&str; 4] = ["core", "cmp", "Ord", "cmp"];
+#[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so
+pub const BOOL_THEN: [&str; 4] = ["core", "bool", "<impl bool>", "then"];
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index fbf4ab272..139e31bc5 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -14,10 +14,9 @@ use rustc_middle::mir::{
Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind,
Terminator, TerminatorKind,
};
-use rustc_middle::traits::{ImplSource, ObligationCause};
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt};
-use rustc_middle::ty::{BoundConstness, TraitRef};
+use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause};
+use rustc_middle::ty::adjustment::PointerCoercion;
+use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt};
use rustc_semver::RustcVersion;
use rustc_span::symbol::sym;
use rustc_span::Span;
@@ -35,7 +34,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
// impl trait is gone in MIR, so check the return type manually
check_ty(
tcx,
- tcx.fn_sig(def_id).subst_identity().output().skip_binder(),
+ tcx.fn_sig(def_id).instantiate_identity().output().skip_binder(),
body.local_decls.iter().next().unwrap().source_info.span,
)?;
@@ -125,7 +124,9 @@ fn check_rvalue<'tcx>(
) => check_operand(tcx, operand, span, body),
Rvalue::Cast(
CastKind::PointerCoercion(
- PointerCoercion::UnsafeFnPointer | PointerCoercion::ClosureFnPointer(_) | PointerCoercion::ReifyFnPointer,
+ PointerCoercion::UnsafeFnPointer
+ | PointerCoercion::ClosureFnPointer(_)
+ | PointerCoercion::ReifyFnPointer,
),
_,
_,
@@ -390,32 +391,39 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
#[expect(clippy::similar_names)] // bit too pedantic
fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>) -> bool {
- // Avoid selecting for simple cases, such as builtin types.
- if ty::util::is_trivially_const_drop(ty) {
- return true;
- }
+ // FIXME(effects, fee1-dead) revert to const destruct once it works again
+ #[expect(unused)]
+ fn is_ty_const_destruct_unused<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>) -> bool {
+ // Avoid selecting for simple cases, such as builtin types.
+ if ty::util::is_trivially_const_drop(ty) {
+ return true;
+ }
- let obligation = Obligation::new(
- tcx,
- ObligationCause::dummy_with_span(body.span),
- ConstCx::new(tcx, body).param_env.with_const(),
- TraitRef::from_lang_item(tcx, LangItem::Destruct, body.span, [ty]).with_constness(BoundConstness::ConstIfConst),
- );
+ // FIXME(effects) constness
+ let obligation = Obligation::new(
+ tcx,
+ ObligationCause::dummy_with_span(body.span),
+ ConstCx::new(tcx, body).param_env,
+ TraitRef::from_lang_item(tcx, LangItem::Destruct, body.span, [ty]),
+ );
- let infcx = tcx.infer_ctxt().build();
- let mut selcx = SelectionContext::new(&infcx);
- let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
- return false;
- };
+ let infcx = tcx.infer_ctxt().build();
+ let mut selcx = SelectionContext::new(&infcx);
+ let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
+ return false;
+ };
+
+ if !matches!(
+ impl_src,
+ ImplSource::Builtin(BuiltinImplSource::Misc, _) | ImplSource::Param(_)
+ ) {
+ return false;
+ }
- if !matches!(
- impl_src,
- ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
- ) {
- return false;
+ let ocx = ObligationCtxt::new(&infcx);
+ ocx.register_obligations(impl_src.nested_obligations());
+ ocx.select_all_or_error().is_empty()
}
- let ocx = ObligationCtxt::new(&infcx);
- ocx.register_obligations(impl_src.nested_obligations());
- ocx.select_all_or_error().is_empty()
+ !ty.needs_drop(tcx, ConstCx::new(tcx, body).param_env)
}
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 582337b47..dc4ee7256 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -8,8 +8,7 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
use rustc_lint::{LateContext, LintContext};
use rustc_session::Session;
use rustc_span::source_map::{original_sp, SourceMap};
-use rustc_span::{hygiene, SourceFile};
-use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP};
+use rustc_span::{hygiene, BytePos, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP};
use std::borrow::Cow;
use std::ops::Range;
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index cf781e18c..ee5a49a20 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -395,7 +395,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
}
}
-/// Return `true` if `sugg` is enclosed in parenthesis.
+/// Returns `true` if `sugg` is enclosed in parenthesis.
pub fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool {
let mut chars = sugg.as_ref().chars();
if chars.next() == Some('(') {
@@ -877,7 +877,7 @@ impl<'tcx> DerefDelegate<'_, 'tcx> {
.cx
.typeck_results()
.type_dependent_def_id(parent_expr.hir_id)
- .map(|did| self.cx.tcx.fn_sig(did).subst_identity().skip_binder())
+ .map(|did| self.cx.tcx.fn_sig(did).instantiate_identity().skip_binder())
{
std::iter::once(receiver)
.chain(call_args.iter())
@@ -1010,7 +1010,9 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
projections_handled = true;
},
// note: unable to trigger `Subslice` kind in tests
- ProjectionKind::Subslice => (),
+ ProjectionKind::Subslice |
+ // Doesn't have surface syntax. Only occurs in patterns.
+ ProjectionKind::OpaqueCast => (),
ProjectionKind::Deref => {
// Explicit derefs are typically handled later on, but
// some items do not need explicit deref, such as array accesses,
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index d650cbe0b..a05f682aa 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -3,33 +3,37 @@
#![allow(clippy::module_name_repetitions)]
use core::ops::ControlFlow;
+use itertools::Itertools;
use rustc_ast::ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety};
-use rustc_infer::infer::{
- type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
- TyCtxtInferExt,
-};
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
use rustc_middle::mir::interpret::{ConstValue, Scalar};
+use rustc_middle::traits::EvaluationResult;
+use rustc_middle::ty::layout::ValidityRequirement;
use rustc_middle::ty::{
- self, layout::ValidityRequirement, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv,
- Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
- UintTy, VariantDef, VariantDiscr,
+ self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
+ GenericParamDefKind, IntTy, List, ParamEnv, Region, RegionKind, ToPredicate, TraitRef, Ty, TyCtxt,
+ TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr,
};
-use rustc_middle::ty::{GenericArg, GenericArgKind};
use rustc_span::symbol::Ident;
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
use rustc_target::abi::{Size, VariantIdx};
-use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
+use rustc_trait_selection::traits::{Obligation, ObligationCause};
use std::iter;
use crate::{match_def_path, path_res, paths};
+mod type_certainty;
+pub use type_certainty::expr_type_is_certain;
+
/// Checks if the given type implements copy.
pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
ty.is_copy_modulo_regions(cx.tcx, cx.param_env)
@@ -90,14 +94,14 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
return false;
}
- for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() {
+ for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied() {
match predicate.kind().skip_binder() {
// For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
// and check substitutions to find `U`.
ty::ClauseKind::Trait(trait_predicate) => {
if trait_predicate
.trait_ref
- .substs
+ .args
.types()
.skip(1) // Skip the implicit `Self` generic parameter
.any(|ty| contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen))
@@ -206,15 +210,9 @@ pub fn implements_trait<'tcx>(
cx: &LateContext<'tcx>,
ty: Ty<'tcx>,
trait_id: DefId,
- ty_params: &[GenericArg<'tcx>],
+ args: &[GenericArg<'tcx>],
) -> bool {
- implements_trait_with_env(
- cx.tcx,
- cx.param_env,
- ty,
- trait_id,
- ty_params.iter().map(|&arg| Some(arg)),
- )
+ implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, trait_id, args.iter().map(|&x| Some(x)))
}
/// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
@@ -223,7 +221,18 @@ pub fn implements_trait_with_env<'tcx>(
param_env: ParamEnv<'tcx>,
ty: Ty<'tcx>,
trait_id: DefId,
- ty_params: impl IntoIterator<Item = Option<GenericArg<'tcx>>>,
+ args: &[GenericArg<'tcx>],
+) -> bool {
+ implements_trait_with_env_from_iter(tcx, param_env, ty, trait_id, args.iter().map(|&x| Some(x)))
+}
+
+/// Same as `implements_trait_from_env` but takes the arguments as an iterator.
+pub fn implements_trait_with_env_from_iter<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ trait_id: DefId,
+ args: impl IntoIterator<Item = impl Into<Option<GenericArg<'tcx>>>>,
) -> bool {
// Clippy shouldn't have infer types
assert!(!ty.has_infer());
@@ -232,19 +241,37 @@ pub fn implements_trait_with_env<'tcx>(
if ty.has_escaping_bound_vars() {
return false;
}
+
let infcx = tcx.infer_ctxt().build();
- let orig = TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span: DUMMY_SP,
- };
- let ty_params = tcx.mk_substs_from_iter(
- ty_params
+ let trait_ref = TraitRef::new(
+ tcx,
+ trait_id,
+ Some(GenericArg::from(ty))
.into_iter()
- .map(|arg| arg.unwrap_or_else(|| infcx.next_ty_var(orig).into())),
+ .chain(args.into_iter().map(|arg| {
+ arg.into().unwrap_or_else(|| {
+ let orig = TypeVariableOrigin {
+ kind: TypeVariableOriginKind::MiscVariable,
+ span: DUMMY_SP,
+ };
+ infcx.next_ty_var(orig).into()
+ })
+ })),
);
+
+ debug_assert_eq!(tcx.def_kind(trait_id), DefKind::Trait);
+ #[cfg(debug_assertions)]
+ assert_generic_args_match(tcx, trait_id, trait_ref.args);
+
+ let obligation = Obligation {
+ cause: ObligationCause::dummy(),
+ param_env,
+ recursion_depth: 0,
+ predicate: ty::Binder::dummy(trait_ref).to_predicate(tcx),
+ };
infcx
- .type_implements_trait(trait_id, [ty.into()].into_iter().chain(ty_params), param_env)
- .must_apply_modulo_regions()
+ .evaluate_obligation(&obligation)
+ .is_ok_and(EvaluationResult::must_apply_modulo_regions)
}
/// Checks whether this type implements `Drop`.
@@ -265,7 +292,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
// because we don't want to lint functions returning empty arrays
is_must_use_ty(cx, *ty)
},
- ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)),
+ ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)),
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() {
if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() {
@@ -314,11 +341,11 @@ fn is_normalizable_helper<'tcx>(
let cause = rustc_middle::traits::ObligationCause::dummy();
let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() {
match ty.kind() {
- ty::Adt(def, substs) => def.variants().iter().all(|variant| {
+ ty::Adt(def, args) => def.variants().iter().all(|variant| {
variant
.fields
.iter()
- .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache))
+ .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, args), cache))
}),
_ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
GenericArgKind::Type(inner_ty) if inner_ty != ty => {
@@ -392,6 +419,11 @@ pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangI
}
}
+/// Gets the diagnostic name of the type, if it has one
+pub fn type_diagnostic_name(cx: &LateContext<'_>, ty: Ty<'_>) -> Option<Symbol> {
+ ty.ty_adt_def().and_then(|adt| cx.tcx.get_diagnostic_name(adt.did()))
+}
+
/// Return `true` if the passed `typ` is `isize` or `usize`.
pub fn is_isize_or_usize(typ: Ty<'_>) -> bool {
matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
@@ -517,14 +549,14 @@ pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
/// otherwise returns `false`
pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
match (&a.kind(), &b.kind()) {
- (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => {
+ (&ty::Adt(did_a, args_a), &ty::Adt(did_b, args_b)) => {
if did_a != did_b {
return false;
}
- substs_a
+ args_a
.iter()
- .zip(substs_b.iter())
+ .zip(args_b.iter())
.all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) {
(GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
(GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
@@ -643,7 +675,7 @@ impl<'tcx> ExprFnSig<'tcx> {
/// If the expression is function like, get the signature for it.
pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> {
if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) {
- Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst_identity(), Some(id)))
+ Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).instantiate_identity(), Some(id)))
} else {
ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs())
}
@@ -661,11 +693,11 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
.and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id)));
Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
},
- ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst(cx.tcx, subs), Some(id))),
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => sig_from_bounds(
+ ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).instantiate(cx.tcx, subs), Some(id))),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => sig_from_bounds(
cx,
ty,
- cx.tcx.item_bounds(def_id).subst_iter(cx.tcx, substs),
+ cx.tcx.item_bounds(def_id).iter_instantiated(cx.tcx, args),
cx.tcx.opt_parent(def_id),
),
ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
@@ -681,7 +713,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
.projection_bounds()
.find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id()))
.map(|p| p.map_bound(|p| p.term.ty().unwrap()));
- Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output, None))
+ Some(ExprFnSig::Trait(bound.map_bound(|b| b.args.type_at(0)), output, None))
},
_ => None,
}
@@ -713,7 +745,7 @@ fn sig_from_bounds<'tcx>(
|| lang_items.fn_once_trait() == Some(p.def_id()))
&& p.self_ty() == ty =>
{
- let i = pred.kind().rebind(p.trait_ref.substs.type_at(1));
+ let i = pred.kind().rebind(p.trait_ref.args.type_at(1));
if inputs.map_or(false, |inputs| i != inputs) {
// Multiple different fn trait impls. Is this even allowed?
return None;
@@ -744,7 +776,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option
for (pred, _) in cx
.tcx
.explicit_item_bounds(ty.def_id)
- .subst_iter_copied(cx.tcx, ty.substs)
+ .iter_instantiated_copied(cx.tcx, ty.args)
{
match pred.kind().skip_binder() {
ty::ClauseKind::Trait(p)
@@ -752,7 +784,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option
|| lang_items.fn_mut_trait() == Some(p.def_id())
|| lang_items.fn_once_trait() == Some(p.def_id())) =>
{
- let i = pred.kind().rebind(p.trait_ref.substs.type_at(1));
+ let i = pred.kind().rebind(p.trait_ref.args.type_at(1));
if inputs.map_or(false, |inputs| inputs != i) {
// Multiple different fn trait impls. Is this even allowed?
@@ -793,7 +825,7 @@ impl core::ops::Add<u32> for EnumValue {
#[expect(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option<EnumValue> {
if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) {
- match tcx.type_of(id).subst_identity().kind() {
+ match tcx.type_of(id).instantiate_identity().kind() {
ty::Int(_) => Some(EnumValue::Signed(match value.size().bytes() {
1 => i128::from(value.assert_bits(Size::from_bytes(1)) as u8 as i8),
2 => i128::from(value.assert_bits(Size::from_bytes(2)) as u16 as i16),
@@ -927,7 +959,7 @@ pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<
Some((adt, adt.variant_with_id(var_id)))
},
Res::SelfCtor(id) => {
- let adt = cx.tcx.type_of(id).subst_identity().ty_adt_def().unwrap();
+ let adt = cx.tcx.type_of(id).instantiate_identity().ty_adt_def().unwrap();
Some((adt, adt.non_enum_variant()))
},
_ => None,
@@ -940,8 +972,7 @@ pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tc
return false;
};
let lang = tcx.lang_items();
- let (Some(fn_once_id), Some(fn_mut_id), Some(fn_id))
- = (lang.fn_once_trait(), lang.fn_mut_trait(), lang.fn_trait())
+ let (Some(fn_once_id), Some(fn_mut_id), Some(fn_id)) = (lang.fn_once_trait(), lang.fn_mut_trait(), lang.fn_trait())
else {
return false;
};
@@ -1014,91 +1045,104 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
}
}
+/// Asserts that the given arguments match the generic parameters of the given item.
+#[allow(dead_code)]
+fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[GenericArg<'tcx>]) {
+ let g = tcx.generics_of(did);
+ let parent = g.parent.map(|did| tcx.generics_of(did));
+ let count = g.parent_count + g.params.len();
+ let params = parent
+ .map_or([].as_slice(), |p| p.params.as_slice())
+ .iter()
+ .chain(&g.params)
+ .map(|x| &x.kind);
+
+ assert!(
+ count == args.len(),
+ "wrong number of arguments for `{did:?}`: expected `{count}`, found {}\n\
+ note: the expected arguments are: `[{}]`\n\
+ the given arguments are: `{args:#?}`",
+ args.len(),
+ params.clone().map(GenericParamDefKind::descr).format(", "),
+ );
+
+ if let Some((idx, (param, arg))) =
+ params
+ .clone()
+ .zip(args.iter().map(|&x| x.unpack()))
+ .enumerate()
+ .find(|(_, (param, arg))| match (param, arg) {
+ (GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_))
+ | (GenericParamDefKind::Type { .. }, GenericArgKind::Type(_))
+ | (GenericParamDefKind::Const { .. }, GenericArgKind::Const(_)) => false,
+ (
+ GenericParamDefKind::Lifetime
+ | GenericParamDefKind::Type { .. }
+ | GenericParamDefKind::Const { .. },
+ _,
+ ) => true,
+ })
+ {
+ panic!(
+ "incorrect argument for `{did:?}` at index `{idx}`: expected a {}, found `{arg:?}`\n\
+ note: the expected arguments are `[{}]`\n\
+ the given arguments are `{args:#?}`",
+ param.descr(),
+ params.clone().map(GenericParamDefKind::descr).format(", "),
+ );
+ }
+}
+
+/// Returns whether `ty` is never-like; i.e., `!` (never) or an enum with zero variants.
+pub fn is_never_like(ty: Ty<'_>) -> bool {
+ ty.is_never() || (ty.is_enum() && ty.ty_adt_def().is_some_and(|def| def.variants().is_empty()))
+}
+
/// Makes the projection type for the named associated type in the given impl or trait impl.
///
/// This function is for associated types which are "known" to exist, and as such, will only return
/// `None` when debug assertions are disabled in order to prevent ICE's. With debug assertions
/// enabled this will check that the named associated type exists, the correct number of
-/// substitutions are given, and that the correct kinds of substitutions are given (lifetime,
+/// arguments are given, and that the correct kinds of arguments are given (lifetime,
/// constant or type). This will not check if type normalization would succeed.
pub fn make_projection<'tcx>(
tcx: TyCtxt<'tcx>,
container_id: DefId,
assoc_ty: Symbol,
- substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+ args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
) -> Option<AliasTy<'tcx>> {
fn helper<'tcx>(
tcx: TyCtxt<'tcx>,
container_id: DefId,
assoc_ty: Symbol,
- substs: SubstsRef<'tcx>,
+ args: GenericArgsRef<'tcx>,
) -> Option<AliasTy<'tcx>> {
- let Some(assoc_item) = tcx
- .associated_items(container_id)
- .find_by_name_and_kind(tcx, Ident::with_dummy_span(assoc_ty), AssocKind::Type, container_id)
- else {
+ let Some(assoc_item) = tcx.associated_items(container_id).find_by_name_and_kind(
+ tcx,
+ Ident::with_dummy_span(assoc_ty),
+ AssocKind::Type,
+ container_id,
+ ) else {
debug_assert!(false, "type `{assoc_ty}` not found in `{container_id:?}`");
return None;
};
#[cfg(debug_assertions)]
- {
- let generics = tcx.generics_of(assoc_item.def_id);
- let generic_count = generics.parent_count + generics.params.len();
- let params = generics
- .parent
- .map_or([].as_slice(), |id| &*tcx.generics_of(id).params)
- .iter()
- .chain(&generics.params)
- .map(|x| &x.kind);
-
- debug_assert!(
- generic_count == substs.len(),
- "wrong number of substs for `{:?}`: found `{}` expected `{generic_count}`.\n\
- note: the expected parameters are: {:#?}\n\
- the given arguments are: `{substs:#?}`",
- assoc_item.def_id,
- substs.len(),
- params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>(),
- );
-
- if let Some((idx, (param, arg))) = params
- .clone()
- .zip(substs.iter().map(GenericArg::unpack))
- .enumerate()
- .find(|(_, (param, arg))| {
- !matches!(
- (param, arg),
- (ty::GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_))
- | (ty::GenericParamDefKind::Type { .. }, GenericArgKind::Type(_))
- | (ty::GenericParamDefKind::Const { .. }, GenericArgKind::Const(_))
- )
- })
- {
- debug_assert!(
- false,
- "mismatched subst type at index {idx}: expected a {}, found `{arg:?}`\n\
- note: the expected parameters are {:#?}\n\
- the given arguments are {substs:#?}",
- param.descr(),
- params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>()
- );
- }
- }
+ assert_generic_args_match(tcx, assoc_item.def_id, args);
- Some(tcx.mk_alias_ty(assoc_item.def_id, substs))
+ Some(tcx.mk_alias_ty(assoc_item.def_id, args))
}
helper(
tcx,
container_id,
assoc_ty,
- tcx.mk_substs_from_iter(substs.into_iter().map(Into::into)),
+ tcx.mk_args_from_iter(args.into_iter().map(Into::into)),
)
}
/// Normalizes the named associated type in the given impl or trait impl.
///
/// This function is for associated types which are "known" to be valid with the given
-/// substitutions, and as such, will only return `None` when debug assertions are disabled in order
+/// arguments, and as such, will only return `None` when debug assertions are disabled in order
/// to prevent ICE's. With debug assertions enabled this will check that type normalization
/// succeeds as well as everything checked by `make_projection`.
pub fn make_normalized_projection<'tcx>(
@@ -1106,25 +1150,20 @@ pub fn make_normalized_projection<'tcx>(
param_env: ParamEnv<'tcx>,
container_id: DefId,
assoc_ty: Symbol,
- substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+ args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
) -> Option<Ty<'tcx>> {
fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
#[cfg(debug_assertions)]
- if let Some((i, subst)) = ty
- .substs
- .iter()
- .enumerate()
- .find(|(_, subst)| subst.has_late_bound_regions())
- {
+ if let Some((i, arg)) = ty.args.iter().enumerate().find(|(_, arg)| arg.has_late_bound_regions()) {
debug_assert!(
false,
- "substs contain late-bound region at index `{i}` which can't be normalized.\n\
+ "args contain late-bound region at index `{i}` which can't be normalized.\n\
use `TyCtxt::erase_late_bound_regions`\n\
- note: subst is `{subst:#?}`",
+ note: arg is `{arg:#?}`",
);
return None;
}
- match tcx.try_normalize_erasing_regions(param_env, Ty::new_projection(tcx,ty.def_id, ty.substs)) {
+ match tcx.try_normalize_erasing_regions(param_env, Ty::new_projection(tcx, ty.def_id, ty.args)) {
Ok(ty) => Some(ty),
Err(e) => {
debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}");
@@ -1132,7 +1171,7 @@ pub fn make_normalized_projection<'tcx>(
},
}
}
- helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, substs)?)
+ helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, args)?)
}
/// Check if given type has inner mutability such as [`std::cell::Cell`] or [`std::cell::RefCell`]
@@ -1147,7 +1186,7 @@ pub fn is_interior_mut_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
&& is_interior_mut_ty(cx, inner_ty)
},
ty::Tuple(fields) => fields.iter().any(|ty| is_interior_mut_ty(cx, ty)),
- ty::Adt(def, substs) => {
+ ty::Adt(def, args) => {
// Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
// that of their type parameters. Note: we don't include `HashSet` and `HashMap`
// because they have no impl for `Hash` or `Ord`.
@@ -1168,7 +1207,7 @@ pub fn is_interior_mut_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
let is_box = Some(def_id) == cx.tcx.lang_items().owned_box();
if is_std_collection || is_box {
// The type is mutable if any of its type parameters are
- substs.types().any(|ty| is_interior_mut_ty(cx, ty))
+ args.types().any(|ty| is_interior_mut_ty(cx, ty))
} else {
!ty.has_escaping_bound_vars()
&& cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
@@ -1184,21 +1223,16 @@ pub fn make_normalized_projection_with_regions<'tcx>(
param_env: ParamEnv<'tcx>,
container_id: DefId,
assoc_ty: Symbol,
- substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+ args: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
) -> Option<Ty<'tcx>> {
fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
#[cfg(debug_assertions)]
- if let Some((i, subst)) = ty
- .substs
- .iter()
- .enumerate()
- .find(|(_, subst)| subst.has_late_bound_regions())
- {
+ if let Some((i, arg)) = ty.args.iter().enumerate().find(|(_, arg)| arg.has_late_bound_regions()) {
debug_assert!(
false,
- "substs contain late-bound region at index `{i}` which can't be normalized.\n\
+ "args contain late-bound region at index `{i}` which can't be normalized.\n\
use `TyCtxt::erase_late_bound_regions`\n\
- note: subst is `{subst:#?}`",
+ note: arg is `{arg:#?}`",
);
return None;
}
@@ -1207,7 +1241,7 @@ pub fn make_normalized_projection_with_regions<'tcx>(
.infer_ctxt()
.build()
.at(&cause, param_env)
- .query_normalize(Ty::new_projection(tcx,ty.def_id, ty.substs))
+ .query_normalize(Ty::new_projection(tcx, ty.def_id, ty.args))
{
Ok(ty) => Some(ty.value),
Err(e) => {
@@ -1216,7 +1250,7 @@ pub fn make_normalized_projection_with_regions<'tcx>(
},
}
}
- helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, substs)?)
+ helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, args)?)
}
pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/certainty.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/certainty.rs
new file mode 100644
index 000000000..0e69ffa22
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/certainty.rs
@@ -0,0 +1,122 @@
+use rustc_hir::def_id::DefId;
+use std::fmt::Debug;
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum Certainty {
+ /// Determining the type requires contextual information.
+ Uncertain,
+
+ /// The type can be determined purely from subexpressions. If the argument is `Some(..)`, the
+ /// specific `DefId` is known. Such arguments are needed to handle path segments whose `res` is
+ /// `Res::Err`.
+ Certain(Option<DefId>),
+
+ /// The heuristic believes that more than one `DefId` applies to a type---this is a bug.
+ Contradiction,
+}
+
+pub trait Meet {
+ fn meet(self, other: Self) -> Self;
+}
+
+pub trait TryJoin: Sized {
+ fn try_join(self, other: Self) -> Option<Self>;
+}
+
+impl Meet for Option<DefId> {
+ fn meet(self, other: Self) -> Self {
+ match (self, other) {
+ (None, _) | (_, None) => None,
+ (Some(lhs), Some(rhs)) => (lhs == rhs).then_some(lhs),
+ }
+ }
+}
+
+impl TryJoin for Option<DefId> {
+ fn try_join(self, other: Self) -> Option<Self> {
+ match (self, other) {
+ (Some(lhs), Some(rhs)) => (lhs == rhs).then_some(Some(lhs)),
+ (Some(def_id), _) | (_, Some(def_id)) => Some(Some(def_id)),
+ (None, None) => Some(None),
+ }
+ }
+}
+
+impl Meet for Certainty {
+ fn meet(self, other: Self) -> Self {
+ match (self, other) {
+ (Certainty::Uncertain, _) | (_, Certainty::Uncertain) => Certainty::Uncertain,
+ (Certainty::Certain(lhs), Certainty::Certain(rhs)) => Certainty::Certain(lhs.meet(rhs)),
+ (Certainty::Certain(inner), _) | (_, Certainty::Certain(inner)) => Certainty::Certain(inner),
+ (Certainty::Contradiction, Certainty::Contradiction) => Certainty::Contradiction,
+ }
+ }
+}
+
+impl Certainty {
+ /// Join two `Certainty`s preserving their `DefId`s (if any). Generally speaking, this method
+ /// should be used only when `self` and `other` refer directly to types. Otherwise,
+ /// `join_clearing_def_ids` should be used.
+ pub fn join(self, other: Self) -> Self {
+ match (self, other) {
+ (Certainty::Contradiction, _) | (_, Certainty::Contradiction) => Certainty::Contradiction,
+
+ (Certainty::Certain(lhs), Certainty::Certain(rhs)) => {
+ if let Some(inner) = lhs.try_join(rhs) {
+ Certainty::Certain(inner)
+ } else {
+ debug_assert!(false, "Contradiction with {lhs:?} and {rhs:?}");
+ Certainty::Contradiction
+ }
+ },
+
+ (Certainty::Certain(inner), _) | (_, Certainty::Certain(inner)) => Certainty::Certain(inner),
+
+ (Certainty::Uncertain, Certainty::Uncertain) => Certainty::Uncertain,
+ }
+ }
+
+ /// Join two `Certainty`s after clearing their `DefId`s. This method should be used when `self`
+ /// or `other` do not necessarily refer to types, e.g., when they are aggregations of other
+ /// `Certainty`s.
+ pub fn join_clearing_def_ids(self, other: Self) -> Self {
+ self.clear_def_id().join(other.clear_def_id())
+ }
+
+ pub fn clear_def_id(self) -> Certainty {
+ if matches!(self, Certainty::Certain(_)) {
+ Certainty::Certain(None)
+ } else {
+ self
+ }
+ }
+
+ pub fn with_def_id(self, def_id: DefId) -> Certainty {
+ if matches!(self, Certainty::Certain(_)) {
+ Certainty::Certain(Some(def_id))
+ } else {
+ self
+ }
+ }
+
+ pub fn to_def_id(self) -> Option<DefId> {
+ match self {
+ Certainty::Certain(inner) => inner,
+ _ => None,
+ }
+ }
+
+ pub fn is_certain(self) -> bool {
+ matches!(self, Self::Certain(_))
+ }
+}
+
+/// Think: `iter.all(/* is certain */)`
+pub fn meet(iter: impl Iterator<Item = Certainty>) -> Certainty {
+ iter.fold(Certainty::Certain(None), Certainty::meet)
+}
+
+/// Think: `iter.any(/* is certain */)`
+pub fn join(iter: impl Iterator<Item = Certainty>) -> Certainty {
+ iter.fold(Certainty::Uncertain, Certainty::join)
+}
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
new file mode 100644
index 000000000..06fd95290
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -0,0 +1,320 @@
+//! A heuristic to tell whether an expression's type can be determined purely from its
+//! subexpressions, and the arguments and locals they use. Put another way, `expr_type_is_certain`
+//! tries to tell whether an expression's type can be determined without appeal to the surrounding
+//! context.
+//!
+//! This is, in some sense, a counterpart to `let_unit_value`'s `expr_needs_inferred_result`.
+//! Intuitively, that function determines whether an expression's type is needed for type inference,
+//! whereas `expr_type_is_certain` determines whether type inference is needed for an expression's
+//! type.
+//!
+//! As a heuristic, `expr_type_is_certain` may produce false negatives, but a false positive should
+//! be considered a bug.
+
+use crate::def_path_res;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{walk_qpath, walk_ty, Visitor};
+use rustc_hir::{self as hir, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty};
+use rustc_span::{Span, Symbol};
+
+mod certainty;
+use certainty::{join, meet, Certainty, Meet};
+
+pub fn expr_type_is_certain(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ expr_type_certainty(cx, expr).is_certain()
+}
+
+fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
+ let certainty = match &expr.kind {
+ ExprKind::Unary(_, expr)
+ | ExprKind::Field(expr, _)
+ | ExprKind::Index(expr, _, _)
+ | ExprKind::AddrOf(_, _, expr) => expr_type_certainty(cx, expr),
+
+ ExprKind::Array(exprs) => join(exprs.iter().map(|expr| expr_type_certainty(cx, expr))),
+
+ ExprKind::Call(callee, args) => {
+ let lhs = expr_type_certainty(cx, callee);
+ let rhs = if type_is_inferrable_from_arguments(cx, expr) {
+ meet(args.iter().map(|arg| expr_type_certainty(cx, arg)))
+ } else {
+ Certainty::Uncertain
+ };
+ lhs.join_clearing_def_ids(rhs)
+ },
+
+ ExprKind::MethodCall(method, receiver, args, _) => {
+ let mut receiver_type_certainty = expr_type_certainty(cx, receiver);
+ // Even if `receiver_type_certainty` is `Certain(Some(..))`, the `Self` type in the method
+ // identified by `type_dependent_def_id(..)` can differ. This can happen as a result of a `deref`,
+ // for example. So update the `DefId` in `receiver_type_certainty` (if any).
+ if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && let Some(self_ty_def_id) = adt_def_id(self_ty(cx, method_def_id))
+ {
+ receiver_type_certainty = receiver_type_certainty.with_def_id(self_ty_def_id);
+ };
+ let lhs = path_segment_certainty(cx, receiver_type_certainty, method, false);
+ let rhs = if type_is_inferrable_from_arguments(cx, expr) {
+ meet(
+ std::iter::once(receiver_type_certainty).chain(args.iter().map(|arg| expr_type_certainty(cx, arg))),
+ )
+ } else {
+ Certainty::Uncertain
+ };
+ lhs.join(rhs)
+ },
+
+ ExprKind::Tup(exprs) => meet(exprs.iter().map(|expr| expr_type_certainty(cx, expr))),
+
+ ExprKind::Binary(_, lhs, rhs) => expr_type_certainty(cx, lhs).meet(expr_type_certainty(cx, rhs)),
+
+ ExprKind::Lit(_) => Certainty::Certain(None),
+
+ ExprKind::Cast(_, ty) => type_certainty(cx, ty),
+
+ ExprKind::If(_, if_expr, Some(else_expr)) => {
+ expr_type_certainty(cx, if_expr).join(expr_type_certainty(cx, else_expr))
+ },
+
+ ExprKind::Path(qpath) => qpath_certainty(cx, qpath, false),
+
+ ExprKind::Struct(qpath, _, _) => qpath_certainty(cx, qpath, true),
+
+ _ => Certainty::Uncertain,
+ };
+
+ let expr_ty = cx.typeck_results().expr_ty(expr);
+ if let Some(def_id) = adt_def_id(expr_ty) {
+ certainty.with_def_id(def_id)
+ } else {
+ certainty
+ }
+}
+
+struct CertaintyVisitor<'cx, 'tcx> {
+ cx: &'cx LateContext<'tcx>,
+ certainty: Certainty,
+}
+
+impl<'cx, 'tcx> CertaintyVisitor<'cx, 'tcx> {
+ fn new(cx: &'cx LateContext<'tcx>) -> Self {
+ Self {
+ cx,
+ certainty: Certainty::Certain(None),
+ }
+ }
+}
+
+impl<'cx, 'tcx> Visitor<'cx> for CertaintyVisitor<'cx, 'tcx> {
+ fn visit_qpath(&mut self, qpath: &'cx QPath<'_>, hir_id: HirId, _: Span) {
+ self.certainty = self.certainty.meet(qpath_certainty(self.cx, qpath, true));
+ if self.certainty != Certainty::Uncertain {
+ walk_qpath(self, qpath, hir_id);
+ }
+ }
+
+ fn visit_ty(&mut self, ty: &'cx hir::Ty<'_>) {
+ if matches!(ty.kind, TyKind::Infer) {
+ self.certainty = Certainty::Uncertain;
+ }
+ if self.certainty != Certainty::Uncertain {
+ walk_ty(self, ty);
+ }
+ }
+}
+
+fn type_certainty(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Certainty {
+ // Handle `TyKind::Path` specially so that its `DefId` can be preserved.
+ //
+ // Note that `CertaintyVisitor::new` initializes the visitor's internal certainty to
+ // `Certainty::Certain(None)`. Furthermore, if a `TyKind::Path` is encountered while traversing
+ // `ty`, the result of the call to `qpath_certainty` is combined with the visitor's internal
+ // certainty using `Certainty::meet`. Thus, if the `TyKind::Path` were not treated specially here,
+ // the resulting certainty would be `Certainty::Certain(None)`.
+ if let TyKind::Path(qpath) = &ty.kind {
+ return qpath_certainty(cx, qpath, true);
+ }
+
+ let mut visitor = CertaintyVisitor::new(cx);
+ visitor.visit_ty(ty);
+ visitor.certainty
+}
+
+fn generic_args_certainty(cx: &LateContext<'_>, args: &GenericArgs<'_>) -> Certainty {
+ let mut visitor = CertaintyVisitor::new(cx);
+ visitor.visit_generic_args(args);
+ visitor.certainty
+}
+
+/// Tries to tell whether a `QPath` resolves to something certain, e.g., whether all of its path
+/// segments generic arguments are are instantiated.
+///
+/// `qpath` could refer to either a type or a value. The heuristic never needs the `DefId` of a
+/// value. So `DefId`s are retained only when `resolves_to_type` is true.
+fn qpath_certainty(cx: &LateContext<'_>, qpath: &QPath<'_>, resolves_to_type: bool) -> Certainty {
+ let certainty = match qpath {
+ QPath::Resolved(ty, path) => {
+ let len = path.segments.len();
+ path.segments.iter().enumerate().fold(
+ ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty)),
+ |parent_certainty, (i, path_segment)| {
+ path_segment_certainty(cx, parent_certainty, path_segment, i != len - 1 || resolves_to_type)
+ },
+ )
+ },
+
+ QPath::TypeRelative(ty, path_segment) => {
+ path_segment_certainty(cx, type_certainty(cx, ty), path_segment, resolves_to_type)
+ },
+
+ QPath::LangItem(lang_item, _, _) => {
+ cx.tcx
+ .lang_items()
+ .get(*lang_item)
+ .map_or(Certainty::Uncertain, |def_id| {
+ let generics = cx.tcx.generics_of(def_id);
+ if generics.parent_count == 0 && generics.params.is_empty() {
+ Certainty::Certain(if resolves_to_type { Some(def_id) } else { None })
+ } else {
+ Certainty::Uncertain
+ }
+ })
+ },
+ };
+ debug_assert!(resolves_to_type || certainty.to_def_id().is_none());
+ certainty
+}
+
+fn path_segment_certainty(
+ cx: &LateContext<'_>,
+ parent_certainty: Certainty,
+ path_segment: &PathSegment<'_>,
+ resolves_to_type: bool,
+) -> Certainty {
+ let certainty = match update_res(cx, parent_certainty, path_segment).unwrap_or(path_segment.res) {
+ // A definition's type is certain if it refers to something without generics (e.g., a crate or module, or
+ // an unparameterized type), or the generics are instantiated with arguments that are certain.
+ //
+ // If the parent is uncertain, then the current path segment must account for the parent's generic arguments.
+ // Consider the following examples, where the current path segment is `None`:
+ // - `Option::None` // uncertain; parent (i.e., `Option`) is uncertain
+ // - `Option::<Vec<u64>>::None` // certain; parent (i.e., `Option::<..>`) is certain
+ // - `Option::None::<Vec<u64>>` // certain; parent (i.e., `Option`) is uncertain
+ Res::Def(_, def_id) => {
+ // Checking `res_generics_def_id(..)` before calling `generics_of` avoids an ICE.
+ if cx.tcx.res_generics_def_id(path_segment.res).is_some() {
+ let generics = cx.tcx.generics_of(def_id);
+ let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && generics.params.is_empty()
+ {
+ Certainty::Certain(None)
+ } else {
+ Certainty::Uncertain
+ };
+ let rhs = path_segment
+ .args
+ .map_or(Certainty::Uncertain, |args| generic_args_certainty(cx, args));
+ // See the comment preceding `qpath_certainty`. `def_id` could refer to a type or a value.
+ let certainty = lhs.join_clearing_def_ids(rhs);
+ if resolves_to_type {
+ if let DefKind::TyAlias { .. } = cx.tcx.def_kind(def_id) {
+ adt_def_id(cx.tcx.type_of(def_id).instantiate_identity())
+ .map_or(certainty, |def_id| certainty.with_def_id(def_id))
+ } else {
+ certainty.with_def_id(def_id)
+ }
+ } else {
+ certainty
+ }
+ } else {
+ Certainty::Certain(None)
+ }
+ },
+
+ Res::PrimTy(_) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::SelfCtor(_) => {
+ Certainty::Certain(None)
+ },
+
+ // `get_parent` because `hir_id` refers to a `Pat`, and we're interested in the node containing the `Pat`.
+ Res::Local(hir_id) => match cx.tcx.hir().get_parent(hir_id) {
+ // An argument's type is always certain.
+ Node::Param(..) => Certainty::Certain(None),
+ // A local's type is certain if its type annotation is certain or it has an initializer whose
+ // type is certain.
+ Node::Local(local) => {
+ let lhs = local.ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty));
+ let rhs = local
+ .init
+ .map_or(Certainty::Uncertain, |init| expr_type_certainty(cx, init));
+ let certainty = lhs.join(rhs);
+ if resolves_to_type {
+ certainty
+ } else {
+ certainty.clear_def_id()
+ }
+ },
+ _ => Certainty::Uncertain,
+ },
+
+ _ => Certainty::Uncertain,
+ };
+ debug_assert!(resolves_to_type || certainty.to_def_id().is_none());
+ certainty
+}
+
+/// For at least some `QPath::TypeRelative`, the path segment's `res` can be `Res::Err`.
+/// `update_res` tries to fix the resolution when `parent_certainty` is `Certain(Some(..))`.
+fn update_res(cx: &LateContext<'_>, parent_certainty: Certainty, path_segment: &PathSegment<'_>) -> Option<Res> {
+ if path_segment.res == Res::Err && let Some(def_id) = parent_certainty.to_def_id() {
+ let mut def_path = cx.get_def_path(def_id);
+ def_path.push(path_segment.ident.name);
+ let reses = def_path_res(cx, &def_path.iter().map(Symbol::as_str).collect::<Vec<_>>());
+ if let [res] = reses.as_slice() { Some(*res) } else { None }
+ } else {
+ None
+ }
+}
+
+#[allow(clippy::cast_possible_truncation)]
+fn type_is_inferrable_from_arguments(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ let Some(callee_def_id) = (match expr.kind {
+ ExprKind::Call(callee, _) => {
+ let callee_ty = cx.typeck_results().expr_ty(callee);
+ if let ty::FnDef(callee_def_id, _) = callee_ty.kind() {
+ Some(*callee_def_id)
+ } else {
+ None
+ }
+ },
+ ExprKind::MethodCall(_, _, _, _) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
+ _ => None,
+ }) else {
+ return false;
+ };
+
+ let generics = cx.tcx.generics_of(callee_def_id);
+ let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+
+ // Check that all type parameters appear in the functions input types.
+ (0..(generics.parent_count + generics.params.len()) as u32).all(|index| {
+ fn_sig
+ .inputs()
+ .iter()
+ .any(|input_ty| contains_param(*input_ty.skip_binder(), index))
+ })
+}
+
+fn self_ty<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId) -> Ty<'tcx> {
+ cx.tcx.fn_sig(method_def_id).skip_binder().inputs().skip_binder()[0]
+}
+
+fn adt_def_id(ty: Ty<'_>) -> Option<DefId> {
+ ty.peel_refs().ty_adt_def().map(AdtDef::did)
+}
+
+fn contains_param(ty: Ty<'_>, index: u32) -> bool {
+ ty.walk()
+ .any(|arg| matches!(arg.unpack(), GenericArgKind::Type(ty) if ty.is_param(index)))
+}
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 985508521..39ef76348 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -1,10 +1,9 @@
-use crate as utils;
-use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend};
+use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend, Visitable};
+use crate::{self as utils, get_enclosing_loop_or_multi_call_closure};
use core::ops::ControlFlow;
-use rustc_hir as hir;
+use hir::def::Res;
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::HirIdSet;
-use rustc_hir::{Expr, ExprKind, HirId, Node};
+use rustc_hir::{self as hir, Expr, ExprKind, HirId, HirIdSet};
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
@@ -129,7 +128,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
}
fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
- if let hir::def::Res::Local(id) = path.res {
+ if let Res::Local(id) = path.res {
if self.binding_ids.contains(&id) {
self.usage_found = true;
}
@@ -155,8 +154,21 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
.is_some()
}
+pub fn local_used_in<'tcx>(cx: &LateContext<'tcx>, local_id: HirId, v: impl Visitable<'tcx>) -> bool {
+ for_each_expr_with_closures(cx, v, |e| {
+ if utils::path_to_local_id(e, local_id) {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(())
+ }
+ })
+ .is_some()
+}
+
pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr<'_>) -> bool {
- let Some(block) = utils::get_enclosing_block(cx, local_id) else { return false };
+ let Some(block) = utils::get_enclosing_block(cx, local_id) else {
+ return false;
+ };
// for _ in 1..3 {
// local
@@ -165,32 +177,21 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr
// let closure = || local;
// closure();
// closure();
- let in_loop_or_closure = cx
- .tcx
- .hir()
- .parent_iter(after.hir_id)
- .take_while(|&(id, _)| id != block.hir_id)
- .any(|(_, node)| {
- matches!(
- node,
- Node::Expr(Expr {
- kind: ExprKind::Loop(..) | ExprKind::Closure { .. },
- ..
- })
- )
- });
- if in_loop_or_closure {
- return true;
- }
+ let loop_start = get_enclosing_loop_or_multi_call_closure(cx, after).map(|e| e.hir_id);
let mut past_expr = false;
for_each_expr_with_closures(cx, block, |e| {
- if e.hir_id == after.hir_id {
+ if past_expr {
+ if utils::path_to_local_id(e, local_id) {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(Descend::Yes)
+ }
+ } else if e.hir_id == after.hir_id {
past_expr = true;
ControlFlow::Continue(Descend::No)
- } else if past_expr && utils::path_to_local_id(e, local_id) {
- ControlFlow::Break(())
} else {
+ past_expr = Some(e.hir_id) == loop_start;
ControlFlow::Continue(Descend::Yes)
}
})
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 8dafa723a..3b47a4513 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -52,6 +52,16 @@ pub trait Visitable<'tcx> {
/// Calls the corresponding `visit_*` function on the visitor.
fn visit<V: Visitor<'tcx>>(self, visitor: &mut V);
}
+impl<'tcx, T> Visitable<'tcx> for &'tcx [T]
+where
+ &'tcx T: Visitable<'tcx>,
+{
+ fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+ for x in self {
+ x.visit(visitor);
+ }
+ }
+}
macro_rules! visitable_ref {
($t:ident, $f:ident) => {
impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> {
@@ -151,7 +161,7 @@ pub fn for_each_expr_with_closures<'tcx, B, C: Continue>(
/// returns `true` if expr contains match expr desugared from try
fn contains_try(expr: &hir::Expr<'_>) -> bool {
for_each_expr(expr, |e| {
- if matches!(e.kind, hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar)) {
+ if matches!(e.kind, hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar(_))) {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
@@ -319,7 +329,7 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) ->
&& self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {},
ExprKind::Unary(UnOp::Deref, e) if self.cx.typeck_results().expr_ty(e).is_ref() => (),
ExprKind::Unary(_, e) if self.cx.typeck_results().expr_ty(e).peel_refs().is_primitive_ty() => (),
- ExprKind::Index(base, _)
+ ExprKind::Index(base, _, _)
if matches!(
self.cx.typeck_results().expr_ty(base).peel_refs().kind(),
ty::Slice(_) | ty::Array(..)
@@ -619,7 +629,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
helper(typeck, true, arg, f)?;
}
},
- ExprKind::Index(borrowed, consumed)
+ ExprKind::Index(borrowed, consumed, _)
| ExprKind::Assign(borrowed, consumed, _)
| ExprKind::AssignOp(_, borrowed, consumed) => {
helper(typeck, false, borrowed, f)?;
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index 4dc906d00..3633ed31d 100644
--- a/src/tools/clippy/declare_clippy_lint/Cargo.toml
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "declare_clippy_lint"
-version = "0.1.72"
+version = "0.1.73"
edition = "2021"
publish = false
diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs
index 3f01e9bb0..e678d4079 100644
--- a/src/tools/clippy/lintcheck/src/config.rs
+++ b/src/tools/clippy/lintcheck/src/config.rs
@@ -1,5 +1,6 @@
use clap::Parser;
-use std::{num::NonZeroUsize, path::PathBuf};
+use std::num::NonZeroUsize;
+use std::path::PathBuf;
#[derive(Clone, Debug, Parser)]
pub(crate) struct LintcheckConfig {
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index de56a6f82..3a022b343 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -15,16 +15,14 @@ use crate::config::LintcheckConfig;
use crate::recursive::LintcheckServer;
use std::collections::{HashMap, HashSet};
-use std::env;
use std::env::consts::EXE_SUFFIX;
use std::fmt::{self, Write as _};
-use std::fs;
use std::io::{self, ErrorKind};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::atomic::{AtomicUsize, Ordering};
-use std::thread;
use std::time::Duration;
+use std::{env, fs, thread};
use cargo_metadata::diagnostic::{Diagnostic, DiagnosticLevel};
use cargo_metadata::Message;
diff --git a/src/tools/clippy/lintcheck/src/recursive.rs b/src/tools/clippy/lintcheck/src/recursive.rs
index 49072e651..994fa3c3b 100644
--- a/src/tools/clippy/lintcheck/src/recursive.rs
+++ b/src/tools/clippy/lintcheck/src/recursive.rs
@@ -3,8 +3,7 @@
//! [`LintcheckServer`] to ask if it should be skipped, and if not sends the stderr of running
//! clippy on the crate to the server
-use crate::ClippyWarning;
-use crate::RecursiveOptions;
+use crate::{ClippyWarning, RecursiveOptions};
use std::collections::HashSet;
use std::io::{BufRead, BufReader, Read, Write};
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 4475d914c..8b3f819f0 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
[toolchain]
-channel = "nightly-2023-06-29"
+channel = "nightly-2023-08-10"
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/rustfmt.toml b/src/tools/clippy/rustfmt.toml
index 18b2a3346..4248f42f6 100644
--- a/src/tools/clippy/rustfmt.toml
+++ b/src/tools/clippy/rustfmt.toml
@@ -4,5 +4,6 @@ match_block_trailing_comma = true
wrap_comments = true
edition = "2021"
error_on_line_overflow = true
+imports_granularity = "Module"
version = "Two"
ignore = ["tests/ui/crashes/ice-10912.rs"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 1eb288b15..1d89477dc 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -130,6 +130,13 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
config.parse_sess_created = Some(Box::new(move |parse_sess| {
track_clippy_args(parse_sess, &clippy_args_var);
track_files(parse_sess);
+
+ // Trigger a rebuild if CLIPPY_CONF_DIR changes. The value must be a valid string so
+ // changes between dirs that are invalid UTF-8 will not trigger rebuilds
+ parse_sess.env_depinfo.get_mut().insert((
+ Symbol::intern("CLIPPY_CONF_DIR"),
+ env::var("CLIPPY_CONF_DIR").ok().map(|dir| Symbol::intern(&dir)),
+ ));
}));
config.register_lints = Some(Box::new(move |sess, lint_store| {
// technically we're ~guaranteed that this is none but might as well call anything that
@@ -185,7 +192,7 @@ You can use tool lints to allow or deny lints from your code, eg.:
);
}
-const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";
+const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml";
#[allow(clippy::too_many_lines)]
pub fn main() {
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index cdc85cb33..26b655076 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -132,8 +132,7 @@ impl ClippyCmd {
let clippy_args: String = self
.clippy_args
.iter()
- .map(|arg| format!("{arg}__CLIPPY_HACKERY__"))
- .collect();
+ .fold(String::new(), |s, arg| s + arg + "__CLIPPY_HACKERY__");
// Currently, `CLIPPY_TERMINAL_WIDTH` is used only to format "unknown field" error messages.
let terminal_width = termize::dimensions().map_or(0, |(w, _)| w);
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 0fd37c640..e46f8bf6f 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -3,17 +3,108 @@
#![feature(is_sorted)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
+#![allow(unused_extern_crates)]
-use compiletest::{status_emitter, CommandBuilder};
+use compiletest::{status_emitter, CommandBuilder, OutputConflictHandling};
use ui_test as compiletest;
use ui_test::Mode as TestMode;
+use std::collections::BTreeMap;
use std::env::{self, remove_var, set_var, var_os};
use std::ffi::{OsStr, OsString};
use std::fs;
use std::path::{Path, PathBuf};
+use std::sync::LazyLock;
use test_utils::IS_RUSTC_TEST_SUITE;
+// Test dependencies may need an `extern crate` here to ensure that they show up
+// in the depinfo file (otherwise cargo thinks they are unused)
+extern crate clippy_lints;
+extern crate clippy_utils;
+extern crate derive_new;
+extern crate futures;
+extern crate if_chain;
+extern crate itertools;
+extern crate parking_lot;
+extern crate quote;
+extern crate syn;
+extern crate tokio;
+
+/// All crates used in UI tests are listed here
+static TEST_DEPENDENCIES: &[&str] = &[
+ "clippy_lints",
+ "clippy_utils",
+ "derive_new",
+ "futures",
+ "if_chain",
+ "itertools",
+ "parking_lot",
+ "quote",
+ "regex",
+ "serde_derive",
+ "serde",
+ "syn",
+ "tokio",
+];
+
+/// Produces a string with an `--extern` flag for all UI test crate
+/// dependencies.
+///
+/// The dependency files are located by parsing the depinfo file for this test
+/// module. This assumes the `-Z binary-dep-depinfo` flag is enabled. All test
+/// dependencies must be added to Cargo.toml at the project root. Test
+/// dependencies that are not *directly* used by this test module require an
+/// `extern crate` declaration.
+static EXTERN_FLAGS: LazyLock<Vec<String>> = LazyLock::new(|| {
+ let current_exe_depinfo = {
+ let mut path = env::current_exe().unwrap();
+ path.set_extension("d");
+ fs::read_to_string(path).unwrap()
+ };
+ let mut crates = BTreeMap::<&str, &str>::new();
+ for line in current_exe_depinfo.lines() {
+ // each dependency is expected to have a Makefile rule like `/path/to/crate-hash.rlib:`
+ let parse_name_path = || {
+ if line.starts_with(char::is_whitespace) {
+ return None;
+ }
+ let path_str = line.strip_suffix(':')?;
+ let path = Path::new(path_str);
+ if !matches!(path.extension()?.to_str()?, "rlib" | "so" | "dylib" | "dll") {
+ return None;
+ }
+ let (name, _hash) = path.file_stem()?.to_str()?.rsplit_once('-')?;
+ // the "lib" prefix is not present for dll files
+ let name = name.strip_prefix("lib").unwrap_or(name);
+ Some((name, path_str))
+ };
+ if let Some((name, path)) = parse_name_path() {
+ if TEST_DEPENDENCIES.contains(&name) {
+ // A dependency may be listed twice if it is available in sysroot,
+ // and the sysroot dependencies are listed first. As of the writing,
+ // this only seems to apply to if_chain.
+ crates.insert(name, path);
+ }
+ }
+ }
+ let not_found: Vec<&str> = TEST_DEPENDENCIES
+ .iter()
+ .copied()
+ .filter(|n| !crates.contains_key(n))
+ .collect();
+ assert!(
+ not_found.is_empty(),
+ "dependencies not found in depinfo: {not_found:?}\n\
+ help: Make sure the `-Z binary-dep-depinfo` rust flag is enabled\n\
+ help: Try adding to dev-dependencies in Cargo.toml\n\
+ help: Be sure to also add `extern crate ...;` to tests/compile-test.rs",
+ );
+ crates
+ .into_iter()
+ .map(|(name, path)| format!("--extern={name}={path}"))
+ .collect()
+});
+
mod test_utils;
// whether to run internal tests or not
@@ -24,12 +115,13 @@ fn base_config(test_dir: &str) -> compiletest::Config {
mode: TestMode::Yolo,
stderr_filters: vec![],
stdout_filters: vec![],
- output_conflict_handling: if var_os("BLESS").is_some() || env::args().any(|arg| arg == "--bless") {
- compiletest::OutputConflictHandling::Bless
+ output_conflict_handling: if var_os("RUSTC_BLESS").is_some_and(|v| v != "0")
+ || env::args().any(|arg| arg == "--bless")
+ {
+ OutputConflictHandling::Bless
} else {
- compiletest::OutputConflictHandling::Error("cargo test -- -- --bless".into())
+ OutputConflictHandling::Error("cargo uibless".into())
},
- dependencies_crate_manifest_path: Some("clippy_test_deps/Cargo.toml".into()),
target: None,
out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap_or("target".into())).join("ui_test"),
..compiletest::Config::rustc(Path::new("tests").join(test_dir))
@@ -44,10 +136,24 @@ fn base_config(test_dir: &str) -> compiletest::Config {
let deps_path = current_exe_path.parent().unwrap();
let profile_path = deps_path.parent().unwrap();
- config.program.args.push("--emit=metadata".into());
- config.program.args.push("-Aunused".into());
- config.program.args.push("-Zui-testing".into());
- config.program.args.push("-Dwarnings".into());
+ config.program.args.extend(
+ [
+ "--emit=metadata",
+ "-Aunused",
+ "-Ainternal_features",
+ "-Zui-testing",
+ "-Dwarnings",
+ &format!("-Ldependency={}", deps_path.display()),
+ ]
+ .map(OsString::from),
+ );
+
+ config.program.args.extend(EXTERN_FLAGS.iter().map(OsString::from));
+
+ if let Some(host_libs) = option_env!("HOST_LIBS") {
+ let dep = format!("-Ldependency={}", Path::new(host_libs).join("deps").display());
+ config.program.args.push(dep.into());
+ }
// Normalize away slashes in windows paths.
config.stderr_filter(r"\\", "/");
@@ -84,9 +190,6 @@ fn run_ui() {
.to_string()
}),
);
- eprintln!(" Compiler: {}", config.program.display());
-
- let name = config.root_dir.display().to_string();
let test_filter = test_filter();
@@ -94,7 +197,7 @@ fn run_ui() {
config,
move |path| compiletest::default_file_filter(path) && test_filter(path),
compiletest::default_per_file_config,
- (status_emitter::Text, status_emitter::Gha::<true> { name }),
+ status_emitter::Text,
)
.unwrap();
check_rustfix_coverage();
@@ -106,9 +209,18 @@ fn run_internal_tests() {
return;
}
let mut config = base_config("ui-internal");
- config.dependency_builder.args.push("--features".into());
- config.dependency_builder.args.push("internal".into());
- compiletest::run_tests(config).unwrap();
+ if let OutputConflictHandling::Error(err) = &mut config.output_conflict_handling {
+ *err = "cargo uitest --features internal -- -- --bless".into();
+ }
+ let test_filter = test_filter();
+
+ compiletest::run_tests_generic(
+ config,
+ move |path| compiletest::default_file_filter(path) && test_filter(path),
+ compiletest::default_per_file_config,
+ status_emitter::Text,
+ )
+ .unwrap();
}
fn run_ui_toml() {
@@ -127,13 +239,11 @@ fn run_ui_toml() {
"$$DIR",
);
- let name = config.root_dir.display().to_string();
-
let test_filter = test_filter();
ui_test::run_tests_generic(
config,
- |path| test_filter(path) && path.extension() == Some("rs".as_ref()),
+ |path| compiletest::default_file_filter(path) && test_filter(path),
|config, path| {
let mut config = config.clone();
config
@@ -142,7 +252,7 @@ fn run_ui_toml() {
.push(("CLIPPY_CONF_DIR".into(), Some(path.parent().unwrap().into())));
Some(config)
},
- (status_emitter::Text, status_emitter::Gha::<true> { name }),
+ status_emitter::Text,
)
.unwrap();
}
@@ -183,8 +293,6 @@ fn run_ui_cargo() {
"$$DIR",
);
- let name = config.root_dir.display().to_string();
-
let test_filter = test_filter();
ui_test::run_tests_generic(
@@ -195,7 +303,7 @@ fn run_ui_cargo() {
config.out_dir = PathBuf::from("target/ui_test_cargo/").join(path.parent().unwrap());
Some(config)
},
- (status_emitter::Text, status_emitter::Gha::<true> { name }),
+ status_emitter::Text,
)
.unwrap();
}
@@ -211,12 +319,45 @@ fn main() {
}
set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
- run_ui();
- run_ui_toml();
- run_ui_cargo();
- run_internal_tests();
- rustfix_coverage_known_exceptions_accuracy();
- ui_cargo_toml_metadata();
+ // The SPEEDTEST_* env variables can be used to check Clippy's performance on your PR. It runs the
+ // affected test 1000 times and gets the average.
+ if let Ok(speedtest) = std::env::var("SPEEDTEST") {
+ println!("----------- STARTING SPEEDTEST -----------");
+ let f = match speedtest.as_str() {
+ "ui" => run_ui as fn(),
+ "cargo" => run_ui_cargo as fn(),
+ "toml" => run_ui_toml as fn(),
+ "internal" => run_internal_tests as fn(),
+ "rustfix-coverage-known-exceptions-accuracy" => rustfix_coverage_known_exceptions_accuracy as fn(),
+ "ui-cargo-toml-metadata" => ui_cargo_toml_metadata as fn(),
+
+ _ => panic!("unknown speedtest: {speedtest} || accepted speedtests are: [ui, cargo, toml, internal]"),
+ };
+
+ let iterations;
+ if let Ok(iterations_str) = std::env::var("SPEEDTEST_ITERATIONS") {
+ iterations = iterations_str
+ .parse::<u64>()
+ .unwrap_or_else(|_| panic!("Couldn't parse `{iterations_str}`, please use a valid u64"));
+ } else {
+ iterations = 1000;
+ }
+
+ let mut sum = 0;
+ for _ in 0..iterations {
+ let start = std::time::Instant::now();
+ f();
+ sum += start.elapsed().as_millis();
+ }
+ println!("average {} time: {} millis.", speedtest.to_uppercase(), sum / 1000);
+ } else {
+ run_ui();
+ run_ui_toml();
+ run_ui_cargo();
+ run_internal_tests();
+ rustfix_coverage_known_exceptions_accuracy();
+ ui_cargo_toml_metadata();
+ }
}
const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[
diff --git a/src/tools/clippy/tests/integration.rs b/src/tools/clippy/tests/integration.rs
index a771d8b87..031982edb 100644
--- a/src/tools/clippy/tests/integration.rs
+++ b/src/tools/clippy/tests/integration.rs
@@ -65,6 +65,30 @@ fn integration_test() {
.expect("unable to run clippy");
let stderr = String::from_utf8_lossy(&output.stderr);
+
+ // debug:
+ eprintln!("{stderr}");
+
+ // this is an internal test to make sure we would correctly panic on a delay_span_bug
+ if repo_name == "matthiaskrgr/clippy_ci_panic_test" {
+ // we need to kind of switch around our logic here:
+ // if we find a panic, everything is fine, if we don't panic, SOMETHING is broken about our testing
+
+ // the repo basically just contains a delay_span_bug that forces rustc/clippy to panic:
+ /*
+ #![feature(rustc_attrs)]
+ #[rustc_error(delay_span_bug_from_inside_query)]
+ fn main() {}
+ */
+
+ if stderr.find("error: internal compiler error").is_some() {
+ eprintln!("we saw that we intentionally panicked, yay");
+ return;
+ }
+
+ panic!("panic caused by delay_span_bug was NOT detected! Something is broken!");
+ }
+
if let Some(backtrace_start) = stderr.find("error: internal compiler error") {
static BACKTRACE_END_MSG: &str = "end of query stack";
let backtrace_end = stderr[backtrace_start..]
diff --git a/src/tools/clippy/tests/lint_message_convention.rs b/src/tools/clippy/tests/lint_message_convention.rs
index 15e5cdd69..98019c755 100644
--- a/src/tools/clippy/tests/lint_message_convention.rs
+++ b/src/tools/clippy/tests/lint_message_convention.rs
@@ -18,18 +18,20 @@ impl Message {
fn new(path: PathBuf) -> Self {
// we don't want the first letter after "error: ", "help: " ... to be capitalized
// also no punctuation (except for "?" ?) at the end of a line
+ // Prefer "try" over "try this".
static REGEX_SET: LazyLock<RegexSet> = LazyLock::new(|| {
RegexSet::new([
"error: [A-Z]",
"help: [A-Z]",
"warning: [A-Z]",
"note: [A-Z]",
- "try this: [A-Z]",
+ "try: [A-Z]",
"error: .*[.!]$",
"help: .*[.!]$",
"warning: .*[.!]$",
"note: .*[.!]$",
- "try this: .*[.!]$",
+ "try: .*[.!]$",
+ "try this",
])
.unwrap()
});
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs
index 1a69bb241..c67166fc4 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
#![warn(clippy::cargo_common_metadata)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs
index 1a69bb241..c67166fc4 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
#![warn(clippy::cargo_common_metadata)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs
index 1a69bb241..c67166fc4 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
#![warn(clippy::cargo_common_metadata)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs
index 1a69bb241..c67166fc4 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
#![warn(clippy::cargo_common_metadata)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs
index 1a69bb241..c67166fc4 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
#![warn(clippy::cargo_common_metadata)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs
index 1a69bb241..c67166fc4 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
#![warn(clippy::cargo_common_metadata)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs
index 4dd9582af..74e40c09e 100644
--- a/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=feature_name
#![warn(clippy::redundant_feature_names)]
#![warn(clippy::negative_feature_names)]
diff --git a/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs
index 4dd9582af..74e40c09e 100644
--- a/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=feature_name
#![warn(clippy::redundant_feature_names)]
#![warn(clippy::negative_feature_names)]
diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs
index c70d92e35..ac21b3a44 100644
--- a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs
@@ -1,3 +1,4 @@
+// FIXME: find a way to add rustflags to ui-cargo tests
//@compile-flags: --remap-path-prefix {{src-base}}=/remapped
#![warn(clippy::self_named_module_files)]
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs
index ece260b74..4bc61dd62 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=multiple_crate_versions
#![warn(clippy::multiple_crate_versions)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs
index ece260b74..4bc61dd62 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=multiple_crate_versions
#![warn(clippy::multiple_crate_versions)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs
index ece260b74..4bc61dd62 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=multiple_crate_versions
#![warn(clippy::multiple_crate_versions)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs
index bb3a39d07..3491ccb0d 100644
--- a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=wildcard_dependencies
#![warn(clippy::wildcard_dependencies)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs
index bb3a39d07..3491ccb0d 100644
--- a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=wildcard_dependencies
#![warn(clippy::wildcard_dependencies)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
index b88aeae2a..d8b158816 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
@@ -1,9 +1,10 @@
-thread '<unnamed>' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs
+thread '<unnamed>' panicked at clippy_lints/src/utils/internal_lints/produce_ice.rs:
+Would you like some help with that?
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: the compiler unexpectedly panicked. this is a bug.
-note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new
+note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml
note: rustc <version> running on <target>
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr
new file mode 100644
index 000000000..a8900da4e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr
@@ -0,0 +1,28 @@
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:40:5
+ |
+LL | std::f32::MAX;
+ | ^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::absolute-paths` implied by `-D warnings`
+
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:41:5
+ |
+LL | core::f32::MAX;
+ | ^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:42:5
+ |
+LL | ::core::f32::MAX;
+ | ^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:58:5
+ |
+LL | ::std::f32::MAX;
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr
new file mode 100644
index 000000000..41b70644b
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr
@@ -0,0 +1,70 @@
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:40:5
+ |
+LL | std::f32::MAX;
+ | ^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::absolute-paths` implied by `-D warnings`
+
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:41:5
+ |
+LL | core::f32::MAX;
+ | ^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:42:5
+ |
+LL | ::core::f32::MAX;
+ | ^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:43:5
+ |
+LL | crate::a::b::c::C;
+ | ^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:44:5
+ |
+LL | crate::a::b::c::d::e::f::F;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:45:5
+ |
+LL | crate::a::A;
+ | ^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:46:5
+ |
+LL | crate::a::b::B;
+ | ^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:47:5
+ |
+LL | crate::a::b::c::C::ZERO;
+ | ^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:48:5
+ |
+LL | helper::b::c::d::e::f();
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:49:5
+ |
+LL | ::helper::b::c::d::e::f();
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+ --> $DIR/absolute_paths.rs:58:5
+ |
+LL | ::std::f32::MAX;
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs
new file mode 100644
index 000000000..d4c250a8f
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs
@@ -0,0 +1,97 @@
+//@aux-build:../../ui/auxiliary/proc_macros.rs:proc-macro
+//@aux-build:helper.rs
+//@revisions: allow_crates disallow_crates
+//@[allow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/allow_crates
+//@[disallow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/disallow_crates
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::absolute_paths)]
+#![feature(decl_macro)]
+
+extern crate helper;
+#[macro_use]
+extern crate proc_macros;
+
+pub mod a {
+ pub mod b {
+ pub mod c {
+ pub struct C;
+
+ impl C {
+ pub const ZERO: u32 = 0;
+ }
+
+ pub mod d {
+ pub mod e {
+ pub mod f {
+ pub struct F;
+ }
+ }
+ }
+ }
+
+ pub struct B;
+ }
+
+ pub struct A;
+}
+
+fn main() {
+ f32::max(1.0, 2.0);
+ std::f32::MAX;
+ core::f32::MAX;
+ ::core::f32::MAX;
+ crate::a::b::c::C;
+ crate::a::b::c::d::e::f::F;
+ crate::a::A;
+ crate::a::b::B;
+ crate::a::b::c::C::ZERO;
+ helper::b::c::d::e::f();
+ ::helper::b::c::d::e::f();
+ fn b() -> a::b::B {
+ todo!()
+ }
+ std::println!("a");
+ let x = 1;
+ std::ptr::addr_of!(x);
+ // Test we handle max segments with `PathRoot` properly; this has 4 segments but we should say it
+ // has 3
+ ::std::f32::MAX;
+ // Do not lint due to the above
+ ::helper::a();
+ // Do not lint
+ helper::a();
+ use crate::a::b::c::C;
+ use a::b;
+ use std::f32::MAX;
+ a::b::c::d::e::f::F;
+ b::c::C;
+ fn a() -> a::A {
+ todo!()
+ }
+ use a::b::c;
+
+ fn c() -> c::C {
+ todo!()
+ }
+ fn d() -> Result<(), ()> {
+ todo!()
+ }
+ external! {
+ crate::a::b::c::C::ZERO;
+ }
+ // For some reason, `path.span.from_expansion()` takes care of this for us
+ with_span! {
+ span
+ crate::a::b::c::C::ZERO;
+ }
+ macro_rules! local_crate {
+ () => {
+ crate::a::b::c::C::ZERO;
+ };
+ }
+ macro local_crate_2_0() {
+ crate::a::b::c::C::ZERO;
+ }
+ local_crate!();
+ local_crate_2_0!();
+}
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml b/src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml
new file mode 100644
index 000000000..59a621e9d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml
@@ -0,0 +1,2 @@
+absolute-paths-max-segments = 2
+absolute-paths-allowed-crates = ["crate", "helper"]
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs b/src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs
new file mode 100644
index 000000000..8e2678f5f
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs
@@ -0,0 +1,11 @@
+pub fn a() {}
+
+pub mod b {
+ pub mod c {
+ pub mod d {
+ pub mod e {
+ pub fn f() {}
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml b/src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml
new file mode 100644
index 000000000..d44d648c6
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml
@@ -0,0 +1 @@
+absolute-paths-max-segments = 2
diff --git a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr
index 6ec79a618..eb1180e60 100644
--- a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr
+++ b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr
@@ -30,7 +30,7 @@ LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64);
| ^^^
|
= note: `-D clippy::print-literal` implied by `-D warnings`
-help: try this
+help: try
|
LL - println!("Hello {} is {:.*}", "x", local_i32, local_f64);
LL + println!("Hello x is {:.*}", local_i32, local_f64);
diff --git a/src/tools/clippy/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs b/src/tools/clippy/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs
index ebadd4e44..60fbaaea3 100644
--- a/src/tools/clippy/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs
+++ b/src/tools/clippy/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs
@@ -7,13 +7,10 @@
extern crate proc_macro;
use core::mem;
-use proc_macro::{
- token_stream::IntoIter,
- Delimiter::{self, Brace, Parenthesis},
- Group, Ident, Literal, Punct,
- Spacing::{self, Alone, Joint},
- Span, TokenStream, TokenTree as TT,
-};
+use proc_macro::token_stream::IntoIter;
+use proc_macro::Delimiter::{self, Brace, Parenthesis};
+use proc_macro::Spacing::{self, Alone, Joint};
+use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree as TT};
type Result<T> = core::result::Result<T, TokenStream>;
diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
index 9eef0e1bf..815d00935 100644
--- a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
+++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
@@ -4,7 +4,7 @@ error: used `expect()` on an `Option` value
LL | let _ = opt.expect("");
| ^^^^^^^^^^^^^^
|
- = help: if this value is `None`, it will panic
+ = note: if this value is `None`, it will panic
= note: `-D clippy::expect-used` implied by `-D warnings`
error: used `expect()` on a `Result` value
@@ -13,7 +13,7 @@ error: used `expect()` on a `Result` value
LL | let _ = res.expect("");
| ^^^^^^^^^^^^^^
|
- = help: if this value is an `Err`, it will panic
+ = note: if this value is an `Err`, it will panic
error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs b/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs
index f267a67f4..78784bfff 100644
--- a/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs
+++ b/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs
@@ -2,6 +2,7 @@
//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)"
#![warn(clippy::trivially_copy_pass_by_ref)]
+#![allow(clippy::needless_pass_by_ref_mut)]
#[derive(Copy, Clone)]
struct Foo(u8);
diff --git a/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.stderr b/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.stderr
index d2b55eff1..db5d68053 100644
--- a/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.stderr
@@ -1,5 +1,5 @@
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/test.rs:14:11
+ --> $DIR/test.rs:15:11
|
LL | fn bad(x: &u16, y: &Foo) {}
| ^^^^ help: consider passing by value instead: `u16`
@@ -7,7 +7,7 @@ LL | fn bad(x: &u16, y: &Foo) {}
= note: `-D clippy::trivially-copy-pass-by-ref` implied by `-D warnings`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/test.rs:14:20
+ --> $DIR/test.rs:15:20
|
LL | fn bad(x: &u16, y: &Foo) {}
| ^^^^ help: consider passing by value instead: `Foo`
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 6ba26e977..cdabe6460 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -1,4 +1,6 @@
error: error reading Clippy's configuration file: unknown field `foobar`, expected one of
+ absolute-paths-allowed-crates
+ absolute-paths-max-segments
accept-comment-above-attributes
accept-comment-above-statement
allow-dbg-in-tests
@@ -68,6 +70,8 @@ LL | foobar = 42
| ^^^^^^
error: error reading Clippy's configuration file: unknown field `barfoo`, expected one of
+ absolute-paths-allowed-crates
+ absolute-paths-max-segments
accept-comment-above-attributes
accept-comment-above-statement
allow-dbg-in-tests
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs
index dde1c6d7c..e300ba18c 100644
--- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs
@@ -9,9 +9,7 @@
#![warn(clippy::unwrap_used)]
#![warn(clippy::get_unwrap)]
-use std::collections::BTreeMap;
-use std::collections::HashMap;
-use std::collections::VecDeque;
+use std::collections::{BTreeMap, HashMap, VecDeque};
struct GetFalsePositive {
arr: [u32; 3],
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
index eb66a5cf5..10219beaf 100644
--- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
@@ -1,199 +1,212 @@
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:40:17
+ --> $DIR/unwrap_used.rs:38:17
|
LL | let _ = boxed_slice.get(1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
|
= note: `-D clippy::get-unwrap` implied by `-D warnings`
error: used `unwrap()` on an `Option` value
- --> $DIR/unwrap_used.rs:40:17
+ --> $DIR/unwrap_used.rs:38:17
|
LL | let _ = boxed_slice.get(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
= note: `-D clippy::unwrap-used` implied by `-D warnings`
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:41:17
+ --> $DIR/unwrap_used.rs:39:17
|
LL | let _ = some_slice.get(0).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]`
error: used `unwrap()` on an `Option` value
- --> $DIR/unwrap_used.rs:41:17
+ --> $DIR/unwrap_used.rs:39:17
|
LL | let _ = some_slice.get(0).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:42:17
+ --> $DIR/unwrap_used.rs:40:17
|
LL | let _ = some_vec.get(0).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]`
error: used `unwrap()` on an `Option` value
- --> $DIR/unwrap_used.rs:42:17
+ --> $DIR/unwrap_used.rs:40:17
|
LL | let _ = some_vec.get(0).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:43:17
+ --> $DIR/unwrap_used.rs:41:17
|
LL | let _ = some_vecdeque.get(0).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]`
error: used `unwrap()` on an `Option` value
- --> $DIR/unwrap_used.rs:43:17
+ --> $DIR/unwrap_used.rs:41:17
|
LL | let _ = some_vecdeque.get(0).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:44:17
+ --> $DIR/unwrap_used.rs:42:17
|
LL | let _ = some_hashmap.get(&1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]`
error: used `unwrap()` on an `Option` value
- --> $DIR/unwrap_used.rs:44:17
+ --> $DIR/unwrap_used.rs:42:17
|
LL | let _ = some_hashmap.get(&1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:45:17
+ --> $DIR/unwrap_used.rs:43:17
|
LL | let _ = some_btreemap.get(&1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]`
error: used `unwrap()` on an `Option` value
- --> $DIR/unwrap_used.rs:45:17
+ --> $DIR/unwrap_used.rs:43:17
|
LL | let _ = some_btreemap.get(&1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:49:21
+ --> $DIR/unwrap_used.rs:47:21
|
LL | let _: u8 = *boxed_slice.get(1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]`
error: used `unwrap()` on an `Option` value
- --> $DIR/unwrap_used.rs:49:22
+ --> $DIR/unwrap_used.rs:47:22
|
LL | let _: u8 = *boxed_slice.get(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:54:9
+ --> $DIR/unwrap_used.rs:52:9
|
LL | *boxed_slice.get_mut(0).unwrap() = 1;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]`
error: used `unwrap()` on an `Option` value
- --> $DIR/unwrap_used.rs:54:10
+ --> $DIR/unwrap_used.rs:52:10
|
LL | *boxed_slice.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:55:9
+ --> $DIR/unwrap_used.rs:53:9
|
LL | *some_slice.get_mut(0).unwrap() = 1;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]`
error: used `unwrap()` on an `Option` value
- --> $DIR/unwrap_used.rs:55:10
+ --> $DIR/unwrap_used.rs:53:10
|
LL | *some_slice.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:56:9
+ --> $DIR/unwrap_used.rs:54:9
|
LL | *some_vec.get_mut(0).unwrap() = 1;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]`
error: used `unwrap()` on an `Option` value
- --> $DIR/unwrap_used.rs:56:10
+ --> $DIR/unwrap_used.rs:54:10
|
LL | *some_vec.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:57:9
+ --> $DIR/unwrap_used.rs:55:9
|
LL | *some_vecdeque.get_mut(0).unwrap() = 1;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]`
error: used `unwrap()` on an `Option` value
- --> $DIR/unwrap_used.rs:57:10
+ --> $DIR/unwrap_used.rs:55:10
|
LL | *some_vecdeque.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:69:17
+ --> $DIR/unwrap_used.rs:67:17
|
LL | let _ = some_vec.get(0..1).unwrap().to_vec();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
error: used `unwrap()` on an `Option` value
- --> $DIR/unwrap_used.rs:69:17
+ --> $DIR/unwrap_used.rs:67:17
|
LL | let _ = some_vec.get(0..1).unwrap().to_vec();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:70:17
+ --> $DIR/unwrap_used.rs:68:17
|
LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
error: used `unwrap()` on an `Option` value
- --> $DIR/unwrap_used.rs:70:17
+ --> $DIR/unwrap_used.rs:68:17
|
LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:77:13
+ --> $DIR/unwrap_used.rs:75:13
|
LL | let _ = boxed_slice.get(1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:95:17
+ --> $DIR/unwrap_used.rs:93:17
|
LL | let _ = Box::new([0]).get(1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&Box::new([0])[1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&Box::new([0])[1]`
error: aborting due to 28 previous errors
diff --git a/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs b/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs
index b6fcca0a7..2940c2732 100644
--- a/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs
+++ b/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs
@@ -1,6 +1,12 @@
+//@aux-build:proc_macros.rs:proc-macro
#![warn(clippy::arc_with_non_send_sync)]
#![allow(unused_variables)]
+
+#[macro_use]
+extern crate proc_macros;
+
use std::cell::RefCell;
+use std::ptr::{null, null_mut};
use std::sync::{Arc, Mutex};
fn foo<T>(x: T) {
@@ -11,14 +17,32 @@ fn issue11076<T>() {
let a: Arc<Vec<T>> = Arc::new(Vec::new());
}
+fn issue11232() {
+ external! {
+ let a: Arc<*const u8> = Arc::new(null());
+ let a: Arc<*mut u8> = Arc::new(null_mut());
+ }
+ with_span! {
+ span
+ let a: Arc<*const u8> = Arc::new(null());
+ let a: Arc<*mut u8> = Arc::new(null_mut());
+ }
+}
+
fn main() {
let _ = Arc::new(42);
- // !Sync
let _ = Arc::new(RefCell::new(42));
+ //~^ ERROR: usage of an `Arc` that is not `Send` or `Sync`
+ //~| NOTE: the trait `Sync` is not implemented for `RefCell<i32>`
+
let mutex = Mutex::new(1);
- // !Send
let _ = Arc::new(mutex.lock().unwrap());
- // !Send + !Sync
+ //~^ ERROR: usage of an `Arc` that is not `Send` or `Sync`
+ //~| NOTE: the trait `Send` is not implemented for `MutexGuard<'_, i32>`
+
let _ = Arc::new(&42 as *const i32);
+ //~^ ERROR: usage of an `Arc` that is not `Send` or `Sync`
+ //~| NOTE: the trait `Send` is not implemented for `*const i32`
+ //~| NOTE: the trait `Sync` is not implemented for `*const i32`
}
diff --git a/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr b/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr
index 7633b38df..de3f2fb9e 100644
--- a/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr
+++ b/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr
@@ -1,5 +1,5 @@
error: usage of an `Arc` that is not `Send` or `Sync`
- --> $DIR/arc_with_non_send_sync.rs:18:13
+ --> $DIR/arc_with_non_send_sync.rs:35:13
|
LL | let _ = Arc::new(RefCell::new(42));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL | let _ = Arc::new(RefCell::new(42));
= note: `-D clippy::arc-with-non-send-sync` implied by `-D warnings`
error: usage of an `Arc` that is not `Send` or `Sync`
- --> $DIR/arc_with_non_send_sync.rs:21:13
+ --> $DIR/arc_with_non_send_sync.rs:40:13
|
LL | let _ = Arc::new(mutex.lock().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL | let _ = Arc::new(mutex.lock().unwrap());
= help: consider using an `Rc` instead or wrapping the inner type with a `Mutex`
error: usage of an `Arc` that is not `Send` or `Sync`
- --> $DIR/arc_with_non_send_sync.rs:23:13
+ --> $DIR/arc_with_non_send_sync.rs:44:13
|
LL | let _ = Arc::new(&42 as *const i32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
index 4f38e50c8..2ac2fa220 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
@@ -481,4 +481,16 @@ pub fn issue_10792() {
let _ = 10 / TWO.c;
}
+pub fn issue_11145() {
+ let mut x: Wrapping<u32> = Wrapping(0_u32);
+ x += 1;
+}
+
+pub fn issue_11262() {
+ let one = 1;
+ let zero = 0;
+ let _ = 2 / one;
+ let _ = 2 / zero;
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/as_conversions.rs b/src/tools/clippy/tests/ui/as_conversions.rs
index 427842a51..69f1c541c 100644
--- a/src/tools/clippy/tests/ui/as_conversions.rs
+++ b/src/tools/clippy/tests/ui/as_conversions.rs
@@ -4,8 +4,7 @@
#![allow(clippy::borrow_as_ptr, unused)]
extern crate proc_macros;
-use proc_macros::external;
-use proc_macros::with_span;
+use proc_macros::{external, with_span};
fn main() {
let i = 0u32 as u64;
diff --git a/src/tools/clippy/tests/ui/as_conversions.stderr b/src/tools/clippy/tests/ui/as_conversions.stderr
index ca41d1378..54037a649 100644
--- a/src/tools/clippy/tests/ui/as_conversions.stderr
+++ b/src/tools/clippy/tests/ui/as_conversions.stderr
@@ -1,5 +1,5 @@
error: using a potentially dangerous silent `as` conversion
- --> $DIR/as_conversions.rs:11:13
+ --> $DIR/as_conversions.rs:10:13
|
LL | let i = 0u32 as u64;
| ^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | let i = 0u32 as u64;
= note: `-D clippy::as-conversions` implied by `-D warnings`
error: using a potentially dangerous silent `as` conversion
- --> $DIR/as_conversions.rs:13:13
+ --> $DIR/as_conversions.rs:12:13
|
LL | let j = &i as *const u64 as *mut u64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL | let j = &i as *const u64 as *mut u64;
= help: consider using a safe wrapper for this conversion
error: using a potentially dangerous silent `as` conversion
- --> $DIR/as_conversions.rs:13:13
+ --> $DIR/as_conversions.rs:12:13
|
LL | let j = &i as *const u64 as *mut u64;
| ^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs b/src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs
index cab216b51..f20df6f0f 100644
--- a/src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/macro_use_helper.rs
@@ -15,8 +15,7 @@ pub mod inner {
// RE-EXPORT
// this will stick in `inner` module
- pub use macro_rules::mut_mut;
- pub use macro_rules::try_err;
+ pub use macro_rules::{mut_mut, try_err};
pub mod nested {
pub use macro_rules::string_add;
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
index fdfe5fc41..c58795575 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
@@ -8,11 +8,11 @@ extern crate syn;
use proc_macro::TokenStream;
use quote::{quote, quote_spanned};
-use syn::parse_macro_input;
use syn::spanned::Spanned;
use syn::token::Star;
use syn::{
- parse_quote, FnArg, ImplItem, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, TraitItem, Type,
+ parse_macro_input, parse_quote, FnArg, ImplItem, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature,
+ TraitItem, Type,
};
#[proc_macro_attribute]
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
index 4d008c8cb..43df65438 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
@@ -5,13 +5,10 @@
extern crate proc_macro;
use core::mem;
-use proc_macro::{
- token_stream::IntoIter,
- Delimiter::{self, Brace, Parenthesis},
- Group, Ident, Literal, Punct,
- Spacing::{self, Alone, Joint},
- Span, TokenStream, TokenTree as TT,
-};
+use proc_macro::token_stream::IntoIter;
+use proc_macro::Delimiter::{self, Brace, Parenthesis};
+use proc_macro::Spacing::{self, Alone, Joint};
+use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree as TT};
type Result<T> = core::result::Result<T, TokenStream>;
diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map.stderr b/src/tools/clippy/tests/ui/bind_instead_of_map.stderr
index b6a81d21b..f17fee746 100644
--- a/src/tools/clippy/tests/ui/bind_instead_of_map.stderr
+++ b/src/tools/clippy/tests/ui/bind_instead_of_map.stderr
@@ -14,7 +14,7 @@ error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed
--> $DIR/bind_instead_of_map.rs:10:13
|
LL | let _ = x.and_then(|o| Some(o + 1));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.map(|o| o + 1)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.map(|o| o + 1)`
error: using `Result.and_then(Ok)`, which is a no-op
--> $DIR/bind_instead_of_map.rs:16:13
diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr
index 0152a93fe..cedbca785 100644
--- a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr
+++ b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr
@@ -9,7 +9,7 @@ note: the lint level is defined here
|
LL | #![deny(clippy::bind_instead_of_map)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: try this
+help: try
|
LL | let _ = Some("42").map(|s| if s.len() < 42 { 0 } else { s.len() });
| ~~~ ~ ~~~~~~~
@@ -20,7 +20,7 @@ error: using `Result.and_then(|x| Ok(y))`, which is more succinctly expressed as
LL | let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Ok(0) } else { Ok(s.len()) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: try this
+help: try
|
LL | let _ = Ok::<_, ()>("42").map(|s| if s.len() < 42 { 0 } else { s.len() });
| ~~~ ~ ~~~~~~~
@@ -31,7 +31,7 @@ error: using `Result.or_else(|x| Err(y))`, which is more succinctly expressed as
LL | let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Err(s.len() + 20) } else { Err(s.len()) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: try this
+help: try
|
LL | let _ = Err::<(), _>("42").map_err(|s| if s.len() < 42 { s.len() + 20 } else { s.len() });
| ~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~
@@ -48,7 +48,7 @@ LL | | }
LL | | });
| |______^
|
-help: try this
+help: try
|
LL ~ Some("42").map(|s| {
LL | if {
@@ -82,7 +82,7 @@ error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed
LL | let _ = Some("").and_then(|s| if s.len() == 20 { Some(m!()) } else { Some(Some(20)) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: try this
+help: try
|
LL | let _ = Some("").map(|s| if s.len() == 20 { m!() } else { Some(20) });
| ~~~ ~~~~ ~~~~~~~~
diff --git a/src/tools/clippy/tests/ui/bool_comparison.fixed b/src/tools/clippy/tests/ui/bool_comparison.fixed
index d6774c035..8689f89d2 100644
--- a/src/tools/clippy/tests/ui/bool_comparison.fixed
+++ b/src/tools/clippy/tests/ui/bool_comparison.fixed
@@ -2,6 +2,7 @@
#![allow(clippy::needless_if)]
#![warn(clippy::bool_comparison)]
+#![allow(clippy::incorrect_partial_ord_impl_on_ord_type)]
fn main() {
let x = true;
diff --git a/src/tools/clippy/tests/ui/bool_comparison.rs b/src/tools/clippy/tests/ui/bool_comparison.rs
index c0483fd73..a1c94aff9 100644
--- a/src/tools/clippy/tests/ui/bool_comparison.rs
+++ b/src/tools/clippy/tests/ui/bool_comparison.rs
@@ -2,6 +2,7 @@
#![allow(clippy::needless_if)]
#![warn(clippy::bool_comparison)]
+#![allow(clippy::incorrect_partial_ord_impl_on_ord_type)]
fn main() {
let x = true;
diff --git a/src/tools/clippy/tests/ui/bool_comparison.stderr b/src/tools/clippy/tests/ui/bool_comparison.stderr
index f4dded365..19bdf3013 100644
--- a/src/tools/clippy/tests/ui/bool_comparison.stderr
+++ b/src/tools/clippy/tests/ui/bool_comparison.stderr
@@ -1,5 +1,5 @@
error: equality checks against true are unnecessary
- --> $DIR/bool_comparison.rs:8:8
+ --> $DIR/bool_comparison.rs:9:8
|
LL | if x == true {
| ^^^^^^^^^ help: try simplifying it as shown: `x`
@@ -7,127 +7,127 @@ LL | if x == true {
= note: `-D clippy::bool-comparison` implied by `-D warnings`
error: equality checks against false can be replaced by a negation
- --> $DIR/bool_comparison.rs:13:8
+ --> $DIR/bool_comparison.rs:14:8
|
LL | if x == false {
| ^^^^^^^^^^ help: try simplifying it as shown: `!x`
error: equality checks against true are unnecessary
- --> $DIR/bool_comparison.rs:18:8
+ --> $DIR/bool_comparison.rs:19:8
|
LL | if true == x {
| ^^^^^^^^^ help: try simplifying it as shown: `x`
error: equality checks against false can be replaced by a negation
- --> $DIR/bool_comparison.rs:23:8
+ --> $DIR/bool_comparison.rs:24:8
|
LL | if false == x {
| ^^^^^^^^^^ help: try simplifying it as shown: `!x`
error: inequality checks against true can be replaced by a negation
- --> $DIR/bool_comparison.rs:28:8
+ --> $DIR/bool_comparison.rs:29:8
|
LL | if x != true {
| ^^^^^^^^^ help: try simplifying it as shown: `!x`
error: inequality checks against false are unnecessary
- --> $DIR/bool_comparison.rs:33:8
+ --> $DIR/bool_comparison.rs:34:8
|
LL | if x != false {
| ^^^^^^^^^^ help: try simplifying it as shown: `x`
error: inequality checks against true can be replaced by a negation
- --> $DIR/bool_comparison.rs:38:8
+ --> $DIR/bool_comparison.rs:39:8
|
LL | if true != x {
| ^^^^^^^^^ help: try simplifying it as shown: `!x`
error: inequality checks against false are unnecessary
- --> $DIR/bool_comparison.rs:43:8
+ --> $DIR/bool_comparison.rs:44:8
|
LL | if false != x {
| ^^^^^^^^^^ help: try simplifying it as shown: `x`
error: less than comparison against true can be replaced by a negation
- --> $DIR/bool_comparison.rs:48:8
+ --> $DIR/bool_comparison.rs:49:8
|
LL | if x < true {
| ^^^^^^^^ help: try simplifying it as shown: `!x`
error: greater than checks against false are unnecessary
- --> $DIR/bool_comparison.rs:53:8
+ --> $DIR/bool_comparison.rs:54:8
|
LL | if false < x {
| ^^^^^^^^^ help: try simplifying it as shown: `x`
error: greater than checks against false are unnecessary
- --> $DIR/bool_comparison.rs:58:8
+ --> $DIR/bool_comparison.rs:59:8
|
LL | if x > false {
| ^^^^^^^^^ help: try simplifying it as shown: `x`
error: less than comparison against true can be replaced by a negation
- --> $DIR/bool_comparison.rs:63:8
+ --> $DIR/bool_comparison.rs:64:8
|
LL | if true > x {
| ^^^^^^^^ help: try simplifying it as shown: `!x`
error: order comparisons between booleans can be simplified
- --> $DIR/bool_comparison.rs:69:8
+ --> $DIR/bool_comparison.rs:70:8
|
LL | if x < y {
| ^^^^^ help: try simplifying it as shown: `!x & y`
error: order comparisons between booleans can be simplified
- --> $DIR/bool_comparison.rs:74:8
+ --> $DIR/bool_comparison.rs:75:8
|
LL | if x > y {
| ^^^^^ help: try simplifying it as shown: `x & !y`
error: this comparison might be written more concisely
- --> $DIR/bool_comparison.rs:122:8
+ --> $DIR/bool_comparison.rs:123:8
|
LL | if a == !b {};
| ^^^^^^^ help: try simplifying it as shown: `a != b`
error: this comparison might be written more concisely
- --> $DIR/bool_comparison.rs:123:8
+ --> $DIR/bool_comparison.rs:124:8
|
LL | if !a == b {};
| ^^^^^^^ help: try simplifying it as shown: `a != b`
error: this comparison might be written more concisely
- --> $DIR/bool_comparison.rs:127:8
+ --> $DIR/bool_comparison.rs:128:8
|
LL | if b == !a {};
| ^^^^^^^ help: try simplifying it as shown: `b != a`
error: this comparison might be written more concisely
- --> $DIR/bool_comparison.rs:128:8
+ --> $DIR/bool_comparison.rs:129:8
|
LL | if !b == a {};
| ^^^^^^^ help: try simplifying it as shown: `b != a`
error: equality checks against false can be replaced by a negation
- --> $DIR/bool_comparison.rs:152:8
+ --> $DIR/bool_comparison.rs:153:8
|
LL | if false == m!(func) {}
| ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)`
error: equality checks against false can be replaced by a negation
- --> $DIR/bool_comparison.rs:153:8
+ --> $DIR/bool_comparison.rs:154:8
|
LL | if m!(func) == false {}
| ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)`
error: equality checks against true are unnecessary
- --> $DIR/bool_comparison.rs:154:8
+ --> $DIR/bool_comparison.rs:155:8
|
LL | if true == m!(func) {}
| ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)`
error: equality checks against true are unnecessary
- --> $DIR/bool_comparison.rs:155:8
+ --> $DIR/bool_comparison.rs:156:8
|
LL | if m!(func) == true {}
| ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)`
diff --git a/src/tools/clippy/tests/ui/borrow_box.rs b/src/tools/clippy/tests/ui/borrow_box.rs
index 3b5b6bf4c..95b6b0f50 100644
--- a/src/tools/clippy/tests/ui/borrow_box.rs
+++ b/src/tools/clippy/tests/ui/borrow_box.rs
@@ -1,6 +1,10 @@
#![deny(clippy::borrowed_box)]
#![allow(dead_code, unused_variables)]
-#![allow(clippy::uninlined_format_args, clippy::disallowed_names)]
+#![allow(
+ clippy::uninlined_format_args,
+ clippy::disallowed_names,
+ clippy::needless_pass_by_ref_mut
+)]
use std::fmt::Display;
diff --git a/src/tools/clippy/tests/ui/borrow_box.stderr b/src/tools/clippy/tests/ui/borrow_box.stderr
index 99cb60a1e..90e752211 100644
--- a/src/tools/clippy/tests/ui/borrow_box.stderr
+++ b/src/tools/clippy/tests/ui/borrow_box.stderr
@@ -1,5 +1,5 @@
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:20:14
+ --> $DIR/borrow_box.rs:24:14
|
LL | let foo: &Box<bool>;
| ^^^^^^^^^^ help: try: `&bool`
@@ -11,55 +11,55 @@ LL | #![deny(clippy::borrowed_box)]
| ^^^^^^^^^^^^^^^^^^^^
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:24:10
+ --> $DIR/borrow_box.rs:28:10
|
LL | foo: &'a Box<bool>,
| ^^^^^^^^^^^^^ help: try: `&'a bool`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:28:17
+ --> $DIR/borrow_box.rs:32:17
|
LL | fn test4(a: &Box<bool>);
| ^^^^^^^^^^ help: try: `&bool`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:94:25
+ --> $DIR/borrow_box.rs:98:25
|
LL | pub fn test14(_display: &Box<dyn Display>) {}
| ^^^^^^^^^^^^^^^^^ help: try: `&dyn Display`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:95:25
+ --> $DIR/borrow_box.rs:99:25
|
LL | pub fn test15(_display: &Box<dyn Display + Send>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:96:29
+ --> $DIR/borrow_box.rs:100:29
|
LL | pub fn test16<'a>(_display: &'a Box<dyn Display + 'a>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (dyn Display + 'a)`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:98:25
+ --> $DIR/borrow_box.rs:102:25
|
LL | pub fn test17(_display: &Box<impl Display>) {}
| ^^^^^^^^^^^^^^^^^^ help: try: `&impl Display`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:99:25
+ --> $DIR/borrow_box.rs:103:25
|
LL | pub fn test18(_display: &Box<impl Display + Send>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(impl Display + Send)`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:100:29
+ --> $DIR/borrow_box.rs:104:29
|
LL | pub fn test19<'a>(_display: &'a Box<impl Display + 'a>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (impl Display + 'a)`
error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
- --> $DIR/borrow_box.rs:105:25
+ --> $DIR/borrow_box.rs:109:25
|
LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)`
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.fixed b/src/tools/clippy/tests/ui/comparison_to_empty.fixed
index c92dd509e..af219eed0 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.fixed
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.fixed
@@ -1,7 +1,8 @@
//@run-rustfix
#![warn(clippy::comparison_to_empty)]
-#![allow(clippy::useless_vec)]
+#![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)]
+#![feature(let_chains)]
fn main() {
// Disallow comparisons to empty
@@ -12,6 +13,11 @@ fn main() {
let v = vec![0];
let _ = v.is_empty();
let _ = !v.is_empty();
+ if (*v).is_empty() {}
+ let s = [0].as_slice();
+ if s.is_empty() {}
+ if s.is_empty() {}
+ if s.is_empty() && s.is_empty() {}
// Allow comparisons to non-empty
let s = String::new();
@@ -21,4 +27,8 @@ fn main() {
let v = vec![0];
let _ = v == [0];
let _ = v != [0];
+ if let [0] = &*v {}
+ let s = [0].as_slice();
+ if let [0] = s {}
+ if let [0] = &*s && s == [0] {}
}
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.rs b/src/tools/clippy/tests/ui/comparison_to_empty.rs
index b34897143..21e65184d 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.rs
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.rs
@@ -1,7 +1,8 @@
//@run-rustfix
#![warn(clippy::comparison_to_empty)]
-#![allow(clippy::useless_vec)]
+#![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)]
+#![feature(let_chains)]
fn main() {
// Disallow comparisons to empty
@@ -12,6 +13,11 @@ fn main() {
let v = vec![0];
let _ = v == [];
let _ = v != [];
+ if let [] = &*v {}
+ let s = [0].as_slice();
+ if let [] = s {}
+ if let [] = &*s {}
+ if let [] = &*s && s == [] {}
// Allow comparisons to non-empty
let s = String::new();
@@ -21,4 +27,8 @@ fn main() {
let v = vec![0];
let _ = v == [0];
let _ = v != [0];
+ if let [0] = &*v {}
+ let s = [0].as_slice();
+ if let [0] = s {}
+ if let [0] = &*s && s == [0] {}
}
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.stderr b/src/tools/clippy/tests/ui/comparison_to_empty.stderr
index cc09b17eb..f29782ed8 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.stderr
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.stderr
@@ -1,5 +1,5 @@
error: comparison to empty slice
- --> $DIR/comparison_to_empty.rs:9:13
+ --> $DIR/comparison_to_empty.rs:10:13
|
LL | let _ = s == "";
| ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
@@ -7,22 +7,52 @@ LL | let _ = s == "";
= note: `-D clippy::comparison-to-empty` implied by `-D warnings`
error: comparison to empty slice
- --> $DIR/comparison_to_empty.rs:10:13
+ --> $DIR/comparison_to_empty.rs:11:13
|
LL | let _ = s != "";
| ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()`
error: comparison to empty slice
- --> $DIR/comparison_to_empty.rs:13:13
+ --> $DIR/comparison_to_empty.rs:14:13
|
LL | let _ = v == [];
| ^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()`
error: comparison to empty slice
- --> $DIR/comparison_to_empty.rs:14:13
+ --> $DIR/comparison_to_empty.rs:15:13
|
LL | let _ = v != [];
| ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()`
-error: aborting due to 4 previous errors
+error: comparison to empty slice using `if let`
+ --> $DIR/comparison_to_empty.rs:16:8
+ |
+LL | if let [] = &*v {}
+ | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(*v).is_empty()`
+
+error: comparison to empty slice using `if let`
+ --> $DIR/comparison_to_empty.rs:18:8
+ |
+LL | if let [] = s {}
+ | ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: comparison to empty slice using `if let`
+ --> $DIR/comparison_to_empty.rs:19:8
+ |
+LL | if let [] = &*s {}
+ | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: comparison to empty slice using `if let`
+ --> $DIR/comparison_to_empty.rs:20:8
+ |
+LL | if let [] = &*s && s == [] {}
+ | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: comparison to empty slice
+ --> $DIR/comparison_to_empty.rs:20:24
+ |
+LL | if let [] = &*s && s == [] {}
+ | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/const_comparisons.rs b/src/tools/clippy/tests/ui/const_comparisons.rs
new file mode 100644
index 000000000..8e265c914
--- /dev/null
+++ b/src/tools/clippy/tests/ui/const_comparisons.rs
@@ -0,0 +1,93 @@
+#![allow(unused)]
+#![warn(clippy::impossible_comparisons)]
+#![warn(clippy::redundant_comparisons)]
+#![allow(clippy::no_effect)]
+#![allow(clippy::short_circuit_statement)]
+#![allow(clippy::manual_range_contains)]
+
+const STATUS_BAD_REQUEST: u16 = 400;
+const STATUS_SERVER_ERROR: u16 = 500;
+
+struct Status {
+ code: u16,
+}
+
+impl PartialEq<u16> for Status {
+ fn eq(&self, other: &u16) -> bool {
+ self.code == *other
+ }
+}
+
+impl PartialOrd<u16> for Status {
+ fn partial_cmp(&self, other: &u16) -> Option<std::cmp::Ordering> {
+ self.code.partial_cmp(other)
+ }
+}
+
+impl PartialEq<Status> for u16 {
+ fn eq(&self, other: &Status) -> bool {
+ *self == other.code
+ }
+}
+
+impl PartialOrd<Status> for u16 {
+ fn partial_cmp(&self, other: &Status) -> Option<std::cmp::Ordering> {
+ self.partial_cmp(&other.code)
+ }
+}
+
+fn main() {
+ let status_code = 500; // Value doesn't matter for the lint
+ let status = Status { code: status_code };
+
+ status_code >= 400 && status_code < 500; // Correct
+ status_code <= 400 && status_code > 500;
+ status_code > 500 && status_code < 400;
+ status_code < 500 && status_code > 500;
+
+ // More complex expressions
+ status_code < { 400 } && status_code > { 500 };
+ status_code < STATUS_BAD_REQUEST && status_code > STATUS_SERVER_ERROR;
+ status_code <= u16::MIN + 1 && status_code > STATUS_SERVER_ERROR;
+ status_code < STATUS_SERVER_ERROR && status_code > STATUS_SERVER_ERROR;
+
+ // Comparing two different types, via the `impl PartialOrd<u16> for Status`
+ status < { 400 } && status > { 500 };
+ status < STATUS_BAD_REQUEST && status > STATUS_SERVER_ERROR;
+ status <= u16::MIN + 1 && status > STATUS_SERVER_ERROR;
+ status < STATUS_SERVER_ERROR && status > STATUS_SERVER_ERROR;
+
+ // Yoda conditions
+ 500 <= status_code && 600 > status_code; // Correct
+ 500 <= status_code && status_code <= 600; // Correct
+ 500 >= status_code && 600 < status_code; // Incorrect
+ 500 >= status_code && status_code > 600; // Incorrect
+
+ // Yoda conditions, comparing two different types
+ 500 <= status && 600 > status; // Correct
+ 500 <= status && status <= 600; // Correct
+ 500 >= status && 600 < status; // Incorrect
+ 500 >= status && status > 600; // Incorrect
+
+ // Expressions where one of the sides has no effect
+ status_code < 200 && status_code <= 299;
+ status_code > 200 && status_code >= 299;
+
+ status_code >= 500 && status_code > 500; // Useless left
+ status_code > 500 && status_code >= 500; // Useless right
+ status_code <= 500 && status_code < 500; // Useless left
+ status_code < 500 && status_code <= 500; // Useless right
+
+ // Other types
+ let name = "Steve";
+ name < "Jennifer" && name > "Shannon";
+
+ let numbers = [1, 2];
+ numbers < [3, 4] && numbers > [5, 6];
+
+ let letter = 'a';
+ letter < 'b' && letter > 'c';
+
+ let area = 42.0;
+ area < std::f32::consts::E && area > std::f32::consts::PI;
+}
diff --git a/src/tools/clippy/tests/ui/const_comparisons.stderr b/src/tools/clippy/tests/ui/const_comparisons.stderr
new file mode 100644
index 000000000..90e6db647
--- /dev/null
+++ b/src/tools/clippy/tests/ui/const_comparisons.stderr
@@ -0,0 +1,228 @@
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:44:5
+ |
+LL | status_code <= 400 && status_code > 500;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `400` < `500`, the expression evaluates to false for any value of `status_code`
+ = note: `-D clippy::impossible-comparisons` implied by `-D warnings`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:45:5
+ |
+LL | status_code > 500 && status_code < 400;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `500` > `400`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:46:5
+ |
+LL | status_code < 500 && status_code > 500;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `status_code` cannot simultaneously be greater than and less than `500`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:49:5
+ |
+LL | status_code < { 400 } && status_code > { 500 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `{ 400 }` < `{ 500 }`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:50:5
+ |
+LL | status_code < STATUS_BAD_REQUEST && status_code > STATUS_SERVER_ERROR;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `STATUS_BAD_REQUEST` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:51:5
+ |
+LL | status_code <= u16::MIN + 1 && status_code > STATUS_SERVER_ERROR;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `u16::MIN + 1` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:52:5
+ |
+LL | status_code < STATUS_SERVER_ERROR && status_code > STATUS_SERVER_ERROR;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `status_code` cannot simultaneously be greater than and less than `STATUS_SERVER_ERROR`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:55:5
+ |
+LL | status < { 400 } && status > { 500 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `{ 400 }` < `{ 500 }`, the expression evaluates to false for any value of `status`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:56:5
+ |
+LL | status < STATUS_BAD_REQUEST && status > STATUS_SERVER_ERROR;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `STATUS_BAD_REQUEST` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:57:5
+ |
+LL | status <= u16::MIN + 1 && status > STATUS_SERVER_ERROR;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `u16::MIN + 1` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:58:5
+ |
+LL | status < STATUS_SERVER_ERROR && status > STATUS_SERVER_ERROR;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `status` cannot simultaneously be greater than and less than `STATUS_SERVER_ERROR`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:63:5
+ |
+LL | 500 >= status_code && 600 < status_code; // Incorrect
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `500` < `600`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:64:5
+ |
+LL | 500 >= status_code && status_code > 600; // Incorrect
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `500` < `600`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:69:5
+ |
+LL | 500 >= status && 600 < status; // Incorrect
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `500` < `600`, the expression evaluates to false for any value of `status`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:70:5
+ |
+LL | 500 >= status && status > 600; // Incorrect
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `500` < `600`, the expression evaluates to false for any value of `status`
+
+error: right-hand side of `&&` operator has no effect
+ --> $DIR/const_comparisons.rs:73:5
+ |
+LL | status_code < 200 && status_code <= 299;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `if `status_code < 200` evaluates to true, status_code <= 299` will always evaluate to true as well
+ --> $DIR/const_comparisons.rs:73:23
+ |
+LL | status_code < 200 && status_code <= 299;
+ | ^^^^^^^^^^^^^^^^^^^^^
+ = note: `-D clippy::redundant-comparisons` implied by `-D warnings`
+
+error: left-hand side of `&&` operator has no effect
+ --> $DIR/const_comparisons.rs:74:5
+ |
+LL | status_code > 200 && status_code >= 299;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `if `status_code >= 299` evaluates to true, status_code > 200` will always evaluate to true as well
+ --> $DIR/const_comparisons.rs:74:5
+ |
+LL | status_code > 200 && status_code >= 299;
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: left-hand side of `&&` operator has no effect
+ --> $DIR/const_comparisons.rs:76:5
+ |
+LL | status_code >= 500 && status_code > 500; // Useless left
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `if `status_code > 500` evaluates to true, status_code >= 500` will always evaluate to true as well
+ --> $DIR/const_comparisons.rs:76:5
+ |
+LL | status_code >= 500 && status_code > 500; // Useless left
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: right-hand side of `&&` operator has no effect
+ --> $DIR/const_comparisons.rs:77:5
+ |
+LL | status_code > 500 && status_code >= 500; // Useless right
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `if `status_code > 500` evaluates to true, status_code >= 500` will always evaluate to true as well
+ --> $DIR/const_comparisons.rs:77:23
+ |
+LL | status_code > 500 && status_code >= 500; // Useless right
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: left-hand side of `&&` operator has no effect
+ --> $DIR/const_comparisons.rs:78:5
+ |
+LL | status_code <= 500 && status_code < 500; // Useless left
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `if `status_code < 500` evaluates to true, status_code <= 500` will always evaluate to true as well
+ --> $DIR/const_comparisons.rs:78:5
+ |
+LL | status_code <= 500 && status_code < 500; // Useless left
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: right-hand side of `&&` operator has no effect
+ --> $DIR/const_comparisons.rs:79:5
+ |
+LL | status_code < 500 && status_code <= 500; // Useless right
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `if `status_code < 500` evaluates to true, status_code <= 500` will always evaluate to true as well
+ --> $DIR/const_comparisons.rs:79:23
+ |
+LL | status_code < 500 && status_code <= 500; // Useless right
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:83:5
+ |
+LL | name < "Jennifer" && name > "Shannon";
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `"Jennifer"` < `"Shannon"`, the expression evaluates to false for any value of `name`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:86:5
+ |
+LL | numbers < [3, 4] && numbers > [5, 6];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `[3, 4]` < `[5, 6]`, the expression evaluates to false for any value of `numbers`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:89:5
+ |
+LL | letter < 'b' && letter > 'c';
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `'b'` < `'c'`, the expression evaluates to false for any value of `letter`
+
+error: boolean expression will never evaluate to 'true'
+ --> $DIR/const_comparisons.rs:92:5
+ |
+LL | area < std::f32::consts::E && area > std::f32::consts::PI;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: since `std::f32::consts::E` < `std::f32::consts::PI`, the expression evaluates to false for any value of `area`
+
+error: aborting due to 25 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6256.rs b/src/tools/clippy/tests/ui/crashes/ice-6256.rs
index 1d336b3cd..bb488c2dc 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6256.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-6256.rs
@@ -1,5 +1,5 @@
// originally from rustc ./tests/ui/regions/issue-78262.rs
-// ICE: to get the signature of a closure, use substs.as_closure().sig() not fn_sig()
+// ICE: to get the signature of a closure, use args.as_closure().sig() not fn_sig()
#![allow(clippy::upper_case_acronyms)]
trait TT {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7169.stderr b/src/tools/clippy/tests/ui/crashes/ice-7169.stderr
index 84e0af3f0..0cd028516 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-7169.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-7169.stderr
@@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_ok()`
--> $DIR/ice-7169.rs:10:12
|
LL | if let Ok(_) = Ok::<_, ()>(A::<String>::default()) {}
- | -------^^^^^-------------------------------------- help: try this: `if Ok::<_, ()>(A::<String>::default()).is_ok()`
+ | -------^^^^^-------------------------------------- help: try: `if Ok::<_, ()>(A::<String>::default()).is_ok()`
|
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
diff --git a/src/tools/clippy/tests/ui/crashes/ice-8250.stderr b/src/tools/clippy/tests/ui/crashes/ice-8250.stderr
index 8ed8f3b3a..e6f3644ef 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-8250.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-8250.stderr
@@ -2,7 +2,7 @@ error: unnecessary use of `splitn`
--> $DIR/ice-8250.rs:2:13
|
LL | let _ = s[1..].splitn(2, '.').next()?;
- | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s[1..].split('.')`
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `s[1..].split('.')`
|
= note: `-D clippy::needless-splitn` implied by `-D warnings`
diff --git a/src/tools/clippy/tests/ui/default_trait_access.fixed b/src/tools/clippy/tests/ui/default_trait_access.fixed
index 14eb6d572..6e541473c 100644
--- a/src/tools/clippy/tests/ui/default_trait_access.fixed
+++ b/src/tools/clippy/tests/ui/default_trait_access.fixed
@@ -7,9 +7,8 @@
extern crate proc_macros;
use proc_macros::with_span;
-use std::default;
use std::default::Default as D2;
-use std::string;
+use std::{default, string};
fn main() {
let s1: String = String::default();
diff --git a/src/tools/clippy/tests/ui/default_trait_access.rs b/src/tools/clippy/tests/ui/default_trait_access.rs
index aa2ced0a7..2ffeb32fb 100644
--- a/src/tools/clippy/tests/ui/default_trait_access.rs
+++ b/src/tools/clippy/tests/ui/default_trait_access.rs
@@ -7,9 +7,8 @@
extern crate proc_macros;
use proc_macros::with_span;
-use std::default;
use std::default::Default as D2;
-use std::string;
+use std::{default, string};
fn main() {
let s1: String = Default::default();
diff --git a/src/tools/clippy/tests/ui/default_trait_access.stderr b/src/tools/clippy/tests/ui/default_trait_access.stderr
index e4f73c08d..103fccf6a 100644
--- a/src/tools/clippy/tests/ui/default_trait_access.stderr
+++ b/src/tools/clippy/tests/ui/default_trait_access.stderr
@@ -1,5 +1,5 @@
error: calling `String::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:15:22
+ --> $DIR/default_trait_access.rs:14:22
|
LL | let s1: String = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `String::default()`
@@ -11,43 +11,43 @@ LL | #![deny(clippy::default_trait_access)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: calling `String::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:19:22
+ --> $DIR/default_trait_access.rs:18:22
|
LL | let s3: String = D2::default();
| ^^^^^^^^^^^^^ help: try: `String::default()`
error: calling `String::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:21:22
+ --> $DIR/default_trait_access.rs:20:22
|
LL | let s4: String = std::default::Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()`
error: calling `String::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:25:22
+ --> $DIR/default_trait_access.rs:24:22
|
LL | let s6: String = default::Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()`
error: calling `GenericDerivedDefault::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:35:46
+ --> $DIR/default_trait_access.rs:34:46
|
LL | let s11: GenericDerivedDefault<String> = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()`
error: calling `TupleDerivedDefault::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:41:36
+ --> $DIR/default_trait_access.rs:40:36
|
LL | let s14: TupleDerivedDefault = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()`
error: calling `ArrayDerivedDefault::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:43:36
+ --> $DIR/default_trait_access.rs:42:36
|
LL | let s15: ArrayDerivedDefault = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()`
error: calling `TupleStructDerivedDefault::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:47:42
+ --> $DIR/default_trait_access.rs:46:42
|
LL | let s17: TupleStructDerivedDefault = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()`
diff --git a/src/tools/clippy/tests/ui/deref_addrof.stderr b/src/tools/clippy/tests/ui/deref_addrof.stderr
index e0287522f..9dd1e246b 100644
--- a/src/tools/clippy/tests/ui/deref_addrof.stderr
+++ b/src/tools/clippy/tests/ui/deref_addrof.stderr
@@ -2,7 +2,7 @@ error: immediately dereferencing a reference
--> $DIR/deref_addrof.rs:24:13
|
LL | let b = *&a;
- | ^^^ help: try this: `a`
+ | ^^^ help: try: `a`
|
= note: `-D clippy::deref-addrof` implied by `-D warnings`
@@ -10,49 +10,49 @@ error: immediately dereferencing a reference
--> $DIR/deref_addrof.rs:26:13
|
LL | let b = *&get_number();
- | ^^^^^^^^^^^^^^ help: try this: `get_number()`
+ | ^^^^^^^^^^^^^^ help: try: `get_number()`
error: immediately dereferencing a reference
--> $DIR/deref_addrof.rs:31:13
|
LL | let b = *&bytes[1..2][0];
- | ^^^^^^^^^^^^^^^^ help: try this: `bytes[1..2][0]`
+ | ^^^^^^^^^^^^^^^^ help: try: `bytes[1..2][0]`
error: immediately dereferencing a reference
--> $DIR/deref_addrof.rs:35:13
|
LL | let b = *&(a);
- | ^^^^^ help: try this: `(a)`
+ | ^^^^^ help: try: `(a)`
error: immediately dereferencing a reference
--> $DIR/deref_addrof.rs:37:13
|
LL | let b = *(&a);
- | ^^^^^ help: try this: `a`
+ | ^^^^^ help: try: `a`
error: immediately dereferencing a reference
--> $DIR/deref_addrof.rs:40:13
|
LL | let b = *((&a));
- | ^^^^^^^ help: try this: `a`
+ | ^^^^^^^ help: try: `a`
error: immediately dereferencing a reference
--> $DIR/deref_addrof.rs:42:13
|
LL | let b = *&&a;
- | ^^^^ help: try this: `&a`
+ | ^^^^ help: try: `&a`
error: immediately dereferencing a reference
--> $DIR/deref_addrof.rs:44:14
|
LL | let b = **&aref;
- | ^^^^^^ help: try this: `aref`
+ | ^^^^^^ help: try: `aref`
error: immediately dereferencing a reference
--> $DIR/deref_addrof.rs:54:17
|
LL | inline!(*& $(@expr self))
- | ^^^^^^^^^^^^^^^^ help: try this: `$(@expr self)`
+ | ^^^^^^^^^^^^^^^^ help: try: `$(@expr self)`
|
= note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -60,7 +60,7 @@ error: immediately dereferencing a reference
--> $DIR/deref_addrof.rs:58:17
|
LL | inline!(*&mut $(@expr self))
- | ^^^^^^^^^^^^^^^^^^^ help: try this: `$(@expr self)`
+ | ^^^^^^^^^^^^^^^^^^^ help: try: `$(@expr self)`
|
= note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr b/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr
index 2c55a4ed6..6fa5069b6 100644
--- a/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr
+++ b/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr
@@ -2,7 +2,7 @@ error: immediately dereferencing a reference
--> $DIR/deref_addrof_double_trigger.rs:10:14
|
LL | let b = **&&a;
- | ^^^^ help: try this: `&a`
+ | ^^^^ help: try: `&a`
|
= note: `-D clippy::deref-addrof` implied by `-D warnings`
@@ -10,13 +10,13 @@ error: immediately dereferencing a reference
--> $DIR/deref_addrof_double_trigger.rs:14:17
|
LL | let y = *&mut x;
- | ^^^^^^^ help: try this: `x`
+ | ^^^^^^^ help: try: `x`
error: immediately dereferencing a reference
--> $DIR/deref_addrof_double_trigger.rs:21:18
|
LL | let y = **&mut &mut x;
- | ^^^^^^^^^^^^ help: try this: `&mut x`
+ | ^^^^^^^^^^^^ help: try: `&mut x`
error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/derive.rs b/src/tools/clippy/tests/ui/derive.rs
index e01079bc9..c76711312 100644
--- a/src/tools/clippy/tests/ui/derive.rs
+++ b/src/tools/clippy/tests/ui/derive.rs
@@ -1,4 +1,8 @@
-#![allow(clippy::incorrect_clone_impl_on_copy_type, dead_code)]
+#![allow(
+ clippy::incorrect_clone_impl_on_copy_type,
+ clippy::incorrect_partial_ord_impl_on_ord_type,
+ dead_code
+)]
#![warn(clippy::expl_impl_clone_on_copy)]
diff --git a/src/tools/clippy/tests/ui/derive.stderr b/src/tools/clippy/tests/ui/derive.stderr
index e1fbb8dcd..5d7ed0918 100644
--- a/src/tools/clippy/tests/ui/derive.stderr
+++ b/src/tools/clippy/tests/ui/derive.stderr
@@ -1,5 +1,5 @@
error: you are implementing `Clone` explicitly on a `Copy` type
- --> $DIR/derive.rs:8:1
+ --> $DIR/derive.rs:12:1
|
LL | / impl Clone for Qux {
LL | | fn clone(&self) -> Self {
@@ -9,7 +9,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
- --> $DIR/derive.rs:8:1
+ --> $DIR/derive.rs:12:1
|
LL | / impl Clone for Qux {
LL | | fn clone(&self) -> Self {
@@ -20,7 +20,7 @@ LL | | }
= note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings`
error: you are implementing `Clone` explicitly on a `Copy` type
- --> $DIR/derive.rs:32:1
+ --> $DIR/derive.rs:36:1
|
LL | / impl<'a> Clone for Lt<'a> {
LL | | fn clone(&self) -> Self {
@@ -30,7 +30,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
- --> $DIR/derive.rs:32:1
+ --> $DIR/derive.rs:36:1
|
LL | / impl<'a> Clone for Lt<'a> {
LL | | fn clone(&self) -> Self {
@@ -40,7 +40,7 @@ LL | | }
| |_^
error: you are implementing `Clone` explicitly on a `Copy` type
- --> $DIR/derive.rs:43:1
+ --> $DIR/derive.rs:47:1
|
LL | / impl Clone for BigArray {
LL | | fn clone(&self) -> Self {
@@ -50,7 +50,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
- --> $DIR/derive.rs:43:1
+ --> $DIR/derive.rs:47:1
|
LL | / impl Clone for BigArray {
LL | | fn clone(&self) -> Self {
@@ -60,7 +60,7 @@ LL | | }
| |_^
error: you are implementing `Clone` explicitly on a `Copy` type
- --> $DIR/derive.rs:54:1
+ --> $DIR/derive.rs:58:1
|
LL | / impl Clone for FnPtr {
LL | | fn clone(&self) -> Self {
@@ -70,7 +70,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
- --> $DIR/derive.rs:54:1
+ --> $DIR/derive.rs:58:1
|
LL | / impl Clone for FnPtr {
LL | | fn clone(&self) -> Self {
@@ -80,7 +80,7 @@ LL | | }
| |_^
error: you are implementing `Clone` explicitly on a `Copy` type
- --> $DIR/derive.rs:74:1
+ --> $DIR/derive.rs:78:1
|
LL | / impl<T: Clone> Clone for Generic2<T> {
LL | | fn clone(&self) -> Self {
@@ -90,7 +90,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
- --> $DIR/derive.rs:74:1
+ --> $DIR/derive.rs:78:1
|
LL | / impl<T: Clone> Clone for Generic2<T> {
LL | | fn clone(&self) -> Self {
diff --git a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs
index 6f12d36d7..1fb3d51c4 100644
--- a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs
+++ b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs
@@ -1,5 +1,6 @@
#![warn(clippy::derive_ord_xor_partial_ord)]
#![allow(clippy::unnecessary_wraps)]
+#![allow(clippy::incorrect_partial_ord_impl_on_ord_type)]
use std::cmp::Ordering;
diff --git a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr
index 58efbb854..bd1488348 100644
--- a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr
+++ b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr
@@ -1,11 +1,11 @@
error: you are deriving `Ord` but have implemented `PartialOrd` explicitly
- --> $DIR/derive_ord_xor_partial_ord.rs:21:10
+ --> $DIR/derive_ord_xor_partial_ord.rs:22:10
|
LL | #[derive(Ord, PartialEq, Eq)]
| ^^^
|
note: `PartialOrd` implemented here
- --> $DIR/derive_ord_xor_partial_ord.rs:24:1
+ --> $DIR/derive_ord_xor_partial_ord.rs:25:1
|
LL | impl PartialOrd for DeriveOrd {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,20 +13,20 @@ LL | impl PartialOrd for DeriveOrd {
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are deriving `Ord` but have implemented `PartialOrd` explicitly
- --> $DIR/derive_ord_xor_partial_ord.rs:30:10
+ --> $DIR/derive_ord_xor_partial_ord.rs:31:10
|
LL | #[derive(Ord, PartialEq, Eq)]
| ^^^
|
note: `PartialOrd` implemented here
- --> $DIR/derive_ord_xor_partial_ord.rs:33:1
+ --> $DIR/derive_ord_xor_partial_ord.rs:34:1
|
LL | impl PartialOrd<DeriveOrdWithExplicitTypeVariable> for DeriveOrdWithExplicitTypeVariable {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are implementing `Ord` explicitly but have derived `PartialOrd`
- --> $DIR/derive_ord_xor_partial_ord.rs:42:1
+ --> $DIR/derive_ord_xor_partial_ord.rs:43:1
|
LL | / impl std::cmp::Ord for DerivePartialOrd {
LL | | fn cmp(&self, other: &Self) -> Ordering {
@@ -36,14 +36,14 @@ LL | | }
| |_^
|
note: `PartialOrd` implemented here
- --> $DIR/derive_ord_xor_partial_ord.rs:39:10
+ --> $DIR/derive_ord_xor_partial_ord.rs:40:10
|
LL | #[derive(PartialOrd, PartialEq, Eq)]
| ^^^^^^^^^^
= note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info)
error: you are implementing `Ord` explicitly but have derived `PartialOrd`
- --> $DIR/derive_ord_xor_partial_ord.rs:62:5
+ --> $DIR/derive_ord_xor_partial_ord.rs:63:5
|
LL | / impl Ord for DerivePartialOrdInUseOrd {
LL | | fn cmp(&self, other: &Self) -> Ordering {
@@ -53,7 +53,7 @@ LL | | }
| |_____^
|
note: `PartialOrd` implemented here
- --> $DIR/derive_ord_xor_partial_ord.rs:59:14
+ --> $DIR/derive_ord_xor_partial_ord.rs:60:14
|
LL | #[derive(PartialOrd, PartialEq, Eq)]
| ^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/entry.stderr b/src/tools/clippy/tests/ui/entry.stderr
index 2c4c49d25..e8a003e9c 100644
--- a/src/tools/clippy/tests/ui/entry.stderr
+++ b/src/tools/clippy/tests/ui/entry.stderr
@@ -4,7 +4,7 @@ error: usage of `contains_key` followed by `insert` on a `HashMap`
LL | / if !m.contains_key(&k) {
LL | | m.insert(k, v);
LL | | }
- | |_____^ help: try this: `m.entry(k).or_insert(v);`
+ | |_____^ help: try: `m.entry(k).or_insert(v);`
|
= note: `-D clippy::map-entry` implied by `-D warnings`
@@ -20,7 +20,7 @@ LL | | }
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ m.entry(k).or_insert_with(|| {
LL + if true {
@@ -43,7 +43,7 @@ LL | | };
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ m.entry(k).or_insert_with(|| {
LL + if true {
@@ -66,7 +66,7 @@ LL | | }
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ if let std::collections::hash_map::Entry::Vacant(e) = m.entry(k) {
LL + if true {
@@ -87,7 +87,7 @@ LL | | m.insert(k, v);
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ m.entry(k).or_insert_with(|| {
LL + foo();
@@ -107,7 +107,7 @@ LL | | };
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ m.entry(k).or_insert_with(|| {
LL + match 0 {
@@ -133,7 +133,7 @@ LL | | };
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ if let std::collections::hash_map::Entry::Vacant(e) = m.entry(k) {
LL + match 0 {
@@ -157,7 +157,7 @@ LL | | }
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ m.entry(k).or_insert_with(|| {
LL + foo();
@@ -192,7 +192,7 @@ error: usage of `contains_key` followed by `insert` on a `HashMap`
LL | / if !m.contains_key(&m!(k)) {
LL | | m.insert(m!(k), m!(v));
LL | | }
- | |_____^ help: try this: `m.entry(m!(k)).or_insert_with(|| m!(v));`
+ | |_____^ help: try: `m.entry(m!(k)).or_insert_with(|| m!(v));`
error: usage of `contains_key` followed by `insert` on a `HashMap`
--> $DIR/entry.rs:152:5
@@ -204,7 +204,7 @@ LL | | m.insert(k, v);
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ m.entry(k).or_insert_with(|| {
LL + let x = (String::new(), String::new());
diff --git a/src/tools/clippy/tests/ui/entry_btree.stderr b/src/tools/clippy/tests/ui/entry_btree.stderr
index 5c6fcdf1a..8f41581d6 100644
--- a/src/tools/clippy/tests/ui/entry_btree.stderr
+++ b/src/tools/clippy/tests/ui/entry_btree.stderr
@@ -8,7 +8,7 @@ LL | | }
| |_____^
|
= note: `-D clippy::map-entry` implied by `-D warnings`
-help: try this
+help: try
|
LL ~ if let std::collections::btree_map::Entry::Vacant(e) = m.entry(k) {
LL + e.insert(v);
diff --git a/src/tools/clippy/tests/ui/entry_with_else.stderr b/src/tools/clippy/tests/ui/entry_with_else.stderr
index e0f6671b4..0d0eb9649 100644
--- a/src/tools/clippy/tests/ui/entry_with_else.stderr
+++ b/src/tools/clippy/tests/ui/entry_with_else.stderr
@@ -9,7 +9,7 @@ LL | | }
| |_____^
|
= note: `-D clippy::map-entry` implied by `-D warnings`
-help: try this
+help: try
|
LL ~ match m.entry(k) {
LL + std::collections::hash_map::Entry::Vacant(e) => {
@@ -31,7 +31,7 @@ LL | | m.insert(k, v2);
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ match m.entry(k) {
LL + std::collections::hash_map::Entry::Occupied(mut e) => {
@@ -53,7 +53,7 @@ LL | | foo();
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ if let std::collections::hash_map::Entry::Vacant(e) = m.entry(k) {
LL + e.insert(v);
@@ -72,7 +72,7 @@ LL | | m.insert(k, v);
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ if let std::collections::hash_map::Entry::Occupied(mut e) = m.entry(k) {
LL + e.insert(v);
@@ -91,7 +91,7 @@ LL | | m.insert(k, v2);
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ match m.entry(k) {
LL + std::collections::hash_map::Entry::Vacant(e) => {
@@ -113,7 +113,7 @@ LL | | m.insert(k, v)
LL | | };
| |_____^
|
-help: try this
+help: try
|
LL ~ match m.entry(k) {
LL + std::collections::hash_map::Entry::Occupied(mut e) => {
@@ -137,7 +137,7 @@ LL | | None
LL | | };
| |_____^
|
-help: try this
+help: try
|
LL ~ if let std::collections::hash_map::Entry::Occupied(mut e) = m.entry(k) {
LL + foo();
diff --git a/src/tools/clippy/tests/ui/error_impl_error.rs b/src/tools/clippy/tests/ui/error_impl_error.rs
new file mode 100644
index 000000000..40ce4181b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/error_impl_error.rs
@@ -0,0 +1,90 @@
+#![allow(unused)]
+#![warn(clippy::error_impl_error)]
+#![no_main]
+
+pub mod a {
+ #[derive(Debug)]
+ pub struct Error;
+
+ impl std::fmt::Display for Error {
+ fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ todo!()
+ }
+ }
+
+ impl std::error::Error for Error {}
+}
+
+mod b {
+ #[derive(Debug)]
+ pub(super) enum Error {}
+
+ impl std::fmt::Display for Error {
+ fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ todo!()
+ }
+ }
+
+ impl std::error::Error for Error {}
+}
+
+pub mod c {
+ pub union Error {
+ a: u32,
+ b: u32,
+ }
+
+ impl std::fmt::Debug for Error {
+ fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ todo!()
+ }
+ }
+
+ impl std::fmt::Display for Error {
+ fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ todo!()
+ }
+ }
+
+ impl std::error::Error for Error {}
+}
+
+pub mod d {
+ pub type Error = std::fmt::Error;
+}
+
+mod e {
+ #[derive(Debug)]
+ pub(super) struct MyError;
+
+ impl std::fmt::Display for MyError {
+ fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ todo!()
+ }
+ }
+
+ impl std::error::Error for MyError {}
+}
+
+pub mod f {
+ pub type MyError = std::fmt::Error;
+}
+
+// Do not lint module-private types
+
+mod g {
+ #[derive(Debug)]
+ enum Error {}
+
+ impl std::fmt::Display for Error {
+ fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ todo!()
+ }
+ }
+
+ impl std::error::Error for Error {}
+}
+
+mod h {
+ type Error = std::fmt::Error;
+}
diff --git a/src/tools/clippy/tests/ui/error_impl_error.stderr b/src/tools/clippy/tests/ui/error_impl_error.stderr
new file mode 100644
index 000000000..f3e04b641
--- /dev/null
+++ b/src/tools/clippy/tests/ui/error_impl_error.stderr
@@ -0,0 +1,45 @@
+error: exported type named `Error` that implements `Error`
+ --> $DIR/error_impl_error.rs:7:16
+ |
+LL | pub struct Error;
+ | ^^^^^
+ |
+note: `Error` was implemented here
+ --> $DIR/error_impl_error.rs:15:5
+ |
+LL | impl std::error::Error for Error {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: `-D clippy::error-impl-error` implied by `-D warnings`
+
+error: exported type named `Error` that implements `Error`
+ --> $DIR/error_impl_error.rs:20:21
+ |
+LL | pub(super) enum Error {}
+ | ^^^^^
+ |
+note: `Error` was implemented here
+ --> $DIR/error_impl_error.rs:28:5
+ |
+LL | impl std::error::Error for Error {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: exported type named `Error` that implements `Error`
+ --> $DIR/error_impl_error.rs:32:15
+ |
+LL | pub union Error {
+ | ^^^^^
+ |
+note: `Error` was implemented here
+ --> $DIR/error_impl_error.rs:49:5
+ |
+LL | impl std::error::Error for Error {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: exported type alias named `Error` that implements `Error`
+ --> $DIR/error_impl_error.rs:53:14
+ |
+LL | pub type Error = std::fmt::Error;
+ | ^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index bf44bcb56..ddabe7616 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -331,7 +331,7 @@ impl dyn TestTrait + '_ {
}
// https://github.com/rust-lang/rust-clippy/issues/7746
-fn angle_brackets_and_substs() {
+fn angle_brackets_and_args() {
let array_opt: Option<&[u8; 3]> = Some(&[4, 8, 7]);
array_opt.map(<[u8; 3]>::as_slice);
@@ -345,3 +345,58 @@ fn angle_brackets_and_substs() {
let dyn_opt: Option<&dyn TestTrait> = Some(&test_struct);
dyn_opt.map(<dyn TestTrait>::method_on_dyn);
}
+
+fn _late_bound_to_early_bound_regions() {
+ struct Foo<'a>(&'a u32);
+ impl<'a> Foo<'a> {
+ fn f(x: &'a u32) -> Self {
+ Foo(x)
+ }
+ }
+ fn f(f: impl for<'a> Fn(&'a u32) -> Foo<'a>) -> Foo<'static> {
+ f(&0)
+ }
+
+ let _ = f(|x| Foo::f(x));
+
+ struct Bar;
+ impl<'a> From<&'a u32> for Bar {
+ fn from(x: &'a u32) -> Bar {
+ Bar
+ }
+ }
+ fn f2(f: impl for<'a> Fn(&'a u32) -> Bar) -> Bar {
+ f(&0)
+ }
+
+ let _ = f2(|x| <Bar>::from(x));
+
+ struct Baz<'a>(&'a u32);
+ fn f3(f: impl Fn(&u32) -> Baz<'_>) -> Baz<'static> {
+ f(&0)
+ }
+
+ let _ = f3(|x| Baz(x));
+}
+
+fn _mixed_late_bound_and_early_bound_regions() {
+ fn f<T>(t: T, f: impl Fn(T, &u32) -> u32) -> u32 {
+ f(t, &0)
+ }
+ fn f2<'a, T: 'a>(_: &'a T, y: &u32) -> u32 {
+ *y
+ }
+ let _ = f(&0, f2);
+}
+
+fn _closure_with_types() {
+ fn f<T>(x: T) -> T {
+ x
+ }
+ fn f2<T: Default>(f: impl Fn(T) -> T) -> T {
+ f(T::default())
+ }
+
+ let _ = f2(|x: u32| f(x));
+ let _ = f2(|x| -> u32 { f(x) });
+}
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index b2af4bf09..92ecff6eb 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -331,7 +331,7 @@ impl dyn TestTrait + '_ {
}
// https://github.com/rust-lang/rust-clippy/issues/7746
-fn angle_brackets_and_substs() {
+fn angle_brackets_and_args() {
let array_opt: Option<&[u8; 3]> = Some(&[4, 8, 7]);
array_opt.map(|a| a.as_slice());
@@ -345,3 +345,58 @@ fn angle_brackets_and_substs() {
let dyn_opt: Option<&dyn TestTrait> = Some(&test_struct);
dyn_opt.map(|d| d.method_on_dyn());
}
+
+fn _late_bound_to_early_bound_regions() {
+ struct Foo<'a>(&'a u32);
+ impl<'a> Foo<'a> {
+ fn f(x: &'a u32) -> Self {
+ Foo(x)
+ }
+ }
+ fn f(f: impl for<'a> Fn(&'a u32) -> Foo<'a>) -> Foo<'static> {
+ f(&0)
+ }
+
+ let _ = f(|x| Foo::f(x));
+
+ struct Bar;
+ impl<'a> From<&'a u32> for Bar {
+ fn from(x: &'a u32) -> Bar {
+ Bar
+ }
+ }
+ fn f2(f: impl for<'a> Fn(&'a u32) -> Bar) -> Bar {
+ f(&0)
+ }
+
+ let _ = f2(|x| <Bar>::from(x));
+
+ struct Baz<'a>(&'a u32);
+ fn f3(f: impl Fn(&u32) -> Baz<'_>) -> Baz<'static> {
+ f(&0)
+ }
+
+ let _ = f3(|x| Baz(x));
+}
+
+fn _mixed_late_bound_and_early_bound_regions() {
+ fn f<T>(t: T, f: impl Fn(T, &u32) -> u32) -> u32 {
+ f(t, &0)
+ }
+ fn f2<'a, T: 'a>(_: &'a T, y: &u32) -> u32 {
+ *y
+ }
+ let _ = f(&0, |x, y| f2(x, y));
+}
+
+fn _closure_with_types() {
+ fn f<T>(x: T) -> T {
+ x
+ }
+ fn f2<T: Default>(f: impl Fn(T) -> T) -> T {
+ f(T::default())
+ }
+
+ let _ = f2(|x: u32| f(x));
+ let _ = f2(|x| -> u32 { f(x) });
+}
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index 0ac0b901d..ff40a2074 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -158,5 +158,11 @@ error: redundant closure
LL | dyn_opt.map(|d| d.method_on_dyn());
| ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
-error: aborting due to 26 previous errors
+error: redundant closure
+ --> $DIR/eta.rs:389:19
+ |
+LL | let _ = f(&0, |x, y| f2(x, y));
+ | ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2`
+
+error: aborting due to 27 previous errors
diff --git a/src/tools/clippy/tests/ui/expect.stderr b/src/tools/clippy/tests/ui/expect.stderr
index be340340d..f787fa973 100644
--- a/src/tools/clippy/tests/ui/expect.stderr
+++ b/src/tools/clippy/tests/ui/expect.stderr
@@ -4,7 +4,7 @@ error: used `expect()` on an `Option` value
LL | let _ = opt.expect("");
| ^^^^^^^^^^^^^^
|
- = help: if this value is `None`, it will panic
+ = note: if this value is `None`, it will panic
= note: `-D clippy::expect-used` implied by `-D warnings`
error: used `expect()` on a `Result` value
@@ -13,7 +13,7 @@ error: used `expect()` on a `Result` value
LL | let _ = res.expect("");
| ^^^^^^^^^^^^^^
|
- = help: if this value is an `Err`, it will panic
+ = note: if this value is an `Err`, it will panic
error: used `expect_err()` on a `Result` value
--> $DIR/expect.rs:12:13
@@ -21,7 +21,7 @@ error: used `expect_err()` on a `Result` value
LL | let _ = res.expect_err("");
| ^^^^^^^^^^^^^^^^^^
|
- = help: if this value is an `Ok`, it will panic
+ = note: if this value is an `Ok`, it will panic
error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/expect_fun_call.stderr b/src/tools/clippy/tests/ui/expect_fun_call.stderr
index 36fb0e5de..a621f681d 100644
--- a/src/tools/clippy/tests/ui/expect_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/expect_fun_call.stderr
@@ -2,7 +2,7 @@ error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:38:26
|
LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
|
= note: `-D clippy::expect-fun-call` implied by `-D warnings`
@@ -10,85 +10,85 @@ error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:41:26
|
LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:44:37
|
LL | with_none_and_format_with_macro.expect(format!("Error {}: fake error", one!()).as_str());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", one!()))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", one!()))`
error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:54:25
|
LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:57:25
|
LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:69:17
|
LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{} {}", 1, 2))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{} {}", 1, 2))`
error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:90:21
|
LL | Some("foo").expect(&get_string());
- | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:91:21
|
LL | Some("foo").expect(get_string().as_ref());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:92:21
|
LL | Some("foo").expect(get_string().as_str());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:94:21
|
LL | Some("foo").expect(get_static_str());
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_static_str()) })`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_static_str()) })`
error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:95:21
|
LL | Some("foo").expect(get_non_static_str(&0));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })`
error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:99:16
|
LL | Some(true).expect(&format!("key {}, {}", 1, 2));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))`
error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:105:17
|
LL | opt_ref.expect(&format!("{:?}", opt_ref));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{:?}", opt_ref))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{:?}", opt_ref))`
error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:109:20
|
LL | format_capture.expect(&format!("{error_code}"));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{error_code}"))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}"))`
error: use of `expect` followed by a function call
--> $DIR/expect_fun_call.rs:112:30
|
LL | format_capture_and_value.expect(&format!("{error_code}, {}", 1));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{error_code}, {}", 1))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}, {}", 1))`
error: aborting due to 15 previous errors
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
index 91863abcc..afc311e3f 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
@@ -2,7 +2,7 @@ error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:70:19
|
LL | let _: &str = &*s;
- | ^^^ help: try this: `&s`
+ | ^^^ help: try: `&s`
|
= note: `-D clippy::explicit-auto-deref` implied by `-D warnings`
@@ -10,229 +10,229 @@ error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:71:19
|
LL | let _: &str = &*{ String::new() };
- | ^^^^^^^^^^^^^^^^^^^ help: try this: `&{ String::new() }`
+ | ^^^^^^^^^^^^^^^^^^^ help: try: `&{ String::new() }`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:72:19
|
LL | let _: &str = &mut *{ String::new() };
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut { String::new() }`
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut { String::new() }`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:76:11
|
LL | f_str(&*s);
- | ^^^ help: try this: `&s`
+ | ^^^ help: try: `&s`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:80:13
|
LL | f_str_t(&*s, &*s); // Don't lint second param.
- | ^^^ help: try this: `&s`
+ | ^^^ help: try: `&s`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:83:24
|
LL | let _: &Box<i32> = &**b;
- | ^^^^ help: try this: `&b`
+ | ^^^^ help: try: `&b`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:89:7
|
LL | c(&*s);
- | ^^^ help: try this: `&s`
+ | ^^^ help: try: `&s`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:95:9
|
LL | &**x
- | ^^^^ help: try this: `x`
+ | ^^^^ help: try: `x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:99:11
|
LL | { &**x }
- | ^^^^ help: try this: `x`
+ | ^^^^ help: try: `x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:103:9
|
LL | &**{ x }
- | ^^^^^^^^ help: try this: `{ x }`
+ | ^^^^^^^^ help: try: `{ x }`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:107:9
|
LL | &***x
- | ^^^^^ help: try this: `x`
+ | ^^^^^ help: try: `x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:124:12
|
LL | f1(&*x);
- | ^^^ help: try this: `&x`
+ | ^^^ help: try: `&x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:125:12
|
LL | f2(&*x);
- | ^^^ help: try this: `&x`
+ | ^^^ help: try: `&x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:126:12
|
LL | f3(&*x);
- | ^^^ help: try this: `&x`
+ | ^^^ help: try: `&x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:127:27
|
LL | f4.callable_str()(&*x);
- | ^^^ help: try this: `&x`
+ | ^^^ help: try: `&x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:128:12
|
LL | f5(&*x);
- | ^^^ help: try this: `&x`
+ | ^^^ help: try: `&x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:129:12
|
LL | f6(&*x);
- | ^^^ help: try this: `&x`
+ | ^^^ help: try: `&x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:130:27
|
LL | f7.callable_str()(&*x);
- | ^^^ help: try this: `&x`
+ | ^^^ help: try: `&x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:131:25
|
LL | f8.callable_t()(&*x);
- | ^^^ help: try this: `&x`
+ | ^^^ help: try: `&x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:132:12
|
LL | f9(&*x);
- | ^^^ help: try this: `&x`
+ | ^^^ help: try: `&x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:133:13
|
LL | f10(&*x);
- | ^^^ help: try this: `&x`
+ | ^^^ help: try: `&x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:134:26
|
LL | f11.callable_t()(&*x);
- | ^^^ help: try this: `&x`
+ | ^^^ help: try: `&x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:138:16
|
LL | let _ = S1(&*s);
- | ^^^ help: try this: `&s`
+ | ^^^ help: try: `&s`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:143:21
|
LL | let _ = S2 { s: &*s };
- | ^^^ help: try this: `&s`
+ | ^^^ help: try: `&s`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:159:30
|
LL | let _ = Self::S1(&**s);
- | ^^^^ help: try this: `s`
+ | ^^^^ help: try: `s`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:160:35
|
LL | let _ = Self::S2 { s: &**s };
- | ^^^^ help: try this: `s`
+ | ^^^^ help: try: `s`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:163:20
|
LL | let _ = E1::S1(&*s);
- | ^^^ help: try this: `&s`
+ | ^^^ help: try: `&s`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:164:25
|
LL | let _ = E1::S2 { s: &*s };
- | ^^^ help: try this: `&s`
+ | ^^^ help: try: `&s`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:182:13
|
LL | let _ = (*b).foo;
- | ^^^^ help: try this: `b`
+ | ^^^^ help: try: `b`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:183:13
|
LL | let _ = (**b).foo;
- | ^^^^^ help: try this: `b`
+ | ^^^^^ help: try: `b`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:198:19
|
LL | let _ = f_str(*ref_str);
- | ^^^^^^^^ help: try this: `ref_str`
+ | ^^^^^^^^ help: try: `ref_str`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:200:19
|
LL | let _ = f_str(**ref_ref_str);
- | ^^^^^^^^^^^^^ help: try this: `ref_ref_str`
+ | ^^^^^^^^^^^^^ help: try: `ref_ref_str`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:210:13
|
LL | f_str(&&*ref_str); // `needless_borrow` will suggest removing both references
- | ^^^^^^^^ help: try this: `ref_str`
+ | ^^^^^^^^ help: try: `ref_str`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:211:12
|
LL | f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference
- | ^^^^^^^^^^ help: try this: `ref_str`
+ | ^^^^^^^^^^ help: try: `ref_str`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:220:41
|
LL | let _ = || -> &'static str { return *s };
- | ^^ help: try this: `s`
+ | ^^ help: try: `s`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:239:9
|
LL | &**x
- | ^^^^ help: try this: `x`
+ | ^^^^ help: try: `x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:262:8
|
LL | c1(*x);
- | ^^ help: try this: `x`
+ | ^^ help: try: `x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:265:20
|
LL | return *x;
- | ^^ help: try this: `x`
+ | ^^ help: try: `x`
error: deref which would be done by auto-deref
--> $DIR/explicit_auto_deref.rs:267:9
|
LL | *x
- | ^^ help: try this: `x`
+ | ^^ help: try: `x`
error: aborting due to 39 previous errors
diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
index 4d72b58cd..4c0b0d8f2 100644
--- a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
+++ b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
@@ -4,6 +4,7 @@
#![allow(
clippy::borrow_deref_ref,
suspicious_double_ref_op,
+ noop_method_call,
clippy::explicit_auto_deref,
clippy::needless_borrow,
clippy::no_effect,
diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.rs b/src/tools/clippy/tests/ui/explicit_deref_methods.rs
index fcd945de3..bc5da35e5 100644
--- a/src/tools/clippy/tests/ui/explicit_deref_methods.rs
+++ b/src/tools/clippy/tests/ui/explicit_deref_methods.rs
@@ -4,6 +4,7 @@
#![allow(
clippy::borrow_deref_ref,
suspicious_double_ref_op,
+ noop_method_call,
clippy::explicit_auto_deref,
clippy::needless_borrow,
clippy::no_effect,
diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.stderr b/src/tools/clippy/tests/ui/explicit_deref_methods.stderr
index d025035b7..e4d2fe3a1 100644
--- a/src/tools/clippy/tests/ui/explicit_deref_methods.stderr
+++ b/src/tools/clippy/tests/ui/explicit_deref_methods.stderr
@@ -1,76 +1,76 @@
error: explicit `deref` method call
- --> $DIR/explicit_deref_methods.rs:54:19
+ --> $DIR/explicit_deref_methods.rs:55:19
|
LL | let b: &str = a.deref();
- | ^^^^^^^^^ help: try this: `&*a`
+ | ^^^^^^^^^ help: try: `&*a`
|
= note: `-D clippy::explicit-deref-methods` implied by `-D warnings`
error: explicit `deref_mut` method call
- --> $DIR/explicit_deref_methods.rs:56:23
+ --> $DIR/explicit_deref_methods.rs:57:23
|
LL | let b: &mut str = a.deref_mut();
- | ^^^^^^^^^^^^^ help: try this: `&mut **a`
+ | ^^^^^^^^^^^^^ help: try: `&mut **a`
error: explicit `deref` method call
- --> $DIR/explicit_deref_methods.rs:59:39
+ --> $DIR/explicit_deref_methods.rs:60:39
|
LL | let b: String = format!("{}, {}", a.deref(), a.deref());
- | ^^^^^^^^^ help: try this: `&*a`
+ | ^^^^^^^^^ help: try: `&*a`
error: explicit `deref` method call
- --> $DIR/explicit_deref_methods.rs:59:50
+ --> $DIR/explicit_deref_methods.rs:60:50
|
LL | let b: String = format!("{}, {}", a.deref(), a.deref());
- | ^^^^^^^^^ help: try this: `&*a`
+ | ^^^^^^^^^ help: try: `&*a`
error: explicit `deref` method call
- --> $DIR/explicit_deref_methods.rs:61:20
+ --> $DIR/explicit_deref_methods.rs:62:20
|
LL | println!("{}", a.deref());
- | ^^^^^^^^^ help: try this: `&*a`
+ | ^^^^^^^^^ help: try: `&*a`
error: explicit `deref` method call
- --> $DIR/explicit_deref_methods.rs:64:11
+ --> $DIR/explicit_deref_methods.rs:65:11
|
LL | match a.deref() {
- | ^^^^^^^^^ help: try this: `&*a`
+ | ^^^^^^^^^ help: try: `&*a`
error: explicit `deref` method call
- --> $DIR/explicit_deref_methods.rs:68:28
+ --> $DIR/explicit_deref_methods.rs:69:28
|
LL | let b: String = concat(a.deref());
- | ^^^^^^^^^ help: try this: `&*a`
+ | ^^^^^^^^^ help: try: `&*a`
error: explicit `deref` method call
- --> $DIR/explicit_deref_methods.rs:70:13
+ --> $DIR/explicit_deref_methods.rs:71:13
|
LL | let b = just_return(a).deref();
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)`
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)`
error: explicit `deref` method call
- --> $DIR/explicit_deref_methods.rs:72:28
+ --> $DIR/explicit_deref_methods.rs:73:28
|
LL | let b: String = concat(just_return(a).deref());
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)`
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)`
error: explicit `deref` method call
- --> $DIR/explicit_deref_methods.rs:74:19
+ --> $DIR/explicit_deref_methods.rs:75:19
|
LL | let b: &str = a.deref().deref();
- | ^^^^^^^^^^^^^^^^^ help: try this: `&**a`
+ | ^^^^^^^^^^^^^^^^^ help: try: `&**a`
error: explicit `deref` method call
- --> $DIR/explicit_deref_methods.rs:77:13
+ --> $DIR/explicit_deref_methods.rs:78:13
|
LL | let b = opt_a.unwrap().deref();
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*opt_a.unwrap()`
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*opt_a.unwrap()`
error: explicit `deref` method call
- --> $DIR/explicit_deref_methods.rs:114:31
+ --> $DIR/explicit_deref_methods.rs:115:31
|
LL | let b: &str = expr_deref!(a.deref());
- | ^^^^^^^^^ help: try this: `&*a`
+ | ^^^^^^^^^ help: try: `&*a`
error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/explicit_write.stderr b/src/tools/clippy/tests/ui/explicit_write.stderr
index 457e9c627..b3aa7274c 100644
--- a/src/tools/clippy/tests/ui/explicit_write.stderr
+++ b/src/tools/clippy/tests/ui/explicit_write.stderr
@@ -2,7 +2,7 @@ error: use of `write!(stdout(), ...).unwrap()`
--> $DIR/explicit_write.rs:24:9
|
LL | write!(std::io::stdout(), "test").unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `print!("test")`
|
= note: `-D clippy::explicit-write` implied by `-D warnings`
@@ -10,73 +10,73 @@ error: use of `write!(stderr(), ...).unwrap()`
--> $DIR/explicit_write.rs:25:9
|
LL | write!(std::io::stderr(), "test").unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprint!("test")`
error: use of `writeln!(stdout(), ...).unwrap()`
--> $DIR/explicit_write.rs:26:9
|
LL | writeln!(std::io::stdout(), "test").unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `println!("test")`
error: use of `writeln!(stderr(), ...).unwrap()`
--> $DIR/explicit_write.rs:27:9
|
LL | writeln!(std::io::stderr(), "test").unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("test")`
error: use of `stdout().write_fmt(...).unwrap()`
--> $DIR/explicit_write.rs:28:9
|
LL | std::io::stdout().write_fmt(format_args!("test")).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `print!("test")`
error: use of `stderr().write_fmt(...).unwrap()`
--> $DIR/explicit_write.rs:29:9
|
LL | std::io::stderr().write_fmt(format_args!("test")).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprint!("test")`
error: use of `writeln!(stdout(), ...).unwrap()`
--> $DIR/explicit_write.rs:32:9
|
LL | writeln!(std::io::stdout(), "test/ntest").unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test/ntest")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `println!("test/ntest")`
error: use of `writeln!(stderr(), ...).unwrap()`
--> $DIR/explicit_write.rs:33:9
|
LL | writeln!(std::io::stderr(), "test/ntest").unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test/ntest")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("test/ntest")`
error: use of `writeln!(stderr(), ...).unwrap()`
--> $DIR/explicit_write.rs:36:9
|
LL | writeln!(std::io::stderr(), "with {}", value).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {}", value)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("with {}", value)`
error: use of `writeln!(stderr(), ...).unwrap()`
--> $DIR/explicit_write.rs:37:9
|
LL | writeln!(std::io::stderr(), "with {} {}", 2, value).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {} {}", 2, value)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("with {} {}", 2, value)`
error: use of `writeln!(stderr(), ...).unwrap()`
--> $DIR/explicit_write.rs:38:9
|
LL | writeln!(std::io::stderr(), "with {value}").unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {value}")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("with {value}")`
error: use of `writeln!(stderr(), ...).unwrap()`
--> $DIR/explicit_write.rs:39:9
|
LL | writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("macro arg {}", one!())`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("macro arg {}", one!())`
error: use of `writeln!(stderr(), ...).unwrap()`
--> $DIR/explicit_write.rs:41:9
|
LL | writeln!(std::io::stderr(), "{:w$}", value, w = width).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("{:w$}", value, w = width)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("{:w$}", value, w = width)`
error: aborting due to 13 previous errors
diff --git a/src/tools/clippy/tests/ui/extend_with_drain.stderr b/src/tools/clippy/tests/ui/extend_with_drain.stderr
index da14ddb25..eb2dd304d 100644
--- a/src/tools/clippy/tests/ui/extend_with_drain.stderr
+++ b/src/tools/clippy/tests/ui/extend_with_drain.stderr
@@ -2,7 +2,7 @@ error: use of `extend` instead of `append` for adding the full range of a second
--> $DIR/extend_with_drain.rs:9:5
|
LL | vec2.extend(vec1.drain(..));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec2.append(&mut vec1)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec2.append(&mut vec1)`
|
= note: `-D clippy::extend-with-drain` implied by `-D warnings`
@@ -10,19 +10,19 @@ error: use of `extend` instead of `append` for adding the full range of a second
--> $DIR/extend_with_drain.rs:14:5
|
LL | vec4.extend(vec3.drain(..));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec4.append(&mut vec3)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec4.append(&mut vec3)`
error: use of `extend` instead of `append` for adding the full range of a second vector
--> $DIR/extend_with_drain.rs:18:5
|
LL | vec11.extend(return_vector().drain(..));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec11.append(&mut return_vector())`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec11.append(&mut return_vector())`
error: use of `extend` instead of `append` for adding the full range of a second vector
--> $DIR/extend_with_drain.rs:49:5
|
LL | y.extend(ref_x.drain(..));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `y.append(ref_x)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `y.append(ref_x)`
error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.fixed b/src/tools/clippy/tests/ui/filter_map_bool_then.fixed
new file mode 100644
index 000000000..e5c9f783f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.fixed
@@ -0,0 +1,58 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+ clippy::clone_on_copy,
+ clippy::map_identity,
+ clippy::unnecessary_lazy_evaluations,
+ clippy::unnecessary_filter_map,
+ unused
+)]
+#![warn(clippy::filter_map_bool_then)]
+
+#[macro_use]
+extern crate proc_macros;
+
+#[derive(Clone, PartialEq)]
+struct NonCopy;
+
+fn main() {
+ let v = vec![1, 2, 3, 4, 5, 6];
+ v.clone().iter().filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+ v.clone().into_iter().filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+ v.clone()
+ .into_iter()
+ .filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+ v.clone()
+ .into_iter()
+ .filter(|&i| i != 1000)
+ .filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+ v.iter()
+ .copied()
+ .filter(|&i| i != 1000)
+ .filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1);
+ // Despite this is non-copy, `is_copy` still returns true (at least now) because it's `&NonCopy`,
+ // and any `&` is `Copy`. So since we can dereference it in `filter` (since it's then `&&NonCopy`),
+ // we can lint this and still get the same input type.
+ // See: <https://doc.rust-lang.org/std/primitive.reference.html#trait-implementations-1>
+ let v = vec![NonCopy, NonCopy];
+ v.clone().iter().filter(|&i| (i == &NonCopy)).map(|i| i);
+ // Do not lint
+ let v = vec![NonCopy, NonCopy];
+ v.clone().into_iter().filter_map(|i| (i == NonCopy).then(|| i));
+ // `&mut` is `!Copy`.
+ let v = vec![NonCopy, NonCopy];
+ v.clone().iter_mut().filter_map(|i| (i == &mut NonCopy).then(|| i));
+ external! {
+ let v = vec![1, 2, 3, 4, 5, 6];
+ v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+ }
+ with_span! {
+ span
+ let v = vec![1, 2, 3, 4, 5, 6];
+ v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+ }
+}
+
+fn issue11309<'a>(iter: impl Iterator<Item = (&'a str, &'a str)>) -> Vec<&'a str> {
+ iter.filter_map(|(_, s): (&str, _)| Some(s)).collect()
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.rs b/src/tools/clippy/tests/ui/filter_map_bool_then.rs
new file mode 100644
index 000000000..7c9b99df7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.rs
@@ -0,0 +1,58 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+ clippy::clone_on_copy,
+ clippy::map_identity,
+ clippy::unnecessary_lazy_evaluations,
+ clippy::unnecessary_filter_map,
+ unused
+)]
+#![warn(clippy::filter_map_bool_then)]
+
+#[macro_use]
+extern crate proc_macros;
+
+#[derive(Clone, PartialEq)]
+struct NonCopy;
+
+fn main() {
+ let v = vec![1, 2, 3, 4, 5, 6];
+ v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+ v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+ v.clone()
+ .into_iter()
+ .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) });
+ v.clone()
+ .into_iter()
+ .filter(|&i| i != 1000)
+ .filter_map(|i| (i % 2 == 0).then(|| i + 1));
+ v.iter()
+ .copied()
+ .filter(|&i| i != 1000)
+ .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1));
+ // Despite this is non-copy, `is_copy` still returns true (at least now) because it's `&NonCopy`,
+ // and any `&` is `Copy`. So since we can dereference it in `filter` (since it's then `&&NonCopy`),
+ // we can lint this and still get the same input type.
+ // See: <https://doc.rust-lang.org/std/primitive.reference.html#trait-implementations-1>
+ let v = vec![NonCopy, NonCopy];
+ v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i));
+ // Do not lint
+ let v = vec![NonCopy, NonCopy];
+ v.clone().into_iter().filter_map(|i| (i == NonCopy).then(|| i));
+ // `&mut` is `!Copy`.
+ let v = vec![NonCopy, NonCopy];
+ v.clone().iter_mut().filter_map(|i| (i == &mut NonCopy).then(|| i));
+ external! {
+ let v = vec![1, 2, 3, 4, 5, 6];
+ v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+ }
+ with_span! {
+ span
+ let v = vec![1, 2, 3, 4, 5, 6];
+ v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+ }
+}
+
+fn issue11309<'a>(iter: impl Iterator<Item = (&'a str, &'a str)>) -> Vec<&'a str> {
+ iter.filter_map(|(_, s): (&str, _)| Some(s)).collect()
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.stderr b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr
new file mode 100644
index 000000000..fffa5252e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr
@@ -0,0 +1,40 @@
+error: usage of `bool::then` in `filter_map`
+ --> $DIR/filter_map_bool_then.rs:20:22
+ |
+LL | v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+ |
+ = note: `-D clippy::filter-map-bool-then` implied by `-D warnings`
+
+error: usage of `bool::then` in `filter_map`
+ --> $DIR/filter_map_bool_then.rs:21:27
+ |
+LL | v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+
+error: usage of `bool::then` in `filter_map`
+ --> $DIR/filter_map_bool_then.rs:24:10
+ |
+LL | .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+
+error: usage of `bool::then` in `filter_map`
+ --> $DIR/filter_map_bool_then.rs:28:10
+ |
+LL | .filter_map(|i| (i % 2 == 0).then(|| i + 1));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+
+error: usage of `bool::then` in `filter_map`
+ --> $DIR/filter_map_bool_then.rs:32:10
+ |
+LL | .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1)`
+
+error: usage of `bool::then` in `filter_map`
+ --> $DIR/filter_map_bool_then.rs:38:22
+ |
+LL | v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i == &NonCopy)).map(|i| i)`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr b/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
index a9fc6abe8..26d9c5e19 100644
--- a/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
+++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
@@ -2,7 +2,7 @@ error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly
--> $DIR/filter_map_next_fixable.rs:9:32
|
LL | let element: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `a.iter().find_map(|s| s.parse().ok())`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.iter().find_map(|s| s.parse().ok())`
|
= note: `-D clippy::filter-map-next` implied by `-D warnings`
@@ -10,7 +10,7 @@ error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly
--> $DIR/filter_map_next_fixable.rs:22:26
|
LL | let _: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `a.iter().find_map(|s| s.parse().ok())`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.iter().find_map(|s| s.parse().ok())`
error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/fn_null_check.rs b/src/tools/clippy/tests/ui/fn_null_check.rs
deleted file mode 100644
index dfdea100c..000000000
--- a/src/tools/clippy/tests/ui/fn_null_check.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-#![allow(unused)]
-#![warn(clippy::fn_null_check)]
-#![allow(clippy::cmp_null)]
-#![allow(clippy::needless_if)]
-#![allow(clippy::ptr_eq)]
-#![allow(clippy::zero_ptr)]
-
-pub const ZPTR: *const () = 0 as *const _;
-pub const NOT_ZPTR: *const () = 1 as *const _;
-
-fn main() {
- let fn_ptr = main;
-
- if (fn_ptr as *mut ()).is_null() {}
- if (fn_ptr as *const u8).is_null() {}
- if (fn_ptr as *const ()) == std::ptr::null() {}
- if (fn_ptr as *const ()) == (0 as *const ()) {}
- if (fn_ptr as *const ()) == ZPTR {}
-
- // no lint
- if (fn_ptr as *const ()) == NOT_ZPTR {}
-}
diff --git a/src/tools/clippy/tests/ui/fn_null_check.stderr b/src/tools/clippy/tests/ui/fn_null_check.stderr
deleted file mode 100644
index 5b9f48a96..000000000
--- a/src/tools/clippy/tests/ui/fn_null_check.stderr
+++ /dev/null
@@ -1,43 +0,0 @@
-error: function pointer assumed to be nullable, even though it isn't
- --> $DIR/fn_null_check.rs:14:8
- |
-LL | if (fn_ptr as *mut ()).is_null() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
- = note: `-D clippy::fn-null-check` implied by `-D warnings`
-
-error: function pointer assumed to be nullable, even though it isn't
- --> $DIR/fn_null_check.rs:15:8
- |
-LL | if (fn_ptr as *const u8).is_null() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
-
-error: function pointer assumed to be nullable, even though it isn't
- --> $DIR/fn_null_check.rs:16:8
- |
-LL | if (fn_ptr as *const ()) == std::ptr::null() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
-
-error: function pointer assumed to be nullable, even though it isn't
- --> $DIR/fn_null_check.rs:17:8
- |
-LL | if (fn_ptr as *const ()) == (0 as *const ()) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
-
-error: function pointer assumed to be nullable, even though it isn't
- --> $DIR/fn_null_check.rs:18:8
- |
-LL | if (fn_ptr as *const ()) == ZPTR {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: try wrapping your function pointer type in `Option<T>` instead, and using `is_none` to check for null pointer value
-
-error: aborting due to 5 previous errors
-
diff --git a/src/tools/clippy/tests/ui/format_collect.rs b/src/tools/clippy/tests/ui/format_collect.rs
new file mode 100644
index 000000000..c7f2b7b69
--- /dev/null
+++ b/src/tools/clippy/tests/ui/format_collect.rs
@@ -0,0 +1,31 @@
+#![allow(unused, dead_code)]
+#![warn(clippy::format_collect)]
+
+fn hex_encode(bytes: &[u8]) -> String {
+ bytes.iter().map(|b| format!("{b:02X}")).collect()
+}
+
+#[rustfmt::skip]
+fn hex_encode_deep(bytes: &[u8]) -> String {
+ bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect()
+}
+
+macro_rules! fmt {
+ ($x:ident) => {
+ format!("{x:02X}", x = $x)
+ };
+}
+
+fn from_macro(bytes: &[u8]) -> String {
+ bytes.iter().map(|x| fmt!(x)).collect()
+}
+
+fn with_block() -> String {
+ (1..10)
+ .map(|s| {
+ let y = 1;
+ format!("{s} {y}")
+ })
+ .collect()
+}
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/format_collect.stderr b/src/tools/clippy/tests/ui/format_collect.stderr
new file mode 100644
index 000000000..d918f1ed4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/format_collect.stderr
@@ -0,0 +1,62 @@
+error: use of `format!` to build up a string from an iterator
+ --> $DIR/format_collect.rs:5:5
+ |
+LL | bytes.iter().map(|b| format!("{b:02X}")).collect()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: call `fold` instead
+ --> $DIR/format_collect.rs:5:18
+ |
+LL | bytes.iter().map(|b| format!("{b:02X}")).collect()
+ | ^^^
+help: ... and use the `write!` macro here
+ --> $DIR/format_collect.rs:5:26
+ |
+LL | bytes.iter().map(|b| format!("{b:02X}")).collect()
+ | ^^^^^^^^^^^^^^^^^^
+ = note: this can be written more efficiently by appending to a `String` directly
+ = note: `-D clippy::format-collect` implied by `-D warnings`
+
+error: use of `format!` to build up a string from an iterator
+ --> $DIR/format_collect.rs:10:5
+ |
+LL | bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: call `fold` instead
+ --> $DIR/format_collect.rs:10:18
+ |
+LL | bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect()
+ | ^^^
+help: ... and use the `write!` macro here
+ --> $DIR/format_collect.rs:10:32
+ |
+LL | bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect()
+ | ^^^^^^^^^^^^^^^^^^
+ = note: this can be written more efficiently by appending to a `String` directly
+
+error: use of `format!` to build up a string from an iterator
+ --> $DIR/format_collect.rs:24:5
+ |
+LL | / (1..10)
+LL | | .map(|s| {
+LL | | let y = 1;
+LL | | format!("{s} {y}")
+LL | | })
+LL | | .collect()
+ | |__________________^
+ |
+help: call `fold` instead
+ --> $DIR/format_collect.rs:25:10
+ |
+LL | .map(|s| {
+ | ^^^
+help: ... and use the `write!` macro here
+ --> $DIR/format_collect.rs:27:13
+ |
+LL | format!("{s} {y}")
+ | ^^^^^^^^^^^^^^^^^^
+ = note: this can be written more efficiently by appending to a `String` directly
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.fixed b/src/tools/clippy/tests/ui/four_forward_slashes.fixed
new file mode 100644
index 000000000..54b2c414b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes.fixed
@@ -0,0 +1,48 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
+#![warn(clippy::four_forward_slashes)]
+#![no_main]
+#![rustfmt::skip]
+
+#[macro_use]
+extern crate proc_macros;
+
+/// whoops
+fn a() {}
+
+/// whoops
+#[allow(dead_code)]
+fn b() {}
+
+/// whoops
+/// two borked comments!
+#[track_caller]
+fn c() {}
+
+fn d() {}
+
+#[test]
+/// between attributes
+#[allow(dead_code)]
+fn g() {}
+
+/// not very start of contents
+fn h() {}
+
+fn i() {
+ //// don't lint me bozo
+ todo!()
+}
+
+external! {
+ //// don't lint me bozo
+ fn e() {}
+}
+
+with_span! {
+ span
+ //// don't lint me bozo
+ fn f() {}
+}
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.rs b/src/tools/clippy/tests/ui/four_forward_slashes.rs
new file mode 100644
index 000000000..facdc8cb1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes.rs
@@ -0,0 +1,48 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
+#![warn(clippy::four_forward_slashes)]
+#![no_main]
+#![rustfmt::skip]
+
+#[macro_use]
+extern crate proc_macros;
+
+//// whoops
+fn a() {}
+
+//// whoops
+#[allow(dead_code)]
+fn b() {}
+
+//// whoops
+//// two borked comments!
+#[track_caller]
+fn c() {}
+
+fn d() {}
+
+#[test]
+//// between attributes
+#[allow(dead_code)]
+fn g() {}
+
+ //// not very start of contents
+fn h() {}
+
+fn i() {
+ //// don't lint me bozo
+ todo!()
+}
+
+external! {
+ //// don't lint me bozo
+ fn e() {}
+}
+
+with_span! {
+ span
+ //// don't lint me bozo
+ fn f() {}
+}
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.stderr b/src/tools/clippy/tests/ui/four_forward_slashes.stderr
new file mode 100644
index 000000000..89162e6b0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes.stderr
@@ -0,0 +1,68 @@
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+ --> $DIR/four_forward_slashes.rs:12:1
+ |
+LL | / //// whoops
+LL | | fn a() {}
+ | |_
+ |
+ = note: `-D clippy::four-forward-slashes` implied by `-D warnings`
+help: make this a doc comment by removing one `/`
+ |
+LL + /// whoops
+ |
+
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+ --> $DIR/four_forward_slashes.rs:15:1
+ |
+LL | / //// whoops
+LL | | #[allow(dead_code)]
+LL | | fn b() {}
+ | |_
+ |
+help: make this a doc comment by removing one `/`
+ |
+LL + /// whoops
+ |
+
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+ --> $DIR/four_forward_slashes.rs:19:1
+ |
+LL | / //// whoops
+LL | | //// two borked comments!
+LL | | #[track_caller]
+LL | | fn c() {}
+ | |_
+ |
+help: turn these into doc comments by removing one `/`
+ |
+LL + /// whoops
+LL ~ /// two borked comments!
+ |
+
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+ --> $DIR/four_forward_slashes.rs:27:1
+ |
+LL | / //// between attributes
+LL | | #[allow(dead_code)]
+LL | | fn g() {}
+ | |_
+ |
+help: make this a doc comment by removing one `/`
+ |
+LL + /// between attributes
+ |
+
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+ --> $DIR/four_forward_slashes.rs:31:1
+ |
+LL | / //// not very start of contents
+LL | | fn h() {}
+ | |_
+ |
+help: make this a doc comment by removing one `/`
+ |
+LL + /// not very start of contents
+ |
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed
new file mode 100644
index 000000000..ce272b4c6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed
@@ -0,0 +1,7 @@
+/// borked doc comment on the first line. doesn't combust!
+fn a() {}
+
+//@run-rustfix
+// This test's entire purpose is to make sure we don't panic if the comment with four slashes
+// extends to the first line of the file. This is likely pretty rare in production, but an ICE is an
+// ICE.
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs
new file mode 100644
index 000000000..d8f82d441
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs
@@ -0,0 +1,7 @@
+//// borked doc comment on the first line. doesn't combust!
+fn a() {}
+
+//@run-rustfix
+// This test's entire purpose is to make sure we don't panic if the comment with four slashes
+// extends to the first line of the file. This is likely pretty rare in production, but an ICE is an
+// ICE.
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr
new file mode 100644
index 000000000..7944da14f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr
@@ -0,0 +1,15 @@
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+ --> $DIR/four_forward_slashes_first_line.rs:1:1
+ |
+LL | / //// borked doc comment on the first line. doesn't combust!
+LL | | fn a() {}
+ | |_
+ |
+ = note: `-D clippy::four-forward-slashes` implied by `-D warnings`
+help: make this a doc comment by removing one `/`
+ |
+LL + /// borked doc comment on the first line. doesn't combust!
+ |
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/get_first.fixed b/src/tools/clippy/tests/ui/get_first.fixed
index a29c0918a..bc2f86566 100644
--- a/src/tools/clippy/tests/ui/get_first.fixed
+++ b/src/tools/clippy/tests/ui/get_first.fixed
@@ -1,9 +1,7 @@
//@run-rustfix
#![warn(clippy::get_first)]
#![allow(clippy::useless_vec)]
-use std::collections::BTreeMap;
-use std::collections::HashMap;
-use std::collections::VecDeque;
+use std::collections::{BTreeMap, HashMap, VecDeque};
struct Bar {
arr: [u32; 3],
diff --git a/src/tools/clippy/tests/ui/get_first.rs b/src/tools/clippy/tests/ui/get_first.rs
index 2062f3ec2..bc0e233fd 100644
--- a/src/tools/clippy/tests/ui/get_first.rs
+++ b/src/tools/clippy/tests/ui/get_first.rs
@@ -1,9 +1,7 @@
//@run-rustfix
#![warn(clippy::get_first)]
#![allow(clippy::useless_vec)]
-use std::collections::BTreeMap;
-use std::collections::HashMap;
-use std::collections::VecDeque;
+use std::collections::{BTreeMap, HashMap, VecDeque};
struct Bar {
arr: [u32; 3],
diff --git a/src/tools/clippy/tests/ui/get_first.stderr b/src/tools/clippy/tests/ui/get_first.stderr
index 4e267ba9a..0899a5905 100644
--- a/src/tools/clippy/tests/ui/get_first.stderr
+++ b/src/tools/clippy/tests/ui/get_first.stderr
@@ -1,5 +1,5 @@
error: accessing first element with `x.get(0)`
- --> $DIR/get_first.rs:20:13
+ --> $DIR/get_first.rs:18:13
|
LL | let _ = x.get(0); // Use x.first()
| ^^^^^^^^ help: try: `x.first()`
@@ -7,13 +7,13 @@ LL | let _ = x.get(0); // Use x.first()
= note: `-D clippy::get-first` implied by `-D warnings`
error: accessing first element with `y.get(0)`
- --> $DIR/get_first.rs:25:13
+ --> $DIR/get_first.rs:23:13
|
LL | let _ = y.get(0); // Use y.first()
| ^^^^^^^^ help: try: `y.first()`
error: accessing first element with `z.get(0)`
- --> $DIR/get_first.rs:30:13
+ --> $DIR/get_first.rs:28:13
|
LL | let _ = z.get(0); // Use z.first()
| ^^^^^^^^ help: try: `z.first()`
diff --git a/src/tools/clippy/tests/ui/get_unwrap.fixed b/src/tools/clippy/tests/ui/get_unwrap.fixed
index 56ee37f02..fda334407 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.fixed
+++ b/src/tools/clippy/tests/ui/get_unwrap.fixed
@@ -9,9 +9,7 @@
#![warn(clippy::unwrap_used)]
#![deny(clippy::get_unwrap)]
-use std::collections::BTreeMap;
-use std::collections::HashMap;
-use std::collections::VecDeque;
+use std::collections::{BTreeMap, HashMap, VecDeque};
struct GetFalsePositive {
arr: [u32; 3],
diff --git a/src/tools/clippy/tests/ui/get_unwrap.rs b/src/tools/clippy/tests/ui/get_unwrap.rs
index af3a619ad..eaf6b005a 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.rs
+++ b/src/tools/clippy/tests/ui/get_unwrap.rs
@@ -9,9 +9,7 @@
#![warn(clippy::unwrap_used)]
#![deny(clippy::get_unwrap)]
-use std::collections::BTreeMap;
-use std::collections::HashMap;
-use std::collections::VecDeque;
+use std::collections::{BTreeMap, HashMap, VecDeque};
struct GetFalsePositive {
arr: [u32; 3],
diff --git a/src/tools/clippy/tests/ui/get_unwrap.stderr b/src/tools/clippy/tests/ui/get_unwrap.stderr
index fd961420d..19dc9071f 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/get_unwrap.stderr
@@ -1,8 +1,8 @@
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:40:17
+ --> $DIR/get_unwrap.rs:38:17
|
LL | let _ = boxed_slice.get(1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
|
note: the lint level is defined here
--> $DIR/get_unwrap.rs:10:9
@@ -11,205 +11,218 @@ LL | #![deny(clippy::get_unwrap)]
| ^^^^^^^^^^^^^^^^^^
error: used `unwrap()` on an `Option` value
- --> $DIR/get_unwrap.rs:40:17
+ --> $DIR/get_unwrap.rs:38:17
|
LL | let _ = boxed_slice.get(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
= note: `-D clippy::unwrap-used` implied by `-D warnings`
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:41:17
+ --> $DIR/get_unwrap.rs:39:17
|
LL | let _ = some_slice.get(0).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]`
error: used `unwrap()` on an `Option` value
- --> $DIR/get_unwrap.rs:41:17
+ --> $DIR/get_unwrap.rs:39:17
|
LL | let _ = some_slice.get(0).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:42:17
+ --> $DIR/get_unwrap.rs:40:17
|
LL | let _ = some_vec.get(0).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]`
error: used `unwrap()` on an `Option` value
- --> $DIR/get_unwrap.rs:42:17
+ --> $DIR/get_unwrap.rs:40:17
|
LL | let _ = some_vec.get(0).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:43:17
+ --> $DIR/get_unwrap.rs:41:17
|
LL | let _ = some_vecdeque.get(0).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]`
error: used `unwrap()` on an `Option` value
- --> $DIR/get_unwrap.rs:43:17
+ --> $DIR/get_unwrap.rs:41:17
|
LL | let _ = some_vecdeque.get(0).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:44:17
+ --> $DIR/get_unwrap.rs:42:17
|
LL | let _ = some_hashmap.get(&1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]`
error: used `unwrap()` on an `Option` value
- --> $DIR/get_unwrap.rs:44:17
+ --> $DIR/get_unwrap.rs:42:17
|
LL | let _ = some_hashmap.get(&1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:45:17
+ --> $DIR/get_unwrap.rs:43:17
|
LL | let _ = some_btreemap.get(&1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]`
error: used `unwrap()` on an `Option` value
- --> $DIR/get_unwrap.rs:45:17
+ --> $DIR/get_unwrap.rs:43:17
|
LL | let _ = some_btreemap.get(&1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:49:21
+ --> $DIR/get_unwrap.rs:47:21
|
LL | let _: u8 = *boxed_slice.get(1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]`
error: used `unwrap()` on an `Option` value
- --> $DIR/get_unwrap.rs:49:22
+ --> $DIR/get_unwrap.rs:47:22
|
LL | let _: u8 = *boxed_slice.get(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:54:9
+ --> $DIR/get_unwrap.rs:52:9
|
LL | *boxed_slice.get_mut(0).unwrap() = 1;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]`
error: used `unwrap()` on an `Option` value
- --> $DIR/get_unwrap.rs:54:10
+ --> $DIR/get_unwrap.rs:52:10
|
LL | *boxed_slice.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:55:9
+ --> $DIR/get_unwrap.rs:53:9
|
LL | *some_slice.get_mut(0).unwrap() = 1;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]`
error: used `unwrap()` on an `Option` value
- --> $DIR/get_unwrap.rs:55:10
+ --> $DIR/get_unwrap.rs:53:10
|
LL | *some_slice.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:56:9
+ --> $DIR/get_unwrap.rs:54:9
|
LL | *some_vec.get_mut(0).unwrap() = 1;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]`
error: used `unwrap()` on an `Option` value
- --> $DIR/get_unwrap.rs:56:10
+ --> $DIR/get_unwrap.rs:54:10
|
LL | *some_vec.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:57:9
+ --> $DIR/get_unwrap.rs:55:9
|
LL | *some_vecdeque.get_mut(0).unwrap() = 1;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]`
error: used `unwrap()` on an `Option` value
- --> $DIR/get_unwrap.rs:57:10
+ --> $DIR/get_unwrap.rs:55:10
|
LL | *some_vecdeque.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:69:17
+ --> $DIR/get_unwrap.rs:67:17
|
LL | let _ = some_vec.get(0..1).unwrap().to_vec();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
error: used `unwrap()` on an `Option` value
- --> $DIR/get_unwrap.rs:69:17
+ --> $DIR/get_unwrap.rs:67:17
|
LL | let _ = some_vec.get(0..1).unwrap().to_vec();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:70:17
+ --> $DIR/get_unwrap.rs:68:17
|
LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
error: used `unwrap()` on an `Option` value
- --> $DIR/get_unwrap.rs:70:17
+ --> $DIR/get_unwrap.rs:68:17
|
LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:80:24
+ --> $DIR/get_unwrap.rs:78:24
|
LL | let _x: &i32 = f.get(1 + 2).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `&f[1 + 2]`
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `&f[1 + 2]`
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:83:18
+ --> $DIR/get_unwrap.rs:81:18
|
LL | let _x = f.get(1 + 2).unwrap().to_string();
- | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `f[1 + 2]`
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:86:18
+ --> $DIR/get_unwrap.rs:84:18
|
LL | let _x = f.get(1 + 2).unwrap().abs();
- | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `f[1 + 2]`
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/get_unwrap.rs:103:33
+ --> $DIR/get_unwrap.rs:101:33
|
LL | let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut rest[linidx(j, k) - linidx(i, k) - 1]`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut rest[linidx(j, k) - linidx(i, k) - 1]`
error: aborting due to 30 previous errors
diff --git a/src/tools/clippy/tests/ui/if_same_then_else.rs b/src/tools/clippy/tests/ui/if_same_then_else.rs
index dad4543f8..e84b20e9f 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else.rs
+++ b/src/tools/clippy/tests/ui/if_same_then_else.rs
@@ -214,4 +214,45 @@ mod issue_8836 {
}
}
+mod issue_11213 {
+ fn reproducer(x: bool) -> bool {
+ if x {
+ 0_u8.is_power_of_two()
+ } else {
+ 0_u16.is_power_of_two()
+ }
+ }
+
+ // a more obvious reproducer that shows
+ // why the code above is problematic:
+ fn v2(x: bool) -> bool {
+ trait Helper {
+ fn is_u8(&self) -> bool;
+ }
+ impl Helper for u8 {
+ fn is_u8(&self) -> bool {
+ true
+ }
+ }
+ impl Helper for u16 {
+ fn is_u8(&self) -> bool {
+ false
+ }
+ }
+
+ // this is certainly not the same code in both branches
+ // it returns a different bool depending on the branch.
+ if x { 0_u8.is_u8() } else { 0_u16.is_u8() }
+ }
+
+ fn do_lint(x: bool) -> bool {
+ // but do lint if the type of the literal is the same
+ if x {
+ 0_u8.is_power_of_two()
+ } else {
+ 0_u8.is_power_of_two()
+ }
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/if_same_then_else.stderr b/src/tools/clippy/tests/ui/if_same_then_else.stderr
index a34fc5655..774cc0868 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else.stderr
+++ b/src/tools/clippy/tests/ui/if_same_then_else.stderr
@@ -108,5 +108,23 @@ LL | | bar + 1;
LL | | }
| |_____^
-error: aborting due to 5 previous errors
+error: this `if` has identical blocks
+ --> $DIR/if_same_then_else.rs:250:14
+ |
+LL | if x {
+ | ______________^
+LL | | 0_u8.is_power_of_two()
+LL | | } else {
+ | |_________^
+ |
+note: same as this
+ --> $DIR/if_same_then_else.rs:252:16
+ |
+LL | } else {
+ | ________________^
+LL | | 0_u8.is_power_of_two()
+LL | | }
+ | |_________^
+
+error: aborting due to 6 previous errors
diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.rs b/src/tools/clippy/tests/ui/if_same_then_else2.rs
index 0b171f21d..c545434ef 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else2.rs
+++ b/src/tools/clippy/tests/ui/if_same_then_else2.rs
@@ -98,7 +98,7 @@ fn if_same_then_else2() -> Result<&'static str, ()> {
};
if true {
- //~^ ERROR: this `if` has identical blocks
+ // FIXME: should emit "this `if` has identical blocks"
Ok("foo")?;
} else {
Ok("foo")?;
diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.stderr b/src/tools/clippy/tests/ui/if_same_then_else2.stderr
index 56e5f3e45..37fe787d1 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else2.stderr
+++ b/src/tools/clippy/tests/ui/if_same_then_else2.stderr
@@ -83,25 +83,6 @@ LL | | };
| |_____^
error: this `if` has identical blocks
- --> $DIR/if_same_then_else2.rs:100:13
- |
-LL | if true {
- | _____________^
-LL | |
-LL | | Ok("foo")?;
-LL | | } else {
- | |_____^
- |
-note: same as this
- --> $DIR/if_same_then_else2.rs:103:12
- |
-LL | } else {
- | ____________^
-LL | | Ok("foo")?;
-LL | | }
- | |_____^
-
-error: this `if` has identical blocks
--> $DIR/if_same_then_else2.rs:124:20
|
LL | } else if true {
@@ -122,5 +103,5 @@ LL | | return Ok(&foo[0..]);
LL | | }
| |_____^
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.rs b/src/tools/clippy/tests/ui/ifs_same_cond.rs
index 5c338e3c5..ad77346b7 100644
--- a/src/tools/clippy/tests/ui/ifs_same_cond.rs
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.rs
@@ -46,6 +46,10 @@ fn ifs_same_cond() {
// ok, functions
} else if v.len() == 42 {
}
+
+ if let Some(env1) = option_env!("ENV1") {
+ } else if let Some(env2) = option_env!("ENV2") {
+ }
}
fn issue10272() {
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.stderr b/src/tools/clippy/tests/ui/ifs_same_cond.stderr
index 8d7093447..3f52c10b7 100644
--- a/src/tools/clippy/tests/ui/ifs_same_cond.stderr
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.stderr
@@ -36,13 +36,13 @@ LL | if 2 * a == 1 {
| ^^^^^^^^^^
error: this `if` has the same condition as a previous `if`
- --> $DIR/ifs_same_cond.rs:54:15
+ --> $DIR/ifs_same_cond.rs:58:15
|
LL | } else if a.contains("ah") {
| ^^^^^^^^^^^^^^^^
|
note: same as this
- --> $DIR/ifs_same_cond.rs:53:8
+ --> $DIR/ifs_same_cond.rs:57:8
|
LL | if a.contains("ah") {
| ^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
new file mode 100644
index 000000000..492219fe4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
@@ -0,0 +1,17 @@
+//@run-rustfix
+
+#![warn(clippy::ignored_unit_patterns)]
+#![allow(clippy::redundant_pattern_matching, clippy::single_match)]
+
+fn foo() -> Result<(), ()> {
+ unimplemented!()
+}
+
+fn main() {
+ match foo() {
+ Ok(()) => {},
+ Err(()) => {},
+ }
+ if let Ok(()) = foo() {}
+ let _ = foo().map_err(|()| todo!());
+}
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.rs b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
new file mode 100644
index 000000000..90af36f8e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
@@ -0,0 +1,17 @@
+//@run-rustfix
+
+#![warn(clippy::ignored_unit_patterns)]
+#![allow(clippy::redundant_pattern_matching, clippy::single_match)]
+
+fn foo() -> Result<(), ()> {
+ unimplemented!()
+}
+
+fn main() {
+ match foo() {
+ Ok(_) => {},
+ Err(_) => {},
+ }
+ if let Ok(_) = foo() {}
+ let _ = foo().map_err(|_| todo!());
+}
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
new file mode 100644
index 000000000..8feea3cc2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
@@ -0,0 +1,28 @@
+error: matching over `()` is more explicit
+ --> $DIR/ignored_unit_patterns.rs:12:12
+ |
+LL | Ok(_) => {},
+ | ^ help: use `()` instead of `_`: `()`
+ |
+ = note: `-D clippy::ignored-unit-patterns` implied by `-D warnings`
+
+error: matching over `()` is more explicit
+ --> $DIR/ignored_unit_patterns.rs:13:13
+ |
+LL | Err(_) => {},
+ | ^ help: use `()` instead of `_`: `()`
+
+error: matching over `()` is more explicit
+ --> $DIR/ignored_unit_patterns.rs:15:15
+ |
+LL | if let Ok(_) = foo() {}
+ | ^ help: use `()` instead of `_`: `()`
+
+error: matching over `()` is more explicit
+ --> $DIR/ignored_unit_patterns.rs:16:28
+ |
+LL | let _ = foo().map_err(|_| todo!());
+ | ^ help: use `()` instead of `_`: `()`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/incorrect_clone_impl_on_copy_type.stderr b/src/tools/clippy/tests/ui/incorrect_clone_impl_on_copy_type.stderr
index 0021841aa..7bcba8ba4 100644
--- a/src/tools/clippy/tests/ui/incorrect_clone_impl_on_copy_type.stderr
+++ b/src/tools/clippy/tests/ui/incorrect_clone_impl_on_copy_type.stderr
@@ -16,7 +16,7 @@ LL | / fn clone_from(&mut self, source: &Self) {
LL | | source.clone();
LL | | *self = source.clone();
LL | | }
- | |_____^ help: remove this
+ | |_____^ help: remove it
error: incorrect implementation of `clone` on a `Copy` type
--> $DIR/incorrect_clone_impl_on_copy_type.rs:81:29
@@ -34,7 +34,7 @@ LL | / fn clone_from(&mut self, source: &Self) {
LL | | source.clone();
LL | | *self = source.clone();
LL | | }
- | |_____^ help: remove this
+ | |_____^ help: remove it
error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed
new file mode 100644
index 000000000..2f51bf274
--- /dev/null
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed
@@ -0,0 +1,145 @@
+//@run-rustfix
+#![no_main]
+
+use std::cmp::Ordering;
+
+// lint
+
+#[derive(Eq, PartialEq)]
+struct A(u32);
+
+impl Ord for A {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for A {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
+}
+
+// do not lint
+
+#[derive(Eq, PartialEq)]
+struct B(u32);
+
+impl Ord for B {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for B {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+// lint, and give `_` a name
+
+#[derive(Eq, PartialEq)]
+struct C(u32);
+
+impl Ord for C {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for C {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
+}
+
+// do not lint derived
+
+#[derive(Eq, Ord, PartialEq, PartialOrd)]
+struct D(u32);
+
+// do not lint if ord is not manually implemented
+
+#[derive(Eq, PartialEq)]
+struct E(u32);
+
+impl PartialOrd for E {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ todo!();
+ }
+}
+
+// do not lint since ord has more restrictive bounds
+
+#[derive(Eq, PartialEq)]
+struct Uwu<A>(A);
+
+impl<A: std::fmt::Debug + Ord + PartialOrd> Ord for Uwu<A> {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl<A: Ord + PartialOrd> PartialOrd for Uwu<A> {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ todo!();
+ }
+}
+
+// do not lint since `Rhs` is not `Self`
+
+#[derive(Eq, PartialEq)]
+struct F(u32);
+
+impl Ord for F {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for F {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl PartialEq<u32> for F {
+ fn eq(&self, other: &u32) -> bool {
+ todo!();
+ }
+}
+
+impl PartialOrd<u32> for F {
+ fn partial_cmp(&self, other: &u32) -> Option<Ordering> {
+ todo!();
+ }
+}
+
+// #11178, do not lint
+
+#[derive(Eq, PartialEq)]
+struct G(u32);
+
+impl Ord for G {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for G {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(Self::cmp(self, other))
+ }
+}
+
+#[derive(Eq, PartialEq)]
+struct H(u32);
+
+impl Ord for H {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for H {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(Ord::cmp(self, other))
+ }
+}
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs
new file mode 100644
index 000000000..47127bdae
--- /dev/null
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs
@@ -0,0 +1,149 @@
+//@run-rustfix
+#![no_main]
+
+use std::cmp::Ordering;
+
+// lint
+
+#[derive(Eq, PartialEq)]
+struct A(u32);
+
+impl Ord for A {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for A {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ todo!();
+ }
+}
+
+// do not lint
+
+#[derive(Eq, PartialEq)]
+struct B(u32);
+
+impl Ord for B {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for B {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+// lint, and give `_` a name
+
+#[derive(Eq, PartialEq)]
+struct C(u32);
+
+impl Ord for C {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for C {
+ fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
+ todo!();
+ }
+}
+
+// do not lint derived
+
+#[derive(Eq, Ord, PartialEq, PartialOrd)]
+struct D(u32);
+
+// do not lint if ord is not manually implemented
+
+#[derive(Eq, PartialEq)]
+struct E(u32);
+
+impl PartialOrd for E {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ todo!();
+ }
+}
+
+// do not lint since ord has more restrictive bounds
+
+#[derive(Eq, PartialEq)]
+struct Uwu<A>(A);
+
+impl<A: std::fmt::Debug + Ord + PartialOrd> Ord for Uwu<A> {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl<A: Ord + PartialOrd> PartialOrd for Uwu<A> {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ todo!();
+ }
+}
+
+// do not lint since `Rhs` is not `Self`
+
+#[derive(Eq, PartialEq)]
+struct F(u32);
+
+impl Ord for F {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for F {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl PartialEq<u32> for F {
+ fn eq(&self, other: &u32) -> bool {
+ todo!();
+ }
+}
+
+impl PartialOrd<u32> for F {
+ fn partial_cmp(&self, other: &u32) -> Option<Ordering> {
+ todo!();
+ }
+}
+
+// #11178, do not lint
+
+#[derive(Eq, PartialEq)]
+struct G(u32);
+
+impl Ord for G {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for G {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(Self::cmp(self, other))
+ }
+}
+
+#[derive(Eq, PartialEq)]
+struct H(u32);
+
+impl Ord for H {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for H {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(Ord::cmp(self, other))
+ }
+}
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr
new file mode 100644
index 000000000..66048fc90
--- /dev/null
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr
@@ -0,0 +1,31 @@
+error: incorrect implementation of `partial_cmp` on an `Ord` type
+ --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:17:1
+ |
+LL | / impl PartialOrd for A {
+LL | | fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ | | _____________________________________________________________-
+LL | || todo!();
+LL | || }
+ | ||_____- help: change this to: `{ Some(self.cmp(other)) }`
+LL | | }
+ | |__^
+ |
+ = note: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default
+
+error: incorrect implementation of `partial_cmp` on an `Ord` type
+ --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:51:1
+ |
+LL | / impl PartialOrd for C {
+LL | | fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
+LL | | todo!();
+LL | | }
+LL | | }
+ | |_^
+ |
+help: change this to
+ |
+LL | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
+ | ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs
new file mode 100644
index 000000000..3a3b84f93
--- /dev/null
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs
@@ -0,0 +1,51 @@
+// This test's filename is... a bit verbose. But it ensures we suggest the correct code when `Ord`
+// is not in scope.
+#![no_main]
+#![no_implicit_prelude]
+
+extern crate std;
+
+use std::cmp::{self, Eq, Ordering, PartialEq, PartialOrd};
+use std::option::Option::{self, Some};
+use std::todo;
+
+// lint
+
+#[derive(Eq, PartialEq)]
+struct A(u32);
+
+impl cmp::Ord for A {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for A {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ // NOTE: This suggestion is wrong, as `Ord` is not in scope. But this should be fine as it isn't
+ // automatically applied
+ todo!();
+ }
+}
+
+#[derive(Eq, PartialEq)]
+struct B(u32);
+
+impl B {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl cmp::Ord for B {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for B {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ // This calls `B.cmp`, not `Ord::cmp`!
+ Some(self.cmp(other))
+ }
+}
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr
new file mode 100644
index 000000000..f4374c281
--- /dev/null
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr
@@ -0,0 +1,31 @@
+error: incorrect implementation of `partial_cmp` on an `Ord` type
+ --> $DIR/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs:23:1
+ |
+LL | / impl PartialOrd for A {
+LL | | fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ | | _____________________________________________________________-
+LL | || // NOTE: This suggestion is wrong, as `Ord` is not in scope. But this should be fine as it isn't
+LL | || // automatically applied
+LL | || todo!();
+LL | || }
+ | ||_____- help: change this to: `{ Some(self.cmp(other)) }`
+LL | | }
+ | |__^
+ |
+ = note: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default
+
+error: incorrect implementation of `partial_cmp` on an `Ord` type
+ --> $DIR/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs:46:1
+ |
+LL | / impl PartialOrd for B {
+LL | | fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ | | _____________________________________________________________-
+LL | || // This calls `B.cmp`, not `Ord::cmp`!
+LL | || Some(self.cmp(other))
+LL | || }
+ | ||_____- help: change this to: `{ Some(std::cmp::Ord::cmp(self, other)) }`
+LL | | }
+ | |__^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr b/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr
index f8a50f022..004260a1d 100644
--- a/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr
+++ b/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr
@@ -4,7 +4,7 @@ error: you seem to be trying to use `match` to destructure a single infallible p
LL | / let data = match wrapper {
LL | | SingleVariantEnum::Variant(i) => i,
LL | | };
- | |______^ help: try this: `let SingleVariantEnum::Variant(data) = wrapper;`
+ | |______^ help: try: `let SingleVariantEnum::Variant(data) = wrapper;`
|
= note: `-D clippy::infallible-destructuring-match` implied by `-D warnings`
@@ -14,7 +14,7 @@ error: you seem to be trying to use `match` to destructure a single infallible p
LL | / let data = match wrapper {
LL | | TupleStruct(i) => i,
LL | | };
- | |______^ help: try this: `let TupleStruct(data) = wrapper;`
+ | |______^ help: try: `let TupleStruct(data) = wrapper;`
error: you seem to be trying to use `match` to destructure a single infallible pattern. Consider using `let`
--> $DIR/infallible_destructuring_match.rs:85:5
@@ -22,7 +22,7 @@ error: you seem to be trying to use `match` to destructure a single infallible p
LL | / let data = match wrapper {
LL | | TupleStructWithNonCopy(ref n) => n,
LL | | };
- | |______^ help: try this: `let TupleStructWithNonCopy(ref data) = wrapper;`
+ | |______^ help: try: `let TupleStructWithNonCopy(ref data) = wrapper;`
error: you seem to be trying to use `match` to destructure a single infallible pattern. Consider using `let`
--> $DIR/infallible_destructuring_match.rs:104:5
@@ -30,7 +30,7 @@ error: you seem to be trying to use `match` to destructure a single infallible p
LL | / let data = match wrapper {
LL | | Ok(i) => i,
LL | | };
- | |______^ help: try this: `let Ok(data) = wrapper;`
+ | |______^ help: try: `let Ok(data) = wrapper;`
error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/inherent_to_string.rs b/src/tools/clippy/tests/ui/inherent_to_string.rs
index aeb0a0c1e..adb0389a0 100644
--- a/src/tools/clippy/tests/ui/inherent_to_string.rs
+++ b/src/tools/clippy/tests/ui/inherent_to_string.rs
@@ -1,5 +1,4 @@
-#![warn(clippy::inherent_to_string)]
-#![deny(clippy::inherent_to_string_shadow_display)]
+#![allow(improper_ctypes_definitions)]
use std::fmt;
@@ -14,6 +13,9 @@ struct D;
struct E;
struct F;
struct G;
+struct H;
+struct I;
+struct J;
impl A {
// Should be detected; emit warning
@@ -80,6 +82,26 @@ impl G {
}
}
+// Issue #11201
+
+impl H {
+ unsafe fn to_string(&self) -> String {
+ "G.to_string()".to_string()
+ }
+}
+
+impl I {
+ extern "C" fn to_string(&self) -> String {
+ "G.to_string()".to_string()
+ }
+}
+
+impl J {
+ unsafe extern "C" fn to_string(&self) -> String {
+ "G.to_string()".to_string()
+ }
+}
+
fn main() {
let a = A;
a.to_string();
diff --git a/src/tools/clippy/tests/ui/inherent_to_string.stderr b/src/tools/clippy/tests/ui/inherent_to_string.stderr
index 443fecae1..579b3c8c5 100644
--- a/src/tools/clippy/tests/ui/inherent_to_string.stderr
+++ b/src/tools/clippy/tests/ui/inherent_to_string.stderr
@@ -1,5 +1,5 @@
error: implementation of inherent method `to_string(&self) -> String` for type `A`
- --> $DIR/inherent_to_string.rs:20:5
+ --> $DIR/inherent_to_string.rs:22:5
|
LL | / fn to_string(&self) -> String {
LL | | "A.to_string()".to_string()
@@ -10,7 +10,7 @@ LL | | }
= note: `-D clippy::inherent-to-string` implied by `-D warnings`
error: type `C` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`
- --> $DIR/inherent_to_string.rs:44:5
+ --> $DIR/inherent_to_string.rs:46:5
|
LL | / fn to_string(&self) -> String {
LL | | "C.to_string()".to_string()
@@ -18,11 +18,7 @@ LL | | }
| |_____^
|
= help: remove the inherent method from type `C`
-note: the lint level is defined here
- --> $DIR/inherent_to_string.rs:2:9
- |
-LL | #![deny(clippy::inherent_to_string_shadow_display)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: `#[deny(clippy::inherent_to_string_shadow_display)]` on by default
error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/issue-7447.rs b/src/tools/clippy/tests/ui/issue-7447.rs
index fdb77f322..de4362c4d 100644
--- a/src/tools/clippy/tests/ui/issue-7447.rs
+++ b/src/tools/clippy/tests/ui/issue-7447.rs
@@ -1,4 +1,7 @@
-use std::{borrow::Cow, collections::BTreeMap, marker::PhantomData, sync::Arc};
+use std::borrow::Cow;
+use std::collections::BTreeMap;
+use std::marker::PhantomData;
+use std::sync::Arc;
fn byte_view<'a>(s: &'a ByteView<'_>) -> BTreeMap<&'a str, ByteView<'a>> {
panic!()
diff --git a/src/tools/clippy/tests/ui/issue-7447.stderr b/src/tools/clippy/tests/ui/issue-7447.stderr
index 8d8c29f13..7a113740c 100644
--- a/src/tools/clippy/tests/ui/issue-7447.stderr
+++ b/src/tools/clippy/tests/ui/issue-7447.stderr
@@ -1,5 +1,5 @@
error: sub-expression diverges
- --> $DIR/issue-7447.rs:23:15
+ --> $DIR/issue-7447.rs:26:15
|
LL | byte_view(panic!());
| ^^^^^^^^
@@ -8,7 +8,7 @@ LL | byte_view(panic!());
= note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
error: sub-expression diverges
- --> $DIR/issue-7447.rs:24:19
+ --> $DIR/issue-7447.rs:27:19
|
LL | group_entries(panic!());
| ^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.fixed b/src/tools/clippy/tests/ui/iter_cloned_collect.fixed
index 2baea06f8..636f572a3 100644
--- a/src/tools/clippy/tests/ui/iter_cloned_collect.fixed
+++ b/src/tools/clippy/tests/ui/iter_cloned_collect.fixed
@@ -3,8 +3,7 @@
#![allow(unused)]
#![allow(clippy::useless_vec)]
-use std::collections::HashSet;
-use std::collections::VecDeque;
+use std::collections::{HashSet, VecDeque};
fn main() {
let v = [1, 2, 3, 4, 5];
diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.rs b/src/tools/clippy/tests/ui/iter_cloned_collect.rs
index 9eac94eb8..518cb75af 100644
--- a/src/tools/clippy/tests/ui/iter_cloned_collect.rs
+++ b/src/tools/clippy/tests/ui/iter_cloned_collect.rs
@@ -3,8 +3,7 @@
#![allow(unused)]
#![allow(clippy::useless_vec)]
-use std::collections::HashSet;
-use std::collections::VecDeque;
+use std::collections::{HashSet, VecDeque};
fn main() {
let v = [1, 2, 3, 4, 5];
diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.stderr b/src/tools/clippy/tests/ui/iter_cloned_collect.stderr
index b38cf547d..b2cc497bf 100644
--- a/src/tools/clippy/tests/ui/iter_cloned_collect.stderr
+++ b/src/tools/clippy/tests/ui/iter_cloned_collect.stderr
@@ -1,5 +1,5 @@
error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
- --> $DIR/iter_cloned_collect.rs:11:27
+ --> $DIR/iter_cloned_collect.rs:10:27
|
LL | let v2: Vec<isize> = v.iter().cloned().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
@@ -7,13 +7,13 @@ LL | let v2: Vec<isize> = v.iter().cloned().collect();
= note: `-D clippy::iter-cloned-collect` implied by `-D warnings`
error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
- --> $DIR/iter_cloned_collect.rs:16:38
+ --> $DIR/iter_cloned_collect.rs:15:38
|
LL | let _: Vec<isize> = vec![1, 2, 3].iter().cloned().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
- --> $DIR/iter_cloned_collect.rs:21:24
+ --> $DIR/iter_cloned_collect.rs:20:24
|
LL | .to_bytes()
| ________________________^
@@ -23,13 +23,13 @@ LL | | .collect();
| |______________________^ help: try: `.to_vec()`
error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
- --> $DIR/iter_cloned_collect.rs:29:24
+ --> $DIR/iter_cloned_collect.rs:28:24
|
LL | let _: Vec<_> = arr.iter().cloned().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
error: called `iter().copied().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
- --> $DIR/iter_cloned_collect.rs:32:26
+ --> $DIR/iter_cloned_collect.rs:31:26
|
LL | let _: Vec<isize> = v.iter().copied().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
index dcae7cecd..eaac48be8 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
@@ -4,7 +4,7 @@ error: unnecessarily eager cloning of iterator items
LL | let _: Option<String> = vec.iter().cloned().last();
| ^^^^^^^^^^----------------
| |
- | help: try this: `.last().cloned()`
+ | help: try: `.last().cloned()`
|
= note: `-D clippy::iter-overeager-cloned` implied by `-D warnings`
@@ -14,7 +14,7 @@ error: unnecessarily eager cloning of iterator items
LL | let _: Option<String> = vec.iter().chain(vec.iter()).cloned().next();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------
| |
- | help: try this: `.next().cloned()`
+ | help: try: `.next().cloned()`
error: unneeded cloning of iterator items
--> $DIR/iter_overeager_cloned.rs:12:20
@@ -22,7 +22,7 @@ error: unneeded cloning of iterator items
LL | let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------
| |
- | help: try this: `.count()`
+ | help: try: `.count()`
|
= note: `-D clippy::redundant-clone` implied by `-D warnings`
@@ -32,7 +32,7 @@ error: unnecessarily eager cloning of iterator items
LL | let _: Vec<_> = vec.iter().cloned().take(2).collect();
| ^^^^^^^^^^-----------------
| |
- | help: try this: `.take(2).cloned()`
+ | help: try: `.take(2).cloned()`
error: unnecessarily eager cloning of iterator items
--> $DIR/iter_overeager_cloned.rs:16:21
@@ -40,7 +40,7 @@ error: unnecessarily eager cloning of iterator items
LL | let _: Vec<_> = vec.iter().cloned().skip(2).collect();
| ^^^^^^^^^^-----------------
| |
- | help: try this: `.skip(2).cloned()`
+ | help: try: `.skip(2).cloned()`
error: unnecessarily eager cloning of iterator items
--> $DIR/iter_overeager_cloned.rs:18:13
@@ -48,7 +48,7 @@ error: unnecessarily eager cloning of iterator items
LL | let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------
| |
- | help: try this: `.nth(2).cloned()`
+ | help: try: `.nth(2).cloned()`
error: unnecessarily eager cloning of iterator items
--> $DIR/iter_overeager_cloned.rs:20:13
@@ -60,7 +60,7 @@ LL | | .cloned()
LL | | .flatten();
| |__________________^
|
-help: try this
+help: try
|
LL ~ .iter()
LL ~ .flatten().cloned();
diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.fixed b/src/tools/clippy/tests/ui/iter_skip_zero.fixed
new file mode 100644
index 000000000..1eb0984fe
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_skip_zero.fixed
@@ -0,0 +1,25 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(clippy::useless_vec, unused)]
+#![warn(clippy::iter_skip_zero)]
+
+#[macro_use]
+extern crate proc_macros;
+
+use std::iter::once;
+
+fn main() {
+ let _ = [1, 2, 3].iter().skip(1);
+ let _ = vec![1, 2, 3].iter().skip(1);
+ let _ = once([1, 2, 3]).skip(1);
+ let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(1)).skip(1);
+ // Don't lint
+ let _ = [1, 2, 3].iter().skip(1);
+ let _ = vec![1, 2, 3].iter().skip(1);
+ external! {
+ let _ = [1, 2, 3].iter().skip(0);
+ }
+ with_span! {
+ let _ = [1, 2, 3].iter().skip(0);
+ }
+}
diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.rs b/src/tools/clippy/tests/ui/iter_skip_zero.rs
new file mode 100644
index 000000000..8c103ab1d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_skip_zero.rs
@@ -0,0 +1,25 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(clippy::useless_vec, unused)]
+#![warn(clippy::iter_skip_zero)]
+
+#[macro_use]
+extern crate proc_macros;
+
+use std::iter::once;
+
+fn main() {
+ let _ = [1, 2, 3].iter().skip(0);
+ let _ = vec![1, 2, 3].iter().skip(0);
+ let _ = once([1, 2, 3]).skip(0);
+ let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0);
+ // Don't lint
+ let _ = [1, 2, 3].iter().skip(1);
+ let _ = vec![1, 2, 3].iter().skip(1);
+ external! {
+ let _ = [1, 2, 3].iter().skip(0);
+ }
+ with_span! {
+ let _ = [1, 2, 3].iter().skip(0);
+ }
+}
diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.stderr b/src/tools/clippy/tests/ui/iter_skip_zero.stderr
new file mode 100644
index 000000000..80fecd59e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_skip_zero.stderr
@@ -0,0 +1,43 @@
+error: usage of `.skip(0)`
+ --> $DIR/iter_skip_zero.rs:12:35
+ |
+LL | let _ = [1, 2, 3].iter().skip(0);
+ | ^ help: if you meant to skip the first element, use: `1`
+ |
+ = note: this call to `skip` does nothing and is useless; remove it
+ = note: `-D clippy::iter-skip-zero` implied by `-D warnings`
+
+error: usage of `.skip(0)`
+ --> $DIR/iter_skip_zero.rs:13:39
+ |
+LL | let _ = vec![1, 2, 3].iter().skip(0);
+ | ^ help: if you meant to skip the first element, use: `1`
+ |
+ = note: this call to `skip` does nothing and is useless; remove it
+
+error: usage of `.skip(0)`
+ --> $DIR/iter_skip_zero.rs:14:34
+ |
+LL | let _ = once([1, 2, 3]).skip(0);
+ | ^ help: if you meant to skip the first element, use: `1`
+ |
+ = note: this call to `skip` does nothing and is useless; remove it
+
+error: usage of `.skip(0)`
+ --> $DIR/iter_skip_zero.rs:15:71
+ |
+LL | let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0);
+ | ^ help: if you meant to skip the first element, use: `1`
+ |
+ = note: this call to `skip` does nothing and is useless; remove it
+
+error: usage of `.skip(0)`
+ --> $DIR/iter_skip_zero.rs:15:62
+ |
+LL | let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0);
+ | ^ help: if you meant to skip the first element, use: `1`
+ |
+ = note: this call to `skip` does nothing and is useless; remove it
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/iter_with_drain.stderr b/src/tools/clippy/tests/ui/iter_with_drain.stderr
index aa394439f..bfaed29a0 100644
--- a/src/tools/clippy/tests/ui/iter_with_drain.stderr
+++ b/src/tools/clippy/tests/ui/iter_with_drain.stderr
@@ -2,7 +2,7 @@ error: `drain(..)` used on a `Vec`
--> $DIR/iter_with_drain.rs:11:34
|
LL | let mut a: BinaryHeap<_> = a.drain(..).collect();
- | ^^^^^^^^^ help: try this: `into_iter()`
+ | ^^^^^^^^^ help: try: `into_iter()`
|
= note: `-D clippy::iter-with-drain` implied by `-D warnings`
@@ -10,31 +10,31 @@ error: `drain(..)` used on a `VecDeque`
--> $DIR/iter_with_drain.rs:14:27
|
LL | let mut a: Vec<_> = a.drain(..).collect();
- | ^^^^^^^^^ help: try this: `into_iter()`
+ | ^^^^^^^^^ help: try: `into_iter()`
error: `drain(..)` used on a `Vec`
--> $DIR/iter_with_drain.rs:15:34
|
LL | let mut a: HashMap<_, _> = a.drain(..).map(|x| (x.clone(), x)).collect();
- | ^^^^^^^^^ help: try this: `into_iter()`
+ | ^^^^^^^^^ help: try: `into_iter()`
error: `drain(..)` used on a `Vec`
--> $DIR/iter_with_drain.rs:21:34
|
LL | let mut a: BinaryHeap<_> = a.drain(0..).collect();
- | ^^^^^^^^^^ help: try this: `into_iter()`
+ | ^^^^^^^^^^ help: try: `into_iter()`
error: `drain(..)` used on a `VecDeque`
--> $DIR/iter_with_drain.rs:24:27
|
LL | let mut a: Vec<_> = a.drain(..a.len()).collect();
- | ^^^^^^^^^^^^^^^^ help: try this: `into_iter()`
+ | ^^^^^^^^^^^^^^^^ help: try: `into_iter()`
error: `drain(..)` used on a `Vec`
--> $DIR/iter_with_drain.rs:25:34
|
LL | let mut a: HashMap<_, _> = a.drain(0..a.len()).map(|x| (x.clone(), x)).collect();
- | ^^^^^^^^^^^^^^^^^ help: try this: `into_iter()`
+ | ^^^^^^^^^^^^^^^^^ help: try: `into_iter()`
error: aborting due to 6 previous errors
diff --git a/src/tools/clippy/tests/ui/let_and_return.rs b/src/tools/clippy/tests/ui/let_and_return.rs
index bb162adc9..64665cc90 100644
--- a/src/tools/clippy/tests/ui/let_and_return.rs
+++ b/src/tools/clippy/tests/ui/let_and_return.rs
@@ -1,6 +1,8 @@
#![allow(unused)]
#![warn(clippy::let_and_return)]
+use std::cell::RefCell;
+
fn test() -> i32 {
let _y = 0; // no warning
let x = 5;
@@ -65,45 +67,46 @@ macro_rules! tuple_encode {
);
}
+fn issue_3792() -> String {
+ use std::io::{self, BufRead, Stdin};
+
+ let stdin = io::stdin();
+ // `Stdin::lock` returns `StdinLock<'static>` so `line` doesn't borrow from `stdin`
+ // https://github.com/rust-lang/rust/pull/93965
+ let line = stdin.lock().lines().next().unwrap().unwrap();
+ line
+}
+
tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7);
mod no_lint_if_stmt_borrows {
- mod issue_3792 {
- use std::io::{self, BufRead, Stdin};
+ use std::cell::RefCell;
+ use std::rc::{Rc, Weak};
+ struct Bar;
- fn read_line() -> String {
- let stdin = io::stdin();
- let line = stdin.lock().lines().next().unwrap().unwrap();
- line
+ impl Bar {
+ fn new() -> Self {
+ Bar {}
}
- }
-
- mod issue_3324 {
- use std::cell::RefCell;
- use std::rc::{Rc, Weak};
-
- fn test(value: Weak<RefCell<Bar>>) -> u32 {
- let value = value.upgrade().unwrap();
- let ret = value.borrow().baz();
- ret
+ fn baz(&self) -> u32 {
+ 0
}
+ }
- struct Bar;
+ fn issue_3324(value: Weak<RefCell<Bar>>) -> u32 {
+ let value = value.upgrade().unwrap();
+ let ret = value.borrow().baz();
+ ret
+ }
- impl Bar {
- fn new() -> Self {
- Bar {}
- }
- fn baz(&self) -> u32 {
- 0
- }
+ fn borrows_in_closure(value: Weak<RefCell<Bar>>) -> u32 {
+ fn f(mut x: impl FnMut() -> u32) -> impl FnMut() -> u32 {
+ x
}
- fn main() {
- let a = Rc::new(RefCell::new(Bar::new()));
- let b = Rc::downgrade(&a);
- test(b);
- }
+ let value = value.upgrade().unwrap();
+ let ret = f(|| value.borrow().baz())();
+ ret
}
mod free_function {
@@ -166,4 +169,14 @@ mod issue_5729 {
}
}
+// https://github.com/rust-lang/rust-clippy/issues/11167
+macro_rules! fn_in_macro {
+ ($b:block) => {
+ fn f() -> usize $b
+ }
+}
+fn_in_macro!({
+ return 1;
+});
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/let_and_return.stderr b/src/tools/clippy/tests/ui/let_and_return.stderr
index 17fd694bf..4ca0a05c8 100644
--- a/src/tools/clippy/tests/ui/let_and_return.stderr
+++ b/src/tools/clippy/tests/ui/let_and_return.stderr
@@ -1,5 +1,5 @@
error: returning the result of a `let` binding from a block
- --> $DIR/let_and_return.rs:7:5
+ --> $DIR/let_and_return.rs:9:5
|
LL | let x = 5;
| ---------- unnecessary `let` binding
@@ -14,7 +14,7 @@ LL ~ 5
|
error: returning the result of a `let` binding from a block
- --> $DIR/let_and_return.rs:13:9
+ --> $DIR/let_and_return.rs:15:9
|
LL | let x = 5;
| ---------- unnecessary `let` binding
@@ -28,7 +28,21 @@ LL ~ 5
|
error: returning the result of a `let` binding from a block
- --> $DIR/let_and_return.rs:164:13
+ --> $DIR/let_and_return.rs:77:5
+ |
+LL | let line = stdin.lock().lines().next().unwrap().unwrap();
+ | --------------------------------------------------------- unnecessary `let` binding
+LL | line
+ | ^^^^
+ |
+help: return the expression directly
+ |
+LL ~
+LL ~ stdin.lock().lines().next().unwrap().unwrap()
+ |
+
+error: returning the result of a `let` binding from a block
+ --> $DIR/let_and_return.rs:167:13
|
LL | let clone = Arc::clone(&self.foo);
| ---------------------------------- unnecessary `let` binding
@@ -41,5 +55,5 @@ LL ~
LL ~ Arc::clone(&self.foo) as _
|
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/let_underscore_lock.rs b/src/tools/clippy/tests/ui/let_underscore_lock.rs
index 4dff4d766..87f12e278 100644
--- a/src/tools/clippy/tests/ui/let_underscore_lock.rs
+++ b/src/tools/clippy/tests/ui/let_underscore_lock.rs
@@ -3,7 +3,8 @@
extern crate parking_lot;
fn main() {
- use parking_lot::{lock_api::RawMutex, Mutex, RwLock};
+ use parking_lot::lock_api::RawMutex;
+ use parking_lot::{Mutex, RwLock};
let p_m: Mutex<()> = Mutex::const_new(RawMutex::INIT, ());
let _ = p_m.lock();
diff --git a/src/tools/clippy/tests/ui/let_underscore_lock.stderr b/src/tools/clippy/tests/ui/let_underscore_lock.stderr
index f137d4112..5027e6b3c 100644
--- a/src/tools/clippy/tests/ui/let_underscore_lock.stderr
+++ b/src/tools/clippy/tests/ui/let_underscore_lock.stderr
@@ -1,5 +1,5 @@
error: non-binding `let` on a synchronization lock
- --> $DIR/let_underscore_lock.rs:9:5
+ --> $DIR/let_underscore_lock.rs:10:5
|
LL | let _ = p_m.lock();
| ^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | let _ = p_m.lock();
= note: `-D clippy::let-underscore-lock` implied by `-D warnings`
error: non-binding `let` on a synchronization lock
- --> $DIR/let_underscore_lock.rs:12:5
+ --> $DIR/let_underscore_lock.rs:13:5
|
LL | let _ = p_m1.lock();
| ^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL | let _ = p_m1.lock();
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
error: non-binding `let` on a synchronization lock
- --> $DIR/let_underscore_lock.rs:15:5
+ --> $DIR/let_underscore_lock.rs:16:5
|
LL | let _ = p_rw.read();
| ^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL | let _ = p_rw.read();
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
error: non-binding `let` on a synchronization lock
- --> $DIR/let_underscore_lock.rs:16:5
+ --> $DIR/let_underscore_lock.rs:17:5
|
LL | let _ = p_rw.write();
| ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.rs b/src/tools/clippy/tests/ui/let_underscore_untyped.rs
index 431d83778..18630c27f 100644
--- a/src/tools/clippy/tests/ui/let_underscore_untyped.rs
+++ b/src/tools/clippy/tests/ui/let_underscore_untyped.rs
@@ -7,8 +7,9 @@ extern crate proc_macros;
use proc_macros::with_span;
use clippy_utils::is_from_proc_macro;
+use std::boxed::Box;
+use std::fmt::Display;
use std::future::Future;
-use std::{boxed::Box, fmt::Display};
fn a() -> u32 {
1
diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
index bbf2508af..e0c39b6ee 100644
--- a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
+++ b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
@@ -1,60 +1,60 @@
error: non-binding `let` without a type annotation
- --> $DIR/let_underscore_untyped.rs:50:5
+ --> $DIR/let_underscore_untyped.rs:51:5
|
LL | let _ = a();
| ^^^^^^^^^^^^
|
help: consider adding a type annotation
- --> $DIR/let_underscore_untyped.rs:50:10
+ --> $DIR/let_underscore_untyped.rs:51:10
|
LL | let _ = a();
| ^
= note: `-D clippy::let-underscore-untyped` implied by `-D warnings`
error: non-binding `let` without a type annotation
- --> $DIR/let_underscore_untyped.rs:51:5
+ --> $DIR/let_underscore_untyped.rs:52:5
|
LL | let _ = b(1);
| ^^^^^^^^^^^^^
|
help: consider adding a type annotation
- --> $DIR/let_underscore_untyped.rs:51:10
+ --> $DIR/let_underscore_untyped.rs:52:10
|
LL | let _ = b(1);
| ^
error: non-binding `let` without a type annotation
- --> $DIR/let_underscore_untyped.rs:53:5
+ --> $DIR/let_underscore_untyped.rs:54:5
|
LL | let _ = d(&1);
| ^^^^^^^^^^^^^^
|
help: consider adding a type annotation
- --> $DIR/let_underscore_untyped.rs:53:10
+ --> $DIR/let_underscore_untyped.rs:54:10
|
LL | let _ = d(&1);
| ^
error: non-binding `let` without a type annotation
- --> $DIR/let_underscore_untyped.rs:54:5
+ --> $DIR/let_underscore_untyped.rs:55:5
|
LL | let _ = e();
| ^^^^^^^^^^^^
|
help: consider adding a type annotation
- --> $DIR/let_underscore_untyped.rs:54:10
+ --> $DIR/let_underscore_untyped.rs:55:10
|
LL | let _ = e();
| ^
error: non-binding `let` without a type annotation
- --> $DIR/let_underscore_untyped.rs:55:5
+ --> $DIR/let_underscore_untyped.rs:56:5
|
LL | let _ = f();
| ^^^^^^^^^^^^
|
help: consider adding a type annotation
- --> $DIR/let_underscore_untyped.rs:55:10
+ --> $DIR/let_underscore_untyped.rs:56:10
|
LL | let _ = f();
| ^
diff --git a/src/tools/clippy/tests/ui/manual_filter.stderr b/src/tools/clippy/tests/ui/manual_filter.stderr
index 53dea9229..f62d3e960 100644
--- a/src/tools/clippy/tests/ui/manual_filter.stderr
+++ b/src/tools/clippy/tests/ui/manual_filter.stderr
@@ -8,7 +8,7 @@ LL | | if x > 0 {
... |
LL | | },
LL | | };
- | |_____^ help: try this: `Some(0).filter(|&x| x <= 0)`
+ | |_____^ help: try: `Some(0).filter(|&x| x <= 0)`
|
= note: `-D clippy::manual-filter` implied by `-D warnings`
@@ -22,7 +22,7 @@ LL | | None
... |
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some(1).filter(|&x| x <= 0)`
+ | |_____^ help: try: `Some(1).filter(|&x| x <= 0)`
error: manual implementation of `Option::filter`
--> $DIR/manual_filter.rs:29:5
@@ -34,7 +34,7 @@ LL | | None
... |
LL | | _ => None,
LL | | };
- | |_____^ help: try this: `Some(2).filter(|&x| x <= 0)`
+ | |_____^ help: try: `Some(2).filter(|&x| x <= 0)`
error: manual implementation of `Option::filter`
--> $DIR/manual_filter.rs:40:5
@@ -46,7 +46,7 @@ LL | | Some(x)
... |
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some(3).filter(|&x| x > 0)`
+ | |_____^ help: try: `Some(3).filter(|&x| x > 0)`
error: manual implementation of `Option::filter`
--> $DIR/manual_filter.rs:52:5
@@ -58,7 +58,7 @@ LL | | Some(x) => {
... |
LL | | },
LL | | };
- | |_____^ help: try this: `y.filter(|&x| x <= 0)`
+ | |_____^ help: try: `y.filter(|&x| x <= 0)`
error: manual implementation of `Option::filter`
--> $DIR/manual_filter.rs:64:5
@@ -70,7 +70,7 @@ LL | | Some(x)
... |
LL | | _ => None,
LL | | };
- | |_____^ help: try this: `Some(5).filter(|&x| x > 0)`
+ | |_____^ help: try: `Some(5).filter(|&x| x > 0)`
error: manual implementation of `Option::filter`
--> $DIR/manual_filter.rs:75:5
@@ -82,7 +82,7 @@ LL | | Some(x)
... |
LL | | _ => None,
LL | | };
- | |_____^ help: try this: `Some(6).as_ref().filter(|&x| x > &0)`
+ | |_____^ help: try: `Some(6).as_ref().filter(|&x| x > &0)`
error: manual implementation of `Option::filter`
--> $DIR/manual_filter.rs:87:5
@@ -94,7 +94,7 @@ LL | | Some(x)
... |
LL | | _ => None,
LL | | };
- | |_____^ help: try this: `Some(String::new()).filter(|x| external_cond)`
+ | |_____^ help: try: `Some(String::new()).filter(|x| external_cond)`
error: manual implementation of `Option::filter`
--> $DIR/manual_filter.rs:98:5
@@ -104,7 +104,7 @@ LL | | if external_cond { Some(x) } else { None }
LL | | } else {
LL | | None
LL | | };
- | |_____^ help: try this: `Some(7).filter(|&x| external_cond)`
+ | |_____^ help: try: `Some(7).filter(|&x| external_cond)`
error: manual implementation of `Option::filter`
--> $DIR/manual_filter.rs:104:5
@@ -116,7 +116,7 @@ LL | | Some(x)
... |
LL | | _ => None,
LL | | };
- | |_____^ help: try this: `Some(8).filter(|&x| x != 0)`
+ | |_____^ help: try: `Some(8).filter(|&x| x != 0)`
error: manual implementation of `Option::filter`
--> $DIR/manual_filter.rs:115:5
@@ -128,7 +128,7 @@ LL | | Some(x)
... |
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some(9).filter(|&x| x > 10 && x < 100)`
+ | |_____^ help: try: `Some(9).filter(|&x| x > 10 && x < 100)`
error: manual implementation of `Option::filter`
--> $DIR/manual_filter.rs:141:5
@@ -142,7 +142,7 @@ LL | | None => None,
LL | | };
| |_____^
|
-help: try this
+help: try
|
LL ~ Some(11).filter(|&x| {
LL + println!("foo");
@@ -161,7 +161,7 @@ LL | | Some(x)
... |
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some(14).filter(|&x| unsafe { f(x) })`
+ | |_____^ help: try: `Some(14).filter(|&x| unsafe { f(x) })`
error: manual implementation of `Option::filter`
--> $DIR/manual_filter.rs:195:13
@@ -173,7 +173,7 @@ LL | | if f(x) { Some(x) } else { None }
LL | | },
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some(15).filter(|&x| unsafe { f(x) })`
+ | |_____^ help: try: `Some(15).filter(|&x| unsafe { f(x) })`
error: manual implementation of `Option::filter`
--> $DIR/manual_filter.rs:205:12
@@ -185,7 +185,7 @@ LL | | if x % 2 == 0 { Some(x) } else { None }
LL | | } else {
LL | | None
LL | | };
- | |_____^ help: try this: `{ Some(16).filter(|&x| x % 2 == 0) }`
+ | |_____^ help: try: `{ Some(16).filter(|&x| x % 2 == 0) }`
error: aborting due to 15 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.fixed b/src/tools/clippy/tests/ui/manual_filter_map.fixed
index 9dd376df2..35872a39a 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.fixed
+++ b/src/tools/clippy/tests/ui/manual_filter_map.fixed
@@ -120,3 +120,27 @@ fn issue_8920() {
.iter()
.filter_map(|f| f.result_field.to_owned().ok());
}
+
+fn issue8010() {
+ #[derive(Clone)]
+ enum Enum {
+ A(i32),
+ B,
+ }
+
+ let iter = [Enum::A(123), Enum::B].into_iter();
+
+ let _x = iter.clone().filter_map(|x| match x { Enum::A(s) => Some(s), _ => None });
+ let _x = iter.clone().filter(|x| matches!(x, Enum::B)).map(|x| match x {
+ Enum::A(s) => s,
+ _ => unreachable!(),
+ });
+ let _x = iter
+ .clone()
+ .filter_map(|x| match x { Enum::A(s) => Some(s), _ => None });
+ #[allow(clippy::unused_unit)]
+ let _x = iter
+ .clone()
+ .filter(|x| matches!(x, Enum::B))
+ .map(|x| if let Enum::B = x { () } else { unreachable!() });
+}
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.rs b/src/tools/clippy/tests/ui/manual_filter_map.rs
index 6dd1e066a..50d8d2722 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.rs
+++ b/src/tools/clippy/tests/ui/manual_filter_map.rs
@@ -133,3 +133,31 @@ fn issue_8920() {
.filter(|f| f.result_field.is_ok())
.map(|f| f.result_field.to_owned().unwrap());
}
+
+fn issue8010() {
+ #[derive(Clone)]
+ enum Enum {
+ A(i32),
+ B,
+ }
+
+ let iter = [Enum::A(123), Enum::B].into_iter();
+
+ let _x = iter.clone().filter(|x| matches!(x, Enum::A(_))).map(|x| match x {
+ Enum::A(s) => s,
+ _ => unreachable!(),
+ });
+ let _x = iter.clone().filter(|x| matches!(x, Enum::B)).map(|x| match x {
+ Enum::A(s) => s,
+ _ => unreachable!(),
+ });
+ let _x = iter
+ .clone()
+ .filter(|x| matches!(x, Enum::A(_)))
+ .map(|x| if let Enum::A(s) = x { s } else { unreachable!() });
+ #[allow(clippy::unused_unit)]
+ let _x = iter
+ .clone()
+ .filter(|x| matches!(x, Enum::B))
+ .map(|x| if let Enum::B = x { () } else { unreachable!() });
+}
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.stderr b/src/tools/clippy/tests/ui/manual_filter_map.stderr
index 882468b0f..0e8672c02 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.stderr
+++ b/src/tools/clippy/tests/ui/manual_filter_map.stderr
@@ -4,6 +4,11 @@ error: `filter(..).map(..)` can be simplified as `filter_map(..)`
LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))`
|
+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
+ --> $DIR/manual_filter_map.rs:9:30
+ |
+LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
+ | ^^^^^^^^^^
= note: `-D clippy::manual-filter-map` implied by `-D warnings`
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
@@ -11,12 +16,24 @@ error: `filter(..).map(..)` can be simplified as `filter_map(..)`
|
LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))`
+ |
+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
+ --> $DIR/manual_filter_map.rs:12:31
+ |
+LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
+ | ^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
--> $DIR/manual_filter_map.rs:15:19
|
LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())`
+ |
+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
+ --> $DIR/manual_filter_map.rs:15:31
+ |
+LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
+ | ^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
--> $DIR/manual_filter_map.rs:18:10
@@ -25,6 +42,12 @@ LL | .filter(|&x| to_ref(to_opt(x)).is_some())
| __________^
LL | | .map(|y| to_ref(to_opt(y)).unwrap());
| |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))`
+ |
+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
+ --> $DIR/manual_filter_map.rs:18:22
+ |
+LL | .filter(|&x| to_ref(to_opt(x)).is_some())
+ | ^^^^^^^^^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
--> $DIR/manual_filter_map.rs:21:10
@@ -33,6 +56,12 @@ LL | .filter(|x| to_ref(to_opt(*x)).is_some())
| __________^
LL | | .map(|y| to_ref(to_opt(y)).unwrap());
| |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))`
+ |
+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
+ --> $DIR/manual_filter_map.rs:21:21
+ |
+LL | .filter(|x| to_ref(to_opt(*x)).is_some())
+ | ^^^^^^^^^^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
--> $DIR/manual_filter_map.rs:25:10
@@ -41,6 +70,12 @@ LL | .filter(|&x| to_ref(to_res(x)).is_ok())
| __________^
LL | | .map(|y| to_ref(to_res(y)).unwrap());
| |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())`
+ |
+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
+ --> $DIR/manual_filter_map.rs:25:22
+ |
+LL | .filter(|&x| to_ref(to_res(x)).is_ok())
+ | ^^^^^^^^^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
--> $DIR/manual_filter_map.rs:28:10
@@ -49,6 +84,12 @@ LL | .filter(|x| to_ref(to_res(*x)).is_ok())
| __________^
LL | | .map(|y| to_ref(to_res(y)).unwrap());
| |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())`
+ |
+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
+ --> $DIR/manual_filter_map.rs:28:21
+ |
+LL | .filter(|x| to_ref(to_res(*x)).is_ok())
+ | ^^^^^^^^^^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
--> $DIR/manual_filter_map.rs:34:27
@@ -75,6 +116,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
|
LL | iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())`
+ |
+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
+ --> $DIR/manual_filter_map.rs:37:41
+ |
+LL | iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
+ | ^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
--> $DIR/manual_filter_map.rs:39:30
@@ -117,6 +164,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
|
LL | iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())`
+ |
+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
+ --> $DIR/manual_filter_map.rs:45:45
+ |
+LL | iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
+ | ^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
--> $DIR/manual_filter_map.rs:93:10
@@ -190,5 +243,23 @@ LL | .filter(|f| f.result_field.is_ok())
LL | | .map(|f| f.result_field.to_owned().unwrap());
| |____________________________________________________^ help: try: `filter_map(|f| f.result_field.to_owned().ok())`
-error: aborting due to 27 previous errors
+error: `filter(..).map(..)` can be simplified as `filter_map(..)`
+ --> $DIR/manual_filter_map.rs:146:27
+ |
+LL | let _x = iter.clone().filter(|x| matches!(x, Enum::A(_))).map(|x| match x {
+ | ___________________________^
+LL | | Enum::A(s) => s,
+LL | | _ => unreachable!(),
+LL | | });
+ | |______^ help: try: `filter_map(|x| match x { Enum::A(s) => Some(s), _ => None })`
+
+error: `filter(..).map(..)` can be simplified as `filter_map(..)`
+ --> $DIR/manual_filter_map.rs:156:10
+ |
+LL | .filter(|x| matches!(x, Enum::A(_)))
+ | __________^
+LL | | .map(|x| if let Enum::A(s) = x { s } else { unreachable!() });
+ | |_____________________________________________________________________^ help: try: `filter_map(|x| match x { Enum::A(s) => Some(s), _ => None })`
+
+error: aborting due to 29 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_find_map.stderr b/src/tools/clippy/tests/ui/manual_find_map.stderr
index 693a06bb5..4e52b5efa 100644
--- a/src/tools/clippy/tests/ui/manual_find_map.stderr
+++ b/src/tools/clippy/tests/ui/manual_find_map.stderr
@@ -4,6 +4,11 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))`
|
+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
+ --> $DIR/manual_find_map.rs:9:28
+ |
+LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
+ | ^^^^^^^^^^
= note: `-D clippy::manual-find-map` implied by `-D warnings`
error: `find(..).map(..)` can be simplified as `find_map(..)`
@@ -11,12 +16,24 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
|
LL | let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))`
+ |
+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
+ --> $DIR/manual_find_map.rs:12:29
+ |
+LL | let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
+ | ^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
--> $DIR/manual_find_map.rs:15:19
|
LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())`
+ |
+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
+ --> $DIR/manual_find_map.rs:15:29
+ |
+LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
+ | ^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
--> $DIR/manual_find_map.rs:18:10
@@ -25,6 +42,12 @@ LL | .find(|&x| to_ref(to_opt(x)).is_some())
| __________^
LL | | .map(|y| to_ref(to_opt(y)).unwrap());
| |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))`
+ |
+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
+ --> $DIR/manual_find_map.rs:18:20
+ |
+LL | .find(|&x| to_ref(to_opt(x)).is_some())
+ | ^^^^^^^^^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
--> $DIR/manual_find_map.rs:21:10
@@ -33,6 +56,12 @@ LL | .find(|x| to_ref(to_opt(*x)).is_some())
| __________^
LL | | .map(|y| to_ref(to_opt(y)).unwrap());
| |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))`
+ |
+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
+ --> $DIR/manual_find_map.rs:21:19
+ |
+LL | .find(|x| to_ref(to_opt(*x)).is_some())
+ | ^^^^^^^^^^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
--> $DIR/manual_find_map.rs:25:10
@@ -41,6 +70,12 @@ LL | .find(|&x| to_ref(to_res(x)).is_ok())
| __________^
LL | | .map(|y| to_ref(to_res(y)).unwrap());
| |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())`
+ |
+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
+ --> $DIR/manual_find_map.rs:25:20
+ |
+LL | .find(|&x| to_ref(to_res(x)).is_ok())
+ | ^^^^^^^^^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
--> $DIR/manual_find_map.rs:28:10
@@ -49,6 +84,12 @@ LL | .find(|x| to_ref(to_res(*x)).is_ok())
| __________^
LL | | .map(|y| to_ref(to_res(y)).unwrap());
| |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())`
+ |
+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
+ --> $DIR/manual_find_map.rs:28:19
+ |
+LL | .find(|x| to_ref(to_res(*x)).is_ok())
+ | ^^^^^^^^^^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
--> $DIR/manual_find_map.rs:34:26
@@ -91,6 +132,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
|
LL | iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())`
+ |
+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
+ --> $DIR/manual_find_map.rs:40:41
+ |
+LL | iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
+ | ^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
--> $DIR/manual_find_map.rs:42:30
@@ -133,6 +180,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
|
LL | iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())`
+ |
+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
+ --> $DIR/manual_find_map.rs:48:45
+ |
+LL | iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
+ | ^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
--> $DIR/manual_find_map.rs:96:10
diff --git a/src/tools/clippy/tests/ui/manual_float_methods.rs b/src/tools/clippy/tests/ui/manual_float_methods.rs
new file mode 100644
index 000000000..af9076cfb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_float_methods.rs
@@ -0,0 +1,55 @@
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(clippy::needless_if, unused)]
+#![warn(clippy::manual_is_infinite, clippy::manual_is_finite)]
+#![feature(inline_const)]
+
+#[macro_use]
+extern crate proc_macros;
+
+const INFINITE: f32 = f32::INFINITY;
+const NEG_INFINITE: f32 = f32::NEG_INFINITY;
+
+fn fn_test() -> f64 {
+ f64::NEG_INFINITY
+}
+
+fn fn_test_not_inf() -> f64 {
+ 112.0
+}
+
+fn main() {
+ let x = 1.0f32;
+ if x == f32::INFINITY || x == f32::NEG_INFINITY {}
+ if x != f32::INFINITY && x != f32::NEG_INFINITY {}
+ if x == INFINITE || x == NEG_INFINITE {}
+ if x != INFINITE && x != NEG_INFINITE {}
+ let x = 1.0f64;
+ if x == f64::INFINITY || x == f64::NEG_INFINITY {}
+ if x != f64::INFINITY && x != f64::NEG_INFINITY {}
+ // Don't lint
+ if x.is_infinite() {}
+ if x.is_finite() {}
+ if x.abs() < f64::INFINITY {}
+ if f64::INFINITY > x.abs() {}
+ if f64::abs(x) < f64::INFINITY {}
+ if f64::INFINITY > f64::abs(x) {}
+ // Is not evaluated by `clippy_utils::constant`
+ if x != f64::INFINITY && x != fn_test() {}
+ // Not -inf
+ if x != f64::INFINITY && x != fn_test_not_inf() {}
+ const X: f64 = 1.0f64;
+ // Will be linted if `const_float_classify` is enabled
+ if const { X == f64::INFINITY || X == f64::NEG_INFINITY } {}
+ if const { X != f64::INFINITY && X != f64::NEG_INFINITY } {}
+ external! {
+ let x = 1.0;
+ if x == f32::INFINITY || x == f32::NEG_INFINITY {}
+ if x != f32::INFINITY && x != f32::NEG_INFINITY {}
+ }
+ with_span! {
+ span
+ let x = 1.0;
+ if x == f32::INFINITY || x == f32::NEG_INFINITY {}
+ if x != f32::INFINITY && x != f32::NEG_INFINITY {}
+ }
+}
diff --git a/src/tools/clippy/tests/ui/manual_float_methods.stderr b/src/tools/clippy/tests/ui/manual_float_methods.stderr
new file mode 100644
index 000000000..a56118b31
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_float_methods.stderr
@@ -0,0 +1,80 @@
+error: manually checking if a float is infinite
+ --> $DIR/manual_float_methods.rs:22:8
+ |
+LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
+ |
+ = note: `-D clippy::manual-is-infinite` implied by `-D warnings`
+
+error: manually checking if a float is finite
+ --> $DIR/manual_float_methods.rs:23:8
+ |
+LL | if x != f32::INFINITY && x != f32::NEG_INFINITY {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::manual-is-finite` implied by `-D warnings`
+help: use the dedicated method instead
+ |
+LL | if x.is_finite() {}
+ | ~~~~~~~~~~~~~
+help: this will alter how it handles NaN; if that is a problem, use instead
+ |
+LL | if x.is_finite() || x.is_nan() {}
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: or, for conciseness
+ |
+LL | if !x.is_infinite() {}
+ | ~~~~~~~~~~~~~~~~
+
+error: manually checking if a float is infinite
+ --> $DIR/manual_float_methods.rs:24:8
+ |
+LL | if x == INFINITE || x == NEG_INFINITE {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
+
+error: manually checking if a float is finite
+ --> $DIR/manual_float_methods.rs:25:8
+ |
+LL | if x != INFINITE && x != NEG_INFINITE {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: use the dedicated method instead
+ |
+LL | if x.is_finite() {}
+ | ~~~~~~~~~~~~~
+help: this will alter how it handles NaN; if that is a problem, use instead
+ |
+LL | if x.is_finite() || x.is_nan() {}
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: or, for conciseness
+ |
+LL | if !x.is_infinite() {}
+ | ~~~~~~~~~~~~~~~~
+
+error: manually checking if a float is infinite
+ --> $DIR/manual_float_methods.rs:27:8
+ |
+LL | if x == f64::INFINITY || x == f64::NEG_INFINITY {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()`
+
+error: manually checking if a float is finite
+ --> $DIR/manual_float_methods.rs:28:8
+ |
+LL | if x != f64::INFINITY && x != f64::NEG_INFINITY {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: use the dedicated method instead
+ |
+LL | if x.is_finite() {}
+ | ~~~~~~~~~~~~~
+help: this will alter how it handles NaN; if that is a problem, use instead
+ |
+LL | if x.is_finite() || x.is_nan() {}
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: or, for conciseness
+ |
+LL | if !x.is_infinite() {}
+ | ~~~~~~~~~~~~~~~~
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_let_else.rs b/src/tools/clippy/tests/ui/manual_let_else.rs
index 46241afec..381b83409 100644
--- a/src/tools/clippy/tests/ui/manual_let_else.rs
+++ b/src/tools/clippy/tests/ui/manual_let_else.rs
@@ -279,7 +279,9 @@ fn not_fire() {
create_binding_if_some_nf!(v, g());
// Already a let-else
- let Some(a) = (if let Some(b) = Some(Some(())) { b } else { return }) else { panic!() };
+ let Some(a) = (if let Some(b) = Some(Some(())) { b } else { return }) else {
+ panic!()
+ };
// If a type annotation is present, don't lint as
// expressing the type might be too hard
@@ -304,9 +306,7 @@ fn not_fire() {
let _x = if let Some(x) = Some(1) {
x
} else {
- let Some(_z) = Some(3) else {
- return
- };
+ let Some(_z) = Some(3) else { return };
1
};
diff --git a/src/tools/clippy/tests/ui/manual_let_else.stderr b/src/tools/clippy/tests/ui/manual_let_else.stderr
index 1eada4f99..912302b17 100644
--- a/src/tools/clippy/tests/ui/manual_let_else.stderr
+++ b/src/tools/clippy/tests/ui/manual_let_else.stderr
@@ -352,7 +352,7 @@ LL + };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:297:5
+ --> $DIR/manual_let_else.rs:299:5
|
LL | / let _ = match ff {
LL | | Some(value) => value,
diff --git a/src/tools/clippy/tests/ui/manual_let_else_question_mark.fixed b/src/tools/clippy/tests/ui/manual_let_else_question_mark.fixed
new file mode 100644
index 000000000..02308bc7c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_let_else_question_mark.fixed
@@ -0,0 +1,63 @@
+//@run-rustfix
+#![allow(unused_braces, unused_variables, dead_code)]
+#![allow(
+ clippy::collapsible_else_if,
+ clippy::unused_unit,
+ clippy::let_unit_value,
+ clippy::match_single_binding,
+ clippy::never_loop
+)]
+#![warn(clippy::manual_let_else, clippy::question_mark)]
+
+enum Variant {
+ A(usize, usize),
+ B(usize),
+ C,
+}
+
+fn g() -> Option<(u8, u8)> {
+ None
+}
+
+fn e() -> Variant {
+ Variant::A(0, 0)
+}
+
+fn main() {}
+
+fn foo() -> Option<()> {
+ // Fire here, normal case
+ let v = g()?;
+
+ // Don't fire here, the pattern is refutable
+ let Variant::A(v, w) = e() else { return None };
+
+ // Fire here, the pattern is irrefutable
+ let (v, w) = g()?;
+
+ // Don't fire manual_let_else in this instance: question mark can be used instead.
+ let v = g()?;
+
+ // Do fire manual_let_else in this instance: question mark cannot be used here due to the return
+ // body.
+ let Some(v) = g() else {
+ return Some(());
+ };
+
+ // Here we could also fire the question_mark lint, but we don't (as it's a match and not an if let).
+ // So we still emit manual_let_else here. For the *resulting* code, we *do* emit the question_mark
+ // lint, so for rustfix reasons, we allow the question_mark lint here.
+ #[allow(clippy::question_mark)]
+ {
+ let Some(v) = g() else { return None };
+ }
+
+ // This is a copy of the case above where we'd fire the question_mark lint, but here we have allowed
+ // it. Make sure that manual_let_else is fired as the fallback.
+ #[allow(clippy::question_mark)]
+ {
+ let Some(v) = g() else { return None };
+ }
+
+ Some(())
+}
diff --git a/src/tools/clippy/tests/ui/manual_let_else_question_mark.rs b/src/tools/clippy/tests/ui/manual_let_else_question_mark.rs
new file mode 100644
index 000000000..9c7ad386d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_let_else_question_mark.rs
@@ -0,0 +1,68 @@
+//@run-rustfix
+#![allow(unused_braces, unused_variables, dead_code)]
+#![allow(
+ clippy::collapsible_else_if,
+ clippy::unused_unit,
+ clippy::let_unit_value,
+ clippy::match_single_binding,
+ clippy::never_loop
+)]
+#![warn(clippy::manual_let_else, clippy::question_mark)]
+
+enum Variant {
+ A(usize, usize),
+ B(usize),
+ C,
+}
+
+fn g() -> Option<(u8, u8)> {
+ None
+}
+
+fn e() -> Variant {
+ Variant::A(0, 0)
+}
+
+fn main() {}
+
+fn foo() -> Option<()> {
+ // Fire here, normal case
+ let Some(v) = g() else { return None };
+
+ // Don't fire here, the pattern is refutable
+ let Variant::A(v, w) = e() else { return None };
+
+ // Fire here, the pattern is irrefutable
+ let Some((v, w)) = g() else { return None };
+
+ // Don't fire manual_let_else in this instance: question mark can be used instead.
+ let v = if let Some(v_some) = g() { v_some } else { return None };
+
+ // Do fire manual_let_else in this instance: question mark cannot be used here due to the return
+ // body.
+ let v = if let Some(v_some) = g() {
+ v_some
+ } else {
+ return Some(());
+ };
+
+ // Here we could also fire the question_mark lint, but we don't (as it's a match and not an if let).
+ // So we still emit manual_let_else here. For the *resulting* code, we *do* emit the question_mark
+ // lint, so for rustfix reasons, we allow the question_mark lint here.
+ #[allow(clippy::question_mark)]
+ {
+ let v = match g() {
+ Some(v_some) => v_some,
+ _ => return None,
+ };
+ }
+
+ // This is a copy of the case above where we'd fire the question_mark lint, but here we have allowed
+ // it. Make sure that manual_let_else is fired as the fallback.
+ #[allow(clippy::question_mark)]
+ {
+ let v = if let Some(v_some) = g() { v_some } else { return None };
+ }
+
+ Some(())
+}
diff --git a/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr b/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr
new file mode 100644
index 000000000..d7d2e127e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr
@@ -0,0 +1,55 @@
+error: this `let...else` may be rewritten with the `?` operator
+ --> $DIR/manual_let_else_question_mark.rs:30:5
+ |
+LL | let Some(v) = g() else { return None };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `let v = g()?;`
+ |
+ = note: `-D clippy::question-mark` implied by `-D warnings`
+
+error: this `let...else` may be rewritten with the `?` operator
+ --> $DIR/manual_let_else_question_mark.rs:36:5
+ |
+LL | let Some((v, w)) = g() else { return None };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `let (v, w) = g()?;`
+
+error: this block may be rewritten with the `?` operator
+ --> $DIR/manual_let_else_question_mark.rs:39:13
+ |
+LL | let v = if let Some(v_some) = g() { v_some } else { return None };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `g()?`
+
+error: this could be rewritten as `let...else`
+ --> $DIR/manual_let_else_question_mark.rs:43:5
+ |
+LL | / let v = if let Some(v_some) = g() {
+LL | | v_some
+LL | | } else {
+LL | | return Some(());
+LL | | };
+ | |______^
+ |
+ = note: `-D clippy::manual-let-else` implied by `-D warnings`
+help: consider writing
+ |
+LL ~ let Some(v) = g() else {
+LL + return Some(());
+LL + };
+ |
+
+error: this could be rewritten as `let...else`
+ --> $DIR/manual_let_else_question_mark.rs:54:9
+ |
+LL | / let v = match g() {
+LL | | Some(v_some) => v_some,
+LL | | _ => return None,
+LL | | };
+ | |__________^ help: consider writing: `let Some(v) = g() else { return None };`
+
+error: this could be rewritten as `let...else`
+ --> $DIR/manual_let_else_question_mark.rs:64:9
+ |
+LL | let v = if let Some(v_some) = g() { v_some } else { return None };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return None };`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_map_option.stderr b/src/tools/clippy/tests/ui/manual_map_option.stderr
index cdc2c0e62..3f9caad4e 100644
--- a/src/tools/clippy/tests/ui/manual_map_option.stderr
+++ b/src/tools/clippy/tests/ui/manual_map_option.stderr
@@ -5,7 +5,7 @@ LL | / match Some(0) {
LL | | Some(_) => Some(2),
LL | | None::<u32> => None,
LL | | };
- | |_____^ help: try this: `Some(0).map(|_| 2)`
+ | |_____^ help: try: `Some(0).map(|_| 2)`
|
= note: `-D clippy::manual-map` implied by `-D warnings`
@@ -16,7 +16,7 @@ LL | / match Some(0) {
LL | | Some(x) => Some(x + 1),
LL | | _ => None,
LL | | };
- | |_____^ help: try this: `Some(0).map(|x| x + 1)`
+ | |_____^ help: try: `Some(0).map(|x| x + 1)`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:25:5
@@ -25,7 +25,7 @@ LL | / match Some("") {
LL | | Some(x) => Some(x.is_empty()),
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some("").map(|x| x.is_empty())`
+ | |_____^ help: try: `Some("").map(|x| x.is_empty())`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:30:5
@@ -35,7 +35,7 @@ LL | | Some(!x)
LL | | } else {
LL | | None
LL | | };
- | |_____^ help: try this: `Some(0).map(|x| !x)`
+ | |_____^ help: try: `Some(0).map(|x| !x)`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:37:5
@@ -44,7 +44,7 @@ LL | / match Some(0) {
LL | | Some(x) => { Some(std::convert::identity(x)) }
LL | | None => { None }
LL | | };
- | |_____^ help: try this: `Some(0).map(std::convert::identity)`
+ | |_____^ help: try: `Some(0).map(std::convert::identity)`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:42:5
@@ -53,7 +53,7 @@ LL | / match Some(&String::new()) {
LL | | Some(x) => Some(str::len(x)),
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some(&String::new()).map(|x| str::len(x))`
+ | |_____^ help: try: `Some(&String::new()).map(|x| str::len(x))`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:52:5
@@ -62,7 +62,7 @@ LL | / match &Some([0, 1]) {
LL | | Some(x) => Some(x[0]),
LL | | &None => None,
LL | | };
- | |_____^ help: try this: `Some([0, 1]).as_ref().map(|x| x[0])`
+ | |_____^ help: try: `Some([0, 1]).as_ref().map(|x| x[0])`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:57:5
@@ -71,7 +71,7 @@ LL | / match &Some(0) {
LL | | &Some(x) => Some(x * 2),
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some(0).map(|x| x * 2)`
+ | |_____^ help: try: `Some(0).map(|x| x * 2)`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:62:5
@@ -80,7 +80,7 @@ LL | / match Some(String::new()) {
LL | | Some(ref x) => Some(x.is_empty()),
LL | | _ => None,
LL | | };
- | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())`
+ | |_____^ help: try: `Some(String::new()).as_ref().map(|x| x.is_empty())`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:67:5
@@ -89,7 +89,7 @@ LL | / match &&Some(String::new()) {
LL | | Some(x) => Some(x.len()),
LL | | _ => None,
LL | | };
- | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())`
+ | |_____^ help: try: `Some(String::new()).as_ref().map(|x| x.len())`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:72:5
@@ -98,7 +98,7 @@ LL | / match &&Some(0) {
LL | | &&Some(x) => Some(x + x),
LL | | &&_ => None,
LL | | };
- | |_____^ help: try this: `Some(0).map(|x| x + x)`
+ | |_____^ help: try: `Some(0).map(|x| x + x)`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:85:9
@@ -107,7 +107,7 @@ LL | / match &mut Some(String::new()) {
LL | | Some(x) => Some(x.push_str("")),
LL | | None => None,
LL | | };
- | |_________^ help: try this: `Some(String::new()).as_mut().map(|x| x.push_str(""))`
+ | |_________^ help: try: `Some(String::new()).as_mut().map(|x| x.push_str(""))`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:91:5
@@ -116,7 +116,7 @@ LL | / match &mut Some(String::new()) {
LL | | Some(ref x) => Some(x.len()),
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())`
+ | |_____^ help: try: `Some(String::new()).as_ref().map(|x| x.len())`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:96:5
@@ -125,7 +125,7 @@ LL | / match &mut &Some(String::new()) {
LL | | Some(x) => Some(x.is_empty()),
LL | | &mut _ => None,
LL | | };
- | |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())`
+ | |_____^ help: try: `Some(String::new()).as_ref().map(|x| x.is_empty())`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:101:5
@@ -134,7 +134,7 @@ LL | / match Some((0, 1, 2)) {
LL | | Some((x, y, z)) => Some(x + y + z),
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some((0, 1, 2)).map(|(x, y, z)| x + y + z)`
+ | |_____^ help: try: `Some((0, 1, 2)).map(|(x, y, z)| x + y + z)`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:106:5
@@ -143,7 +143,7 @@ LL | / match Some([1, 2, 3]) {
LL | | Some([first, ..]) => Some(first),
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some([1, 2, 3]).map(|[first, ..]| first)`
+ | |_____^ help: try: `Some([1, 2, 3]).map(|[first, ..]| first)`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:111:5
@@ -152,7 +152,7 @@ LL | / match &Some((String::new(), "test")) {
LL | | Some((x, y)) => Some((y, x)),
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))`
+ | |_____^ help: try: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:169:5
@@ -161,7 +161,7 @@ LL | / match Some(0) {
LL | | Some(x) => Some(vec![x]),
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some(0).map(|x| vec![x])`
+ | |_____^ help: try: `Some(0).map(|x| vec![x])`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:174:5
@@ -170,7 +170,7 @@ LL | / match option_env!("") {
LL | | Some(x) => Some(String::from(x)),
LL | | None => None,
LL | | };
- | |_____^ help: try this: `option_env!("").map(String::from)`
+ | |_____^ help: try: `option_env!("").map(String::from)`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:194:12
@@ -181,7 +181,7 @@ LL | | Some(x + 1)
LL | | } else {
LL | | None
LL | | };
- | |_____^ help: try this: `{ Some(0).map(|x| x + 1) }`
+ | |_____^ help: try: `{ Some(0).map(|x| x + 1) }`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option.rs:202:12
@@ -192,7 +192,7 @@ LL | | Some(x + 1)
LL | | } else {
LL | | None
LL | | };
- | |_____^ help: try this: `{ Some(0).map(|x| x + 1) }`
+ | |_____^ help: try: `{ Some(0).map(|x| x + 1) }`
error: aborting due to 21 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.stderr b/src/tools/clippy/tests/ui/manual_map_option_2.stderr
index d35b6252f..8c78fcffc 100644
--- a/src/tools/clippy/tests/ui/manual_map_option_2.stderr
+++ b/src/tools/clippy/tests/ui/manual_map_option_2.stderr
@@ -12,7 +12,7 @@ LL | | };
| |_____^
|
= note: `-D clippy::manual-map` implied by `-D warnings`
-help: try this
+help: try
|
LL ~ let _ = Some(0).map(|x| {
LL + let y = (String::new(), String::new());
@@ -32,7 +32,7 @@ LL | | None => None,
LL | | };
| |_____^
|
-help: try this
+help: try
|
LL ~ let _ = s.as_ref().map(|x| {
LL + if let Some(ref s) = s { (x.clone(), s) } else { panic!() }
@@ -47,7 +47,7 @@ LL | let _ = match Some(0) {
LL | | Some(x) => Some(f(x)),
LL | | None => None,
LL | | };
- | |_________^ help: try this: `Some(0).map(|x| f(x))`
+ | |_________^ help: try: `Some(0).map(|x| f(x))`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option_2.rs:67:13
@@ -57,7 +57,7 @@ LL | let _ = match Some(0) {
LL | | Some(x) => unsafe { Some(f(x)) },
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some(0).map(|x| unsafe { f(x) })`
+ | |_____^ help: try: `Some(0).map(|x| unsafe { f(x) })`
error: manual implementation of `Option::map`
--> $DIR/manual_map_option_2.rs:71:13
@@ -67,7 +67,7 @@ LL | let _ = match Some(0) {
LL | | Some(x) => Some(unsafe { f(x) }),
LL | | None => None,
LL | | };
- | |_____^ help: try this: `Some(0).map(|x| unsafe { f(x) })`
+ | |_____^ help: try: `Some(0).map(|x| unsafe { f(x) })`
error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.fixed b/src/tools/clippy/tests/ui/manual_range_patterns.fixed
index 9eee8f371..6bfcf263a 100644
--- a/src/tools/clippy/tests/ui/manual_range_patterns.fixed
+++ b/src/tools/clippy/tests/ui/manual_range_patterns.fixed
@@ -25,6 +25,10 @@ fn main() {
1..=10 => true,
_ => false,
};
+ let _ = matches!(f, -5..=3);
+ let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1); // 2 is missing
+ let _ = matches!(f, -1000001..=1000001);
+ let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_002);
macro_rules! mac {
($e:expr) => {
diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.rs b/src/tools/clippy/tests/ui/manual_range_patterns.rs
index 10743a7d0..4a429bb2a 100644
--- a/src/tools/clippy/tests/ui/manual_range_patterns.rs
+++ b/src/tools/clippy/tests/ui/manual_range_patterns.rs
@@ -25,6 +25,10 @@ fn main() {
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true,
_ => false,
};
+ let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1 | 2);
+ let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1); // 2 is missing
+ let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_001);
+ let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_002);
macro_rules! mac {
($e:expr) => {
diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.stderr b/src/tools/clippy/tests/ui/manual_range_patterns.stderr
index bc9e33501..b1b55d483 100644
--- a/src/tools/clippy/tests/ui/manual_range_patterns.stderr
+++ b/src/tools/clippy/tests/ui/manual_range_patterns.stderr
@@ -37,7 +37,19 @@ LL | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10`
error: this OR pattern can be rewritten using a range
- --> $DIR/manual_range_patterns.rs:31:26
+ --> $DIR/manual_range_patterns.rs:28:25
+ |
+LL | let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1 | 2);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-5..=3`
+
+error: this OR pattern can be rewritten using a range
+ --> $DIR/manual_range_patterns.rs:30:25
+ |
+LL | let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_001);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-1000001..=1000001`
+
+error: this OR pattern can be rewritten using a range
+ --> $DIR/manual_range_patterns.rs:35:26
|
LL | matches!($e, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10`
@@ -47,5 +59,5 @@ LL | mac!(f);
|
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 7 previous errors
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_retain.fixed b/src/tools/clippy/tests/ui/manual_retain.fixed
index 09fb0d758..c95d40fec 100644
--- a/src/tools/clippy/tests/ui/manual_retain.fixed
+++ b/src/tools/clippy/tests/ui/manual_retain.fixed
@@ -1,12 +1,7 @@
//@run-rustfix
#![warn(clippy::manual_retain)]
#![allow(unused, clippy::redundant_clone)]
-use std::collections::BTreeMap;
-use std::collections::BTreeSet;
-use std::collections::BinaryHeap;
-use std::collections::HashMap;
-use std::collections::HashSet;
-use std::collections::VecDeque;
+use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
fn main() {
binary_heap_retain();
diff --git a/src/tools/clippy/tests/ui/manual_retain.rs b/src/tools/clippy/tests/ui/manual_retain.rs
index 7fee4c95c..9a3434f48 100644
--- a/src/tools/clippy/tests/ui/manual_retain.rs
+++ b/src/tools/clippy/tests/ui/manual_retain.rs
@@ -1,12 +1,7 @@
//@run-rustfix
#![warn(clippy::manual_retain)]
#![allow(unused, clippy::redundant_clone)]
-use std::collections::BTreeMap;
-use std::collections::BTreeSet;
-use std::collections::BinaryHeap;
-use std::collections::HashMap;
-use std::collections::HashSet;
-use std::collections::VecDeque;
+use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
fn main() {
binary_heap_retain();
diff --git a/src/tools/clippy/tests/ui/manual_retain.stderr b/src/tools/clippy/tests/ui/manual_retain.stderr
index 89316ce1d..0936a2384 100644
--- a/src/tools/clippy/tests/ui/manual_retain.stderr
+++ b/src/tools/clippy/tests/ui/manual_retain.stderr
@@ -1,5 +1,5 @@
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:51:5
+ --> $DIR/manual_retain.rs:46:5
|
LL | btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|k, _| k % 2 == 0)`
@@ -7,13 +7,13 @@ LL | btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect()
= note: `-D clippy::manual-retain` implied by `-D warnings`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:52:5
+ --> $DIR/manual_retain.rs:47:5
|
LL | btree_map = btree_map.into_iter().filter(|(_, v)| v % 2 == 0).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|_, &mut v| v % 2 == 0)`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:53:5
+ --> $DIR/manual_retain.rs:48:5
|
LL | / btree_map = btree_map
LL | | .into_iter()
@@ -22,37 +22,37 @@ LL | | .collect();
| |__________________^ help: consider calling `.retain()` instead: `btree_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:75:5
+ --> $DIR/manual_retain.rs:70:5
|
LL | btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:76:5
+ --> $DIR/manual_retain.rs:71:5
|
LL | btree_set = btree_set.iter().filter(|&x| x % 2 == 0).cloned().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:77:5
+ --> $DIR/manual_retain.rs:72:5
|
LL | btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:107:5
+ --> $DIR/manual_retain.rs:102:5
|
LL | hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|k, _| k % 2 == 0)`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:108:5
+ --> $DIR/manual_retain.rs:103:5
|
LL | hash_map = hash_map.into_iter().filter(|(_, v)| v % 2 == 0).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|_, &mut v| v % 2 == 0)`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:109:5
+ --> $DIR/manual_retain.rs:104:5
|
LL | / hash_map = hash_map
LL | | .into_iter()
@@ -61,61 +61,61 @@ LL | | .collect();
| |__________________^ help: consider calling `.retain()` instead: `hash_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:130:5
+ --> $DIR/manual_retain.rs:125:5
|
LL | hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:131:5
+ --> $DIR/manual_retain.rs:126:5
|
LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:132:5
+ --> $DIR/manual_retain.rs:127:5
|
LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:161:5
+ --> $DIR/manual_retain.rs:156:5
|
LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `s.retain(|c| c != 'o')`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:173:5
+ --> $DIR/manual_retain.rs:168:5
|
LL | vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:174:5
+ --> $DIR/manual_retain.rs:169:5
|
LL | vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:175:5
+ --> $DIR/manual_retain.rs:170:5
|
LL | vec = vec.into_iter().filter(|x| x % 2 == 0).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:197:5
+ --> $DIR/manual_retain.rs:192:5
|
LL | vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:198:5
+ --> $DIR/manual_retain.rs:193:5
|
LL | vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).cloned().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)`
error: this expression can be written more simply using `.retain()`
- --> $DIR/manual_retain.rs:199:5
+ --> $DIR/manual_retain.rs:194:5
|
LL | vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)`
diff --git a/src/tools/clippy/tests/ui/manual_split_once.stderr b/src/tools/clippy/tests/ui/manual_split_once.stderr
index 78da5a16c..f454f95b4 100644
--- a/src/tools/clippy/tests/ui/manual_split_once.stderr
+++ b/src/tools/clippy/tests/ui/manual_split_once.stderr
@@ -2,7 +2,7 @@ error: manual implementation of `split_once`
--> $DIR/manual_split_once.rs:13:13
|
LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1`
|
= note: `-D clippy::manual-split-once` implied by `-D warnings`
@@ -10,73 +10,73 @@ error: manual implementation of `split_once`
--> $DIR/manual_split_once.rs:14:13
|
LL | let _ = "key=value".splitn(2, '=').skip(1).next().unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1`
error: manual implementation of `split_once`
--> $DIR/manual_split_once.rs:15:18
|
LL | let (_, _) = "key=value".splitn(2, '=').next_tuple().unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=')`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=')`
error: manual implementation of `split_once`
--> $DIR/manual_split_once.rs:18:13
|
LL | let _ = s.splitn(2, '=').nth(1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').unwrap().1`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1`
error: manual implementation of `split_once`
--> $DIR/manual_split_once.rs:21:13
|
LL | let _ = s.splitn(2, '=').nth(1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').unwrap().1`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1`
error: manual implementation of `split_once`
--> $DIR/manual_split_once.rs:24:13
|
LL | let _ = s.splitn(2, '=').skip(1).next().unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=').unwrap().1`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1`
error: manual implementation of `split_once`
--> $DIR/manual_split_once.rs:27:17
|
LL | let _ = s.splitn(2, '=').nth(1)?;
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=')?.1`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=')?.1`
error: manual implementation of `split_once`
--> $DIR/manual_split_once.rs:28:17
|
LL | let _ = s.splitn(2, '=').skip(1).next()?;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.split_once('=')?.1`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=')?.1`
error: manual implementation of `rsplit_once`
--> $DIR/manual_split_once.rs:29:17
|
LL | let _ = s.rsplitn(2, '=').nth(1)?;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=')?.0`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=')?.0`
error: manual implementation of `rsplit_once`
--> $DIR/manual_split_once.rs:30:17
|
LL | let _ = s.rsplitn(2, '=').skip(1).next()?;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=')?.0`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=')?.0`
error: manual implementation of `rsplit_once`
--> $DIR/manual_split_once.rs:38:13
|
LL | let _ = "key=value".rsplitn(2, '=').nth(1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').unwrap().0`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".rsplit_once('=').unwrap().0`
error: manual implementation of `rsplit_once`
--> $DIR/manual_split_once.rs:39:18
|
LL | let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".rsplit_once('=').map(|(x, y)| (y, x))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".rsplit_once('=').map(|(x, y)| (y, x))`
error: manual implementation of `rsplit_once`
--> $DIR/manual_split_once.rs:40:13
|
LL | let _ = s.rsplitn(2, '=').nth(1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit_once('=').map(|x| x.0)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=').map(|x| x.0)`
error: manual implementation of `split_once`
--> $DIR/manual_split_once.rs:44:5
@@ -182,7 +182,7 @@ error: manual implementation of `split_once`
--> $DIR/manual_split_once.rs:141:13
|
LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split_once('=').unwrap().1`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1`
error: manual implementation of `split_once`
--> $DIR/manual_split_once.rs:143:5
diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.stderr b/src/tools/clippy/tests/ui/manual_str_repeat.stderr
index bdfee7cab..331bb6ea5 100644
--- a/src/tools/clippy/tests/ui/manual_str_repeat.stderr
+++ b/src/tools/clippy/tests/ui/manual_str_repeat.stderr
@@ -2,7 +2,7 @@ error: manual implementation of `str::repeat` using iterators
--> $DIR/manual_str_repeat.rs:9:21
|
LL | let _: String = std::iter::repeat("test").take(10).collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"test".repeat(10)`
|
= note: `-D clippy::manual-str-repeat` implied by `-D warnings`
@@ -10,55 +10,55 @@ error: manual implementation of `str::repeat` using iterators
--> $DIR/manual_str_repeat.rs:10:21
|
LL | let _: String = std::iter::repeat('x').take(10).collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"x".repeat(10)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"x".repeat(10)`
error: manual implementation of `str::repeat` using iterators
--> $DIR/manual_str_repeat.rs:11:21
|
LL | let _: String = std::iter::repeat('/'').take(10).collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"'".repeat(10)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"'".repeat(10)`
error: manual implementation of `str::repeat` using iterators
--> $DIR/manual_str_repeat.rs:12:21
|
LL | let _: String = std::iter::repeat('"').take(10).collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"/"".repeat(10)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"/"".repeat(10)`
error: manual implementation of `str::repeat` using iterators
--> $DIR/manual_str_repeat.rs:16:13
|
LL | let _ = repeat(x).take(count + 2).collect::<String>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count + 2)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count + 2)`
error: manual implementation of `str::repeat` using iterators
--> $DIR/manual_str_repeat.rs:25:21
|
LL | let _: String = repeat(*x).take(count).collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*x).repeat(count)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*x).repeat(count)`
error: manual implementation of `str::repeat` using iterators
--> $DIR/manual_str_repeat.rs:34:21
|
LL | let _: String = repeat(x).take(count).collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count)`
error: manual implementation of `str::repeat` using iterators
--> $DIR/manual_str_repeat.rs:46:21
|
LL | let _: String = repeat(Cow::Borrowed("test")).take(count).collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Cow::Borrowed("test").repeat(count)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Cow::Borrowed("test").repeat(count)`
error: manual implementation of `str::repeat` using iterators
--> $DIR/manual_str_repeat.rs:49:21
|
LL | let _: String = repeat(x).take(count).collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count)`
error: manual implementation of `str::repeat` using iterators
--> $DIR/manual_str_repeat.rs:64:21
|
LL | let _: String = std::iter::repeat("test").take(10).collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"test".repeat(10)`
error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_try_fold.rs b/src/tools/clippy/tests/ui/manual_try_fold.rs
index 4521e9fa1..05c658579 100644
--- a/src/tools/clippy/tests/ui/manual_try_fold.rs
+++ b/src/tools/clippy/tests/ui/manual_try_fold.rs
@@ -3,9 +3,7 @@
#![warn(clippy::manual_try_fold)]
#![feature(try_trait_v2)]
-use std::ops::ControlFlow;
-use std::ops::FromResidual;
-use std::ops::Try;
+use std::ops::{ControlFlow, FromResidual, Try};
#[macro_use]
extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/manual_try_fold.stderr b/src/tools/clippy/tests/ui/manual_try_fold.stderr
index a0cf5b3b5..f1bb97c6d 100644
--- a/src/tools/clippy/tests/ui/manual_try_fold.stderr
+++ b/src/tools/clippy/tests/ui/manual_try_fold.stderr
@@ -1,5 +1,5 @@
error: usage of `Iterator::fold` on a type that implements `Try`
- --> $DIR/manual_try_fold.rs:61:10
+ --> $DIR/manual_try_fold.rs:59:10
|
LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)`
@@ -7,19 +7,19 @@ LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i))
= note: `-D clippy::manual-try-fold` implied by `-D warnings`
error: usage of `Iterator::fold` on a type that implements `Try`
- --> $DIR/manual_try_fold.rs:65:10
+ --> $DIR/manual_try_fold.rs:63:10
|
LL | .fold(NotOption(0i32, 0i32), |sum, i| NotOption(0i32, 0i32));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(..., |sum, i| ...)`
error: usage of `Iterator::fold` on a type that implements `Try`
- --> $DIR/manual_try_fold.rs:68:10
+ --> $DIR/manual_try_fold.rs:66:10
|
LL | .fold(NotOptionButWorse(0i32), |sum, i| NotOptionButWorse(0i32));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)`
error: usage of `Iterator::fold` on a type that implements `Try`
- --> $DIR/manual_try_fold.rs:98:10
+ --> $DIR/manual_try_fold.rs:96:10
|
LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)`
diff --git a/src/tools/clippy/tests/ui/map_collect_result_unit.stderr b/src/tools/clippy/tests/ui/map_collect_result_unit.stderr
index 8b06e13ba..596e51e57 100644
--- a/src/tools/clippy/tests/ui/map_collect_result_unit.stderr
+++ b/src/tools/clippy/tests/ui/map_collect_result_unit.stderr
@@ -2,7 +2,7 @@ error: `.map().collect()` can be replaced with `.try_for_each()`
--> $DIR/map_collect_result_unit.rs:6:17
|
LL | let _ = (0..3).map(|t| Err(t + 1)).collect::<Result<(), _>>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(0..3).try_for_each(|t| Err(t + 1))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(0..3).try_for_each(|t| Err(t + 1))`
|
= note: `-D clippy::map-collect-result-unit` implied by `-D warnings`
@@ -10,7 +10,7 @@ error: `.map().collect()` can be replaced with `.try_for_each()`
--> $DIR/map_collect_result_unit.rs:7:32
|
LL | let _: Result<(), _> = (0..3).map(|t| Err(t + 1)).collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(0..3).try_for_each(|t| Err(t + 1))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(0..3).try_for_each(|t| Err(t + 1))`
error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.stderr b/src/tools/clippy/tests/ui/map_unwrap_or.stderr
index 9f4a4a9ae..5b3c61acf 100644
--- a/src/tools/clippy/tests/ui/map_unwrap_or.stderr
+++ b/src/tools/clippy/tests/ui/map_unwrap_or.stderr
@@ -162,7 +162,7 @@ error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be do
--> $DIR/map_unwrap_or.rs:99:13
|
LL | let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `res.map_or_else(|_e| 0, |x| x + 1)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)`
error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead
--> $DIR/map_unwrap_or.rs:106:13
diff --git a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr
index 1837bc2ca..71dc009f2 100644
--- a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr
+++ b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr
@@ -5,7 +5,7 @@ LL | let _ = opt.map(|x| x + 1)
| _____________^
LL | | // Should lint even though this call is on a separate line.
LL | | .unwrap_or_else(|| 0);
- | |_____________________________^ help: try this: `opt.map_or_else(|| 0, |x| x + 1)`
+ | |_____________________________^ help: try: `opt.map_or_else(|| 0, |x| x + 1)`
|
= note: `-D clippy::map-unwrap-or` implied by `-D warnings`
@@ -16,7 +16,7 @@ LL | let _ = res.map(|x| x + 1)
| _____________^
LL | | // should lint even though this call is on a separate line
LL | | .unwrap_or_else(|_e| 0);
- | |_______________________________^ help: try this: `res.map_or_else(|_e| 0, |x| x + 1)`
+ | |_______________________________^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)`
error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/match_as_ref.fixed b/src/tools/clippy/tests/ui/match_as_ref.fixed
index 8fa3f5325..61d414bdf 100644
--- a/src/tools/clippy/tests/ui/match_as_ref.fixed
+++ b/src/tools/clippy/tests/ui/match_as_ref.fixed
@@ -12,7 +12,9 @@ fn match_as_ref() {
}
mod issue4437 {
- use std::{error::Error, fmt, num::ParseIntError};
+ use std::error::Error;
+ use std::fmt;
+ use std::num::ParseIntError;
#[derive(Debug)]
struct E {
diff --git a/src/tools/clippy/tests/ui/match_as_ref.rs b/src/tools/clippy/tests/ui/match_as_ref.rs
index 02a177914..cd39514c5 100644
--- a/src/tools/clippy/tests/ui/match_as_ref.rs
+++ b/src/tools/clippy/tests/ui/match_as_ref.rs
@@ -18,7 +18,9 @@ fn match_as_ref() {
}
mod issue4437 {
- use std::{error::Error, fmt, num::ParseIntError};
+ use std::error::Error;
+ use std::fmt;
+ use std::num::ParseIntError;
#[derive(Debug)]
struct E {
diff --git a/src/tools/clippy/tests/ui/match_as_ref.stderr b/src/tools/clippy/tests/ui/match_as_ref.stderr
index c3b62849c..2e6955eb8 100644
--- a/src/tools/clippy/tests/ui/match_as_ref.stderr
+++ b/src/tools/clippy/tests/ui/match_as_ref.stderr
@@ -6,7 +6,7 @@ LL | let borrowed: Option<&()> = match owned {
LL | | None => None,
LL | | Some(ref v) => Some(v),
LL | | };
- | |_____^ help: try this: `owned.as_ref()`
+ | |_____^ help: try: `owned.as_ref()`
|
= note: `-D clippy::match-as-ref` implied by `-D warnings`
@@ -18,16 +18,16 @@ LL | let borrow_mut: Option<&mut ()> = match mut_owned {
LL | | None => None,
LL | | Some(ref mut v) => Some(v),
LL | | };
- | |_____^ help: try this: `mut_owned.as_mut()`
+ | |_____^ help: try: `mut_owned.as_mut()`
error: use `as_ref()` instead
- --> $DIR/match_as_ref.rs:30:13
+ --> $DIR/match_as_ref.rs:32:13
|
LL | / match self.source {
LL | | Some(ref s) => Some(s),
LL | | None => None,
LL | | }
- | |_____________^ help: try this: `self.source.as_ref().map(|x| x as _)`
+ | |_____________^ help: try: `self.source.as_ref().map(|x| x as _)`
error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
index 60f590661..f19149cf9 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
@@ -5,7 +5,8 @@
unreachable_patterns,
dead_code,
clippy::equatable_if_let,
- clippy::needless_borrowed_reference
+ clippy::needless_borrowed_reference,
+ clippy::redundant_guards
)]
fn main() {
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
index afdf1069f..8f4e58981 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
@@ -5,7 +5,8 @@
unreachable_patterns,
dead_code,
clippy::equatable_if_let,
- clippy::needless_borrowed_reference
+ clippy::needless_borrowed_reference,
+ clippy::redundant_guards
)]
fn main() {
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
index b72fe10b7..b57b26284 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
@@ -1,55 +1,55 @@
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:15:14
+ --> $DIR/match_expr_like_matches_macro.rs:16:14
|
LL | let _y = match x {
| ______________^
LL | | Some(0) => true,
LL | | _ => false,
LL | | };
- | |_____^ help: try this: `matches!(x, Some(0))`
+ | |_____^ help: try: `matches!(x, Some(0))`
|
= note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/match_expr_like_matches_macro.rs:21:14
+ --> $DIR/match_expr_like_matches_macro.rs:22:14
|
LL | let _w = match x {
| ______________^
LL | | Some(_) => true,
LL | | _ => false,
LL | | };
- | |_____^ help: try this: `x.is_some()`
+ | |_____^ help: try: `x.is_some()`
|
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/match_expr_like_matches_macro.rs:27:14
+ --> $DIR/match_expr_like_matches_macro.rs:28:14
|
LL | let _z = match x {
| ______________^
LL | | Some(_) => false,
LL | | None => true,
LL | | };
- | |_____^ help: try this: `x.is_none()`
+ | |_____^ help: try: `x.is_none()`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:33:15
+ --> $DIR/match_expr_like_matches_macro.rs:34:15
|
LL | let _zz = match x {
| _______________^
LL | | Some(r) if r == 0 => false,
LL | | _ => true,
LL | | };
- | |_____^ help: try this: `!matches!(x, Some(r) if r == 0)`
+ | |_____^ help: try: `!matches!(x, Some(r) if r == 0)`
error: if let .. else expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:39:16
+ --> $DIR/match_expr_like_matches_macro.rs:40:16
|
LL | let _zzz = if let Some(5) = x { true } else { false };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `matches!(x, Some(5))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(x, Some(5))`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:63:20
+ --> $DIR/match_expr_like_matches_macro.rs:64:20
|
LL | let _ans = match x {
| ____________________^
@@ -57,10 +57,10 @@ LL | | E::A(_) => true,
LL | | E::B(_) => true,
LL | | _ => false,
LL | | };
- | |_________^ help: try this: `matches!(x, E::A(_) | E::B(_))`
+ | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:73:20
+ --> $DIR/match_expr_like_matches_macro.rs:74:20
|
LL | let _ans = match x {
| ____________________^
@@ -70,10 +70,10 @@ LL | | }
LL | | E::B(_) => true,
LL | | _ => false,
LL | | };
- | |_________^ help: try this: `matches!(x, E::A(_) | E::B(_))`
+ | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:83:20
+ --> $DIR/match_expr_like_matches_macro.rs:84:20
|
LL | let _ans = match x {
| ____________________^
@@ -81,67 +81,67 @@ LL | | E::B(_) => false,
LL | | E::C => false,
LL | | _ => true,
LL | | };
- | |_________^ help: try this: `!matches!(x, E::B(_) | E::C)`
+ | |_________^ help: try: `!matches!(x, E::B(_) | E::C)`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:143:18
+ --> $DIR/match_expr_like_matches_macro.rs:144:18
|
LL | let _z = match &z {
| __________________^
LL | | Some(3) => true,
LL | | _ => false,
LL | | };
- | |_________^ help: try this: `matches!(z, Some(3))`
+ | |_________^ help: try: `matches!(z, Some(3))`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:152:18
+ --> $DIR/match_expr_like_matches_macro.rs:153:18
|
LL | let _z = match &z {
| __________________^
LL | | Some(3) => true,
LL | | _ => false,
LL | | };
- | |_________^ help: try this: `matches!(&z, Some(3))`
+ | |_________^ help: try: `matches!(&z, Some(3))`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:169:21
+ --> $DIR/match_expr_like_matches_macro.rs:170:21
|
LL | let _ = match &z {
| _____________________^
LL | | AnEnum::X => true,
LL | | _ => false,
LL | | };
- | |_____________^ help: try this: `matches!(&z, AnEnum::X)`
+ | |_____________^ help: try: `matches!(&z, AnEnum::X)`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:183:20
+ --> $DIR/match_expr_like_matches_macro.rs:184:20
|
LL | let _res = match &val {
| ____________________^
LL | | &Some(ref _a) => true,
LL | | _ => false,
LL | | };
- | |_________^ help: try this: `matches!(&val, &Some(ref _a))`
+ | |_________^ help: try: `matches!(&val, &Some(ref _a))`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:195:20
+ --> $DIR/match_expr_like_matches_macro.rs:196:20
|
LL | let _res = match &val {
| ____________________^
LL | | &Some(ref _a) => true,
LL | | _ => false,
LL | | };
- | |_________^ help: try this: `matches!(&val, &Some(ref _a))`
+ | |_________^ help: try: `matches!(&val, &Some(ref _a))`
error: match expression looks like `matches!` macro
- --> $DIR/match_expr_like_matches_macro.rs:253:14
+ --> $DIR/match_expr_like_matches_macro.rs:254:14
|
LL | let _y = match Some(5) {
| ______________^
LL | | Some(0) => true,
LL | | _ => false,
LL | | };
- | |_____^ help: try this: `matches!(Some(5), Some(0))`
+ | |_____^ help: try: `matches!(Some(5), Some(0))`
error: aborting due to 14 previous errors
diff --git a/src/tools/clippy/tests/ui/match_on_vec_items.stderr b/src/tools/clippy/tests/ui/match_on_vec_items.stderr
index 9b1f05286..fc4a3ce19 100644
--- a/src/tools/clippy/tests/ui/match_on_vec_items.stderr
+++ b/src/tools/clippy/tests/ui/match_on_vec_items.stderr
@@ -2,7 +2,7 @@ error: indexing into a vector may panic
--> $DIR/match_on_vec_items.rs:10:11
|
LL | match arr[idx] {
- | ^^^^^^^^ help: try this: `arr.get(idx)`
+ | ^^^^^^^^ help: try: `arr.get(idx)`
|
= note: `-D clippy::match-on-vec-items` implied by `-D warnings`
@@ -10,43 +10,43 @@ error: indexing into a vector may panic
--> $DIR/match_on_vec_items.rs:17:11
|
LL | match arr[range] {
- | ^^^^^^^^^^ help: try this: `arr.get(range)`
+ | ^^^^^^^^^^ help: try: `arr.get(range)`
error: indexing into a vector may panic
--> $DIR/match_on_vec_items.rs:30:11
|
LL | match arr[idx] {
- | ^^^^^^^^ help: try this: `arr.get(idx)`
+ | ^^^^^^^^ help: try: `arr.get(idx)`
error: indexing into a vector may panic
--> $DIR/match_on_vec_items.rs:37:11
|
LL | match arr[range] {
- | ^^^^^^^^^^ help: try this: `arr.get(range)`
+ | ^^^^^^^^^^ help: try: `arr.get(range)`
error: indexing into a vector may panic
--> $DIR/match_on_vec_items.rs:50:11
|
LL | match arr[idx] {
- | ^^^^^^^^ help: try this: `arr.get(idx)`
+ | ^^^^^^^^ help: try: `arr.get(idx)`
error: indexing into a vector may panic
--> $DIR/match_on_vec_items.rs:57:11
|
LL | match arr[range] {
- | ^^^^^^^^^^ help: try this: `arr.get(range)`
+ | ^^^^^^^^^^ help: try: `arr.get(range)`
error: indexing into a vector may panic
--> $DIR/match_on_vec_items.rs:70:11
|
LL | match arr[idx] {
- | ^^^^^^^^ help: try this: `arr.get(idx)`
+ | ^^^^^^^^ help: try: `arr.get(idx)`
error: indexing into a vector may panic
--> $DIR/match_on_vec_items.rs:77:11
|
LL | match arr[range] {
- | ^^^^^^^^^^ help: try this: `arr.get(range)`
+ | ^^^^^^^^^^ help: try: `arr.get(range)`
error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/match_ref_pats.stderr b/src/tools/clippy/tests/ui/match_ref_pats.stderr
index 7d9646c84..1294e0fe5 100644
--- a/src/tools/clippy/tests/ui/match_ref_pats.stderr
+++ b/src/tools/clippy/tests/ui/match_ref_pats.stderr
@@ -35,7 +35,7 @@ error: redundant pattern matching, consider using `is_none()`
--> $DIR/match_ref_pats.rs:38:12
|
LL | if let &None = a {
- | -------^^^^^---- help: try this: `if a.is_none()`
+ | -------^^^^^---- help: try: `if a.is_none()`
|
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
@@ -43,7 +43,7 @@ error: redundant pattern matching, consider using `is_none()`
--> $DIR/match_ref_pats.rs:43:12
|
LL | if let &None = &b {
- | -------^^^^^----- help: try this: `if b.is_none()`
+ | -------^^^^^----- help: try: `if b.is_none()`
error: you don't need to add `&` to all patterns
--> $DIR/match_ref_pats.rs:103:9
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr
index 7f0c70745..a73481875 100644
--- a/src/tools/clippy/tests/ui/match_same_arms2.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr
@@ -144,7 +144,7 @@ LL | | E::A => false,
LL | | E::B => false,
LL | | _ => true,
LL | | };
- | |_____^ help: try this: `!matches!(x, E::A | E::B)`
+ | |_____^ help: try: `!matches!(x, E::A | E::B)`
|
= note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr
index 105b4c4b4..40ff4fbd3 100644
--- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr
+++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr
@@ -2,7 +2,7 @@ error: wildcard matches only a single variant and will also match any future add
--> $DIR/match_wildcard_for_single_variants.rs:24:13
|
LL | _ => (),
- | ^ help: try this: `Self::Rgb(..)`
+ | ^ help: try: `Self::Rgb(..)`
|
= note: `-D clippy::match-wildcard-for-single-variants` implied by `-D warnings`
@@ -10,55 +10,55 @@ error: wildcard matches only a single variant and will also match any future add
--> $DIR/match_wildcard_for_single_variants.rs:34:9
|
LL | _ => {},
- | ^ help: try this: `Foo::C`
+ | ^ help: try: `Foo::C`
error: wildcard matches only a single variant and will also match any future added variants
--> $DIR/match_wildcard_for_single_variants.rs:44:9
|
LL | _ => {},
- | ^ help: try this: `Color::Blue`
+ | ^ help: try: `Color::Blue`
error: wildcard matches only a single variant and will also match any future added variants
--> $DIR/match_wildcard_for_single_variants.rs:52:9
|
LL | _ => {},
- | ^ help: try this: `Color::Blue`
+ | ^ help: try: `Color::Blue`
error: wildcard matches only a single variant and will also match any future added variants
--> $DIR/match_wildcard_for_single_variants.rs:58:9
|
LL | _ => {},
- | ^ help: try this: `Color::Blue`
+ | ^ help: try: `Color::Blue`
error: wildcard matches only a single variant and will also match any future added variants
--> $DIR/match_wildcard_for_single_variants.rs:75:9
|
LL | &_ => (),
- | ^^ help: try this: `Color::Blue`
+ | ^^ help: try: `Color::Blue`
error: wildcard matches only a single variant and will also match any future added variants
--> $DIR/match_wildcard_for_single_variants.rs:84:9
|
LL | _ => (),
- | ^ help: try this: `C::Blue`
+ | ^ help: try: `C::Blue`
error: wildcard matches only a single variant and will also match any future added variants
--> $DIR/match_wildcard_for_single_variants.rs:91:9
|
LL | _ => (),
- | ^ help: try this: `Color::Blue`
+ | ^ help: try: `Color::Blue`
error: wildcard matches only a single variant and will also match any future added variants
--> $DIR/match_wildcard_for_single_variants.rs:126:13
|
LL | _ => (),
- | ^ help: try this: `Enum::__Private`
+ | ^ help: try: `Enum::__Private`
error: wildcard matches only a single variant and will also match any future added variants
--> $DIR/match_wildcard_for_single_variants.rs:153:13
|
LL | _ => 2,
- | ^ help: try this: `Foo::B`
+ | ^ help: try: `Foo::B`
error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs
index 589eab5cd..cb1f695c6 100644
--- a/src/tools/clippy/tests/ui/methods.rs
+++ b/src/tools/clippy/tests/ui/methods.rs
@@ -25,10 +25,7 @@
#[macro_use]
extern crate option_helpers;
-use std::collections::BTreeMap;
-use std::collections::HashMap;
-use std::collections::HashSet;
-use std::collections::VecDeque;
+use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
use std::ops::Mul;
use std::rc::{self, Rc};
use std::sync::{self, Arc};
diff --git a/src/tools/clippy/tests/ui/methods.stderr b/src/tools/clippy/tests/ui/methods.stderr
index 73ec48643..6be38b24f 100644
--- a/src/tools/clippy/tests/ui/methods.stderr
+++ b/src/tools/clippy/tests/ui/methods.stderr
@@ -1,5 +1,5 @@
error: methods called `new` usually return `Self`
- --> $DIR/methods.rs:106:5
+ --> $DIR/methods.rs:103:5
|
LL | / fn new() -> i32 {
LL | | 0
@@ -9,7 +9,7 @@ LL | | }
= note: `-D clippy::new-ret-no-self` implied by `-D warnings`
error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
- --> $DIR/methods.rs:127:13
+ --> $DIR/methods.rs:124:13
|
LL | let _ = v.iter().filter(|&x| {
| _____________^
diff --git a/src/tools/clippy/tests/ui/methods_fixable.stderr b/src/tools/clippy/tests/ui/methods_fixable.stderr
index 187714c75..6f45d100d 100644
--- a/src/tools/clippy/tests/ui/methods_fixable.stderr
+++ b/src/tools/clippy/tests/ui/methods_fixable.stderr
@@ -2,7 +2,7 @@ error: called `filter(..).next()` on an `Iterator`. This is more succinctly expr
--> $DIR/methods_fixable.rs:11:13
|
LL | let _ = v.iter().filter(|&x| *x < 0).next();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `v.iter().find(|&x| *x < 0)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.iter().find(|&x| *x < 0)`
|
= note: `-D clippy::filter-next` implied by `-D warnings`
diff --git a/src/tools/clippy/tests/ui/methods_unfixable.rs b/src/tools/clippy/tests/ui/methods_unfixable.rs
new file mode 100644
index 000000000..3d88ce4b6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/methods_unfixable.rs
@@ -0,0 +1,10 @@
+#![warn(clippy::filter_next)]
+
+fn main() {
+ issue10029();
+}
+
+pub fn issue10029() {
+ let iter = (0..10);
+ let _ = iter.filter(|_| true).next();
+}
diff --git a/src/tools/clippy/tests/ui/methods_unfixable.stderr b/src/tools/clippy/tests/ui/methods_unfixable.stderr
new file mode 100644
index 000000000..6e101fe16
--- /dev/null
+++ b/src/tools/clippy/tests/ui/methods_unfixable.stderr
@@ -0,0 +1,15 @@
+error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
+ --> $DIR/methods_unfixable.rs:9:13
+ |
+LL | let _ = iter.filter(|_| true).next();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `iter.find(|_| true)`
+ |
+help: you will also need to make `iter` mutable, because `find` takes `&mut self`
+ --> $DIR/methods_unfixable.rs:8:9
+ |
+LL | let iter = (0..10);
+ | ^^^^
+ = note: `-D clippy::filter-next` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/min_ident_chars.rs b/src/tools/clippy/tests/ui/min_ident_chars.rs
index b5b9e66aa..03784442e 100644
--- a/src/tools/clippy/tests/ui/min_ident_chars.rs
+++ b/src/tools/clippy/tests/ui/min_ident_chars.rs
@@ -3,8 +3,7 @@
#![warn(clippy::min_ident_chars)]
extern crate proc_macros;
-use proc_macros::external;
-use proc_macros::with_span;
+use proc_macros::{external, with_span};
struct A {
a: u32,
@@ -82,3 +81,7 @@ fn b() {}
fn wrong_pythagoras(a: f32, b: f32) -> f32 {
a * a + a * b
}
+
+mod issue_11163 {
+ struct Array<T, const N: usize>([T; N]);
+}
diff --git a/src/tools/clippy/tests/ui/min_ident_chars.stderr b/src/tools/clippy/tests/ui/min_ident_chars.stderr
index 66a63f657..4dff6588b 100644
--- a/src/tools/clippy/tests/ui/min_ident_chars.stderr
+++ b/src/tools/clippy/tests/ui/min_ident_chars.stderr
@@ -1,5 +1,5 @@
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:9:8
+ --> $DIR/min_ident_chars.rs:8:8
|
LL | struct A {
| ^
@@ -7,169 +7,169 @@ LL | struct A {
= note: `-D clippy::min-ident-chars` implied by `-D warnings`
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:10:5
+ --> $DIR/min_ident_chars.rs:9:5
|
LL | a: u32,
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:12:5
+ --> $DIR/min_ident_chars.rs:11:5
|
LL | A: u32,
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:13:5
+ --> $DIR/min_ident_chars.rs:12:5
|
LL | I: u32,
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:16:8
+ --> $DIR/min_ident_chars.rs:15:8
|
LL | struct B(u32);
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:18:8
+ --> $DIR/min_ident_chars.rs:17:8
|
LL | struct O {
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:19:5
+ --> $DIR/min_ident_chars.rs:18:5
|
LL | o: u32,
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:24:6
+ --> $DIR/min_ident_chars.rs:23:6
|
LL | enum C {
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:25:5
+ --> $DIR/min_ident_chars.rs:24:5
|
LL | D,
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:26:5
+ --> $DIR/min_ident_chars.rs:25:5
|
LL | E,
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:27:5
+ --> $DIR/min_ident_chars.rs:26:5
|
LL | F,
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:51:9
+ --> $DIR/min_ident_chars.rs:50:9
|
LL | let h = 1;
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:52:9
+ --> $DIR/min_ident_chars.rs:51:9
|
LL | let e = 2;
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:53:9
+ --> $DIR/min_ident_chars.rs:52:9
|
LL | let l = 3;
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:54:9
+ --> $DIR/min_ident_chars.rs:53:9
|
LL | let l = 4;
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:55:9
+ --> $DIR/min_ident_chars.rs:54:9
|
LL | let o = 6;
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:59:10
+ --> $DIR/min_ident_chars.rs:58:10
|
LL | let (h, o, w) = (1, 2, 3);
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:59:13
+ --> $DIR/min_ident_chars.rs:58:13
|
LL | let (h, o, w) = (1, 2, 3);
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:60:10
+ --> $DIR/min_ident_chars.rs:59:10
|
LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {}
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:60:14
+ --> $DIR/min_ident_chars.rs:59:14
|
LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {}
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:60:17
+ --> $DIR/min_ident_chars.rs:59:17
|
LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {}
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:62:16
+ --> $DIR/min_ident_chars.rs:61:16
|
LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {}
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:62:19
+ --> $DIR/min_ident_chars.rs:61:19
|
LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {}
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:62:29
+ --> $DIR/min_ident_chars.rs:61:29
|
LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {}
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:66:9
+ --> $DIR/min_ident_chars.rs:65:9
|
LL | let o = 1;
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:67:9
+ --> $DIR/min_ident_chars.rs:66:9
|
LL | let o = O { o };
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:81:4
+ --> $DIR/min_ident_chars.rs:80:4
|
LL | fn b() {}
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:82:21
+ --> $DIR/min_ident_chars.rs:81:21
|
LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 {
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:82:29
+ --> $DIR/min_ident_chars.rs:81:29
|
LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 {
| ^
diff --git a/src/tools/clippy/tests/ui/min_max.rs b/src/tools/clippy/tests/ui/min_max.rs
index 24e52afd6..1215a0228 100644
--- a/src/tools/clippy/tests/ui/min_max.rs
+++ b/src/tools/clippy/tests/ui/min_max.rs
@@ -1,9 +1,7 @@
#![warn(clippy::all)]
#![allow(clippy::manual_clamp)]
-use std::cmp::max as my_max;
-use std::cmp::min as my_min;
-use std::cmp::{max, min};
+use std::cmp::{max as my_max, max, min as my_min, min};
const LARGE: usize = 3;
diff --git a/src/tools/clippy/tests/ui/min_max.stderr b/src/tools/clippy/tests/ui/min_max.stderr
index 069d90686..402b094f4 100644
--- a/src/tools/clippy/tests/ui/min_max.stderr
+++ b/src/tools/clippy/tests/ui/min_max.stderr
@@ -1,5 +1,5 @@
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:24:5
+ --> $DIR/min_max.rs:22:5
|
LL | min(1, max(3, x));
| ^^^^^^^^^^^^^^^^^
@@ -7,73 +7,73 @@ LL | min(1, max(3, x));
= note: `-D clippy::min-max` implied by `-D warnings`
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:25:5
+ --> $DIR/min_max.rs:23:5
|
LL | min(max(3, x), 1);
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:26:5
+ --> $DIR/min_max.rs:24:5
|
LL | max(min(x, 1), 3);
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:27:5
+ --> $DIR/min_max.rs:25:5
|
LL | max(3, min(x, 1));
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:29:5
+ --> $DIR/min_max.rs:27:5
|
LL | my_max(3, my_min(x, 1));
| ^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:39:5
+ --> $DIR/min_max.rs:37:5
|
LL | min("Apple", max("Zoo", s));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:40:5
+ --> $DIR/min_max.rs:38:5
|
LL | max(min(s, "Apple"), "Zoo");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:45:5
+ --> $DIR/min_max.rs:43:5
|
LL | x.min(1).max(3);
| ^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:46:5
+ --> $DIR/min_max.rs:44:5
|
LL | x.max(3).min(1);
| ^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:47:5
+ --> $DIR/min_max.rs:45:5
|
LL | f.max(3f32).min(1f32);
| ^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:53:5
+ --> $DIR/min_max.rs:51:5
|
LL | max(x.min(1), 3);
| ^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:56:5
+ --> $DIR/min_max.rs:54:5
|
LL | s.max("Zoo").min("Apple");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> $DIR/min_max.rs:57:5
+ --> $DIR/min_max.rs:55:5
|
LL | s.min("Apple").max("Zoo");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index b1980b1b5..3aaee67e1 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -99,4 +99,5 @@ impl const Drop for D {
}
// Lint this, since it can be dropped in const contexts
+// FIXME(effects)
fn d(this: D) {}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
index 7be2cc0ca..66cf4e315 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -89,11 +89,5 @@ LL | | 46
LL | | }
| |_^
-error: this could be a `const fn`
- --> $DIR/could_be_const.rs:102:1
- |
-LL | fn d(this: D) {}
- | ^^^^^^^^^^^^^^^^
-
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/missing_doc.rs b/src/tools/clippy/tests/ui/missing_doc.rs
index cff1706a8..83ebf09c8 100644
--- a/src/tools/clippy/tests/ui/missing_doc.rs
+++ b/src/tools/clippy/tests/ui/missing_doc.rs
@@ -96,10 +96,8 @@ mod internal_impl {
}
/// dox
pub mod public_interface {
- pub use crate::internal_impl::documented as foo;
pub use crate::internal_impl::globbed::*;
- pub use crate::internal_impl::undocumented1 as bar;
- pub use crate::internal_impl::{documented, undocumented2};
+ pub use crate::internal_impl::{documented as foo, documented, undocumented1 as bar, undocumented2};
}
fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_spin_loop.stderr b/src/tools/clippy/tests/ui/missing_spin_loop.stderr
index 485da00dc..5795c2c21 100644
--- a/src/tools/clippy/tests/ui/missing_spin_loop.stderr
+++ b/src/tools/clippy/tests/ui/missing_spin_loop.stderr
@@ -2,7 +2,7 @@ error: busy-waiting loop should at least have a spin loop hint
--> $DIR/missing_spin_loop.rs:11:37
|
LL | while b.load(Ordering::Acquire) {}
- | ^^ help: try this: `{ std::hint::spin_loop() }`
+ | ^^ help: try: `{ std::hint::spin_loop() }`
|
= note: `-D clippy::missing-spin-loop` implied by `-D warnings`
@@ -10,31 +10,31 @@ error: busy-waiting loop should at least have a spin loop hint
--> $DIR/missing_spin_loop.rs:13:37
|
LL | while !b.load(Ordering::SeqCst) {}
- | ^^ help: try this: `{ std::hint::spin_loop() }`
+ | ^^ help: try: `{ std::hint::spin_loop() }`
error: busy-waiting loop should at least have a spin loop hint
--> $DIR/missing_spin_loop.rs:15:46
|
LL | while b.load(Ordering::Acquire) == false {}
- | ^^ help: try this: `{ std::hint::spin_loop() }`
+ | ^^ help: try: `{ std::hint::spin_loop() }`
error: busy-waiting loop should at least have a spin loop hint
--> $DIR/missing_spin_loop.rs:17:49
|
LL | while { true == b.load(Ordering::Acquire) } {}
- | ^^ help: try this: `{ std::hint::spin_loop() }`
+ | ^^ help: try: `{ std::hint::spin_loop() }`
error: busy-waiting loop should at least have a spin loop hint
--> $DIR/missing_spin_loop.rs:19:93
|
LL | while b.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed) != Ok(true) {}
- | ^^ help: try this: `{ std::hint::spin_loop() }`
+ | ^^ help: try: `{ std::hint::spin_loop() }`
error: busy-waiting loop should at least have a spin loop hint
--> $DIR/missing_spin_loop.rs:21:94
|
LL | while Ok(false) != b.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {}
- | ^^ help: try this: `{ std::hint::spin_loop() }`
+ | ^^ help: try: `{ std::hint::spin_loop() }`
error: aborting due to 6 previous errors
diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr
index 2b3b6873c..3322a7aae 100644
--- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr
+++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr
@@ -2,7 +2,7 @@ error: busy-waiting loop should at least have a spin loop hint
--> $DIR/missing_spin_loop_no_std.rs:13:37
|
LL | while b.load(Ordering::Acquire) {}
- | ^^ help: try this: `{ core::hint::spin_loop() }`
+ | ^^ help: try: `{ core::hint::spin_loop() }`
|
= note: `-D clippy::missing-spin-loop` implied by `-D warnings`
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed
index 0c275504d..3ca20c07d 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.fixed
+++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed
@@ -1,6 +1,11 @@
//@run-rustfix
#![feature(never_type)]
-#![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)]
+#![allow(
+ unused_mut,
+ unused_tuple_struct_fields,
+ clippy::redundant_allocation,
+ clippy::needless_pass_by_ref_mut
+)]
#![warn(clippy::must_use_candidate)]
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.rs b/src/tools/clippy/tests/ui/must_use_candidates.rs
index d1c926773..dc4e0118e 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.rs
+++ b/src/tools/clippy/tests/ui/must_use_candidates.rs
@@ -1,6 +1,11 @@
//@run-rustfix
#![feature(never_type)]
-#![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)]
+#![allow(
+ unused_mut,
+ unused_tuple_struct_fields,
+ clippy::redundant_allocation,
+ clippy::needless_pass_by_ref_mut
+)]
#![warn(clippy::must_use_candidate)]
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.stderr b/src/tools/clippy/tests/ui/must_use_candidates.stderr
index 0fa3849d0..5fb302ccb 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.stderr
+++ b/src/tools/clippy/tests/ui/must_use_candidates.stderr
@@ -1,5 +1,5 @@
error: this function could have a `#[must_use]` attribute
- --> $DIR/must_use_candidates.rs:12:1
+ --> $DIR/must_use_candidates.rs:17:1
|
LL | pub fn pure(i: u8) -> u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn pure(i: u8) -> u8`
@@ -7,25 +7,25 @@ LL | pub fn pure(i: u8) -> u8 {
= note: `-D clippy::must-use-candidate` implied by `-D warnings`
error: this method could have a `#[must_use]` attribute
- --> $DIR/must_use_candidates.rs:17:5
+ --> $DIR/must_use_candidates.rs:22:5
|
LL | pub fn inherent_pure(&self) -> u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn inherent_pure(&self) -> u8`
error: this function could have a `#[must_use]` attribute
- --> $DIR/must_use_candidates.rs:48:1
+ --> $DIR/must_use_candidates.rs:53:1
|
LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool`
error: this function could have a `#[must_use]` attribute
- --> $DIR/must_use_candidates.rs:60:1
+ --> $DIR/must_use_candidates.rs:65:1
|
LL | pub fn rcd(_x: Rc<u32>) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn rcd(_x: Rc<u32>) -> bool`
error: this function could have a `#[must_use]` attribute
- --> $DIR/must_use_candidates.rs:68:1
+ --> $DIR/must_use_candidates.rs:73:1
|
LL | pub fn arcd(_x: Arc<u32>) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn arcd(_x: Arc<u32>) -> bool`
diff --git a/src/tools/clippy/tests/ui/mut_from_ref.rs b/src/tools/clippy/tests/ui/mut_from_ref.rs
index 7de153305..8c0c23b65 100644
--- a/src/tools/clippy/tests/ui/mut_from_ref.rs
+++ b/src/tools/clippy/tests/ui/mut_from_ref.rs
@@ -1,4 +1,4 @@
-#![allow(unused, clippy::needless_lifetimes)]
+#![allow(unused, clippy::needless_lifetimes, clippy::needless_pass_by_ref_mut)]
#![warn(clippy::mut_from_ref)]
struct Foo;
diff --git a/src/tools/clippy/tests/ui/mut_key.rs b/src/tools/clippy/tests/ui/mut_key.rs
index 1c0ba6645..15d68c089 100644
--- a/src/tools/clippy/tests/ui/mut_key.rs
+++ b/src/tools/clippy/tests/ui/mut_key.rs
@@ -2,7 +2,8 @@ use std::cell::Cell;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::hash::{Hash, Hasher};
use std::rc::Rc;
-use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering::Relaxed;
use std::sync::Arc;
struct Key(AtomicUsize);
diff --git a/src/tools/clippy/tests/ui/mut_key.stderr b/src/tools/clippy/tests/ui/mut_key.stderr
index 25dd029b1..95b9546bf 100644
--- a/src/tools/clippy/tests/ui/mut_key.stderr
+++ b/src/tools/clippy/tests/ui/mut_key.stderr
@@ -1,5 +1,5 @@
error: mutable key type
- --> $DIR/mut_key.rs:30:32
+ --> $DIR/mut_key.rs:31:32
|
LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,97 +7,97 @@ LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> Hash
= note: `-D clippy::mutable-key-type` implied by `-D warnings`
error: mutable key type
- --> $DIR/mut_key.rs:30:72
+ --> $DIR/mut_key.rs:31:72
|
LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
| ^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:31:5
+ --> $DIR/mut_key.rs:32:5
|
LL | let _other: HashMap<Key, bool> = HashMap::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:58:22
+ --> $DIR/mut_key.rs:59:22
|
LL | fn tuples_bad<U>(_m: &mut HashMap<(Key, U), bool>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:70:5
+ --> $DIR/mut_key.rs:71:5
|
LL | let _map = HashMap::<Cell<usize>, usize>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:71:5
+ --> $DIR/mut_key.rs:72:5
|
LL | let _map = HashMap::<&mut Cell<usize>, usize>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:72:5
+ --> $DIR/mut_key.rs:73:5
|
LL | let _map = HashMap::<&mut usize, usize>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:74:5
+ --> $DIR/mut_key.rs:75:5
|
LL | let _map = HashMap::<Vec<Cell<usize>>, usize>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:75:5
+ --> $DIR/mut_key.rs:76:5
|
LL | let _map = HashMap::<BTreeMap<Cell<usize>, ()>, usize>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:76:5
+ --> $DIR/mut_key.rs:77:5
|
LL | let _map = HashMap::<BTreeMap<(), Cell<usize>>, usize>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:77:5
+ --> $DIR/mut_key.rs:78:5
|
LL | let _map = HashMap::<BTreeSet<Cell<usize>>, usize>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:78:5
+ --> $DIR/mut_key.rs:79:5
|
LL | let _map = HashMap::<Option<Cell<usize>>, usize>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:79:5
+ --> $DIR/mut_key.rs:80:5
|
LL | let _map = HashMap::<Option<Vec<Cell<usize>>>, usize>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:80:5
+ --> $DIR/mut_key.rs:81:5
|
LL | let _map = HashMap::<Result<&mut usize, ()>, usize>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:82:5
+ --> $DIR/mut_key.rs:83:5
|
LL | let _map = HashMap::<Box<Cell<usize>>, usize>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:83:5
+ --> $DIR/mut_key.rs:84:5
|
LL | let _map = HashMap::<Rc<Cell<usize>>, usize>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: mutable key type
- --> $DIR/mut_key.rs:84:5
+ --> $DIR/mut_key.rs:85:5
|
LL | let _map = HashMap::<Arc<Cell<usize>>, usize>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/mut_mut.rs b/src/tools/clippy/tests/ui/mut_mut.rs
index b72134283..fe7d53e8e 100644
--- a/src/tools/clippy/tests/ui/mut_mut.rs
+++ b/src/tools/clippy/tests/ui/mut_mut.rs
@@ -1,7 +1,12 @@
//@aux-build:proc_macros.rs:proc-macro
#![warn(clippy::mut_mut)]
#![allow(unused)]
-#![allow(clippy::no_effect, clippy::uninlined_format_args, clippy::unnecessary_operation)]
+#![allow(
+ clippy::no_effect,
+ clippy::uninlined_format_args,
+ clippy::unnecessary_operation,
+ clippy::needless_pass_by_ref_mut
+)]
extern crate proc_macros;
use proc_macros::{external, inline_macros};
diff --git a/src/tools/clippy/tests/ui/mut_mut.stderr b/src/tools/clippy/tests/ui/mut_mut.stderr
index 93b857eb2..58a1c4e68 100644
--- a/src/tools/clippy/tests/ui/mut_mut.stderr
+++ b/src/tools/clippy/tests/ui/mut_mut.stderr
@@ -1,5 +1,5 @@
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:9:11
+ --> $DIR/mut_mut.rs:14:11
|
LL | fn fun(x: &mut &mut u32) -> bool {
| ^^^^^^^^^^^^^
@@ -7,13 +7,13 @@ LL | fn fun(x: &mut &mut u32) -> bool {
= note: `-D clippy::mut-mut` implied by `-D warnings`
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:26:17
+ --> $DIR/mut_mut.rs:31:17
|
LL | let mut x = &mut &mut 1u32;
| ^^^^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:41:25
+ --> $DIR/mut_mut.rs:46:25
|
LL | let mut z = inline!(&mut $(&mut 3u32));
| ^
@@ -21,37 +21,37 @@ LL | let mut z = inline!(&mut $(&mut 3u32));
= note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this expression mutably borrows a mutable reference. Consider reborrowing
- --> $DIR/mut_mut.rs:28:21
+ --> $DIR/mut_mut.rs:33:21
|
LL | let mut y = &mut x;
| ^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:32:32
+ --> $DIR/mut_mut.rs:37:32
|
LL | let y: &mut &mut u32 = &mut &mut 2;
| ^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:32:16
+ --> $DIR/mut_mut.rs:37:16
|
LL | let y: &mut &mut u32 = &mut &mut 2;
| ^^^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:37:37
+ --> $DIR/mut_mut.rs:42:37
|
LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2;
| ^^^^^^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:37:16
+ --> $DIR/mut_mut.rs:42:16
|
LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2;
| ^^^^^^^^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:37:21
+ --> $DIR/mut_mut.rs:42:21
|
LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2;
| ^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/mut_reference.rs b/src/tools/clippy/tests/ui/mut_reference.rs
index 73906121c..00661c51a 100644
--- a/src/tools/clippy/tests/ui/mut_reference.rs
+++ b/src/tools/clippy/tests/ui/mut_reference.rs
@@ -1,8 +1,21 @@
-#![allow(unused_variables)]
+#![allow(unused_variables, dead_code)]
fn takes_an_immutable_reference(a: &i32) {}
fn takes_a_mutable_reference(a: &mut i32) {}
+mod issue11268 {
+ macro_rules! x {
+ ($f:expr) => {
+ $f(&mut 1);
+ };
+ }
+
+ fn f() {
+ x!(super::takes_an_immutable_reference);
+ x!(super::takes_a_mutable_reference);
+ }
+}
+
struct MyStruct;
impl MyStruct {
diff --git a/src/tools/clippy/tests/ui/mut_reference.stderr b/src/tools/clippy/tests/ui/mut_reference.stderr
index 062d30b26..4ce1cfa4f 100644
--- a/src/tools/clippy/tests/ui/mut_reference.stderr
+++ b/src/tools/clippy/tests/ui/mut_reference.stderr
@@ -1,5 +1,5 @@
error: the function `takes_an_immutable_reference` doesn't need a mutable reference
- --> $DIR/mut_reference.rs:17:34
+ --> $DIR/mut_reference.rs:30:34
|
LL | takes_an_immutable_reference(&mut 42);
| ^^^^^^^
@@ -7,13 +7,13 @@ LL | takes_an_immutable_reference(&mut 42);
= note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings`
error: the function `as_ptr` doesn't need a mutable reference
- --> $DIR/mut_reference.rs:19:12
+ --> $DIR/mut_reference.rs:32:12
|
LL | as_ptr(&mut 42);
| ^^^^^^^
error: the method `takes_an_immutable_reference` doesn't need a mutable reference
- --> $DIR/mut_reference.rs:23:44
+ --> $DIR/mut_reference.rs:36:44
|
LL | my_struct.takes_an_immutable_reference(&mut 42);
| ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr
index db3b52b88..2d9b8f159 100644
--- a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr
@@ -2,7 +2,7 @@ error: this pattern creates a reference to a reference
--> $DIR/needless_borrow_pat.rs:59:14
|
LL | Some(ref x) => x,
- | ^^^^^ help: try this: `x`
+ | ^^^^^ help: try: `x`
|
= note: `-D clippy::needless-borrow` implied by `-D warnings`
@@ -12,7 +12,7 @@ error: this pattern creates a reference to a reference
LL | Some(ref x) => *x,
| ^^^^^
|
-help: try this
+help: try
|
LL | Some(x) => x,
| ~ ~
@@ -23,7 +23,7 @@ error: this pattern creates a reference to a reference
LL | Some(ref x) => {
| ^^^^^
|
-help: try this
+help: try
|
LL ~ Some(x) => {
LL | f1(x);
@@ -34,13 +34,13 @@ error: this pattern creates a reference to a reference
--> $DIR/needless_borrow_pat.rs:81:14
|
LL | Some(ref x) => m1!(x),
- | ^^^^^ help: try this: `x`
+ | ^^^^^ help: try: `x`
error: this pattern creates a reference to a reference
--> $DIR/needless_borrow_pat.rs:86:15
|
LL | let _ = |&ref x: &&String| {
- | ^^^^^ help: try this: `x`
+ | ^^^^^ help: try: `x`
error: this pattern creates a reference to a reference
--> $DIR/needless_borrow_pat.rs:91:10
@@ -48,7 +48,7 @@ error: this pattern creates a reference to a reference
LL | let (ref y,) = (&x,);
| ^^^^^
|
-help: try this
+help: try
|
LL ~ let (y,) = (&x,);
LL ~ let _: &String = y;
@@ -58,7 +58,7 @@ error: this pattern creates a reference to a reference
--> $DIR/needless_borrow_pat.rs:101:14
|
LL | Some(ref x) => x.0,
- | ^^^^^ help: try this: `x`
+ | ^^^^^ help: try: `x`
error: this pattern creates a reference to a reference
--> $DIR/needless_borrow_pat.rs:111:14
@@ -66,7 +66,7 @@ error: this pattern creates a reference to a reference
LL | E::A(ref x) | E::B(ref x) => *x,
| ^^^^^ ^^^^^
|
-help: try this
+help: try
|
LL | E::A(x) | E::B(x) => x,
| ~ ~ ~
@@ -75,7 +75,7 @@ error: this pattern creates a reference to a reference
--> $DIR/needless_borrow_pat.rs:117:21
|
LL | if let Some(ref x) = Some(&String::new());
- | ^^^^^ help: try this: `x`
+ | ^^^^^ help: try: `x`
error: this pattern creates a reference to a reference
--> $DIR/needless_borrow_pat.rs:125:12
@@ -83,7 +83,7 @@ error: this pattern creates a reference to a reference
LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
| ^^^^^
|
-help: try this
+help: try
|
LL ~ fn f2<'a>(&x: &&'a String) -> &'a String {
LL | let _: &String = x;
@@ -94,7 +94,7 @@ error: this pattern creates a reference to a reference
--> $DIR/needless_borrow_pat.rs:132:11
|
LL | fn f(&ref x: &&String) {
- | ^^^^^ help: try this: `x`
+ | ^^^^^ help: try: `x`
error: this pattern creates a reference to a reference
--> $DIR/needless_borrow_pat.rs:140:11
@@ -102,7 +102,7 @@ error: this pattern creates a reference to a reference
LL | fn f(&ref x: &&String) {
| ^^^^^
|
-help: try this
+help: try
|
LL ~ fn f(&x: &&String) {
LL ~ let _: &String = x;
diff --git a/src/tools/clippy/tests/ui/needless_else.stderr b/src/tools/clippy/tests/ui/needless_else.stderr
index ea6930851..49cd78501 100644
--- a/src/tools/clippy/tests/ui/needless_else.stderr
+++ b/src/tools/clippy/tests/ui/needless_else.stderr
@@ -1,4 +1,4 @@
-error: this else branch is empty
+error: this `else` branch is empty
--> $DIR/needless_else.rs:24:7
|
LL | } else {
diff --git a/src/tools/clippy/tests/ui/needless_if.fixed b/src/tools/clippy/tests/ui/needless_if.fixed
index 5e6e140c2..6001c9e93 100644
--- a/src/tools/clippy/tests/ui/needless_if.fixed
+++ b/src/tools/clippy/tests/ui/needless_if.fixed
@@ -16,8 +16,7 @@
#![warn(clippy::needless_if)]
extern crate proc_macros;
-use proc_macros::external;
-use proc_macros::with_span;
+use proc_macros::{external, with_span};
fn maybe_side_effect() -> bool {
true
diff --git a/src/tools/clippy/tests/ui/needless_if.rs b/src/tools/clippy/tests/ui/needless_if.rs
index eb28ce73b..c6be4766d 100644
--- a/src/tools/clippy/tests/ui/needless_if.rs
+++ b/src/tools/clippy/tests/ui/needless_if.rs
@@ -16,8 +16,7 @@
#![warn(clippy::needless_if)]
extern crate proc_macros;
-use proc_macros::external;
-use proc_macros::with_span;
+use proc_macros::{external, with_span};
fn maybe_side_effect() -> bool {
true
diff --git a/src/tools/clippy/tests/ui/needless_if.stderr b/src/tools/clippy/tests/ui/needless_if.stderr
index 5cb42c369..14de40095 100644
--- a/src/tools/clippy/tests/ui/needless_if.stderr
+++ b/src/tools/clippy/tests/ui/needless_if.stderr
@@ -1,5 +1,5 @@
error: this `if` branch is empty
- --> $DIR/needless_if.rs:28:5
+ --> $DIR/needless_if.rs:27:5
|
LL | if (true) {}
| ^^^^^^^^^^^^ help: you can remove it
@@ -7,13 +7,13 @@ LL | if (true) {}
= note: `-D clippy::needless-if` implied by `-D warnings`
error: this `if` branch is empty
- --> $DIR/needless_if.rs:30:5
+ --> $DIR/needless_if.rs:29:5
|
LL | if maybe_side_effect() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `maybe_side_effect();`
error: this `if` branch is empty
- --> $DIR/needless_if.rs:35:5
+ --> $DIR/needless_if.rs:34:5
|
LL | / if {
LL | | return;
@@ -28,7 +28,7 @@ LL + });
|
error: this `if` branch is empty
- --> $DIR/needless_if.rs:47:5
+ --> $DIR/needless_if.rs:46:5
|
LL | / if {
LL | | if let true = true && true { true } else { false }
@@ -44,19 +44,19 @@ LL + } && true);
|
error: this `if` branch is empty
- --> $DIR/needless_if.rs:85:5
+ --> $DIR/needless_if.rs:84:5
|
LL | if { maybe_side_effect() } {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });`
error: this `if` branch is empty
- --> $DIR/needless_if.rs:87:5
+ --> $DIR/needless_if.rs:86:5
|
LL | if { maybe_side_effect() } && true {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);`
error: this `if` branch is empty
- --> $DIR/needless_if.rs:91:5
+ --> $DIR/needless_if.rs:90:5
|
LL | if true {}
| ^^^^^^^^^^ help: you can remove it: `true;`
diff --git a/src/tools/clippy/tests/ui/needless_option_as_deref.stderr b/src/tools/clippy/tests/ui/needless_option_as_deref.stderr
index 20d28a968..4c0d502a2 100644
--- a/src/tools/clippy/tests/ui/needless_option_as_deref.stderr
+++ b/src/tools/clippy/tests/ui/needless_option_as_deref.stderr
@@ -2,7 +2,7 @@ error: derefed type is same as origin
--> $DIR/needless_option_as_deref.rs:9:29
|
LL | let _: Option<&usize> = Some(&1).as_deref();
- | ^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&1)`
+ | ^^^^^^^^^^^^^^^^^^^ help: try: `Some(&1)`
|
= note: `-D clippy::needless-option-as-deref` implied by `-D warnings`
@@ -10,13 +10,13 @@ error: derefed type is same as origin
--> $DIR/needless_option_as_deref.rs:10:33
|
LL | let _: Option<&mut usize> = Some(&mut 1).as_deref_mut();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&mut 1)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&mut 1)`
error: derefed type is same as origin
--> $DIR/needless_option_as_deref.rs:14:13
|
LL | let _ = x.as_deref_mut();
- | ^^^^^^^^^^^^^^^^ help: try this: `x`
+ | ^^^^^^^^^^^^^^^^ help: try: `x`
error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
new file mode 100644
index 000000000..4e79e5f53
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
@@ -0,0 +1,254 @@
+#![allow(clippy::if_same_then_else, clippy::no_effect)]
+#![feature(lint_reasons)]
+
+// just ignore everywhere for now
+//@ignore-32bit
+//@ignore-64bit
+
+use std::ptr::NonNull;
+
+fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ *x += *b + s.len() as u32;
+}
+
+// Should not warn.
+fn foo2(s: &mut Vec<u32>) {
+ s.push(8);
+}
+
+// Should not warn because we return it.
+fn foo3(s: &mut Vec<u32>) -> &mut Vec<u32> {
+ s
+}
+
+// Should not warn because `s` is used as mutable.
+fn foo4(s: &mut Vec<u32>) {
+ Vec::push(s, 4);
+}
+
+// Should not warn.
+fn foo5(s: &mut Vec<u32>) {
+ foo2(s);
+}
+
+fn foo6(s: &mut Vec<u32>) {
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ non_mut_ref(s);
+}
+
+fn non_mut_ref(_: &Vec<u32>) {}
+
+struct Bar;
+
+impl Bar {
+ // Should not warn on `&mut self`.
+ fn bar(&mut self) {}
+
+ fn mushroom(&self, vec: &mut Vec<i32>) -> usize {
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ vec.len()
+ }
+
+ fn badger(&mut self, vec: &mut Vec<i32>) -> usize {
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ vec.len()
+ }
+}
+
+trait Babar {
+ // Should not warn here since it's a trait method.
+ fn method(arg: &mut u32);
+}
+
+impl Babar for Bar {
+ // Should not warn here since it's a trait method.
+ fn method(a: &mut u32) {}
+}
+
+// Should not warn (checking variable aliasing).
+fn alias_check(s: &mut Vec<u32>) {
+ let mut alias = s;
+ let mut alias2 = alias;
+ let mut alias3 = alias2;
+ alias3.push(0);
+}
+
+// Should not warn (checking variable aliasing).
+fn alias_check2(mut s: &mut Vec<u32>) {
+ let mut alias = &mut s;
+ alias.push(0);
+}
+
+struct Mut<T> {
+ ptr: NonNull<T>,
+}
+
+impl<T> Mut<T> {
+ // Should not warn because `NonNull::from` also accepts `&mut`.
+ fn new(ptr: &mut T) -> Self {
+ Mut {
+ ptr: NonNull::from(ptr),
+ }
+ }
+}
+
+// Should not warn.
+fn unused(_: &mut u32, _b: &mut u8) {}
+
+// Should not warn.
+async fn f1(x: &mut i32) {
+ *x += 1;
+}
+// Should not warn.
+async fn f2(x: &mut i32, y: String) {
+ *x += 1;
+}
+// Should not warn.
+async fn f3(x: &mut i32, y: String, z: String) {
+ *x += 1;
+}
+// Should not warn.
+async fn f4(x: &mut i32, y: i32) {
+ *x += 1;
+}
+// Should not warn.
+async fn f5(x: i32, y: &mut i32) {
+ *y += 1;
+}
+// Should not warn.
+async fn f6(x: i32, y: &mut i32, z: &mut i32) {
+ *y += 1;
+ *z += 1;
+}
+// Should not warn.
+async fn f7(x: &mut i32, y: i32, z: &mut i32, a: i32) {
+ *x += 1;
+ *z += 1;
+}
+
+async fn a1(x: &mut i32) {
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ println!("{:?}", x);
+}
+async fn a2(x: &mut i32, y: String) {
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ println!("{:?}", x);
+}
+async fn a3(x: &mut i32, y: String, z: String) {
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ println!("{:?}", x);
+}
+async fn a4(x: &mut i32, y: i32) {
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ println!("{:?}", x);
+}
+async fn a5(x: i32, y: &mut i32) {
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ println!("{:?}", x);
+}
+async fn a6(x: i32, y: &mut i32) {
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ println!("{:?}", x);
+}
+async fn a7(x: i32, y: i32, z: &mut i32) {
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ println!("{:?}", z);
+}
+async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ println!("{:?}", z);
+}
+
+// Should not warn (passed as closure which takes `&mut`).
+fn passed_as_closure(s: &mut u32) {}
+
+// Should not warn.
+fn passed_as_local(s: &mut u32) {}
+
+// Should not warn.
+fn ty_unify_1(s: &mut u32) {}
+
+// Should not warn.
+fn ty_unify_2(s: &mut u32) {}
+
+// Should not warn.
+fn passed_as_field(s: &mut u32) {}
+
+fn closure_takes_mut(s: fn(&mut u32)) {}
+
+struct A {
+ s: fn(&mut u32),
+}
+
+// Should warn.
+fn used_as_path(s: &mut u32) {}
+
+// Make sure lint attributes work fine
+#[expect(clippy::needless_pass_by_ref_mut)]
+fn lint_attr(s: &mut u32) {}
+
+#[cfg(not(feature = "a"))]
+fn cfg_warn(s: &mut u32) {}
+//~^ ERROR: this argument is a mutable reference, but not used mutably
+//~| NOTE: this is cfg-gated and may require further changes
+
+#[cfg(not(feature = "a"))]
+mod foo {
+ fn cfg_warn(s: &mut u32) {}
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ //~| NOTE: this is cfg-gated and may require further changes
+}
+
+// Should not warn.
+async fn inner_async(x: &mut i32, y: &mut u32) {
+ async {
+ *y += 1;
+ *x += 1;
+ }
+ .await;
+}
+
+async fn inner_async2(x: &mut i32, y: &mut u32) {
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ async {
+ *x += 1;
+ }
+ .await;
+}
+
+async fn inner_async3(x: &mut i32, y: &mut u32) {
+ //~^ ERROR: this argument is a mutable reference, but not used mutably
+ async {
+ *y += 1;
+ }
+ .await;
+}
+
+// Should not warn.
+async fn async_vec(b: &mut Vec<bool>) {
+ b.append(&mut vec![]);
+}
+
+// Should not warn.
+async fn async_vec2(b: &mut Vec<bool>) {
+ b.push(true);
+}
+
+fn main() {
+ let mut u = 0;
+ let mut v = vec![0];
+ foo(&mut v, &0, &mut u);
+ foo2(&mut v);
+ foo3(&mut v);
+ foo4(&mut v);
+ foo5(&mut v);
+ alias_check(&mut v);
+ alias_check2(&mut v);
+ println!("{u}");
+ closure_takes_mut(passed_as_closure);
+ A { s: passed_as_field };
+ used_as_path;
+ let _: fn(&mut u32) = passed_as_local;
+ let _ = if v[0] == 0 { ty_unify_1 } else { ty_unify_2 };
+}
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
new file mode 100644
index 000000000..2e06e7252
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
@@ -0,0 +1,110 @@
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:6:11
+ |
+LL | fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
+ | ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
+ |
+ = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:31:12
+ |
+LL | fn foo6(s: &mut Vec<u32>) {
+ | ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:44:29
+ |
+LL | fn mushroom(&self, vec: &mut Vec<i32>) -> usize {
+ | ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:49:31
+ |
+LL | fn badger(&mut self, vec: &mut Vec<i32>) -> usize {
+ | ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:126:16
+ |
+LL | async fn a1(x: &mut i32) {
+ | ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:130:16
+ |
+LL | async fn a2(x: &mut i32, y: String) {
+ | ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:134:16
+ |
+LL | async fn a3(x: &mut i32, y: String, z: String) {
+ | ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:138:16
+ |
+LL | async fn a4(x: &mut i32, y: i32) {
+ | ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:142:24
+ |
+LL | async fn a5(x: i32, y: &mut i32) {
+ | ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:146:24
+ |
+LL | async fn a6(x: i32, y: &mut i32) {
+ | ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:150:32
+ |
+LL | async fn a7(x: i32, y: i32, z: &mut i32) {
+ | ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:154:24
+ |
+LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
+ | ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:154:45
+ |
+LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
+ | ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:188:16
+ |
+LL | fn cfg_warn(s: &mut u32) {}
+ | ^^^^^^^^ help: consider changing to: `&u32`
+ |
+ = note: this is cfg-gated and may require further changes
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:194:20
+ |
+LL | fn cfg_warn(s: &mut u32) {}
+ | ^^^^^^^^ help: consider changing to: `&u32`
+ |
+ = note: this is cfg-gated and may require further changes
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:208:39
+ |
+LL | async fn inner_async2(x: &mut i32, y: &mut u32) {
+ | ^^^^^^^^ help: consider changing to: `&u32`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:216:26
+ |
+LL | async fn inner_async3(x: &mut i32, y: &mut u32) {
+ | ^^^^^^^^ help: consider changing to: `&i32`
+
+error: aborting due to 17 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed b/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed
new file mode 100644
index 000000000..d6e47d07b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed
@@ -0,0 +1,40 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+ clippy::needless_return,
+ clippy::no_effect,
+ clippy::unit_arg,
+ clippy::useless_conversion,
+ unused
+)]
+
+#[macro_use]
+extern crate proc_macros;
+
+fn a() -> u32 {
+ return 0;
+}
+
+fn b() -> Result<u32, u32> {
+ return Err(0);
+}
+
+// Do not lint
+fn c() -> Option<()> {
+ return None?;
+}
+
+fn main() -> Result<(), ()> {
+ Err(())?;
+ return Ok::<(), ()>(());
+ Err(())?;
+ Ok::<(), ()>(());
+ return Err(().into());
+ external! {
+ return Err(())?;
+ }
+ with_span! {
+ return Err(())?;
+ }
+ Err(())
+}
diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs b/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs
new file mode 100644
index 000000000..4fc04d363
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs
@@ -0,0 +1,40 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+ clippy::needless_return,
+ clippy::no_effect,
+ clippy::unit_arg,
+ clippy::useless_conversion,
+ unused
+)]
+
+#[macro_use]
+extern crate proc_macros;
+
+fn a() -> u32 {
+ return 0;
+}
+
+fn b() -> Result<u32, u32> {
+ return Err(0);
+}
+
+// Do not lint
+fn c() -> Option<()> {
+ return None?;
+}
+
+fn main() -> Result<(), ()> {
+ return Err(())?;
+ return Ok::<(), ()>(());
+ Err(())?;
+ Ok::<(), ()>(());
+ return Err(().into());
+ external! {
+ return Err(())?;
+ }
+ with_span! {
+ return Err(())?;
+ }
+ Err(())
+}
diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr b/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr
new file mode 100644
index 000000000..e1d91638d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr
@@ -0,0 +1,10 @@
+error: unneeded `return` statement with `?` operator
+ --> $DIR/needless_return_with_question_mark.rs:28:5
+ |
+LL | return Err(())?;
+ | ^^^^^^^ help: remove it
+ |
+ = note: `-D clippy::needless-return-with-question-mark` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/needless_splitn.stderr b/src/tools/clippy/tests/ui/needless_splitn.stderr
index f607d8e1a..0005f7581 100644
--- a/src/tools/clippy/tests/ui/needless_splitn.stderr
+++ b/src/tools/clippy/tests/ui/needless_splitn.stderr
@@ -2,7 +2,7 @@ error: unnecessary use of `splitn`
--> $DIR/needless_splitn.rs:14:13
|
LL | let _ = str.splitn(2, '=').next();
- | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')`
+ | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')`
|
= note: `-D clippy::needless-splitn` implied by `-D warnings`
@@ -10,73 +10,73 @@ error: unnecessary use of `splitn`
--> $DIR/needless_splitn.rs:15:13
|
LL | let _ = str.splitn(2, '=').nth(0);
- | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')`
+ | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')`
error: unnecessary use of `splitn`
--> $DIR/needless_splitn.rs:18:18
|
LL | let (_, _) = str.splitn(3, '=').next_tuple().unwrap();
- | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')`
+ | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')`
error: unnecessary use of `rsplitn`
--> $DIR/needless_splitn.rs:21:13
|
LL | let _ = str.rsplitn(2, '=').next();
- | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')`
+ | ^^^^^^^^^^^^^^^^^^^ help: try: `str.rsplit('=')`
error: unnecessary use of `rsplitn`
--> $DIR/needless_splitn.rs:22:13
|
LL | let _ = str.rsplitn(2, '=').nth(0);
- | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')`
+ | ^^^^^^^^^^^^^^^^^^^ help: try: `str.rsplit('=')`
error: unnecessary use of `rsplitn`
--> $DIR/needless_splitn.rs:25:18
|
LL | let (_, _) = str.rsplitn(3, '=').next_tuple().unwrap();
- | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')`
+ | ^^^^^^^^^^^^^^^^^^^ help: try: `str.rsplit('=')`
error: unnecessary use of `splitn`
--> $DIR/needless_splitn.rs:27:13
|
LL | let _ = str.splitn(5, '=').next();
- | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')`
+ | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')`
error: unnecessary use of `splitn`
--> $DIR/needless_splitn.rs:28:13
|
LL | let _ = str.splitn(5, '=').nth(3);
- | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')`
+ | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')`
error: unnecessary use of `splitn`
--> $DIR/needless_splitn.rs:34:13
|
LL | let _ = s.splitn(2, '=').next()?;
- | ^^^^^^^^^^^^^^^^ help: try this: `s.split('=')`
+ | ^^^^^^^^^^^^^^^^ help: try: `s.split('=')`
error: unnecessary use of `splitn`
--> $DIR/needless_splitn.rs:35:13
|
LL | let _ = s.splitn(2, '=').nth(0)?;
- | ^^^^^^^^^^^^^^^^ help: try this: `s.split('=')`
+ | ^^^^^^^^^^^^^^^^ help: try: `s.split('=')`
error: unnecessary use of `rsplitn`
--> $DIR/needless_splitn.rs:36:13
|
LL | let _ = s.rsplitn(2, '=').next()?;
- | ^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit('=')`
+ | ^^^^^^^^^^^^^^^^^ help: try: `s.rsplit('=')`
error: unnecessary use of `rsplitn`
--> $DIR/needless_splitn.rs:37:13
|
LL | let _ = s.rsplitn(2, '=').nth(0)?;
- | ^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit('=')`
+ | ^^^^^^^^^^^^^^^^^ help: try: `s.rsplit('=')`
error: unnecessary use of `splitn`
--> $DIR/needless_splitn.rs:45:13
|
LL | let _ = "key=value".splitn(2, '=').nth(0).unwrap();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split('=')`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split('=')`
error: aborting due to 13 previous errors
diff --git a/src/tools/clippy/tests/ui/numbered_fields.stderr b/src/tools/clippy/tests/ui/numbered_fields.stderr
index 60c0d7898..26f7ad904 100644
--- a/src/tools/clippy/tests/ui/numbered_fields.stderr
+++ b/src/tools/clippy/tests/ui/numbered_fields.stderr
@@ -7,7 +7,7 @@ LL | | 0: 1u32,
LL | | 1: 42,
LL | | 2: 23u8,
LL | | };
- | |_____^ help: try this instead: `TupleStruct(1u32, 42, 23u8)`
+ | |_____^ help: try: `TupleStruct(1u32, 42, 23u8)`
|
= note: `-D clippy::init-numbered-fields` implied by `-D warnings`
@@ -20,7 +20,7 @@ LL | | 0: 1u32,
LL | | 2: 2u8,
LL | | 1: 3u32,
LL | | };
- | |_____^ help: try this instead: `TupleStruct(1u32, 3u32, 2u8)`
+ | |_____^ help: try: `TupleStruct(1u32, 3u32, 2u8)`
error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.rs b/src/tools/clippy/tests/ui/option_env_unwrap.rs
index 65a1b467f..61dbad939 100644
--- a/src/tools/clippy/tests/ui/option_env_unwrap.rs
+++ b/src/tools/clippy/tests/ui/option_env_unwrap.rs
@@ -9,6 +9,7 @@ use proc_macros::{external, inline_macros};
fn main() {
let _ = option_env!("PATH").unwrap();
let _ = option_env!("PATH").expect("environment variable PATH isn't set");
+ let _ = option_env!("__Y__do_not_use").unwrap(); // This test only works if you don't have a __Y__do_not_use env variable in your environment.
let _ = inline!(option_env!($"PATH").unwrap());
let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
let _ = external!(option_env!($"PATH").unwrap());
diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.stderr b/src/tools/clippy/tests/ui/option_env_unwrap.stderr
index 7bba62686..cfa9dd58a 100644
--- a/src/tools/clippy/tests/ui/option_env_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/option_env_unwrap.stderr
@@ -16,7 +16,15 @@ LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set
= help: consider using the `env!` macro instead
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:12:21
+ --> $DIR/option_env_unwrap.rs:12:13
+ |
+LL | let _ = option_env!("__Y__do_not_use").unwrap(); // This test only works if you don't have a __Y__do_not_use env variable in your env...
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using the `env!` macro instead
+
+error: this will panic at run-time if the environment variable doesn't exist at compile-time
+ --> $DIR/option_env_unwrap.rs:13:21
|
LL | let _ = inline!(option_env!($"PATH").unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +33,7 @@ LL | let _ = inline!(option_env!($"PATH").unwrap());
= note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:13:21
+ --> $DIR/option_env_unwrap.rs:14:21
|
LL | let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -34,7 +42,7 @@ LL | let _ = inline!(option_env!($"PATH").expect($"environment variable PATH
= note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:14:13
+ --> $DIR/option_env_unwrap.rs:15:13
|
LL | let _ = external!(option_env!($"PATH").unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -43,7 +51,7 @@ LL | let _ = external!(option_env!($"PATH").unwrap());
= note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this will panic at run-time if the environment variable doesn't exist at compile-time
- --> $DIR/option_env_unwrap.rs:15:13
+ --> $DIR/option_env_unwrap.rs:16:13
|
LL | let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -51,5 +59,5 @@ LL | let _ = external!(option_env!($"PATH").expect($"environment variable PA
= help: consider using the `env!` macro instead
= note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index 8e59e4375..6fee3cce6 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -5,7 +5,8 @@
clippy::redundant_closure,
clippy::ref_option_ref,
clippy::equatable_if_let,
- clippy::let_unit_value
+ clippy::let_unit_value,
+ clippy::redundant_locals
)]
fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index e72edf2a8..4b3cf948a 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -5,7 +5,8 @@
clippy::redundant_closure,
clippy::ref_option_ref,
clippy::equatable_if_let,
- clippy::let_unit_value
+ clippy::let_unit_value,
+ clippy::redundant_locals
)]
fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index aa2da2174..350f0f07e 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -1,5 +1,5 @@
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:12:5
+ --> $DIR/option_if_let_else.rs:13:5
|
LL | / if let Some(x) = string {
LL | | (true, x)
@@ -11,19 +11,19 @@ LL | | }
= note: `-D clippy::option-if-let-else` implied by `-D warnings`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:30:13
+ --> $DIR/option_if_let_else.rs:31:13
|
LL | let _ = if let Some(s) = *string { s.len() } else { 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:31:13
+ --> $DIR/option_if_let_else.rs:32:13
|
LL | let _ = if let Some(s) = &num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:32:13
+ --> $DIR/option_if_let_else.rs:33:13
|
LL | let _ = if let Some(s) = &mut num {
| _____________^
@@ -43,13 +43,13 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:38:13
+ --> $DIR/option_if_let_else.rs:39:13
|
LL | let _ = if let Some(ref s) = num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:39:13
+ --> $DIR/option_if_let_else.rs:40:13
|
LL | let _ = if let Some(mut s) = num {
| _____________^
@@ -69,7 +69,7 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:45:13
+ --> $DIR/option_if_let_else.rs:46:13
|
LL | let _ = if let Some(ref mut s) = num {
| _____________^
@@ -89,7 +89,7 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:54:5
+ --> $DIR/option_if_let_else.rs:55:5
|
LL | / if let Some(x) = arg {
LL | | let y = x * x;
@@ -108,7 +108,7 @@ LL + })
|
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:67:13
+ --> $DIR/option_if_let_else.rs:68:13
|
LL | let _ = if let Some(x) = arg {
| _____________^
@@ -120,7 +120,7 @@ LL | | };
| |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:76:13
+ --> $DIR/option_if_let_else.rs:77:13
|
LL | let _ = if let Some(x) = arg {
| _____________^
@@ -143,7 +143,7 @@ LL ~ }, |x| x * x * x * x);
|
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:109:13
+ --> $DIR/option_if_let_else.rs:110:13
|
LL | / if let Some(idx) = s.find('.') {
LL | | vec![s[..idx].to_string(), s[idx..].to_string()]
@@ -153,7 +153,7 @@ LL | | }
| |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:120:5
+ --> $DIR/option_if_let_else.rs:121:5
|
LL | / if let Ok(binding) = variable {
LL | | println!("Ok {binding}");
@@ -172,13 +172,13 @@ LL + })
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:142:13
+ --> $DIR/option_if_let_else.rs:143:13
|
LL | let _ = if let Some(x) = optional { x + 2 } else { 5 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:152:13
+ --> $DIR/option_if_let_else.rs:153:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
@@ -200,13 +200,13 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:180:13
+ --> $DIR/option_if_let_else.rs:181:13
|
LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:184:13
+ --> $DIR/option_if_let_else.rs:185:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
@@ -226,7 +226,7 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:223:13
+ --> $DIR/option_if_let_else.rs:224:13
|
LL | let _ = match s {
| _____________^
@@ -236,7 +236,7 @@ LL | | };
| |_____^ help: try: `s.map_or(1, |string| string.len())`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:227:13
+ --> $DIR/option_if_let_else.rs:228:13
|
LL | let _ = match Some(10) {
| _____________^
@@ -246,7 +246,7 @@ LL | | };
| |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:233:13
+ --> $DIR/option_if_let_else.rs:234:13
|
LL | let _ = match res {
| _____________^
@@ -256,7 +256,7 @@ LL | | };
| |_____^ help: try: `res.map_or(1, |a| a + 1)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:237:13
+ --> $DIR/option_if_let_else.rs:238:13
|
LL | let _ = match res {
| _____________^
@@ -266,13 +266,13 @@ LL | | };
| |_____^ help: try: `res.map_or(1, |a| a + 1)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:241:13
+ --> $DIR/option_if_let_else.rs:242:13
|
LL | let _ = if let Ok(a) = res { a + 1 } else { 5 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:258:9
+ --> $DIR/option_if_let_else.rs:259:9
|
LL | / match initial {
LL | | Some(value) => do_something(value),
@@ -281,7 +281,7 @@ LL | | }
| |_________^ help: try: `initial.as_ref().map_or({}, |value| do_something(value))`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:265:9
+ --> $DIR/option_if_let_else.rs:266:9
|
LL | / match initial {
LL | | Some(value) => do_something2(value),
diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr
index 0305387b9..5be5f10b0 100644
--- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr
+++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr
@@ -4,7 +4,7 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns
LL | x.field.map(do_nothing);
| ^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }`
+ | help: try: `if let Some(x_field) = x.field { do_nothing(x_field) }`
|
= note: `-D clippy::option-map-unit-fn` implied by `-D warnings`
@@ -14,7 +14,7 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns
LL | x.field.map(do_nothing);
| ^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }`
+ | help: try: `if let Some(x_field) = x.field { do_nothing(x_field) }`
error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:42:5
@@ -22,7 +22,7 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns
LL | x.field.map(diverge);
| ^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(x_field) = x.field { diverge(x_field) }`
+ | help: try: `if let Some(x_field) = x.field { diverge(x_field) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:48:5
@@ -30,7 +30,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | x.field.map(|value| x.do_option_nothing(value + captured));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }`
+ | help: try: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:50:5
@@ -38,7 +38,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | x.field.map(|value| { x.do_option_plus_one(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }`
+ | help: try: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:53:5
@@ -46,7 +46,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | x.field.map(|value| do_nothing(value + captured));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
+ | help: try: `if let Some(value) = x.field { do_nothing(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:55:5
@@ -54,7 +54,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | x.field.map(|value| { do_nothing(value + captured) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
+ | help: try: `if let Some(value) = x.field { do_nothing(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:57:5
@@ -62,7 +62,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | x.field.map(|value| { do_nothing(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
+ | help: try: `if let Some(value) = x.field { do_nothing(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:59:5
@@ -70,7 +70,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | x.field.map(|value| { { do_nothing(value + captured); } });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
+ | help: try: `if let Some(value) = x.field { do_nothing(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:62:5
@@ -78,7 +78,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | x.field.map(|value| diverge(value + captured));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
+ | help: try: `if let Some(value) = x.field { diverge(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:64:5
@@ -86,7 +86,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | x.field.map(|value| { diverge(value + captured) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
+ | help: try: `if let Some(value) = x.field { diverge(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:66:5
@@ -94,7 +94,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | x.field.map(|value| { diverge(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
+ | help: try: `if let Some(value) = x.field { diverge(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:68:5
@@ -102,7 +102,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | x.field.map(|value| { { diverge(value + captured); } });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
+ | help: try: `if let Some(value) = x.field { diverge(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:73:5
@@ -110,7 +110,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | x.field.map(|value| { let y = plus_one(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }`
+ | help: try: `if let Some(value) = x.field { let y = plus_one(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:75:5
@@ -118,7 +118,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | x.field.map(|value| { plus_one(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
+ | help: try: `if let Some(value) = x.field { plus_one(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:77:5
@@ -126,7 +126,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | x.field.map(|value| { { plus_one(value + captured); } });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
+ | help: try: `if let Some(value) = x.field { plus_one(value + captured); }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:80:5
@@ -134,7 +134,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | x.field.map(|ref value| { do_nothing(value + captured) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }`
+ | help: try: `if let Some(ref value) = x.field { do_nothing(value + captured) }`
error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:82:5
@@ -142,7 +142,7 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns
LL | option().map(do_nothing);
| ^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(a) = option() { do_nothing(a) }`
+ | help: try: `if let Some(a) = option() { do_nothing(a) }`
error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()`
--> $DIR/option_map_unit_fn_fixable.rs:84:5
@@ -150,7 +150,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns
LL | option().map(|value| println!("{:?}", value));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Some(value) = option() { println!("{:?}", value) }`
+ | help: try: `if let Some(value) = option() { println!("{:?}", value) }`
error: aborting due to 19 previous errors
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 703debb7a..581f3ad45 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -9,8 +9,7 @@
clippy::useless_vec
)]
-use std::collections::BTreeMap;
-use std::collections::HashMap;
+use std::collections::{BTreeMap, HashMap};
use std::time::Duration;
/// Checks implementation of the `OR_FUN_CALL` lint.
@@ -191,7 +190,7 @@ mod issue8239 {
acc.push_str(&f);
acc
})
- .unwrap_or_default();
+ .unwrap_or(String::new());
}
fn more_to_max_suggestion_highest_lines_1() {
@@ -204,7 +203,7 @@ mod issue8239 {
acc.push_str(&f);
acc
})
- .unwrap_or_default();
+ .unwrap_or(String::new());
}
fn equal_to_max_suggestion_highest_lines() {
@@ -216,7 +215,7 @@ mod issue8239 {
acc.push_str(&f);
acc
})
- .unwrap_or_default();
+ .unwrap_or(String::new());
}
fn less_than_max_suggestion_highest_lines() {
@@ -227,7 +226,7 @@ mod issue8239 {
acc.push_str(&f);
acc
})
- .unwrap_or_default();
+ .unwrap_or(String::new());
}
}
@@ -258,4 +257,59 @@ mod issue8993 {
}
}
+mod lazy {
+ use super::*;
+
+ fn foo() {
+ struct Foo;
+
+ impl Foo {
+ fn new() -> Foo {
+ Foo
+ }
+ }
+
+ struct FakeDefault;
+ impl FakeDefault {
+ fn default() -> Self {
+ FakeDefault
+ }
+ }
+
+ impl Default for FakeDefault {
+ fn default() -> Self {
+ FakeDefault
+ }
+ }
+
+ let with_new = Some(vec![1]);
+ with_new.unwrap_or_default();
+
+ let with_default_trait = Some(1);
+ with_default_trait.unwrap_or_default();
+
+ let with_default_type = Some(1);
+ with_default_type.unwrap_or_default();
+
+ let real_default = None::<FakeDefault>;
+ real_default.unwrap_or_default();
+
+ let mut map = HashMap::<u64, String>::new();
+ map.entry(42).or_default();
+
+ let mut btree = BTreeMap::<u64, String>::new();
+ btree.entry(42).or_default();
+
+ let stringy = Some(String::new());
+ let _ = stringy.unwrap_or_default();
+
+ // negative tests
+ let self_default = None::<FakeDefault>;
+ self_default.unwrap_or_else(<FakeDefault>::default);
+
+ let without_default = Some(Foo);
+ without_default.unwrap_or_else(Foo::new);
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index bb86fe0d4..1f3987eb8 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -9,8 +9,7 @@
clippy::useless_vec
)]
-use std::collections::BTreeMap;
-use std::collections::HashMap;
+use std::collections::{BTreeMap, HashMap};
use std::time::Duration;
/// Checks implementation of the `OR_FUN_CALL` lint.
@@ -258,4 +257,59 @@ mod issue8993 {
}
}
+mod lazy {
+ use super::*;
+
+ fn foo() {
+ struct Foo;
+
+ impl Foo {
+ fn new() -> Foo {
+ Foo
+ }
+ }
+
+ struct FakeDefault;
+ impl FakeDefault {
+ fn default() -> Self {
+ FakeDefault
+ }
+ }
+
+ impl Default for FakeDefault {
+ fn default() -> Self {
+ FakeDefault
+ }
+ }
+
+ let with_new = Some(vec![1]);
+ with_new.unwrap_or_else(Vec::new);
+
+ let with_default_trait = Some(1);
+ with_default_trait.unwrap_or_else(Default::default);
+
+ let with_default_type = Some(1);
+ with_default_type.unwrap_or_else(u64::default);
+
+ let real_default = None::<FakeDefault>;
+ real_default.unwrap_or_else(<FakeDefault as Default>::default);
+
+ let mut map = HashMap::<u64, String>::new();
+ map.entry(42).or_insert_with(String::new);
+
+ let mut btree = BTreeMap::<u64, String>::new();
+ btree.entry(42).or_insert_with(String::new);
+
+ let stringy = Some(String::new());
+ let _ = stringy.unwrap_or_else(String::new);
+
+ // negative tests
+ let self_default = None::<FakeDefault>;
+ self_default.unwrap_or_else(<FakeDefault>::default);
+
+ let without_default = Some(Foo);
+ without_default.unwrap_or_else(Foo::new);
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index 0b5c686be..519f09165 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -1,172 +1,192 @@
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:54:22
+ --> $DIR/or_fun_call.rs:53:22
|
LL | with_constructor.unwrap_or(make());
- | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)`
+ | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(make)`
|
= note: `-D clippy::or-fun-call` implied by `-D warnings`
-error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:57:14
+error: use of `unwrap_or` to construct default value
+ --> $DIR/or_fun_call.rs:56:14
|
LL | with_new.unwrap_or(Vec::new());
- | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+ |
+ = note: `-D clippy::unwrap-or-default` implied by `-D warnings`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:60:21
+ --> $DIR/or_fun_call.rs:59:21
|
LL | with_const_args.unwrap_or(Vec::with_capacity(12));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Vec::with_capacity(12))`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:63:14
+ --> $DIR/or_fun_call.rs:62:14
|
LL | with_err.unwrap_or(make());
- | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())`
+ | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| make())`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:66:19
+ --> $DIR/or_fun_call.rs:65:19
|
LL | with_err_args.unwrap_or(Vec::with_capacity(12));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Vec::with_capacity(12))`
-error: use of `unwrap_or` followed by a call to `default`
- --> $DIR/or_fun_call.rs:69:24
+error: use of `unwrap_or` to construct default value
+ --> $DIR/or_fun_call.rs:68:24
|
LL | with_default_trait.unwrap_or(Default::default());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-error: use of `unwrap_or` followed by a call to `default`
- --> $DIR/or_fun_call.rs:72:23
+error: use of `unwrap_or` to construct default value
+ --> $DIR/or_fun_call.rs:71:23
|
LL | with_default_type.unwrap_or(u64::default());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:75:18
+ --> $DIR/or_fun_call.rs:74:18
|
LL | self_default.unwrap_or(<FakeDefault>::default());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(<FakeDefault>::default)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(<FakeDefault>::default)`
-error: use of `unwrap_or` followed by a call to `default`
- --> $DIR/or_fun_call.rs:78:18
+error: use of `unwrap_or` to construct default value
+ --> $DIR/or_fun_call.rs:77:18
|
LL | real_default.unwrap_or(<FakeDefault as Default>::default());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:81:14
+error: use of `unwrap_or` to construct default value
+ --> $DIR/or_fun_call.rs:80:14
|
LL | with_vec.unwrap_or(vec![]);
- | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
+ | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:84:21
+ --> $DIR/or_fun_call.rs:83:21
|
LL | without_default.unwrap_or(Foo::new());
- | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)`
-error: use of `or_insert` followed by a call to `new`
- --> $DIR/or_fun_call.rs:87:19
+error: use of `or_insert` to construct default value
+ --> $DIR/or_fun_call.rs:86:19
|
LL | map.entry(42).or_insert(String::new());
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
-error: use of `or_insert` followed by a call to `new`
- --> $DIR/or_fun_call.rs:90:23
+error: use of `or_insert` to construct default value
+ --> $DIR/or_fun_call.rs:89:23
|
LL | map_vec.entry(42).or_insert(vec![]);
- | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+ | ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
-error: use of `or_insert` followed by a call to `new`
- --> $DIR/or_fun_call.rs:93:21
+error: use of `or_insert` to construct default value
+ --> $DIR/or_fun_call.rs:92:21
|
LL | btree.entry(42).or_insert(String::new());
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
-error: use of `or_insert` followed by a call to `new`
- --> $DIR/or_fun_call.rs:96:25
+error: use of `or_insert` to construct default value
+ --> $DIR/or_fun_call.rs:95:25
|
LL | btree_vec.entry(42).or_insert(vec![]);
- | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+ | ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
-error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:99:21
+error: use of `unwrap_or` to construct default value
+ --> $DIR/or_fun_call.rs:98:21
|
LL | let _ = stringy.unwrap_or(String::new());
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:107:21
+ --> $DIR/or_fun_call.rs:106:21
|
LL | let _ = Some(1).unwrap_or(map[&1]);
- | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])`
+ | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:109:21
+ --> $DIR/or_fun_call.rs:108:21
|
LL | let _ = Some(1).unwrap_or(map[&1]);
- | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])`
+ | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])`
error: use of `or` followed by a function call
- --> $DIR/or_fun_call.rs:133:35
+ --> $DIR/or_fun_call.rs:132:35
|
LL | let _ = Some("a".to_string()).or(Some("b".to_string()));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_else(|| Some("b".to_string()))`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:172:14
+ --> $DIR/or_fun_call.rs:171:14
|
LL | None.unwrap_or(ptr_to_ref(s));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| ptr_to_ref(s))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:178:14
+ --> $DIR/or_fun_call.rs:177:14
|
LL | None.unwrap_or(unsafe { ptr_to_ref(s) });
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
error: use of `unwrap_or` followed by a function call
- --> $DIR/or_fun_call.rs:180:14
+ --> $DIR/or_fun_call.rs:179:14
|
LL | None.unwrap_or( unsafe { ptr_to_ref(s) } );
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
-error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:194:14
+error: use of `map_or` followed by a function call
+ --> $DIR/or_fun_call.rs:254:25
|
-LL | .unwrap_or(String::new());
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
+LL | let _ = Some(4).map_or(g(), |v| v);
+ | ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(g, |v| v)`
-error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:207:14
+error: use of `map_or` followed by a function call
+ --> $DIR/or_fun_call.rs:255:25
|
-LL | .unwrap_or(String::new());
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
+LL | let _ = Some(4).map_or(g(), f);
+ | ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)`
-error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:219:14
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/or_fun_call.rs:286:18
|
-LL | .unwrap_or(String::new());
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
+LL | with_new.unwrap_or_else(Vec::new);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-error: use of `unwrap_or` followed by a call to `new`
- --> $DIR/or_fun_call.rs:230:10
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/or_fun_call.rs:289:28
|
-LL | .unwrap_or(String::new());
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
+LL | with_default_trait.unwrap_or_else(Default::default);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-error: use of `map_or` followed by a function call
- --> $DIR/or_fun_call.rs:255:25
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/or_fun_call.rs:292:27
|
-LL | let _ = Some(4).map_or(g(), |v| v);
- | ^^^^^^^^^^^^^^^^^^ help: try this: `map_or_else(g, |v| v)`
+LL | with_default_type.unwrap_or_else(u64::default);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-error: use of `map_or` followed by a function call
- --> $DIR/or_fun_call.rs:256:25
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/or_fun_call.rs:295:22
|
-LL | let _ = Some(4).map_or(g(), f);
- | ^^^^^^^^^^^^^^ help: try this: `map_or_else(g, f)`
+LL | real_default.unwrap_or_else(<FakeDefault as Default>::default);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `or_insert_with` to construct default value
+ --> $DIR/or_fun_call.rs:298:23
+ |
+LL | map.entry(42).or_insert_with(String::new);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+
+error: use of `or_insert_with` to construct default value
+ --> $DIR/or_fun_call.rs:301:25
+ |
+LL | btree.entry(42).or_insert_with(String::new);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/or_fun_call.rs:304:25
+ |
+LL | let _ = stringy.unwrap_or_else(String::new);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-error: aborting due to 28 previous errors
+error: aborting due to 31 previous errors
diff --git a/src/tools/clippy/tests/ui/or_then_unwrap.stderr b/src/tools/clippy/tests/ui/or_then_unwrap.stderr
index da88154c5..2a1a52407 100644
--- a/src/tools/clippy/tests/ui/or_then_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/or_then_unwrap.stderr
@@ -2,7 +2,7 @@ error: found `.or(Some(…)).unwrap()`
--> $DIR/or_then_unwrap.rs:24:20
|
LL | let _ = option.or(Some("fallback")).unwrap(); // should trigger lint
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or("fallback")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")`
|
= note: `-D clippy::or-then-unwrap` implied by `-D warnings`
@@ -10,13 +10,13 @@ error: found `.or(Ok(…)).unwrap()`
--> $DIR/or_then_unwrap.rs:27:20
|
LL | let _ = result.or::<&str>(Ok("fallback")).unwrap(); // should trigger lint
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or("fallback")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")`
error: found `.or(Some(…)).unwrap()`
--> $DIR/or_then_unwrap.rs:31:31
|
LL | let _ = option.map(|v| v).or(Some("fallback")).unwrap().to_string().chars(); // should trigger lint
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or("fallback")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")`
error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn.stderr b/src/tools/clippy/tests/ui/panic_in_result_fn.stderr
index 97787bc84..b758fc238 100644
--- a/src/tools/clippy/tests/ui/panic_in_result_fn.stderr
+++ b/src/tools/clippy/tests/ui/panic_in_result_fn.stderr
@@ -1,4 +1,4 @@
-error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
+error: used `panic!()` or assertion in a function that returns `Result`
--> $DIR/panic_in_result_fn.rs:6:5
|
LL | / fn result_with_panic() -> Result<bool, String> // should emit lint
@@ -7,7 +7,7 @@ LL | | panic!("error");
LL | | }
| |_____^
|
- = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+ = help: `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
--> $DIR/panic_in_result_fn.rs:8:9
|
@@ -15,55 +15,7 @@ LL | panic!("error");
| ^^^^^^^^^^^^^^^
= note: `-D clippy::panic-in-result-fn` implied by `-D warnings`
-error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:11:5
- |
-LL | / fn result_with_unimplemented() -> Result<bool, String> // should emit lint
-LL | | {
-LL | | unimplemented!();
-LL | | }
- | |_____^
- |
- = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
-note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:13:9
- |
-LL | unimplemented!();
- | ^^^^^^^^^^^^^^^^
-
-error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:16:5
- |
-LL | / fn result_with_unreachable() -> Result<bool, String> // should emit lint
-LL | | {
-LL | | unreachable!();
-LL | | }
- | |_____^
- |
- = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
-note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:18:9
- |
-LL | unreachable!();
- | ^^^^^^^^^^^^^^
-
-error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:21:5
- |
-LL | / fn result_with_todo() -> Result<bool, String> // should emit lint
-LL | | {
-LL | | todo!("Finish this");
-LL | | }
- | |_____^
- |
- = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
-note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:23:9
- |
-LL | todo!("Finish this");
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
+error: used `panic!()` or assertion in a function that returns `Result`
--> $DIR/panic_in_result_fn.rs:52:1
|
LL | / fn function_result_with_panic() -> Result<bool, String> // should emit lint
@@ -72,28 +24,12 @@ LL | | panic!("error");
LL | | }
| |_^
|
- = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+ = help: `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
--> $DIR/panic_in_result_fn.rs:54:5
|
LL | panic!("error");
| ^^^^^^^^^^^^^^^
-error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:67:1
- |
-LL | / fn main() -> Result<(), String> {
-LL | | todo!("finish main method");
-LL | | Ok(())
-LL | | }
- | |_^
- |
- = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
-note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:68:5
- |
-LL | todo!("finish main method");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 6 previous errors
+error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr b/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr
index eb0aacbb6..0dd213a7e 100644
--- a/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr
+++ b/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr
@@ -1,4 +1,4 @@
-error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
+error: used `panic!()` or assertion in a function that returns `Result`
--> $DIR/panic_in_result_fn_assertions.rs:7:5
|
LL | / fn result_with_assert_with_message(x: i32) -> Result<bool, String> // should emit lint
@@ -8,7 +8,7 @@ LL | | Ok(true)
LL | | }
| |_____^
|
- = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+ = help: `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
--> $DIR/panic_in_result_fn_assertions.rs:9:9
|
@@ -16,7 +16,7 @@ LL | assert!(x == 5, "wrong argument");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::panic-in-result-fn` implied by `-D warnings`
-error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
+error: used `panic!()` or assertion in a function that returns `Result`
--> $DIR/panic_in_result_fn_assertions.rs:13:5
|
LL | / fn result_with_assert_eq(x: i32) -> Result<bool, String> // should emit lint
@@ -26,14 +26,14 @@ LL | | Ok(true)
LL | | }
| |_____^
|
- = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+ = help: `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
--> $DIR/panic_in_result_fn_assertions.rs:15:9
|
LL | assert_eq!(x, 5);
| ^^^^^^^^^^^^^^^^
-error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
+error: used `panic!()` or assertion in a function that returns `Result`
--> $DIR/panic_in_result_fn_assertions.rs:19:5
|
LL | / fn result_with_assert_ne(x: i32) -> Result<bool, String> // should emit lint
@@ -43,7 +43,7 @@ LL | | Ok(true)
LL | | }
| |_____^
|
- = help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
+ = help: `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
--> $DIR/panic_in_result_fn_assertions.rs:21:9
|
diff --git a/src/tools/clippy/tests/ui/print_literal.stderr b/src/tools/clippy/tests/ui/print_literal.stderr
index 6404dacda..71c8d188f 100644
--- a/src/tools/clippy/tests/ui/print_literal.stderr
+++ b/src/tools/clippy/tests/ui/print_literal.stderr
@@ -5,7 +5,7 @@ LL | print!("Hello {}", "world");
| ^^^^^^^
|
= note: `-D clippy::print-literal` implied by `-D warnings`
-help: try this
+help: try
|
LL - print!("Hello {}", "world");
LL + print!("Hello world");
@@ -17,7 +17,7 @@ error: literal with an empty format string
LL | println!("Hello {} {}", world, "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - println!("Hello {} {}", world, "world");
LL + println!("Hello {} world", world);
@@ -29,7 +29,7 @@ error: literal with an empty format string
LL | println!("Hello {}", "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - println!("Hello {}", "world");
LL + println!("Hello world");
@@ -41,7 +41,7 @@ error: literal with an empty format string
LL | println!("{} {:.4}", "a literal", 5);
| ^^^^^^^^^^^
|
-help: try this
+help: try
|
LL - println!("{} {:.4}", "a literal", 5);
LL + println!("a literal {:.4}", 5);
@@ -53,7 +53,7 @@ error: literal with an empty format string
LL | println!("{0} {1}", "hello", "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - println!("{0} {1}", "hello", "world");
LL + println!("hello {1}", "world");
@@ -65,7 +65,7 @@ error: literal with an empty format string
LL | println!("{0} {1}", "hello", "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - println!("{0} {1}", "hello", "world");
LL + println!("{0} world", "hello");
@@ -77,7 +77,7 @@ error: literal with an empty format string
LL | println!("{1} {0}", "hello", "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - println!("{1} {0}", "hello", "world");
LL + println!("world {0}", "hello");
@@ -89,7 +89,7 @@ error: literal with an empty format string
LL | println!("{1} {0}", "hello", "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - println!("{1} {0}", "hello", "world");
LL + println!("{1} hello", "world");
@@ -101,7 +101,7 @@ error: literal with an empty format string
LL | println!("{foo} {bar}", foo = "hello", bar = "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - println!("{foo} {bar}", foo = "hello", bar = "world");
LL + println!("hello {bar}", bar = "world");
@@ -113,7 +113,7 @@ error: literal with an empty format string
LL | println!("{foo} {bar}", foo = "hello", bar = "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - println!("{foo} {bar}", foo = "hello", bar = "world");
LL + println!("{foo} world", foo = "hello");
@@ -125,7 +125,7 @@ error: literal with an empty format string
LL | println!("{bar} {foo}", foo = "hello", bar = "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - println!("{bar} {foo}", foo = "hello", bar = "world");
LL + println!("world {foo}", foo = "hello");
@@ -137,7 +137,7 @@ error: literal with an empty format string
LL | println!("{bar} {foo}", foo = "hello", bar = "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - println!("{bar} {foo}", foo = "hello", bar = "world");
LL + println!("{bar} hello", bar = "world");
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
index 709f74ee6..08075c382 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.rs
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -3,7 +3,8 @@
unused,
clippy::many_single_char_names,
clippy::needless_lifetimes,
- clippy::redundant_clone
+ clippy::redundant_clone,
+ clippy::needless_pass_by_ref_mut
)]
#![warn(clippy::ptr_arg)]
@@ -266,3 +267,16 @@ mod issue_9218 {
todo!()
}
}
+
+mod issue_11181 {
+ extern "C" fn allowed(_v: &Vec<u32>) {}
+
+ struct S;
+ impl S {
+ extern "C" fn allowed(_v: &Vec<u32>) {}
+ }
+
+ trait T {
+ extern "C" fn allowed(_v: &Vec<u32>) {}
+ }
+}
diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr
index d663b070b..0e9dd760f 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.stderr
+++ b/src/tools/clippy/tests/ui/ptr_arg.stderr
@@ -1,5 +1,5 @@
error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:13:14
+ --> $DIR/ptr_arg.rs:14:14
|
LL | fn do_vec(x: &Vec<i64>) {
| ^^^^^^^^^ help: change this to: `&[i64]`
@@ -7,43 +7,43 @@ LL | fn do_vec(x: &Vec<i64>) {
= note: `-D clippy::ptr-arg` implied by `-D warnings`
error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:17:18
+ --> $DIR/ptr_arg.rs:18:18
|
LL | fn do_vec_mut(x: &mut Vec<i64>) {
| ^^^^^^^^^^^^^ help: change this to: `&mut [i64]`
error: writing `&String` instead of `&str` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:21:14
+ --> $DIR/ptr_arg.rs:22:14
|
LL | fn do_str(x: &String) {
| ^^^^^^^ help: change this to: `&str`
error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:25:18
+ --> $DIR/ptr_arg.rs:26:18
|
LL | fn do_str_mut(x: &mut String) {
| ^^^^^^^^^^^ help: change this to: `&mut str`
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:29:15
+ --> $DIR/ptr_arg.rs:30:15
|
LL | fn do_path(x: &PathBuf) {
| ^^^^^^^^ help: change this to: `&Path`
error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:33:19
+ --> $DIR/ptr_arg.rs:34:19
|
LL | fn do_path_mut(x: &mut PathBuf) {
| ^^^^^^^^^^^^ help: change this to: `&mut Path`
error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:41:18
+ --> $DIR/ptr_arg.rs:42:18
|
LL | fn do_vec(x: &Vec<i64>);
| ^^^^^^^^^ help: change this to: `&[i64]`
error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:54:14
+ --> $DIR/ptr_arg.rs:55:14
|
LL | fn cloned(x: &Vec<u8>) -> Vec<u8> {
| ^^^^^^^^
@@ -60,7 +60,7 @@ LL ~ x.to_owned()
|
error: writing `&String` instead of `&str` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:63:18
+ --> $DIR/ptr_arg.rs:64:18
|
LL | fn str_cloned(x: &String) -> String {
| ^^^^^^^
@@ -76,7 +76,7 @@ LL ~ x.to_owned()
|
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:71:19
+ --> $DIR/ptr_arg.rs:72:19
|
LL | fn path_cloned(x: &PathBuf) -> PathBuf {
| ^^^^^^^^
@@ -92,7 +92,7 @@ LL ~ x.to_path_buf()
|
error: writing `&String` instead of `&str` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:79:44
+ --> $DIR/ptr_arg.rs:80:44
|
LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) {
| ^^^^^^^
@@ -106,19 +106,19 @@ LL ~ let c = y;
|
error: using a reference to `Cow` is not recommended
- --> $DIR/ptr_arg.rs:93:25
+ --> $DIR/ptr_arg.rs:94:25
|
LL | fn test_cow_with_ref(c: &Cow<[i32]>) {}
| ^^^^^^^^^^^ help: change this to: `&[i32]`
error: writing `&String` instead of `&str` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:122:66
+ --> $DIR/ptr_arg.rs:123:66
|
LL | fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec<u32>, _s: &String) {}
| ^^^^^^^ help: change this to: `&str`
error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:151:21
+ --> $DIR/ptr_arg.rs:152:21
|
LL | fn foo_vec(vec: &Vec<u8>) {
| ^^^^^^^^
@@ -131,7 +131,7 @@ LL ~ let _ = vec.to_owned().clone();
|
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:156:23
+ --> $DIR/ptr_arg.rs:157:23
|
LL | fn foo_path(path: &PathBuf) {
| ^^^^^^^^
@@ -144,7 +144,7 @@ LL ~ let _ = path.to_path_buf().clone();
|
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:161:21
+ --> $DIR/ptr_arg.rs:162:21
|
LL | fn foo_str(str: &PathBuf) {
| ^^^^^^^^
@@ -157,43 +157,43 @@ LL ~ let _ = str.to_path_buf().clone();
|
error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:167:29
+ --> $DIR/ptr_arg.rs:168:29
|
LL | fn mut_vec_slice_methods(v: &mut Vec<u32>) {
| ^^^^^^^^^^^^^ help: change this to: `&mut [u32]`
error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:229:17
+ --> $DIR/ptr_arg.rs:230:17
|
LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
| ^^^^^^^^^^^^^ help: change this to: `&mut [u32]`
error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:229:35
+ --> $DIR/ptr_arg.rs:230:35
|
LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
| ^^^^^^^^^^^ help: change this to: `&mut str`
error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:229:51
+ --> $DIR/ptr_arg.rs:230:51
|
LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
| ^^^^^^^^^^^^ help: change this to: `&mut Path`
error: using a reference to `Cow` is not recommended
- --> $DIR/ptr_arg.rs:252:39
+ --> $DIR/ptr_arg.rs:253:39
|
LL | fn cow_elided_lifetime<'a>(input: &'a Cow<str>) -> &'a str {
| ^^^^^^^^^^^^ help: change this to: `&str`
error: using a reference to `Cow` is not recommended
- --> $DIR/ptr_arg.rs:257:36
+ --> $DIR/ptr_arg.rs:258:36
|
LL | fn cow_bad_ret_ty_1<'a>(input: &'a Cow<'a, str>) -> &'static str {
| ^^^^^^^^^^^^^^^^ help: change this to: `&str`
error: using a reference to `Cow` is not recommended
- --> $DIR/ptr_arg.rs:260:40
+ --> $DIR/ptr_arg.rs:261:40
|
LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str {
| ^^^^^^^^^^^^^^^^ help: change this to: `&str`
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
index 26a64c861..84babb974 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
@@ -3,8 +3,22 @@
#![warn(clippy::ptr_as_ptr)]
+#[macro_use]
extern crate proc_macros;
-use proc_macros::{external, inline_macros};
+
+mod issue_11278_a {
+ #[derive(Debug)]
+ pub struct T<D: std::fmt::Debug + ?Sized> {
+ pub p: D,
+ }
+}
+
+mod issue_11278_b {
+ pub fn f(o: &mut super::issue_11278_a::T<dyn std::fmt::Debug>) -> super::issue_11278_a::T<String> {
+ // Retain `super`
+ *unsafe { Box::from_raw(Box::into_raw(Box::new(o)).cast::<super::issue_11278_a::T<String>>()) }
+ }
+}
#[inline_macros]
fn main() {
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.rs b/src/tools/clippy/tests/ui/ptr_as_ptr.rs
index ea40d4947..34fd76428 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.rs
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.rs
@@ -3,8 +3,22 @@
#![warn(clippy::ptr_as_ptr)]
+#[macro_use]
extern crate proc_macros;
-use proc_macros::{external, inline_macros};
+
+mod issue_11278_a {
+ #[derive(Debug)]
+ pub struct T<D: std::fmt::Debug + ?Sized> {
+ pub p: D,
+ }
+}
+
+mod issue_11278_b {
+ pub fn f(o: &mut super::issue_11278_a::T<dyn std::fmt::Debug>) -> super::issue_11278_a::T<String> {
+ // Retain `super`
+ *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T<String>) }
+ }
+}
#[inline_macros]
fn main() {
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
index 78d733994..e64f33515 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
@@ -1,37 +1,43 @@
error: `as` casting between raw pointers without changing its mutability
- --> $DIR/ptr_as_ptr.rs:14:13
+ --> $DIR/ptr_as_ptr.rs:19:33
|
-LL | let _ = ptr as *const i32;
- | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
+LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T<String>) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `Box::into_raw(Box::new(o)).cast::<super::issue_11278_a::T<String>>()`
|
= note: `-D clippy::ptr-as-ptr` implied by `-D warnings`
error: `as` casting between raw pointers without changing its mutability
- --> $DIR/ptr_as_ptr.rs:15:13
+ --> $DIR/ptr_as_ptr.rs:28:13
+ |
+LL | let _ = ptr as *const i32;
+ | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
+
+error: `as` casting between raw pointers without changing its mutability
+ --> $DIR/ptr_as_ptr.rs:29:13
|
LL | let _ = mut_ptr as *mut i32;
| ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
error: `as` casting between raw pointers without changing its mutability
- --> $DIR/ptr_as_ptr.rs:20:17
+ --> $DIR/ptr_as_ptr.rs:34:17
|
LL | let _ = *ptr_ptr as *const i32;
| ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::<i32>()`
error: `as` casting between raw pointers without changing its mutability
- --> $DIR/ptr_as_ptr.rs:33:25
+ --> $DIR/ptr_as_ptr.rs:47:25
|
LL | let _: *const i32 = ptr as *const _;
| ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()`
error: `as` casting between raw pointers without changing its mutability
- --> $DIR/ptr_as_ptr.rs:34:23
+ --> $DIR/ptr_as_ptr.rs:48:23
|
LL | let _: *mut i32 = mut_ptr as _;
| ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()`
error: `as` casting between raw pointers without changing its mutability
- --> $DIR/ptr_as_ptr.rs:37:21
+ --> $DIR/ptr_as_ptr.rs:51:21
|
LL | let _ = inline!($ptr as *const i32);
| ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::<i32>()`
@@ -39,16 +45,16 @@ LL | let _ = inline!($ptr as *const i32);
= note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `as` casting between raw pointers without changing its mutability
- --> $DIR/ptr_as_ptr.rs:58:13
+ --> $DIR/ptr_as_ptr.rs:72:13
|
LL | let _ = ptr as *const i32;
| ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
error: `as` casting between raw pointers without changing its mutability
- --> $DIR/ptr_as_ptr.rs:59:13
+ --> $DIR/ptr_as_ptr.rs:73:13
|
LL | let _ = mut_ptr as *mut i32;
| ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index 2d8920ccc..20b9e42a7 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -138,6 +138,23 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
// no warning
let _ = if let Err(e) = x { Err(e) } else { Ok(0) };
+ // issue #11283
+ // no warning
+ #[warn(clippy::question_mark_used)]
+ {
+ if let Err(err) = Ok(()) {
+ return Err(err);
+ }
+
+ if Err::<i32, _>(0).is_err() {
+ return Err(0);
+ } else {
+ return Ok(0);
+ }
+
+ unreachable!()
+ }
+
Ok(y)
}
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index 69451c17e..8bdafd46e 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -170,6 +170,23 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
// no warning
let _ = if let Err(e) = x { Err(e) } else { Ok(0) };
+ // issue #11283
+ // no warning
+ #[warn(clippy::question_mark_used)]
+ {
+ if let Err(err) = Ok(()) {
+ return Err(err);
+ }
+
+ if Err::<i32, _>(0).is_err() {
+ return Err(0);
+ } else {
+ return Ok(0);
+ }
+
+ unreachable!()
+ }
+
Ok(y)
}
diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr
index 2cfd75863..62489c8c8 100644
--- a/src/tools/clippy/tests/ui/question_mark.stderr
+++ b/src/tools/clippy/tests/ui/question_mark.stderr
@@ -115,7 +115,7 @@ LL | | }
| |_____^ help: replace it with: `x?;`
error: this block may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:197:5
+ --> $DIR/question_mark.rs:214:5
|
LL | / if let Err(err) = func_returning_result() {
LL | | return Err(err);
@@ -123,7 +123,7 @@ LL | | }
| |_____^ help: replace it with: `func_returning_result()?;`
error: this block may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:204:5
+ --> $DIR/question_mark.rs:221:5
|
LL | / if let Err(err) = func_returning_result() {
LL | | return Err(err);
@@ -131,7 +131,7 @@ LL | | }
| |_____^ help: replace it with: `func_returning_result()?;`
error: this block may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:281:13
+ --> $DIR/question_mark.rs:298:13
|
LL | / if a.is_none() {
LL | | return None;
diff --git a/src/tools/clippy/tests/ui/range_contains.fixed b/src/tools/clippy/tests/ui/range_contains.fixed
index 0a92ee7c8..47c524811 100644
--- a/src/tools/clippy/tests/ui/range_contains.fixed
+++ b/src/tools/clippy/tests/ui/range_contains.fixed
@@ -5,6 +5,8 @@
#![allow(clippy::no_effect)]
#![allow(clippy::short_circuit_statement)]
#![allow(clippy::unnecessary_operation)]
+#![allow(clippy::impossible_comparisons)]
+#![allow(clippy::redundant_comparisons)]
fn main() {
let x = 9_i32;
diff --git a/src/tools/clippy/tests/ui/range_contains.rs b/src/tools/clippy/tests/ui/range_contains.rs
index 7a83be609..a35315a64 100644
--- a/src/tools/clippy/tests/ui/range_contains.rs
+++ b/src/tools/clippy/tests/ui/range_contains.rs
@@ -5,6 +5,8 @@
#![allow(clippy::no_effect)]
#![allow(clippy::short_circuit_statement)]
#![allow(clippy::unnecessary_operation)]
+#![allow(clippy::impossible_comparisons)]
+#![allow(clippy::redundant_comparisons)]
fn main() {
let x = 9_i32;
diff --git a/src/tools/clippy/tests/ui/range_contains.stderr b/src/tools/clippy/tests/ui/range_contains.stderr
index ea34023a4..1265db695 100644
--- a/src/tools/clippy/tests/ui/range_contains.stderr
+++ b/src/tools/clippy/tests/ui/range_contains.stderr
@@ -1,5 +1,5 @@
error: manual `Range::contains` implementation
- --> $DIR/range_contains.rs:13:5
+ --> $DIR/range_contains.rs:15:5
|
LL | x >= 8 && x < 12;
| ^^^^^^^^^^^^^^^^ help: use: `(8..12).contains(&x)`
@@ -7,121 +7,121 @@ LL | x >= 8 && x < 12;
= note: `-D clippy::manual-range-contains` implied by `-D warnings`
error: manual `Range::contains` implementation
- --> $DIR/range_contains.rs:14:5
+ --> $DIR/range_contains.rs:16:5
|
LL | x < 42 && x >= 21;
| ^^^^^^^^^^^^^^^^^ help: use: `(21..42).contains(&x)`
error: manual `Range::contains` implementation
- --> $DIR/range_contains.rs:15:5
+ --> $DIR/range_contains.rs:17:5
|
LL | 100 > x && 1 <= x;
| ^^^^^^^^^^^^^^^^^ help: use: `(1..100).contains(&x)`
error: manual `RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:18:5
+ --> $DIR/range_contains.rs:20:5
|
LL | x >= 9 && x <= 99;
| ^^^^^^^^^^^^^^^^^ help: use: `(9..=99).contains(&x)`
error: manual `RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:19:5
+ --> $DIR/range_contains.rs:21:5
|
LL | x <= 33 && x >= 1;
| ^^^^^^^^^^^^^^^^^ help: use: `(1..=33).contains(&x)`
error: manual `RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:20:5
+ --> $DIR/range_contains.rs:22:5
|
LL | 999 >= x && 1 <= x;
| ^^^^^^^^^^^^^^^^^^ help: use: `(1..=999).contains(&x)`
error: manual `!Range::contains` implementation
- --> $DIR/range_contains.rs:23:5
+ --> $DIR/range_contains.rs:25:5
|
LL | x < 8 || x >= 12;
| ^^^^^^^^^^^^^^^^ help: use: `!(8..12).contains(&x)`
error: manual `!Range::contains` implementation
- --> $DIR/range_contains.rs:24:5
+ --> $DIR/range_contains.rs:26:5
|
LL | x >= 42 || x < 21;
| ^^^^^^^^^^^^^^^^^ help: use: `!(21..42).contains(&x)`
error: manual `!Range::contains` implementation
- --> $DIR/range_contains.rs:25:5
+ --> $DIR/range_contains.rs:27:5
|
LL | 100 <= x || 1 > x;
| ^^^^^^^^^^^^^^^^^ help: use: `!(1..100).contains(&x)`
error: manual `!RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:28:5
+ --> $DIR/range_contains.rs:30:5
|
LL | x < 9 || x > 99;
| ^^^^^^^^^^^^^^^ help: use: `!(9..=99).contains(&x)`
error: manual `!RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:29:5
+ --> $DIR/range_contains.rs:31:5
|
LL | x > 33 || x < 1;
| ^^^^^^^^^^^^^^^ help: use: `!(1..=33).contains(&x)`
error: manual `!RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:30:5
+ --> $DIR/range_contains.rs:32:5
|
LL | 999 < x || 1 > x;
| ^^^^^^^^^^^^^^^^ help: use: `!(1..=999).contains(&x)`
error: manual `Range::contains` implementation
- --> $DIR/range_contains.rs:45:5
+ --> $DIR/range_contains.rs:47:5
|
LL | y >= 0. && y < 1.;
| ^^^^^^^^^^^^^^^^^ help: use: `(0. ..1.).contains(&y)`
error: manual `!RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:46:5
+ --> $DIR/range_contains.rs:48:5
|
LL | y < 0. || y > 1.;
| ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)`
error: manual `RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:49:5
+ --> $DIR/range_contains.rs:51:5
|
LL | x >= -10 && x <= 10;
| ^^^^^^^^^^^^^^^^^^^ help: use: `(-10..=10).contains(&x)`
error: manual `RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:51:5
+ --> $DIR/range_contains.rs:53:5
|
LL | y >= -3. && y <= 3.;
| ^^^^^^^^^^^^^^^^^^^ help: use: `(-3. ..=3.).contains(&y)`
error: manual `RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:56:30
+ --> $DIR/range_contains.rs:58:30
|
LL | (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
| ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&z)`
error: manual `RangeInclusive::contains` implementation
- --> $DIR/range_contains.rs:56:5
+ --> $DIR/range_contains.rs:58:5
|
LL | (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
| ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&x)`
error: manual `!Range::contains` implementation
- --> $DIR/range_contains.rs:57:29
+ --> $DIR/range_contains.rs:59:29
|
LL | (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
| ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&z)`
error: manual `!Range::contains` implementation
- --> $DIR/range_contains.rs:57:5
+ --> $DIR/range_contains.rs:59:5
|
LL | (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
| ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&x)`
error: manual `Range::contains` implementation
- --> $DIR/range_contains.rs:76:5
+ --> $DIR/range_contains.rs:78:5
|
LL | x >= 8 && x < 35;
| ^^^^^^^^^^^^^^^^ help: use: `(8..35).contains(&x)`
diff --git a/src/tools/clippy/tests/ui/read_line_without_trim.fixed b/src/tools/clippy/tests/ui/read_line_without_trim.fixed
new file mode 100644
index 000000000..cb6aab84e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/read_line_without_trim.fixed
@@ -0,0 +1,36 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::read_line_without_trim)]
+
+fn main() {
+ let mut input = String::new();
+ std::io::stdin().read_line(&mut input).unwrap();
+ input.pop();
+ let _x: i32 = input.parse().unwrap(); // don't trigger here, newline character is popped
+
+ let mut input = String::new();
+ std::io::stdin().read_line(&mut input).unwrap();
+ let _x: i32 = input.trim_end().parse().unwrap();
+
+ let mut input = String::new();
+ std::io::stdin().read_line(&mut input).unwrap();
+ let _x = input.trim_end().parse::<i32>().unwrap();
+
+ let mut input = String::new();
+ std::io::stdin().read_line(&mut input).unwrap();
+ let _x = input.trim_end().parse::<u32>().unwrap();
+
+ let mut input = String::new();
+ std::io::stdin().read_line(&mut input).unwrap();
+ let _x = input.trim_end().parse::<f32>().unwrap();
+
+ let mut input = String::new();
+ std::io::stdin().read_line(&mut input).unwrap();
+ let _x = input.trim_end().parse::<bool>().unwrap();
+
+ let mut input = String::new();
+ std::io::stdin().read_line(&mut input).unwrap();
+ // this is actually ok, so don't lint here
+ let _x = input.parse::<String>().unwrap();
+}
diff --git a/src/tools/clippy/tests/ui/read_line_without_trim.rs b/src/tools/clippy/tests/ui/read_line_without_trim.rs
new file mode 100644
index 000000000..bdc409a70
--- /dev/null
+++ b/src/tools/clippy/tests/ui/read_line_without_trim.rs
@@ -0,0 +1,36 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::read_line_without_trim)]
+
+fn main() {
+ let mut input = String::new();
+ std::io::stdin().read_line(&mut input).unwrap();
+ input.pop();
+ let _x: i32 = input.parse().unwrap(); // don't trigger here, newline character is popped
+
+ let mut input = String::new();
+ std::io::stdin().read_line(&mut input).unwrap();
+ let _x: i32 = input.parse().unwrap();
+
+ let mut input = String::new();
+ std::io::stdin().read_line(&mut input).unwrap();
+ let _x = input.parse::<i32>().unwrap();
+
+ let mut input = String::new();
+ std::io::stdin().read_line(&mut input).unwrap();
+ let _x = input.parse::<u32>().unwrap();
+
+ let mut input = String::new();
+ std::io::stdin().read_line(&mut input).unwrap();
+ let _x = input.parse::<f32>().unwrap();
+
+ let mut input = String::new();
+ std::io::stdin().read_line(&mut input).unwrap();
+ let _x = input.parse::<bool>().unwrap();
+
+ let mut input = String::new();
+ std::io::stdin().read_line(&mut input).unwrap();
+ // this is actually ok, so don't lint here
+ let _x = input.parse::<String>().unwrap();
+}
diff --git a/src/tools/clippy/tests/ui/read_line_without_trim.stderr b/src/tools/clippy/tests/ui/read_line_without_trim.stderr
new file mode 100644
index 000000000..f3d7b6042
--- /dev/null
+++ b/src/tools/clippy/tests/ui/read_line_without_trim.stderr
@@ -0,0 +1,73 @@
+error: calling `.parse()` without trimming the trailing newline character
+ --> $DIR/read_line_without_trim.rs:14:25
+ |
+LL | let _x: i32 = input.parse().unwrap();
+ | ----- ^^^^^^^
+ | |
+ | help: try: `input.trim_end()`
+ |
+note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause `.parse()` to fail
+ --> $DIR/read_line_without_trim.rs:13:5
+ |
+LL | std::io::stdin().read_line(&mut input).unwrap();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: `-D clippy::read-line-without-trim` implied by `-D warnings`
+
+error: calling `.parse()` without trimming the trailing newline character
+ --> $DIR/read_line_without_trim.rs:18:20
+ |
+LL | let _x = input.parse::<i32>().unwrap();
+ | ----- ^^^^^^^^^^^^^^
+ | |
+ | help: try: `input.trim_end()`
+ |
+note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause `.parse()` to fail
+ --> $DIR/read_line_without_trim.rs:17:5
+ |
+LL | std::io::stdin().read_line(&mut input).unwrap();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: calling `.parse()` without trimming the trailing newline character
+ --> $DIR/read_line_without_trim.rs:22:20
+ |
+LL | let _x = input.parse::<u32>().unwrap();
+ | ----- ^^^^^^^^^^^^^^
+ | |
+ | help: try: `input.trim_end()`
+ |
+note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause `.parse()` to fail
+ --> $DIR/read_line_without_trim.rs:21:5
+ |
+LL | std::io::stdin().read_line(&mut input).unwrap();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: calling `.parse()` without trimming the trailing newline character
+ --> $DIR/read_line_without_trim.rs:26:20
+ |
+LL | let _x = input.parse::<f32>().unwrap();
+ | ----- ^^^^^^^^^^^^^^
+ | |
+ | help: try: `input.trim_end()`
+ |
+note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause `.parse()` to fail
+ --> $DIR/read_line_without_trim.rs:25:5
+ |
+LL | std::io::stdin().read_line(&mut input).unwrap();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: calling `.parse()` without trimming the trailing newline character
+ --> $DIR/read_line_without_trim.rs:30:20
+ |
+LL | let _x = input.parse::<bool>().unwrap();
+ | ----- ^^^^^^^^^^^^^^^
+ | |
+ | help: try: `input.trim_end()`
+ |
+note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause `.parse()` to fail
+ --> $DIR/read_line_without_trim.rs:29:5
+ |
+LL | std::io::stdin().read_line(&mut input).unwrap();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
index 30807e0f8..ff2ad8644 100644
--- a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
+++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
@@ -1,5 +1,9 @@
#![warn(clippy::read_zero_byte_vec)]
-#![allow(clippy::unused_io_amount)]
+#![allow(
+ clippy::unused_io_amount,
+ clippy::needless_pass_by_ref_mut,
+ clippy::slow_vector_initialization
+)]
use std::fs::File;
use std::io;
use std::io::prelude::*;
diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
index 08ba9753d..4c7f605f4 100644
--- a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
+++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
@@ -1,5 +1,5 @@
error: reading zero byte data to `Vec`
- --> $DIR/read_zero_byte_vec.rs:17:5
+ --> $DIR/read_zero_byte_vec.rs:21:5
|
LL | f.read_exact(&mut data).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data).unwrap();`
@@ -7,55 +7,55 @@ LL | f.read_exact(&mut data).unwrap();
= note: `-D clippy::read-zero-byte-vec` implied by `-D warnings`
error: reading zero byte data to `Vec`
- --> $DIR/read_zero_byte_vec.rs:21:5
+ --> $DIR/read_zero_byte_vec.rs:25:5
|
LL | f.read_exact(&mut data2)?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)?;`
error: reading zero byte data to `Vec`
- --> $DIR/read_zero_byte_vec.rs:25:5
+ --> $DIR/read_zero_byte_vec.rs:29:5
|
LL | f.read_exact(&mut data3)?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: reading zero byte data to `Vec`
- --> $DIR/read_zero_byte_vec.rs:29:5
+ --> $DIR/read_zero_byte_vec.rs:33:5
|
LL | let _ = f.read(&mut data4)?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: reading zero byte data to `Vec`
- --> $DIR/read_zero_byte_vec.rs:34:9
+ --> $DIR/read_zero_byte_vec.rs:38:9
|
LL | f.read(&mut data5)
| ^^^^^^^^^^^^^^^^^^
error: reading zero byte data to `Vec`
- --> $DIR/read_zero_byte_vec.rs:40:9
+ --> $DIR/read_zero_byte_vec.rs:44:9
|
LL | f.read(&mut data6)
| ^^^^^^^^^^^^^^^^^^
error: reading zero byte data to `Vec`
- --> $DIR/read_zero_byte_vec.rs:70:5
+ --> $DIR/read_zero_byte_vec.rs:74:5
|
LL | r.read(&mut data).await.unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: reading zero byte data to `Vec`
- --> $DIR/read_zero_byte_vec.rs:74:5
+ --> $DIR/read_zero_byte_vec.rs:78:5
|
LL | r.read_exact(&mut data2).await.unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: reading zero byte data to `Vec`
- --> $DIR/read_zero_byte_vec.rs:80:5
+ --> $DIR/read_zero_byte_vec.rs:84:5
|
LL | r.read(&mut data).await.unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: reading zero byte data to `Vec`
- --> $DIR/read_zero_byte_vec.rs:84:5
+ --> $DIR/read_zero_byte_vec.rs:88:5
|
LL | r.read_exact(&mut data2).await.unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/readonly_write_lock.rs b/src/tools/clippy/tests/ui/readonly_write_lock.rs
new file mode 100644
index 000000000..656b45787
--- /dev/null
+++ b/src/tools/clippy/tests/ui/readonly_write_lock.rs
@@ -0,0 +1,42 @@
+#![warn(clippy::readonly_write_lock)]
+
+use std::sync::RwLock;
+
+fn mutate_i32(x: &mut i32) {
+ *x += 1;
+}
+
+fn accept_i32(_: i32) {}
+
+fn main() {
+ let lock = RwLock::new(42);
+ let lock2 = RwLock::new(1234);
+
+ {
+ let writer = lock.write().unwrap();
+ dbg!(&writer);
+ }
+
+ {
+ let writer = lock.write().unwrap();
+ accept_i32(*writer);
+ }
+
+ {
+ let mut writer = lock.write().unwrap();
+ mutate_i32(&mut writer);
+ dbg!(&writer);
+ }
+
+ {
+ let mut writer = lock.write().unwrap();
+ *writer += 1;
+ }
+
+ {
+ let mut writer1 = lock.write().unwrap();
+ let mut writer2 = lock2.write().unwrap();
+ *writer2 += 1;
+ *writer1 = *writer2;
+ }
+}
diff --git a/src/tools/clippy/tests/ui/readonly_write_lock.stderr b/src/tools/clippy/tests/ui/readonly_write_lock.stderr
new file mode 100644
index 000000000..e3d8fce7b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/readonly_write_lock.stderr
@@ -0,0 +1,16 @@
+error: this write lock is used only for reading
+ --> $DIR/readonly_write_lock.rs:16:22
+ |
+LL | let writer = lock.write().unwrap();
+ | ^^^^^^^^^^^^ help: consider using a read lock instead: `lock.read()`
+ |
+ = note: `-D clippy::readonly-write-lock` implied by `-D warnings`
+
+error: this write lock is used only for reading
+ --> $DIR/readonly_write_lock.rs:21:22
+ |
+LL | let writer = lock.write().unwrap();
+ | ^^^^^^^^^^^^ help: consider using a read lock instead: `lock.read()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_allocation.rs b/src/tools/clippy/tests/ui/redundant_allocation.rs
index 574d34aed..9eb58a3e5 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation.rs
+++ b/src/tools/clippy/tests/ui/redundant_allocation.rs
@@ -8,8 +8,7 @@ pub struct SubT<T> {
}
mod outer_box {
- use crate::MyStruct;
- use crate::SubT;
+ use crate::{MyStruct, SubT};
use std::boxed::Box;
use std::rc::Rc;
use std::sync::Arc;
@@ -28,8 +27,7 @@ mod outer_box {
}
mod outer_rc {
- use crate::MyStruct;
- use crate::SubT;
+ use crate::{MyStruct, SubT};
use std::boxed::Box;
use std::rc::Rc;
use std::sync::Arc;
@@ -48,8 +46,7 @@ mod outer_rc {
}
mod outer_arc {
- use crate::MyStruct;
- use crate::SubT;
+ use crate::{MyStruct, SubT};
use std::boxed::Box;
use std::rc::Rc;
use std::sync::Arc;
diff --git a/src/tools/clippy/tests/ui/redundant_allocation.stderr b/src/tools/clippy/tests/ui/redundant_allocation.stderr
index e0826fefa..a9a1eed70 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation.stderr
+++ b/src/tools/clippy/tests/ui/redundant_allocation.stderr
@@ -1,5 +1,5 @@
error: usage of `Box<Rc<T>>`
- --> $DIR/redundant_allocation.rs:17:30
+ --> $DIR/redundant_allocation.rs:16:30
|
LL | pub fn box_test6<T>(foo: Box<Rc<T>>) {}
| ^^^^^^^^^^
@@ -9,7 +9,7 @@ LL | pub fn box_test6<T>(foo: Box<Rc<T>>) {}
= note: `-D clippy::redundant-allocation` implied by `-D warnings`
error: usage of `Box<Arc<T>>`
- --> $DIR/redundant_allocation.rs:19:30
+ --> $DIR/redundant_allocation.rs:18:30
|
LL | pub fn box_test7<T>(foo: Box<Arc<T>>) {}
| ^^^^^^^^^^^
@@ -18,7 +18,7 @@ LL | pub fn box_test7<T>(foo: Box<Arc<T>>) {}
= help: consider using just `Box<T>` or `Arc<T>`
error: usage of `Box<Rc<SubT<usize>>>`
- --> $DIR/redundant_allocation.rs:21:27
+ --> $DIR/redundant_allocation.rs:20:27
|
LL | pub fn box_test8() -> Box<Rc<SubT<usize>>> {
| ^^^^^^^^^^^^^^^^^^^^
@@ -27,7 +27,7 @@ LL | pub fn box_test8() -> Box<Rc<SubT<usize>>> {
= help: consider using just `Box<SubT<usize>>` or `Rc<SubT<usize>>`
error: usage of `Box<Arc<T>>`
- --> $DIR/redundant_allocation.rs:25:30
+ --> $DIR/redundant_allocation.rs:24:30
|
LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
| ^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
= help: consider using just `Box<T>` or `Arc<T>`
error: usage of `Box<Arc<SubT<T>>>`
- --> $DIR/redundant_allocation.rs:25:46
+ --> $DIR/redundant_allocation.rs:24:46
|
LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
| ^^^^^^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
= help: consider using just `Box<SubT<T>>` or `Arc<SubT<T>>`
error: usage of `Rc<Box<bool>>`
- --> $DIR/redundant_allocation.rs:37:24
+ --> $DIR/redundant_allocation.rs:35:24
|
LL | pub fn rc_test5(a: Rc<Box<bool>>) {}
| ^^^^^^^^^^^^^
@@ -54,7 +54,7 @@ LL | pub fn rc_test5(a: Rc<Box<bool>>) {}
= help: consider using just `Rc<bool>` or `Box<bool>`
error: usage of `Rc<Arc<bool>>`
- --> $DIR/redundant_allocation.rs:39:24
+ --> $DIR/redundant_allocation.rs:37:24
|
LL | pub fn rc_test7(a: Rc<Arc<bool>>) {}
| ^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ LL | pub fn rc_test7(a: Rc<Arc<bool>>) {}
= help: consider using just `Rc<bool>` or `Arc<bool>`
error: usage of `Rc<Box<SubT<usize>>>`
- --> $DIR/redundant_allocation.rs:41:26
+ --> $DIR/redundant_allocation.rs:39:26
|
LL | pub fn rc_test8() -> Rc<Box<SubT<usize>>> {
| ^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL | pub fn rc_test8() -> Rc<Box<SubT<usize>>> {
= help: consider using just `Rc<SubT<usize>>` or `Box<SubT<usize>>`
error: usage of `Rc<Arc<T>>`
- --> $DIR/redundant_allocation.rs:45:29
+ --> $DIR/redundant_allocation.rs:43:29
|
LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
| ^^^^^^^^^^
@@ -81,7 +81,7 @@ LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
= help: consider using just `Rc<T>` or `Arc<T>`
error: usage of `Rc<Arc<SubT<T>>>`
- --> $DIR/redundant_allocation.rs:45:44
+ --> $DIR/redundant_allocation.rs:43:44
|
LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
| ^^^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
= help: consider using just `Rc<SubT<T>>` or `Arc<SubT<T>>`
error: usage of `Arc<Box<bool>>`
- --> $DIR/redundant_allocation.rs:57:25
+ --> $DIR/redundant_allocation.rs:54:25
|
LL | pub fn arc_test5(a: Arc<Box<bool>>) {}
| ^^^^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL | pub fn arc_test5(a: Arc<Box<bool>>) {}
= help: consider using just `Arc<bool>` or `Box<bool>`
error: usage of `Arc<Rc<bool>>`
- --> $DIR/redundant_allocation.rs:59:25
+ --> $DIR/redundant_allocation.rs:56:25
|
LL | pub fn arc_test6(a: Arc<Rc<bool>>) {}
| ^^^^^^^^^^^^^
@@ -108,7 +108,7 @@ LL | pub fn arc_test6(a: Arc<Rc<bool>>) {}
= help: consider using just `Arc<bool>` or `Rc<bool>`
error: usage of `Arc<Box<SubT<usize>>>`
- --> $DIR/redundant_allocation.rs:61:27
+ --> $DIR/redundant_allocation.rs:58:27
|
LL | pub fn arc_test8() -> Arc<Box<SubT<usize>>> {
| ^^^^^^^^^^^^^^^^^^^^^
@@ -117,7 +117,7 @@ LL | pub fn arc_test8() -> Arc<Box<SubT<usize>>> {
= help: consider using just `Arc<SubT<usize>>` or `Box<SubT<usize>>`
error: usage of `Arc<Rc<T>>`
- --> $DIR/redundant_allocation.rs:65:30
+ --> $DIR/redundant_allocation.rs:62:30
|
LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
| ^^^^^^^^^^
@@ -126,7 +126,7 @@ LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
= help: consider using just `Arc<T>` or `Rc<T>`
error: usage of `Arc<Rc<SubT<T>>>`
- --> $DIR/redundant_allocation.rs:65:45
+ --> $DIR/redundant_allocation.rs:62:45
|
LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
| ^^^^^^^^^^^^^^^^
@@ -135,7 +135,7 @@ LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
= help: consider using just `Arc<SubT<T>>` or `Rc<SubT<T>>`
error: usage of `Rc<Box<Box<dyn T>>>`
- --> $DIR/redundant_allocation.rs:87:27
+ --> $DIR/redundant_allocation.rs:84:27
|
LL | pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {}
| ^^^^^^^^^^^^^^^^^^^
@@ -144,7 +144,7 @@ LL | pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {}
= help: consider using just `Rc<Box<dyn T>>` or `Box<Box<dyn T>>`
error: usage of `Rc<Box<Box<str>>>`
- --> $DIR/redundant_allocation.rs:119:31
+ --> $DIR/redundant_allocation.rs:116:31
|
LL | pub fn test_rc_box_str(_: Rc<Box<Box<str>>>) {}
| ^^^^^^^^^^^^^^^^^
@@ -153,7 +153,7 @@ LL | pub fn test_rc_box_str(_: Rc<Box<Box<str>>>) {}
= help: consider using just `Rc<Box<str>>` or `Box<Box<str>>`
error: usage of `Rc<Box<Box<[usize]>>>`
- --> $DIR/redundant_allocation.rs:120:33
+ --> $DIR/redundant_allocation.rs:117:33
|
LL | pub fn test_rc_box_slice(_: Rc<Box<Box<[usize]>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^
@@ -162,7 +162,7 @@ LL | pub fn test_rc_box_slice(_: Rc<Box<Box<[usize]>>>) {}
= help: consider using just `Rc<Box<[usize]>>` or `Box<Box<[usize]>>`
error: usage of `Rc<Box<Box<Path>>>`
- --> $DIR/redundant_allocation.rs:121:32
+ --> $DIR/redundant_allocation.rs:118:32
|
LL | pub fn test_rc_box_path(_: Rc<Box<Box<Path>>>) {}
| ^^^^^^^^^^^^^^^^^^
@@ -171,7 +171,7 @@ LL | pub fn test_rc_box_path(_: Rc<Box<Box<Path>>>) {}
= help: consider using just `Rc<Box<Path>>` or `Box<Box<Path>>`
error: usage of `Rc<Box<Box<DynSized>>>`
- --> $DIR/redundant_allocation.rs:122:34
+ --> $DIR/redundant_allocation.rs:119:34
|
LL | pub fn test_rc_box_custom(_: Rc<Box<Box<DynSized>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed b/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed
index edb7715f4..b97863daf 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed
+++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed
@@ -16,9 +16,7 @@ pub enum MyEnum {
}
mod outer_box {
- use crate::MyEnum;
- use crate::MyStruct;
- use crate::SubT;
+ use crate::{MyEnum, MyStruct, SubT};
use std::boxed::Box;
use std::rc::Rc;
use std::sync::Arc;
@@ -35,9 +33,7 @@ mod outer_box {
}
mod outer_rc {
- use crate::MyEnum;
- use crate::MyStruct;
- use crate::SubT;
+ use crate::{MyEnum, MyStruct, SubT};
use std::boxed::Box;
use std::rc::Rc;
use std::sync::Arc;
@@ -54,9 +50,7 @@ mod outer_rc {
}
mod outer_arc {
- use crate::MyEnum;
- use crate::MyStruct;
- use crate::SubT;
+ use crate::{MyEnum, MyStruct, SubT};
use std::boxed::Box;
use std::rc::Rc;
use std::sync::Arc;
diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs b/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs
index c59422dd9..bffb6f8c0 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs
+++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs
@@ -16,9 +16,7 @@ pub enum MyEnum {
}
mod outer_box {
- use crate::MyEnum;
- use crate::MyStruct;
- use crate::SubT;
+ use crate::{MyEnum, MyStruct, SubT};
use std::boxed::Box;
use std::rc::Rc;
use std::sync::Arc;
@@ -35,9 +33,7 @@ mod outer_box {
}
mod outer_rc {
- use crate::MyEnum;
- use crate::MyStruct;
- use crate::SubT;
+ use crate::{MyEnum, MyStruct, SubT};
use std::boxed::Box;
use std::rc::Rc;
use std::sync::Arc;
@@ -54,9 +50,7 @@ mod outer_rc {
}
mod outer_arc {
- use crate::MyEnum;
- use crate::MyStruct;
- use crate::SubT;
+ use crate::{MyEnum, MyStruct, SubT};
use std::boxed::Box;
use std::rc::Rc;
use std::sync::Arc;
diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr b/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr
index 8dd4a6a26..524ca5bf4 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr
+++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr
@@ -1,5 +1,5 @@
error: usage of `Box<&T>`
- --> $DIR/redundant_allocation_fixable.rs:26:30
+ --> $DIR/redundant_allocation_fixable.rs:24:30
|
LL | pub fn box_test1<T>(foo: Box<&T>) {}
| ^^^^^^^ help: try: `&T`
@@ -8,7 +8,7 @@ LL | pub fn box_test1<T>(foo: Box<&T>) {}
= note: `-D clippy::redundant-allocation` implied by `-D warnings`
error: usage of `Box<&MyStruct>`
- --> $DIR/redundant_allocation_fixable.rs:28:27
+ --> $DIR/redundant_allocation_fixable.rs:26:27
|
LL | pub fn box_test2(foo: Box<&MyStruct>) {}
| ^^^^^^^^^^^^^^ help: try: `&MyStruct`
@@ -16,7 +16,7 @@ LL | pub fn box_test2(foo: Box<&MyStruct>) {}
= note: `&MyStruct` is already a pointer, `Box<&MyStruct>` allocates a pointer on the heap
error: usage of `Box<&MyEnum>`
- --> $DIR/redundant_allocation_fixable.rs:30:27
+ --> $DIR/redundant_allocation_fixable.rs:28:27
|
LL | pub fn box_test3(foo: Box<&MyEnum>) {}
| ^^^^^^^^^^^^ help: try: `&MyEnum`
@@ -24,7 +24,7 @@ LL | pub fn box_test3(foo: Box<&MyEnum>) {}
= note: `&MyEnum` is already a pointer, `Box<&MyEnum>` allocates a pointer on the heap
error: usage of `Box<Box<T>>`
- --> $DIR/redundant_allocation_fixable.rs:34:30
+ --> $DIR/redundant_allocation_fixable.rs:32:30
|
LL | pub fn box_test5<T>(foo: Box<Box<T>>) {}
| ^^^^^^^^^^^ help: try: `Box<T>`
@@ -32,7 +32,7 @@ LL | pub fn box_test5<T>(foo: Box<Box<T>>) {}
= note: `Box<T>` is already on the heap, `Box<Box<T>>` makes an extra allocation
error: usage of `Rc<&T>`
- --> $DIR/redundant_allocation_fixable.rs:45:29
+ --> $DIR/redundant_allocation_fixable.rs:41:29
|
LL | pub fn rc_test1<T>(foo: Rc<&T>) {}
| ^^^^^^ help: try: `&T`
@@ -40,7 +40,7 @@ LL | pub fn rc_test1<T>(foo: Rc<&T>) {}
= note: `&T` is already a pointer, `Rc<&T>` allocates a pointer on the heap
error: usage of `Rc<&MyStruct>`
- --> $DIR/redundant_allocation_fixable.rs:47:26
+ --> $DIR/redundant_allocation_fixable.rs:43:26
|
LL | pub fn rc_test2(foo: Rc<&MyStruct>) {}
| ^^^^^^^^^^^^^ help: try: `&MyStruct`
@@ -48,7 +48,7 @@ LL | pub fn rc_test2(foo: Rc<&MyStruct>) {}
= note: `&MyStruct` is already a pointer, `Rc<&MyStruct>` allocates a pointer on the heap
error: usage of `Rc<&MyEnum>`
- --> $DIR/redundant_allocation_fixable.rs:49:26
+ --> $DIR/redundant_allocation_fixable.rs:45:26
|
LL | pub fn rc_test3(foo: Rc<&MyEnum>) {}
| ^^^^^^^^^^^ help: try: `&MyEnum`
@@ -56,7 +56,7 @@ LL | pub fn rc_test3(foo: Rc<&MyEnum>) {}
= note: `&MyEnum` is already a pointer, `Rc<&MyEnum>` allocates a pointer on the heap
error: usage of `Rc<Rc<bool>>`
- --> $DIR/redundant_allocation_fixable.rs:53:24
+ --> $DIR/redundant_allocation_fixable.rs:49:24
|
LL | pub fn rc_test6(a: Rc<Rc<bool>>) {}
| ^^^^^^^^^^^^ help: try: `Rc<bool>`
@@ -64,7 +64,7 @@ LL | pub fn rc_test6(a: Rc<Rc<bool>>) {}
= note: `Rc<bool>` is already on the heap, `Rc<Rc<bool>>` makes an extra allocation
error: usage of `Arc<&T>`
- --> $DIR/redundant_allocation_fixable.rs:64:30
+ --> $DIR/redundant_allocation_fixable.rs:58:30
|
LL | pub fn arc_test1<T>(foo: Arc<&T>) {}
| ^^^^^^^ help: try: `&T`
@@ -72,7 +72,7 @@ LL | pub fn arc_test1<T>(foo: Arc<&T>) {}
= note: `&T` is already a pointer, `Arc<&T>` allocates a pointer on the heap
error: usage of `Arc<&MyStruct>`
- --> $DIR/redundant_allocation_fixable.rs:66:27
+ --> $DIR/redundant_allocation_fixable.rs:60:27
|
LL | pub fn arc_test2(foo: Arc<&MyStruct>) {}
| ^^^^^^^^^^^^^^ help: try: `&MyStruct`
@@ -80,7 +80,7 @@ LL | pub fn arc_test2(foo: Arc<&MyStruct>) {}
= note: `&MyStruct` is already a pointer, `Arc<&MyStruct>` allocates a pointer on the heap
error: usage of `Arc<&MyEnum>`
- --> $DIR/redundant_allocation_fixable.rs:68:27
+ --> $DIR/redundant_allocation_fixable.rs:62:27
|
LL | pub fn arc_test3(foo: Arc<&MyEnum>) {}
| ^^^^^^^^^^^^ help: try: `&MyEnum`
@@ -88,7 +88,7 @@ LL | pub fn arc_test3(foo: Arc<&MyEnum>) {}
= note: `&MyEnum` is already a pointer, `Arc<&MyEnum>` allocates a pointer on the heap
error: usage of `Arc<Arc<bool>>`
- --> $DIR/redundant_allocation_fixable.rs:72:25
+ --> $DIR/redundant_allocation_fixable.rs:66:25
|
LL | pub fn arc_test7(a: Arc<Arc<bool>>) {}
| ^^^^^^^^^^^^^^ help: try: `Arc<bool>`
diff --git a/src/tools/clippy/tests/ui/redundant_guards.fixed b/src/tools/clippy/tests/ui/redundant_guards.fixed
new file mode 100644
index 000000000..49d7336ee
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_guards.fixed
@@ -0,0 +1,146 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![feature(if_let_guard)]
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::redundant_guards)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct A(u32);
+
+struct B {
+ e: Option<A>,
+}
+
+struct C(u32, u32);
+
+#[derive(PartialEq)]
+struct FloatWrapper(f32);
+fn issue11304() {
+ match 0.1 {
+ x if x == 0.0 => todo!(),
+ _ => todo!(),
+ }
+ match FloatWrapper(0.1) {
+ x if x == FloatWrapper(0.0) => todo!(),
+ _ => todo!(),
+ }
+}
+
+fn main() {
+ let c = C(1, 2);
+ match c {
+ C(x, 1) => ..,
+ _ => todo!(),
+ };
+
+ let x = Some(Some(1));
+ match x {
+ Some(Some(1)) if true => ..,
+ Some(Some(1)) => {
+ println!("a");
+ ..
+ },
+ Some(Some(1)) => ..,
+ Some(Some(2)) => ..,
+ // Don't lint, since x is used in the body
+ Some(x) if let Some(1) = x => {
+ x;
+ ..
+ }
+ _ => todo!(),
+ };
+ let y = 1;
+ match x {
+ // Don't inline these, since y is not from the pat
+ Some(x) if matches!(y, 1 if true) => ..,
+ Some(x) if let 1 = y => ..,
+ Some(x) if y == 2 => ..,
+ _ => todo!(),
+ };
+ let a = A(1);
+ match a {
+ _ if a.0 == 1 => {},
+ _ => todo!(),
+ }
+ let b = B { e: Some(A(0)) };
+ match b {
+ B { e: Some(A(2)) } => ..,
+ _ => todo!(),
+ };
+ // Do not lint, since we cannot represent this as a pattern (at least, without a conversion)
+ let v = Some(vec![1u8, 2, 3]);
+ match v {
+ Some(x) if x == [1] => {},
+ _ => {},
+ }
+
+ external! {
+ let x = Some(Some(1));
+ match x {
+ Some(x) if let Some(1) = x => ..,
+ _ => todo!(),
+ };
+ }
+ with_span! {
+ span
+ let x = Some(Some(1));
+ match x {
+ Some(x) if let Some(1) = x => ..,
+ _ => todo!(),
+ };
+ }
+}
+
+enum E {
+ A(&'static str),
+ B(&'static str),
+ C(&'static str),
+}
+
+fn i() {
+ match E::A("") {
+ // Do not lint
+ E::A(x) | E::B(x) | E::C(x) if x == "from an or pattern" => {},
+ E::A("not from an or pattern") => {},
+ _ => {},
+ };
+}
+
+fn h(v: Option<u32>) {
+ match v {
+ Some(0) => ..,
+ _ => ..,
+ };
+}
+
+// Do not lint
+
+fn f(s: Option<std::ffi::OsString>) {
+ match s {
+ Some(x) if x == "a" => {},
+ _ => {},
+ }
+}
+
+struct S {
+ a: usize,
+}
+
+impl PartialEq for S {
+ fn eq(&self, _: &Self) -> bool {
+ true
+ }
+}
+
+impl Eq for S {}
+
+static CONST_S: S = S { a: 1 };
+
+fn g(opt_s: Option<S>) {
+ match opt_s {
+ Some(x) if x == CONST_S => {},
+ _ => {},
+ }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_guards.rs b/src/tools/clippy/tests/ui/redundant_guards.rs
new file mode 100644
index 000000000..87761010d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_guards.rs
@@ -0,0 +1,146 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![feature(if_let_guard)]
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::redundant_guards)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct A(u32);
+
+struct B {
+ e: Option<A>,
+}
+
+struct C(u32, u32);
+
+#[derive(PartialEq)]
+struct FloatWrapper(f32);
+fn issue11304() {
+ match 0.1 {
+ x if x == 0.0 => todo!(),
+ _ => todo!(),
+ }
+ match FloatWrapper(0.1) {
+ x if x == FloatWrapper(0.0) => todo!(),
+ _ => todo!(),
+ }
+}
+
+fn main() {
+ let c = C(1, 2);
+ match c {
+ C(x, y) if let 1 = y => ..,
+ _ => todo!(),
+ };
+
+ let x = Some(Some(1));
+ match x {
+ Some(x) if matches!(x, Some(1) if true) => ..,
+ Some(x) if matches!(x, Some(1)) => {
+ println!("a");
+ ..
+ },
+ Some(x) if let Some(1) = x => ..,
+ Some(x) if x == Some(2) => ..,
+ // Don't lint, since x is used in the body
+ Some(x) if let Some(1) = x => {
+ x;
+ ..
+ }
+ _ => todo!(),
+ };
+ let y = 1;
+ match x {
+ // Don't inline these, since y is not from the pat
+ Some(x) if matches!(y, 1 if true) => ..,
+ Some(x) if let 1 = y => ..,
+ Some(x) if y == 2 => ..,
+ _ => todo!(),
+ };
+ let a = A(1);
+ match a {
+ _ if a.0 == 1 => {},
+ _ => todo!(),
+ }
+ let b = B { e: Some(A(0)) };
+ match b {
+ B { e } if matches!(e, Some(A(2))) => ..,
+ _ => todo!(),
+ };
+ // Do not lint, since we cannot represent this as a pattern (at least, without a conversion)
+ let v = Some(vec![1u8, 2, 3]);
+ match v {
+ Some(x) if x == [1] => {},
+ _ => {},
+ }
+
+ external! {
+ let x = Some(Some(1));
+ match x {
+ Some(x) if let Some(1) = x => ..,
+ _ => todo!(),
+ };
+ }
+ with_span! {
+ span
+ let x = Some(Some(1));
+ match x {
+ Some(x) if let Some(1) = x => ..,
+ _ => todo!(),
+ };
+ }
+}
+
+enum E {
+ A(&'static str),
+ B(&'static str),
+ C(&'static str),
+}
+
+fn i() {
+ match E::A("") {
+ // Do not lint
+ E::A(x) | E::B(x) | E::C(x) if x == "from an or pattern" => {},
+ E::A(y) if y == "not from an or pattern" => {},
+ _ => {},
+ };
+}
+
+fn h(v: Option<u32>) {
+ match v {
+ x if matches!(x, Some(0)) => ..,
+ _ => ..,
+ };
+}
+
+// Do not lint
+
+fn f(s: Option<std::ffi::OsString>) {
+ match s {
+ Some(x) if x == "a" => {},
+ _ => {},
+ }
+}
+
+struct S {
+ a: usize,
+}
+
+impl PartialEq for S {
+ fn eq(&self, _: &Self) -> bool {
+ true
+ }
+}
+
+impl Eq for S {}
+
+static CONST_S: S = S { a: 1 };
+
+fn g(opt_s: Option<S>) {
+ match opt_s {
+ Some(x) if x == CONST_S => {},
+ _ => {},
+ }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_guards.stderr b/src/tools/clippy/tests/ui/redundant_guards.stderr
new file mode 100644
index 000000000..5bdf43d23
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_guards.stderr
@@ -0,0 +1,98 @@
+error: redundant guard
+ --> $DIR/redundant_guards.rs:34:20
+ |
+LL | C(x, y) if let 1 = y => ..,
+ | ^^^^^^^^^
+ |
+ = note: `-D clippy::redundant-guards` implied by `-D warnings`
+help: try
+ |
+LL - C(x, y) if let 1 = y => ..,
+LL + C(x, 1) => ..,
+ |
+
+error: redundant guard
+ --> $DIR/redundant_guards.rs:40:20
+ |
+LL | Some(x) if matches!(x, Some(1) if true) => ..,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL | Some(Some(1)) if true => ..,
+ | ~~~~~~~ ~~~~~~~
+
+error: redundant guard
+ --> $DIR/redundant_guards.rs:41:20
+ |
+LL | Some(x) if matches!(x, Some(1)) => {
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL - Some(x) if matches!(x, Some(1)) => {
+LL + Some(Some(1)) => {
+ |
+
+error: redundant guard
+ --> $DIR/redundant_guards.rs:45:20
+ |
+LL | Some(x) if let Some(1) = x => ..,
+ | ^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL - Some(x) if let Some(1) = x => ..,
+LL + Some(Some(1)) => ..,
+ |
+
+error: redundant guard
+ --> $DIR/redundant_guards.rs:46:20
+ |
+LL | Some(x) if x == Some(2) => ..,
+ | ^^^^^^^^^^^^
+ |
+help: try
+ |
+LL - Some(x) if x == Some(2) => ..,
+LL + Some(Some(2)) => ..,
+ |
+
+error: redundant guard
+ --> $DIR/redundant_guards.rs:69:20
+ |
+LL | B { e } if matches!(e, Some(A(2))) => ..,
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL - B { e } if matches!(e, Some(A(2))) => ..,
+LL + B { e: Some(A(2)) } => ..,
+ |
+
+error: redundant guard
+ --> $DIR/redundant_guards.rs:106:20
+ |
+LL | E::A(y) if y == "not from an or pattern" => {},
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL - E::A(y) if y == "not from an or pattern" => {},
+LL + E::A("not from an or pattern") => {},
+ |
+
+error: redundant guard
+ --> $DIR/redundant_guards.rs:113:14
+ |
+LL | x if matches!(x, Some(0)) => ..,
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL - x if matches!(x, Some(0)) => ..,
+LL + Some(0) => ..,
+ |
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_locals.rs b/src/tools/clippy/tests/ui/redundant_locals.rs
new file mode 100644
index 000000000..80af38f47
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_locals.rs
@@ -0,0 +1,120 @@
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(unused, clippy::no_effect, clippy::needless_pass_by_ref_mut)]
+#![warn(clippy::redundant_locals)]
+
+extern crate proc_macros;
+use proc_macros::{external, with_span};
+
+fn main() {}
+
+fn immutable() {
+ let x = 1;
+ let x = x;
+}
+
+fn mutable() {
+ let mut x = 1;
+ let mut x = x;
+}
+
+fn upgraded_mutability() {
+ let x = 1;
+ let mut x = x;
+}
+
+fn downgraded_mutability() {
+ let mut x = 1;
+ let x = x;
+}
+
+// see #11290
+fn shadow_mutation() {
+ let mut x = 1;
+ {
+ let mut x = x;
+ x = 2;
+ }
+}
+
+fn coercion(par: &mut i32) {
+ let par: &i32 = par;
+
+ let x: &mut i32 = &mut 1;
+ let x: &i32 = x;
+}
+
+fn parameter(x: i32) {
+ let x = x;
+}
+
+fn many() {
+ let x = 1;
+ let x = x;
+ let x = x;
+ let x = x;
+ let x = x;
+}
+
+fn interleaved() {
+ let a = 1;
+ let b = 2;
+ let a = a;
+ let b = b;
+}
+
+fn block() {
+ {
+ let x = 1;
+ let x = x;
+ }
+}
+
+fn closure() {
+ || {
+ let x = 1;
+ let x = x;
+ };
+ |x: i32| {
+ let x = x;
+ };
+}
+
+fn consequential_drop_order() {
+ use std::sync::Mutex;
+
+ let mutex = Mutex::new(1);
+ let guard = mutex.lock().unwrap();
+
+ {
+ let guard = guard;
+ }
+}
+
+fn inconsequential_drop_order() {
+ let x = 1;
+
+ {
+ let x = x;
+ }
+}
+
+fn macros() {
+ macro_rules! rebind {
+ ($x:ident) => {
+ let $x = 1;
+ let $x = $x;
+ };
+ }
+
+ rebind!(x);
+
+ external! {
+ let x = 1;
+ let x = x;
+ }
+ with_span! {
+ span
+ let x = 1;
+ let x = x;
+ }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_locals.stderr b/src/tools/clippy/tests/ui/redundant_locals.stderr
new file mode 100644
index 000000000..587de0575
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_locals.stderr
@@ -0,0 +1,136 @@
+error: redundant redefinition of a binding
+ --> $DIR/redundant_locals.rs:11:9
+ |
+LL | let x = 1;
+ | ^
+LL | let x = x;
+ | ^^^^^^^^^^
+ |
+ = help: remove the redefinition of `x`
+ = note: `-D clippy::redundant-locals` implied by `-D warnings`
+
+error: redundant redefinition of a binding
+ --> $DIR/redundant_locals.rs:16:9
+ |
+LL | let mut x = 1;
+ | ^^^^^
+LL | let mut x = x;
+ | ^^^^^^^^^^^^^^
+ |
+ = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+ --> $DIR/redundant_locals.rs:46:14
+ |
+LL | fn parameter(x: i32) {
+ | ^
+LL | let x = x;
+ | ^^^^^^^^^^
+ |
+ = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+ --> $DIR/redundant_locals.rs:51:9
+ |
+LL | let x = 1;
+ | ^
+LL | let x = x;
+ | ^^^^^^^^^^
+ |
+ = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+ --> $DIR/redundant_locals.rs:52:9
+ |
+LL | let x = x;
+ | ^
+LL | let x = x;
+ | ^^^^^^^^^^
+ |
+ = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+ --> $DIR/redundant_locals.rs:53:9
+ |
+LL | let x = x;
+ | ^
+LL | let x = x;
+ | ^^^^^^^^^^
+ |
+ = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+ --> $DIR/redundant_locals.rs:54:9
+ |
+LL | let x = x;
+ | ^
+LL | let x = x;
+ | ^^^^^^^^^^
+ |
+ = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+ --> $DIR/redundant_locals.rs:59:9
+ |
+LL | let a = 1;
+ | ^
+LL | let b = 2;
+LL | let a = a;
+ | ^^^^^^^^^^
+ |
+ = help: remove the redefinition of `a`
+
+error: redundant redefinition of a binding
+ --> $DIR/redundant_locals.rs:60:9
+ |
+LL | let b = 2;
+ | ^
+LL | let a = a;
+LL | let b = b;
+ | ^^^^^^^^^^
+ |
+ = help: remove the redefinition of `b`
+
+error: redundant redefinition of a binding
+ --> $DIR/redundant_locals.rs:67:13
+ |
+LL | let x = 1;
+ | ^
+LL | let x = x;
+ | ^^^^^^^^^^
+ |
+ = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+ --> $DIR/redundant_locals.rs:74:13
+ |
+LL | let x = 1;
+ | ^
+LL | let x = x;
+ | ^^^^^^^^^^
+ |
+ = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+ --> $DIR/redundant_locals.rs:77:6
+ |
+LL | |x: i32| {
+ | ^
+LL | let x = x;
+ | ^^^^^^^^^^
+ |
+ = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+ --> $DIR/redundant_locals.rs:94:9
+ |
+LL | let x = 1;
+ | ^
+...
+LL | let x = x;
+ | ^^^^^^^^^^
+ |
+ = help: remove the redefinition of `x`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr
index e9ea3f2e6..28f33f0c9 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr
@@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_drop_order.rs:17:12
|
LL | if let Ok(_) = m.lock() {}
- | -------^^^^^----------- help: try this: `if m.lock().is_ok()`
+ | -------^^^^^----------- help: try: `if m.lock().is_ok()`
|
= note: this will change drop order of the result, as well as all temporaries
= note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important
@@ -12,7 +12,7 @@ error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_drop_order.rs:18:12
|
LL | if let Err(_) = Err::<(), _>(m.lock().unwrap().0) {}
- | -------^^^^^^------------------------------------ help: try this: `if Err::<(), _>(m.lock().unwrap().0).is_err()`
+ | -------^^^^^^------------------------------------ help: try: `if Err::<(), _>(m.lock().unwrap().0).is_err()`
|
= note: this will change drop order of the result, as well as all temporaries
= note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important
@@ -21,7 +21,7 @@ error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_drop_order.rs:21:16
|
LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {}
- | -------^^^^^----------------------------------------- help: try this: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()`
+ | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()`
|
= note: this will change drop order of the result, as well as all temporaries
= note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important
@@ -30,7 +30,7 @@ error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_drop_order.rs:23:12
|
LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {
- | -------^^^^^----------------------------------------- help: try this: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()`
+ | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()`
|
= note: this will change drop order of the result, as well as all temporaries
= note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important
@@ -39,31 +39,31 @@ error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_drop_order.rs:26:12
|
LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {}
- | -------^^^^^----------------------------------------- help: try this: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()`
+ | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()`
error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_drop_order.rs:27:12
|
LL | if let Err(_) = Err::<std::sync::MutexGuard<()>, _>(()) {}
- | -------^^^^^^------------------------------------------ help: try this: `if Err::<std::sync::MutexGuard<()>, _>(()).is_err()`
+ | -------^^^^^^------------------------------------------ help: try: `if Err::<std::sync::MutexGuard<()>, _>(()).is_err()`
error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_drop_order.rs:29:12
|
LL | if let Ok(_) = Ok::<_, ()>(String::new()) {}
- | -------^^^^^----------------------------- help: try this: `if Ok::<_, ()>(String::new()).is_ok()`
+ | -------^^^^^----------------------------- help: try: `if Ok::<_, ()>(String::new()).is_ok()`
error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_drop_order.rs:30:12
|
LL | if let Err(_) = Err::<(), _>((String::new(), ())) {}
- | -------^^^^^^------------------------------------ help: try this: `if Err::<(), _>((String::new(), ())).is_err()`
+ | -------^^^^^^------------------------------------ help: try: `if Err::<(), _>((String::new(), ())).is_err()`
error: redundant pattern matching, consider using `is_some()`
--> $DIR/redundant_pattern_matching_drop_order.rs:33:12
|
LL | if let Some(_) = Some(m.lock()) {}
- | -------^^^^^^^----------------- help: try this: `if Some(m.lock()).is_some()`
+ | -------^^^^^^^----------------- help: try: `if Some(m.lock()).is_some()`
|
= note: this will change drop order of the result, as well as all temporaries
= note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important
@@ -72,7 +72,7 @@ error: redundant pattern matching, consider using `is_some()`
--> $DIR/redundant_pattern_matching_drop_order.rs:34:12
|
LL | if let Some(_) = Some(m.lock().unwrap().0) {}
- | -------^^^^^^^---------------------------- help: try this: `if Some(m.lock().unwrap().0).is_some()`
+ | -------^^^^^^^---------------------------- help: try: `if Some(m.lock().unwrap().0).is_some()`
|
= note: this will change drop order of the result, as well as all temporaries
= note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important
@@ -81,7 +81,7 @@ error: redundant pattern matching, consider using `is_none()`
--> $DIR/redundant_pattern_matching_drop_order.rs:37:16
|
LL | if let None = None::<std::sync::MutexGuard<()>> {}
- | -------^^^^------------------------------------ help: try this: `if None::<std::sync::MutexGuard<()>>.is_none()`
+ | -------^^^^------------------------------------ help: try: `if None::<std::sync::MutexGuard<()>>.is_none()`
|
= note: this will change drop order of the result, as well as all temporaries
= note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important
@@ -90,7 +90,7 @@ error: redundant pattern matching, consider using `is_none()`
--> $DIR/redundant_pattern_matching_drop_order.rs:39:12
|
LL | if let None = None::<std::sync::MutexGuard<()>> {
- | -------^^^^------------------------------------ help: try this: `if None::<std::sync::MutexGuard<()>>.is_none()`
+ | -------^^^^------------------------------------ help: try: `if None::<std::sync::MutexGuard<()>>.is_none()`
|
= note: this will change drop order of the result, as well as all temporaries
= note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important
@@ -99,25 +99,25 @@ error: redundant pattern matching, consider using `is_none()`
--> $DIR/redundant_pattern_matching_drop_order.rs:43:12
|
LL | if let None = None::<std::sync::MutexGuard<()>> {}
- | -------^^^^------------------------------------ help: try this: `if None::<std::sync::MutexGuard<()>>.is_none()`
+ | -------^^^^------------------------------------ help: try: `if None::<std::sync::MutexGuard<()>>.is_none()`
error: redundant pattern matching, consider using `is_some()`
--> $DIR/redundant_pattern_matching_drop_order.rs:45:12
|
LL | if let Some(_) = Some(String::new()) {}
- | -------^^^^^^^---------------------- help: try this: `if Some(String::new()).is_some()`
+ | -------^^^^^^^---------------------- help: try: `if Some(String::new()).is_some()`
error: redundant pattern matching, consider using `is_some()`
--> $DIR/redundant_pattern_matching_drop_order.rs:46:12
|
LL | if let Some(_) = Some((String::new(), ())) {}
- | -------^^^^^^^---------------------------- help: try this: `if Some((String::new(), ())).is_some()`
+ | -------^^^^^^^---------------------------- help: try: `if Some((String::new(), ())).is_some()`
error: redundant pattern matching, consider using `is_ready()`
--> $DIR/redundant_pattern_matching_drop_order.rs:49:12
|
LL | if let Ready(_) = Ready(m.lock()) {}
- | -------^^^^^^^^------------------ help: try this: `if Ready(m.lock()).is_ready()`
+ | -------^^^^^^^^------------------ help: try: `if Ready(m.lock()).is_ready()`
|
= note: this will change drop order of the result, as well as all temporaries
= note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important
@@ -126,7 +126,7 @@ error: redundant pattern matching, consider using `is_ready()`
--> $DIR/redundant_pattern_matching_drop_order.rs:50:12
|
LL | if let Ready(_) = Ready(m.lock().unwrap().0) {}
- | -------^^^^^^^^----------------------------- help: try this: `if Ready(m.lock().unwrap().0).is_ready()`
+ | -------^^^^^^^^----------------------------- help: try: `if Ready(m.lock().unwrap().0).is_ready()`
|
= note: this will change drop order of the result, as well as all temporaries
= note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important
@@ -135,7 +135,7 @@ error: redundant pattern matching, consider using `is_pending()`
--> $DIR/redundant_pattern_matching_drop_order.rs:53:16
|
LL | if let Pending = Pending::<std::sync::MutexGuard<()>> {}
- | -------^^^^^^^--------------------------------------- help: try this: `if Pending::<std::sync::MutexGuard<()>>.is_pending()`
+ | -------^^^^^^^--------------------------------------- help: try: `if Pending::<std::sync::MutexGuard<()>>.is_pending()`
|
= note: this will change drop order of the result, as well as all temporaries
= note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important
@@ -144,7 +144,7 @@ error: redundant pattern matching, consider using `is_pending()`
--> $DIR/redundant_pattern_matching_drop_order.rs:55:12
|
LL | if let Pending = Pending::<std::sync::MutexGuard<()>> {
- | -------^^^^^^^--------------------------------------- help: try this: `if Pending::<std::sync::MutexGuard<()>>.is_pending()`
+ | -------^^^^^^^--------------------------------------- help: try: `if Pending::<std::sync::MutexGuard<()>>.is_pending()`
|
= note: this will change drop order of the result, as well as all temporaries
= note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important
@@ -153,19 +153,19 @@ error: redundant pattern matching, consider using `is_pending()`
--> $DIR/redundant_pattern_matching_drop_order.rs:59:12
|
LL | if let Pending = Pending::<std::sync::MutexGuard<()>> {}
- | -------^^^^^^^--------------------------------------- help: try this: `if Pending::<std::sync::MutexGuard<()>>.is_pending()`
+ | -------^^^^^^^--------------------------------------- help: try: `if Pending::<std::sync::MutexGuard<()>>.is_pending()`
error: redundant pattern matching, consider using `is_ready()`
--> $DIR/redundant_pattern_matching_drop_order.rs:61:12
|
LL | if let Ready(_) = Ready(String::new()) {}
- | -------^^^^^^^^----------------------- help: try this: `if Ready(String::new()).is_ready()`
+ | -------^^^^^^^^----------------------- help: try: `if Ready(String::new()).is_ready()`
error: redundant pattern matching, consider using `is_ready()`
--> $DIR/redundant_pattern_matching_drop_order.rs:62:12
|
LL | if let Ready(_) = Ready((String::new(), ())) {}
- | -------^^^^^^^^----------------------------- help: try this: `if Ready((String::new(), ())).is_ready()`
+ | -------^^^^^^^^----------------------------- help: try: `if Ready((String::new(), ())).is_ready()`
error: aborting due to 22 previous errors
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed
index 75ed14344..02f197aa2 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed
@@ -8,10 +8,8 @@
clippy::uninlined_format_args
)]
-use std::net::{
- IpAddr::{self, V4, V6},
- Ipv4Addr, Ipv6Addr,
-};
+use std::net::IpAddr::{self, V4, V6};
+use std::net::{Ipv4Addr, Ipv6Addr};
fn main() {
let ipaddr: IpAddr = V4(Ipv4Addr::LOCALHOST);
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs
index 9ac77409f..5c1e1810f 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs
@@ -8,10 +8,8 @@
clippy::uninlined_format_args
)]
-use std::net::{
- IpAddr::{self, V4, V6},
- Ipv4Addr, Ipv6Addr,
-};
+use std::net::IpAddr::{self, V4, V6};
+use std::net::{Ipv4Addr, Ipv6Addr};
fn main() {
let ipaddr: IpAddr = V4(Ipv4Addr::LOCALHOST);
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr
index 6d1fb2964..bec8d3088 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr
@@ -1,130 +1,130 @@
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:18:12
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:16:12
|
LL | if let V4(_) = &ipaddr {}
- | -------^^^^^---------- help: try this: `if ipaddr.is_ipv4()`
+ | -------^^^^^---------- help: try: `if ipaddr.is_ipv4()`
|
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:20:12
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:18:12
|
LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
- | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()`
+ | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:22:12
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:20:12
|
LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
- | -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()`
+ | -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:24:15
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:22:15
|
LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
- | ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()`
+ | ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:26:15
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:24:15
|
LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
- | ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()`
+ | ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:36:5
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:34:5
|
LL | / match V4(Ipv4Addr::LOCALHOST) {
LL | | V4(_) => true,
LL | | V6(_) => false,
LL | | };
- | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()`
+ | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:41:5
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:39:5
|
LL | / match V4(Ipv4Addr::LOCALHOST) {
LL | | V4(_) => false,
LL | | V6(_) => true,
LL | | };
- | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv6()`
+ | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:46:5
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:44:5
|
LL | / match V6(Ipv6Addr::LOCALHOST) {
LL | | V4(_) => false,
LL | | V6(_) => true,
LL | | };
- | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv6()`
+ | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:51:5
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:49:5
|
LL | / match V6(Ipv6Addr::LOCALHOST) {
LL | | V4(_) => true,
LL | | V6(_) => false,
LL | | };
- | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv4()`
+ | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:56:20
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:54:20
|
LL | let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) {
- | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()`
+ | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:64:20
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:62:20
|
LL | let _ = if let V4(_) = gen_ipaddr() {
- | -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv4()`
+ | -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:66:19
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:64:19
|
LL | } else if let V6(_) = gen_ipaddr() {
- | -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv6()`
+ | -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:78:12
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:76:12
|
LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
- | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()`
+ | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:80:12
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:78:12
|
LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
- | -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()`
+ | -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:82:15
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:80:15
|
LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
- | ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()`
+ | ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:84:15
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:82:15
|
LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
- | ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()`
+ | ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:86:5
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:84:5
|
LL | / match V4(Ipv4Addr::LOCALHOST) {
LL | | V4(_) => true,
LL | | V6(_) => false,
LL | | };
- | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()`
+ | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> $DIR/redundant_pattern_matching_ipaddr.rs:91:5
+ --> $DIR/redundant_pattern_matching_ipaddr.rs:89:5
|
LL | / match V6(Ipv6Addr::LOCALHOST) {
LL | | V4(_) => false,
LL | | V6(_) => true,
LL | | };
- | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv6()`
+ | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: aborting due to 18 previous errors
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
index a63ba5809..d9fcd98c5 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
@@ -10,6 +10,20 @@
clippy::equatable_if_let,
clippy::if_same_then_else
)]
+#![feature(let_chains, if_let_guard)]
+
+fn issue_11174<T>(boolean: bool, maybe_some: Option<T>) -> bool {
+ maybe_some.is_none() && (!boolean)
+}
+
+fn issue_11174_edge_cases<T>(boolean: bool, boolean2: bool, maybe_some: Option<T>) {
+ let _ = maybe_some.is_none() && (boolean || boolean2); // guard needs parentheses
+ let _ = match maybe_some { // can't use `matches!` here
+ // because `expr` metavars in macros don't allow let exprs
+ None if let Some(x) = Some(0) && x > 5 => true,
+ _ => false
+ };
+}
fn main() {
if None::<()>.is_none() {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
index 631f90916..cbd9494f1 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
@@ -10,6 +10,20 @@
clippy::equatable_if_let,
clippy::if_same_then_else
)]
+#![feature(let_chains, if_let_guard)]
+
+fn issue_11174<T>(boolean: bool, maybe_some: Option<T>) -> bool {
+ matches!(maybe_some, None if !boolean)
+}
+
+fn issue_11174_edge_cases<T>(boolean: bool, boolean2: bool, maybe_some: Option<T>) {
+ let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses
+ let _ = match maybe_some { // can't use `matches!` here
+ // because `expr` metavars in macros don't allow let exprs
+ None if let Some(x) = Some(0) && x > 5 => true,
+ _ => false
+ };
+}
fn main() {
if let None = None::<()> {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
index 717b603c4..b0e43924d 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
@@ -1,200 +1,212 @@
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:15:12
+ --> $DIR/redundant_pattern_matching_option.rs:16:5
|
-LL | if let None = None::<()> {}
- | -------^^^^------------- help: try this: `if None::<()>.is_none()`
+LL | matches!(maybe_some, None if !boolean)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (!boolean)`
|
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+error: redundant pattern matching, consider using `is_none()`
+ --> $DIR/redundant_pattern_matching_option.rs:20:13
+ |
+LL | let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (boolean || boolean2)`
+
+error: redundant pattern matching, consider using `is_none()`
+ --> $DIR/redundant_pattern_matching_option.rs:29:12
+ |
+LL | if let None = None::<()> {}
+ | -------^^^^------------- help: try: `if None::<()>.is_none()`
+
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:17:12
+ --> $DIR/redundant_pattern_matching_option.rs:31:12
|
LL | if let Some(_) = Some(42) {}
- | -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
+ | -------^^^^^^^----------- help: try: `if Some(42).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:19:12
+ --> $DIR/redundant_pattern_matching_option.rs:33:12
|
LL | if let Some(_) = Some(42) {
- | -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
+ | -------^^^^^^^----------- help: try: `if Some(42).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:25:15
+ --> $DIR/redundant_pattern_matching_option.rs:39:15
|
LL | while let Some(_) = Some(42) {}
- | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
+ | ----------^^^^^^^----------- help: try: `while Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:27:15
+ --> $DIR/redundant_pattern_matching_option.rs:41:15
|
LL | while let None = Some(42) {}
- | ----------^^^^----------- help: try this: `while Some(42).is_none()`
+ | ----------^^^^----------- help: try: `while Some(42).is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:29:15
+ --> $DIR/redundant_pattern_matching_option.rs:43:15
|
LL | while let None = None::<()> {}
- | ----------^^^^------------- help: try this: `while None::<()>.is_none()`
+ | ----------^^^^------------- help: try: `while None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:32:15
+ --> $DIR/redundant_pattern_matching_option.rs:46:15
|
LL | while let Some(_) = v.pop() {
- | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
+ | ----------^^^^^^^---------- help: try: `while v.pop().is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:40:5
+ --> $DIR/redundant_pattern_matching_option.rs:54:5
|
LL | / match Some(42) {
LL | | Some(_) => true,
LL | | None => false,
LL | | };
- | |_____^ help: try this: `Some(42).is_some()`
+ | |_____^ help: try: `Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:45:5
+ --> $DIR/redundant_pattern_matching_option.rs:59:5
|
LL | / match None::<()> {
LL | | Some(_) => false,
LL | | None => true,
LL | | };
- | |_____^ help: try this: `None::<()>.is_none()`
+ | |_____^ help: try: `None::<()>.is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:50:13
+ --> $DIR/redundant_pattern_matching_option.rs:64:13
|
LL | let _ = match None::<()> {
| _____________^
LL | | Some(_) => false,
LL | | None => true,
LL | | };
- | |_____^ help: try this: `None::<()>.is_none()`
+ | |_____^ help: try: `None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:56:20
+ --> $DIR/redundant_pattern_matching_option.rs:70:20
|
LL | let _ = if let Some(_) = opt { true } else { false };
- | -------^^^^^^^------ help: try this: `if opt.is_some()`
+ | -------^^^^^^^------ help: try: `if opt.is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:62:20
+ --> $DIR/redundant_pattern_matching_option.rs:76:20
|
LL | let _ = if let Some(_) = gen_opt() {
- | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
+ | -------^^^^^^^------------ help: try: `if gen_opt().is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:64:19
+ --> $DIR/redundant_pattern_matching_option.rs:78:19
|
LL | } else if let None = gen_opt() {
- | -------^^^^------------ help: try this: `if gen_opt().is_none()`
+ | -------^^^^------------ help: try: `if gen_opt().is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:70:12
+ --> $DIR/redundant_pattern_matching_option.rs:84:12
|
LL | if let Some(..) = gen_opt() {}
- | -------^^^^^^^^------------ help: try this: `if gen_opt().is_some()`
+ | -------^^^^^^^^------------ help: try: `if gen_opt().is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:85:12
+ --> $DIR/redundant_pattern_matching_option.rs:99:12
|
LL | if let Some(_) = Some(42) {}
- | -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
+ | -------^^^^^^^----------- help: try: `if Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:87:12
+ --> $DIR/redundant_pattern_matching_option.rs:101:12
|
LL | if let None = None::<()> {}
- | -------^^^^------------- help: try this: `if None::<()>.is_none()`
+ | -------^^^^------------- help: try: `if None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:89:15
+ --> $DIR/redundant_pattern_matching_option.rs:103:15
|
LL | while let Some(_) = Some(42) {}
- | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
+ | ----------^^^^^^^----------- help: try: `while Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:91:15
+ --> $DIR/redundant_pattern_matching_option.rs:105:15
|
LL | while let None = None::<()> {}
- | ----------^^^^------------- help: try this: `while None::<()>.is_none()`
+ | ----------^^^^------------- help: try: `while None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:93:5
+ --> $DIR/redundant_pattern_matching_option.rs:107:5
|
LL | / match Some(42) {
LL | | Some(_) => true,
LL | | None => false,
LL | | };
- | |_____^ help: try this: `Some(42).is_some()`
+ | |_____^ help: try: `Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:98:5
+ --> $DIR/redundant_pattern_matching_option.rs:112:5
|
LL | / match None::<()> {
LL | | Some(_) => false,
LL | | None => true,
LL | | };
- | |_____^ help: try this: `None::<()>.is_none()`
+ | |_____^ help: try: `None::<()>.is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:106:12
+ --> $DIR/redundant_pattern_matching_option.rs:120:12
|
LL | if let None = *(&None::<()>) {}
- | -------^^^^----------------- help: try this: `if (&None::<()>).is_none()`
+ | -------^^^^----------------- help: try: `if (&None::<()>).is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:107:12
+ --> $DIR/redundant_pattern_matching_option.rs:121:12
|
LL | if let None = *&None::<()> {}
- | -------^^^^--------------- help: try this: `if (&None::<()>).is_none()`
+ | -------^^^^--------------- help: try: `if (&None::<()>).is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:113:5
+ --> $DIR/redundant_pattern_matching_option.rs:127:5
|
LL | / match x {
LL | | Some(_) => true,
LL | | _ => false,
LL | | };
- | |_____^ help: try this: `x.is_some()`
+ | |_____^ help: try: `x.is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:118:5
+ --> $DIR/redundant_pattern_matching_option.rs:132:5
|
LL | / match x {
LL | | None => true,
LL | | _ => false,
LL | | };
- | |_____^ help: try this: `x.is_none()`
+ | |_____^ help: try: `x.is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:123:5
+ --> $DIR/redundant_pattern_matching_option.rs:137:5
|
LL | / match x {
LL | | Some(_) => false,
LL | | _ => true,
LL | | };
- | |_____^ help: try this: `x.is_none()`
+ | |_____^ help: try: `x.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:128:5
+ --> $DIR/redundant_pattern_matching_option.rs:142:5
|
LL | / match x {
LL | | None => false,
LL | | _ => true,
LL | | };
- | |_____^ help: try this: `x.is_some()`
+ | |_____^ help: try: `x.is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:143:13
+ --> $DIR/redundant_pattern_matching_option.rs:157:13
|
LL | let _ = matches!(x, Some(_));
- | ^^^^^^^^^^^^^^^^^^^^ help: try this: `x.is_some()`
+ | ^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:145:13
+ --> $DIR/redundant_pattern_matching_option.rs:159:13
|
LL | let _ = matches!(x, None);
- | ^^^^^^^^^^^^^^^^^ help: try this: `x.is_none()`
+ | ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()`
-error: aborting due to 28 previous errors
+error: aborting due to 30 previous errors
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr
index b89fde35f..28d3606c4 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr
@@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_pending()`
--> $DIR/redundant_pattern_matching_poll.rs:17:12
|
LL | if let Pending = Pending::<()> {}
- | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()`
+ | -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()`
|
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
@@ -10,31 +10,31 @@ error: redundant pattern matching, consider using `is_ready()`
--> $DIR/redundant_pattern_matching_poll.rs:19:12
|
LL | if let Ready(_) = Ready(42) {}
- | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()`
+ | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_ready()`
--> $DIR/redundant_pattern_matching_poll.rs:21:12
|
LL | if let Ready(_) = Ready(42) {
- | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()`
+ | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_ready()`
--> $DIR/redundant_pattern_matching_poll.rs:27:15
|
LL | while let Ready(_) = Ready(42) {}
- | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()`
+ | ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_pending()`
--> $DIR/redundant_pattern_matching_poll.rs:29:15
|
LL | while let Pending = Ready(42) {}
- | ----------^^^^^^^------------ help: try this: `while Ready(42).is_pending()`
+ | ----------^^^^^^^------------ help: try: `while Ready(42).is_pending()`
error: redundant pattern matching, consider using `is_pending()`
--> $DIR/redundant_pattern_matching_poll.rs:31:15
|
LL | while let Pending = Pending::<()> {}
- | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()`
+ | ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()`
error: redundant pattern matching, consider using `is_ready()`
--> $DIR/redundant_pattern_matching_poll.rs:37:5
@@ -43,7 +43,7 @@ LL | / match Ready(42) {
LL | | Ready(_) => true,
LL | | Pending => false,
LL | | };
- | |_____^ help: try this: `Ready(42).is_ready()`
+ | |_____^ help: try: `Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_pending()`
--> $DIR/redundant_pattern_matching_poll.rs:42:5
@@ -52,7 +52,7 @@ LL | / match Pending::<()> {
LL | | Ready(_) => false,
LL | | Pending => true,
LL | | };
- | |_____^ help: try this: `Pending::<()>.is_pending()`
+ | |_____^ help: try: `Pending::<()>.is_pending()`
error: redundant pattern matching, consider using `is_pending()`
--> $DIR/redundant_pattern_matching_poll.rs:47:13
@@ -62,49 +62,49 @@ LL | let _ = match Pending::<()> {
LL | | Ready(_) => false,
LL | | Pending => true,
LL | | };
- | |_____^ help: try this: `Pending::<()>.is_pending()`
+ | |_____^ help: try: `Pending::<()>.is_pending()`
error: redundant pattern matching, consider using `is_ready()`
--> $DIR/redundant_pattern_matching_poll.rs:53:20
|
LL | let _ = if let Ready(_) = poll { true } else { false };
- | -------^^^^^^^^------- help: try this: `if poll.is_ready()`
+ | -------^^^^^^^^------- help: try: `if poll.is_ready()`
error: redundant pattern matching, consider using `is_ready()`
--> $DIR/redundant_pattern_matching_poll.rs:57:20
|
LL | let _ = if let Ready(_) = gen_poll() {
- | -------^^^^^^^^------------- help: try this: `if gen_poll().is_ready()`
+ | -------^^^^^^^^------------- help: try: `if gen_poll().is_ready()`
error: redundant pattern matching, consider using `is_pending()`
--> $DIR/redundant_pattern_matching_poll.rs:59:19
|
LL | } else if let Pending = gen_poll() {
- | -------^^^^^^^------------- help: try this: `if gen_poll().is_pending()`
+ | -------^^^^^^^------------- help: try: `if gen_poll().is_pending()`
error: redundant pattern matching, consider using `is_ready()`
--> $DIR/redundant_pattern_matching_poll.rs:75:12
|
LL | if let Ready(_) = Ready(42) {}
- | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()`
+ | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_pending()`
--> $DIR/redundant_pattern_matching_poll.rs:77:12
|
LL | if let Pending = Pending::<()> {}
- | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()`
+ | -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()`
error: redundant pattern matching, consider using `is_ready()`
--> $DIR/redundant_pattern_matching_poll.rs:79:15
|
LL | while let Ready(_) = Ready(42) {}
- | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()`
+ | ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_pending()`
--> $DIR/redundant_pattern_matching_poll.rs:81:15
|
LL | while let Pending = Pending::<()> {}
- | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()`
+ | ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()`
error: redundant pattern matching, consider using `is_ready()`
--> $DIR/redundant_pattern_matching_poll.rs:83:5
@@ -113,7 +113,7 @@ LL | / match Ready(42) {
LL | | Ready(_) => true,
LL | | Pending => false,
LL | | };
- | |_____^ help: try this: `Ready(42).is_ready()`
+ | |_____^ help: try: `Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_pending()`
--> $DIR/redundant_pattern_matching_poll.rs:88:5
@@ -122,7 +122,7 @@ LL | / match Pending::<()> {
LL | | Ready(_) => false,
LL | | Pending => true,
LL | | };
- | |_____^ help: try this: `Pending::<()>.is_pending()`
+ | |_____^ help: try: `Pending::<()>.is_pending()`
error: aborting due to 18 previous errors
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
index f6ce666bb..2b1ce9f54 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
@@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_result.rs:16:12
|
LL | if let Ok(_) = &result {}
- | -------^^^^^---------- help: try this: `if result.is_ok()`
+ | -------^^^^^---------- help: try: `if result.is_ok()`
|
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
@@ -10,25 +10,25 @@ error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_result.rs:18:12
|
LL | if let Ok(_) = Ok::<i32, i32>(42) {}
- | -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
+ | -------^^^^^--------------------- help: try: `if Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_result.rs:20:12
|
LL | if let Err(_) = Err::<i32, i32>(42) {}
- | -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
+ | -------^^^^^^---------------------- help: try: `if Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_result.rs:22:15
|
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
- | ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
+ | ----------^^^^^--------------------- help: try: `while Ok::<i32, i32>(10).is_ok()`
error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_result.rs:24:15
|
LL | while let Err(_) = Ok::<i32, i32>(10) {}
- | ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
+ | ----------^^^^^^--------------------- help: try: `while Ok::<i32, i32>(10).is_err()`
error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_result.rs:34:5
@@ -37,7 +37,7 @@ LL | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => true,
LL | | Err(_) => false,
LL | | };
- | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
+ | |_____^ help: try: `Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_result.rs:39:5
@@ -46,7 +46,7 @@ LL | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => false,
LL | | Err(_) => true,
LL | | };
- | |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
+ | |_____^ help: try: `Ok::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_result.rs:44:5
@@ -55,7 +55,7 @@ LL | / match Err::<i32, i32>(42) {
LL | | Ok(_) => false,
LL | | Err(_) => true,
LL | | };
- | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
+ | |_____^ help: try: `Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_result.rs:49:5
@@ -64,73 +64,73 @@ LL | / match Err::<i32, i32>(42) {
LL | | Ok(_) => true,
LL | | Err(_) => false,
LL | | };
- | |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
+ | |_____^ help: try: `Err::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_result.rs:54:20
|
LL | let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
- | -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
+ | -------^^^^^--------------------- help: try: `if Ok::<usize, ()>(4).is_ok()`
error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_result.rs:62:20
|
LL | let _ = if let Ok(_) = gen_res() {
- | -------^^^^^------------ help: try this: `if gen_res().is_ok()`
+ | -------^^^^^------------ help: try: `if gen_res().is_ok()`
error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_result.rs:64:19
|
LL | } else if let Err(_) = gen_res() {
- | -------^^^^^^------------ help: try this: `if gen_res().is_err()`
+ | -------^^^^^^------------ help: try: `if gen_res().is_err()`
error: redundant pattern matching, consider using `is_some()`
--> $DIR/redundant_pattern_matching_result.rs:87:19
|
LL | while let Some(_) = r#try!(result_opt()) {}
- | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
+ | ----------^^^^^^^----------------------- help: try: `while r#try!(result_opt()).is_some()`
error: redundant pattern matching, consider using `is_some()`
--> $DIR/redundant_pattern_matching_result.rs:88:16
|
LL | if let Some(_) = r#try!(result_opt()) {}
- | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
+ | -------^^^^^^^----------------------- help: try: `if r#try!(result_opt()).is_some()`
error: redundant pattern matching, consider using `is_some()`
--> $DIR/redundant_pattern_matching_result.rs:94:12
|
LL | if let Some(_) = m!() {}
- | -------^^^^^^^------- help: try this: `if m!().is_some()`
+ | -------^^^^^^^------- help: try: `if m!().is_some()`
error: redundant pattern matching, consider using `is_some()`
--> $DIR/redundant_pattern_matching_result.rs:95:15
|
LL | while let Some(_) = m!() {}
- | ----------^^^^^^^------- help: try this: `while m!().is_some()`
+ | ----------^^^^^^^------- help: try: `while m!().is_some()`
error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_result.rs:113:12
|
LL | if let Ok(_) = Ok::<i32, i32>(42) {}
- | -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
+ | -------^^^^^--------------------- help: try: `if Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_result.rs:115:12
|
LL | if let Err(_) = Err::<i32, i32>(42) {}
- | -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
+ | -------^^^^^^---------------------- help: try: `if Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_result.rs:117:15
|
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
- | ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
+ | ----------^^^^^--------------------- help: try: `while Ok::<i32, i32>(10).is_ok()`
error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_result.rs:119:15
|
LL | while let Err(_) = Ok::<i32, i32>(10) {}
- | ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
+ | ----------^^^^^^--------------------- help: try: `while Ok::<i32, i32>(10).is_err()`
error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_result.rs:121:5
@@ -139,7 +139,7 @@ LL | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => true,
LL | | Err(_) => false,
LL | | };
- | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
+ | |_____^ help: try: `Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_result.rs:126:5
@@ -148,7 +148,7 @@ LL | / match Err::<i32, i32>(42) {
LL | | Ok(_) => false,
LL | | Err(_) => true,
LL | | };
- | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
+ | |_____^ help: try: `Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_result.rs:136:5
@@ -157,7 +157,7 @@ LL | / match x {
LL | | Ok(_) => true,
LL | | _ => false,
LL | | };
- | |_____^ help: try this: `x.is_ok()`
+ | |_____^ help: try: `x.is_ok()`
error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_result.rs:141:5
@@ -166,7 +166,7 @@ LL | / match x {
LL | | Ok(_) => false,
LL | | _ => true,
LL | | };
- | |_____^ help: try this: `x.is_err()`
+ | |_____^ help: try: `x.is_err()`
error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_result.rs:146:5
@@ -175,7 +175,7 @@ LL | / match x {
LL | | Err(_) => true,
LL | | _ => false,
LL | | };
- | |_____^ help: try this: `x.is_err()`
+ | |_____^ help: try: `x.is_err()`
error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_result.rs:151:5
@@ -184,19 +184,19 @@ LL | / match x {
LL | | Err(_) => false,
LL | | _ => true,
LL | | };
- | |_____^ help: try this: `x.is_ok()`
+ | |_____^ help: try: `x.is_ok()`
error: redundant pattern matching, consider using `is_ok()`
--> $DIR/redundant_pattern_matching_result.rs:172:13
|
LL | let _ = matches!(x, Ok(_));
- | ^^^^^^^^^^^^^^^^^^ help: try this: `x.is_ok()`
+ | ^^^^^^^^^^^^^^^^^^ help: try: `x.is_ok()`
error: redundant pattern matching, consider using `is_err()`
--> $DIR/redundant_pattern_matching_result.rs:174:13
|
LL | let _ = matches!(x, Err(_));
- | ^^^^^^^^^^^^^^^^^^^ help: try this: `x.is_err()`
+ | ^^^^^^^^^^^^^^^^^^^ help: try: `x.is_err()`
error: aborting due to 28 previous errors
diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr
index eb36cd516..016feb103 100644
--- a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr
+++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr
@@ -5,7 +5,7 @@ LL | Some(ref x) => x,
| ^^^^^
|
= note: `-D clippy::ref-binding-to-reference` implied by `-D warnings`
-help: try this
+help: try
|
LL | Some(x) => &x,
| ~ ~~
@@ -16,7 +16,7 @@ error: this pattern creates a reference to a reference
LL | Some(ref x) => {
| ^^^^^
|
-help: try this
+help: try
|
LL ~ Some(x) => {
LL | f1(x);
@@ -30,7 +30,7 @@ error: this pattern creates a reference to a reference
LL | Some(ref x) => m2!(x),
| ^^^^^
|
-help: try this
+help: try
|
LL | Some(x) => m2!(&x),
| ~ ~~
@@ -41,7 +41,7 @@ error: this pattern creates a reference to a reference
LL | let _ = |&ref x: &&String| {
| ^^^^^
|
-help: try this
+help: try
|
LL ~ let _ = |&x: &&String| {
LL ~ let _: &&String = &x;
@@ -53,7 +53,7 @@ error: this pattern creates a reference to a reference
LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
| ^^^^^
|
-help: try this
+help: try
|
LL ~ fn f2<'a>(&x: &&'a String) -> &'a String {
LL ~ let _: &&String = &x;
@@ -66,7 +66,7 @@ error: this pattern creates a reference to a reference
LL | fn f(&ref x: &&String) {
| ^^^^^
|
-help: try this
+help: try
|
LL ~ fn f(&x: &&String) {
LL ~ let _: &&String = &x;
@@ -78,7 +78,7 @@ error: this pattern creates a reference to a reference
LL | fn f(&ref x: &&String) {
| ^^^^^
|
-help: try this
+help: try
|
LL ~ fn f(&x: &&String) {
LL ~ let _: &&String = &x;
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index cc2295ea5..e78b9e5c9 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -27,16 +27,18 @@
#![allow(clippy::single_char_add_str)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::recursive_format_impl)]
+#![allow(clippy::unwrap_or_default)]
#![allow(clippy::invisible_characters)]
+#![allow(invalid_reference_casting)]
#![allow(suspicious_double_ref_op)]
#![allow(invalid_nan_comparisons)]
-#![allow(invalid_reference_casting)]
#![allow(drop_bounds)]
#![allow(dropping_copy_types)]
#![allow(dropping_references)]
#![allow(for_loops_over_fallibles)]
#![allow(forgetting_copy_types)]
#![allow(forgetting_references)]
+#![allow(useless_ptr_null_checks)]
#![allow(array_into_iter)]
#![allow(invalid_atomic_ordering)]
#![allow(invalid_value)]
@@ -77,6 +79,7 @@
#![warn(clippy::single_char_add_str)]
#![warn(clippy::module_name_repetitions)]
#![warn(clippy::recursive_format_impl)]
+#![warn(clippy::unwrap_or_default)]
#![warn(clippy::invisible_characters)]
#![warn(invalid_reference_casting)]
#![warn(suspicious_double_ref_op)]
@@ -89,6 +92,7 @@
#![warn(for_loops_over_fallibles)]
#![warn(forgetting_copy_types)]
#![warn(forgetting_references)]
+#![warn(useless_ptr_null_checks)]
#![warn(array_into_iter)]
#![warn(invalid_atomic_ordering)]
#![warn(invalid_value)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 399335aff..2e6ef60cb 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -27,16 +27,18 @@
#![allow(clippy::single_char_add_str)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::recursive_format_impl)]
+#![allow(clippy::unwrap_or_default)]
#![allow(clippy::invisible_characters)]
+#![allow(invalid_reference_casting)]
#![allow(suspicious_double_ref_op)]
#![allow(invalid_nan_comparisons)]
-#![allow(invalid_reference_casting)]
#![allow(drop_bounds)]
#![allow(dropping_copy_types)]
#![allow(dropping_references)]
#![allow(for_loops_over_fallibles)]
#![allow(forgetting_copy_types)]
#![allow(forgetting_references)]
+#![allow(useless_ptr_null_checks)]
#![allow(array_into_iter)]
#![allow(invalid_atomic_ordering)]
#![allow(invalid_value)]
@@ -77,6 +79,7 @@
#![warn(clippy::single_char_push_str)]
#![warn(clippy::stutter)]
#![warn(clippy::to_string_in_display)]
+#![warn(clippy::unwrap_or_else_default)]
#![warn(clippy::zero_width_space)]
#![warn(clippy::cast_ref_to_mut)]
#![warn(clippy::clone_double_ref)]
@@ -89,6 +92,7 @@
#![warn(clippy::for_loops_over_fallibles)]
#![warn(clippy::forget_copy)]
#![warn(clippy::forget_ref)]
+#![warn(clippy::fn_null_check)]
#![warn(clippy::into_iter_on_array)]
#![warn(clippy::invalid_atomic_ordering)]
#![warn(clippy::invalid_ref)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 079371330..57e991e56 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
- --> $DIR/rename.rs:52:9
+ --> $DIR/rename.rs:54:9
|
LL | #![warn(clippy::almost_complete_letter_range)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -7,310 +7,322 @@ LL | #![warn(clippy::almost_complete_letter_range)]
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
- --> $DIR/rename.rs:53:9
+ --> $DIR/rename.rs:55:9
|
LL | #![warn(clippy::blacklisted_name)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
- --> $DIR/rename.rs:54:9
+ --> $DIR/rename.rs:56:9
|
LL | #![warn(clippy::block_in_if_condition_expr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
- --> $DIR/rename.rs:55:9
+ --> $DIR/rename.rs:57:9
|
LL | #![warn(clippy::block_in_if_condition_stmt)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
- --> $DIR/rename.rs:56:9
+ --> $DIR/rename.rs:58:9
|
LL | #![warn(clippy::box_vec)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
- --> $DIR/rename.rs:57:9
+ --> $DIR/rename.rs:59:9
|
LL | #![warn(clippy::const_static_lifetime)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
- --> $DIR/rename.rs:58:9
+ --> $DIR/rename.rs:60:9
|
LL | #![warn(clippy::cyclomatic_complexity)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
- --> $DIR/rename.rs:59:9
+ --> $DIR/rename.rs:61:9
|
LL | #![warn(clippy::derive_hash_xor_eq)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
- --> $DIR/rename.rs:60:9
+ --> $DIR/rename.rs:62:9
|
LL | #![warn(clippy::disallowed_method)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
- --> $DIR/rename.rs:61:9
+ --> $DIR/rename.rs:63:9
|
LL | #![warn(clippy::disallowed_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
- --> $DIR/rename.rs:62:9
+ --> $DIR/rename.rs:64:9
|
LL | #![warn(clippy::eval_order_dependence)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
- --> $DIR/rename.rs:63:9
+ --> $DIR/rename.rs:65:9
|
LL | #![warn(clippy::identity_conversion)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
- --> $DIR/rename.rs:64:9
+ --> $DIR/rename.rs:66:9
|
LL | #![warn(clippy::if_let_some_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
- --> $DIR/rename.rs:65:9
+ --> $DIR/rename.rs:67:9
|
LL | #![warn(clippy::integer_arithmetic)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
- --> $DIR/rename.rs:66:9
+ --> $DIR/rename.rs:68:9
|
LL | #![warn(clippy::logic_bug)]
| ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
- --> $DIR/rename.rs:67:9
+ --> $DIR/rename.rs:69:9
|
LL | #![warn(clippy::new_without_default_derive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
- --> $DIR/rename.rs:68:9
+ --> $DIR/rename.rs:70:9
|
LL | #![warn(clippy::option_and_then_some)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
- --> $DIR/rename.rs:69:9
+ --> $DIR/rename.rs:71:9
|
LL | #![warn(clippy::option_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
- --> $DIR/rename.rs:70:9
+ --> $DIR/rename.rs:72:9
|
LL | #![warn(clippy::option_map_unwrap_or)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
- --> $DIR/rename.rs:71:9
+ --> $DIR/rename.rs:73:9
|
LL | #![warn(clippy::option_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
- --> $DIR/rename.rs:72:9
+ --> $DIR/rename.rs:74:9
|
LL | #![warn(clippy::option_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
- --> $DIR/rename.rs:73:9
+ --> $DIR/rename.rs:75:9
|
LL | #![warn(clippy::ref_in_deref)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
- --> $DIR/rename.rs:74:9
+ --> $DIR/rename.rs:76:9
|
LL | #![warn(clippy::result_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
- --> $DIR/rename.rs:75:9
+ --> $DIR/rename.rs:77:9
|
LL | #![warn(clippy::result_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
- --> $DIR/rename.rs:76:9
+ --> $DIR/rename.rs:78:9
|
LL | #![warn(clippy::result_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
- --> $DIR/rename.rs:77:9
+ --> $DIR/rename.rs:79:9
|
LL | #![warn(clippy::single_char_push_str)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
- --> $DIR/rename.rs:78:9
+ --> $DIR/rename.rs:80:9
|
LL | #![warn(clippy::stutter)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
- --> $DIR/rename.rs:79:9
+ --> $DIR/rename.rs:81:9
|
LL | #![warn(clippy::to_string_in_display)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
+error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
+ --> $DIR/rename.rs:82:9
+ |
+LL | #![warn(clippy::unwrap_or_else_default)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
+
error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
- --> $DIR/rename.rs:80:9
+ --> $DIR/rename.rs:83:9
|
LL | #![warn(clippy::zero_width_space)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
- --> $DIR/rename.rs:81:9
+ --> $DIR/rename.rs:84:9
|
LL | #![warn(clippy::cast_ref_to_mut)]
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
- --> $DIR/rename.rs:82:9
+ --> $DIR/rename.rs:85:9
|
LL | #![warn(clippy::clone_double_ref)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
- --> $DIR/rename.rs:83:9
+ --> $DIR/rename.rs:86:9
|
LL | #![warn(clippy::cmp_nan)]
| ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
- --> $DIR/rename.rs:84:9
+ --> $DIR/rename.rs:87:9
|
LL | #![warn(clippy::drop_bounds)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
- --> $DIR/rename.rs:85:9
+ --> $DIR/rename.rs:88:9
|
LL | #![warn(clippy::drop_copy)]
| ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
error: lint `clippy::drop_ref` has been renamed to `dropping_references`
- --> $DIR/rename.rs:86:9
+ --> $DIR/rename.rs:89:9
|
LL | #![warn(clippy::drop_ref)]
| ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
- --> $DIR/rename.rs:87:9
+ --> $DIR/rename.rs:90:9
|
LL | #![warn(clippy::for_loop_over_option)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
- --> $DIR/rename.rs:88:9
+ --> $DIR/rename.rs:91:9
|
LL | #![warn(clippy::for_loop_over_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
- --> $DIR/rename.rs:89:9
+ --> $DIR/rename.rs:92:9
|
LL | #![warn(clippy::for_loops_over_fallibles)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
- --> $DIR/rename.rs:90:9
+ --> $DIR/rename.rs:93:9
|
LL | #![warn(clippy::forget_copy)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
- --> $DIR/rename.rs:91:9
+ --> $DIR/rename.rs:94:9
|
LL | #![warn(clippy::forget_ref)]
| ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
+error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
+ --> $DIR/rename.rs:95:9
+ |
+LL | #![warn(clippy::fn_null_check)]
+ | ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
+
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
- --> $DIR/rename.rs:92:9
+ --> $DIR/rename.rs:96:9
|
LL | #![warn(clippy::into_iter_on_array)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
- --> $DIR/rename.rs:93:9
+ --> $DIR/rename.rs:97:9
|
LL | #![warn(clippy::invalid_atomic_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
- --> $DIR/rename.rs:94:9
+ --> $DIR/rename.rs:98:9
|
LL | #![warn(clippy::invalid_ref)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
- --> $DIR/rename.rs:95:9
+ --> $DIR/rename.rs:99:9
|
LL | #![warn(clippy::invalid_utf8_in_unchecked)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
- --> $DIR/rename.rs:96:9
+ --> $DIR/rename.rs:100:9
|
LL | #![warn(clippy::let_underscore_drop)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
- --> $DIR/rename.rs:97:9
+ --> $DIR/rename.rs:101:9
|
LL | #![warn(clippy::mem_discriminant_non_enum)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
- --> $DIR/rename.rs:98:9
+ --> $DIR/rename.rs:102:9
|
LL | #![warn(clippy::panic_params)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
- --> $DIR/rename.rs:99:9
+ --> $DIR/rename.rs:103:9
|
LL | #![warn(clippy::positional_named_format_parameters)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
- --> $DIR/rename.rs:100:9
+ --> $DIR/rename.rs:104:9
|
LL | #![warn(clippy::temporary_cstring_as_ptr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
- --> $DIR/rename.rs:101:9
+ --> $DIR/rename.rs:105:9
|
LL | #![warn(clippy::undropped_manually_drops)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
- --> $DIR/rename.rs:102:9
+ --> $DIR/rename.rs:106:9
|
LL | #![warn(clippy::unknown_clippy_lints)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
error: lint `clippy::unused_label` has been renamed to `unused_labels`
- --> $DIR/rename.rs:103:9
+ --> $DIR/rename.rs:107:9
|
LL | #![warn(clippy::unused_label)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
-error: aborting due to 52 previous errors
+error: aborting due to 54 previous errors
diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.fixed b/src/tools/clippy/tests/ui/result_map_or_into_option.fixed
index 119ff2591..6850eeb7a 100644
--- a/src/tools/clippy/tests/ui/result_map_or_into_option.fixed
+++ b/src/tools/clippy/tests/ui/result_map_or_into_option.fixed
@@ -15,5 +15,5 @@ fn main() {
// A non-Some `f` closure where the argument is not used as the
// return should not emit the lint
let opt: Result<u32, &str> = Ok(1);
- opt.map_or(None, |_x| Some(1));
+ _ = opt.map_or(None, |_x| Some(1));
}
diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.rs b/src/tools/clippy/tests/ui/result_map_or_into_option.rs
index eeeef830a..8e1518144 100644
--- a/src/tools/clippy/tests/ui/result_map_or_into_option.rs
+++ b/src/tools/clippy/tests/ui/result_map_or_into_option.rs
@@ -15,5 +15,5 @@ fn main() {
// A non-Some `f` closure where the argument is not used as the
// return should not emit the lint
let opt: Result<u32, &str> = Ok(1);
- opt.map_or(None, |_x| Some(1));
+ _ = opt.map_or(None, |_x| Some(1));
}
diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr
index 782febd52..ad941fa8b 100644
--- a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr
+++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr
@@ -4,7 +4,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns
LL | x.field.map(do_nothing);
| ^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }`
+ | help: try: `if let Ok(x_field) = x.field { do_nothing(x_field) }`
|
= note: `-D clippy::result-map-unit-fn` implied by `-D warnings`
@@ -14,7 +14,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns
LL | x.field.map(do_nothing);
| ^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }`
+ | help: try: `if let Ok(x_field) = x.field { do_nothing(x_field) }`
error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:39:5
@@ -22,7 +22,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns
LL | x.field.map(diverge);
| ^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(x_field) = x.field { diverge(x_field) }`
+ | help: try: `if let Ok(x_field) = x.field { diverge(x_field) }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:45:5
@@ -30,7 +30,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| x.do_result_nothing(value + captured));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }`
+ | help: try: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:47:5
@@ -38,7 +38,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| { x.do_result_plus_one(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }`
+ | help: try: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:50:5
@@ -46,7 +46,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| do_nothing(value + captured));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }`
+ | help: try: `if let Ok(value) = x.field { do_nothing(value + captured) }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:52:5
@@ -54,7 +54,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| { do_nothing(value + captured) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }`
+ | help: try: `if let Ok(value) = x.field { do_nothing(value + captured) }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:54:5
@@ -62,7 +62,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| { do_nothing(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }`
+ | help: try: `if let Ok(value) = x.field { do_nothing(value + captured); }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:56:5
@@ -70,7 +70,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| { { do_nothing(value + captured); } });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }`
+ | help: try: `if let Ok(value) = x.field { do_nothing(value + captured); }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:59:5
@@ -78,7 +78,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| diverge(value + captured));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }`
+ | help: try: `if let Ok(value) = x.field { diverge(value + captured) }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:61:5
@@ -86,7 +86,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| { diverge(value + captured) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }`
+ | help: try: `if let Ok(value) = x.field { diverge(value + captured) }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:63:5
@@ -94,7 +94,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| { diverge(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }`
+ | help: try: `if let Ok(value) = x.field { diverge(value + captured); }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:65:5
@@ -102,7 +102,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| { { diverge(value + captured); } });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }`
+ | help: try: `if let Ok(value) = x.field { diverge(value + captured); }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:70:5
@@ -110,7 +110,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| { let y = plus_one(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { let y = plus_one(value + captured); }`
+ | help: try: `if let Ok(value) = x.field { let y = plus_one(value + captured); }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:72:5
@@ -118,7 +118,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| { plus_one(value + captured); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }`
+ | help: try: `if let Ok(value) = x.field { plus_one(value + captured); }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:74:5
@@ -126,7 +126,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| { { plus_one(value + captured); } });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }`
+ | help: try: `if let Ok(value) = x.field { plus_one(value + captured); }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:77:5
@@ -134,7 +134,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|ref value| { do_nothing(value + captured) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(ref value) = x.field { do_nothing(value + captured) }`
+ | help: try: `if let Ok(ref value) = x.field { do_nothing(value + captured) }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_fixable.rs:79:5
@@ -142,7 +142,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| println!("{:?}", value));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { println!("{:?}", value) }`
+ | help: try: `if let Ok(value) = x.field { println!("{:?}", value) }`
error: aborting due to 18 previous errors
diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr
index d0e534f63..75ec1ba80 100644
--- a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr
@@ -4,7 +4,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| { do_nothing(value); do_nothing(value) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { ... }`
+ | help: try: `if let Ok(value) = x.field { ... }`
|
= note: `-D clippy::result-map-unit-fn` implied by `-D warnings`
@@ -14,7 +14,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { ... }`
+ | help: try: `if let Ok(value) = x.field { ... }`
error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()`
--> $DIR/result_map_unit_fn_unfixable.rs:29:5
@@ -23,7 +23,7 @@ LL | // x.field.map(|value| {
LL | || do_nothing(value);
LL | || do_nothing(value)
LL | || });
- | ||______^- help: try this: `if let Ok(value) = x.field { ... }`
+ | ||______^- help: try: `if let Ok(value) = x.field { ... }`
| |______|
|
@@ -33,7 +33,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns
LL | x.field.map(|value| { do_nothing(value); do_nothing(value); });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(value) = x.field { ... }`
+ | help: try: `if let Ok(value) = x.field { ... }`
error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
--> $DIR/result_map_unit_fn_unfixable.rs:37:5
@@ -41,7 +41,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns
LL | "12".parse::<i32>().map(diverge);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(a) = "12".parse::<i32>() { diverge(a) }`
+ | help: try: `if let Ok(a) = "12".parse::<i32>() { diverge(a) }`
error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()`
--> $DIR/result_map_unit_fn_unfixable.rs:43:5
@@ -49,7 +49,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns
LL | y.map(do_nothing);
| ^^^^^^^^^^^^^^^^^-
| |
- | help: try this: `if let Ok(_y) = y { do_nothing(_y) }`
+ | help: try: `if let Ok(_y) = y { do_nothing(_y) }`
error: aborting due to 6 previous errors
diff --git a/src/tools/clippy/tests/ui/self_assignment.rs b/src/tools/clippy/tests/ui/self_assignment.rs
index ec3ae1209..a7f9fbaae 100644
--- a/src/tools/clippy/tests/ui/self_assignment.rs
+++ b/src/tools/clippy/tests/ui/self_assignment.rs
@@ -1,5 +1,5 @@
#![warn(clippy::self_assignment)]
-#![allow(clippy::useless_vec)]
+#![allow(clippy::useless_vec, clippy::needless_pass_by_ref_mut)]
pub struct S<'a> {
a: i32,
@@ -14,7 +14,7 @@ pub fn positives(mut a: usize, b: &mut u32, mut s: S) {
*b = *b;
s = s;
s.a = s.a;
- s.b[10] = s.b[5 + 5];
+ s.b[9] = s.b[5 + 4];
s.c[0][1] = s.c[0][1];
s.b[a] = s.b[a];
*s.e = *s.e;
diff --git a/src/tools/clippy/tests/ui/self_assignment.stderr b/src/tools/clippy/tests/ui/self_assignment.stderr
index bed88244e..25b8569fa 100644
--- a/src/tools/clippy/tests/ui/self_assignment.stderr
+++ b/src/tools/clippy/tests/ui/self_assignment.stderr
@@ -24,11 +24,11 @@ error: self-assignment of `s.a` to `s.a`
LL | s.a = s.a;
| ^^^^^^^^^
-error: self-assignment of `s.b[5 + 5]` to `s.b[10]`
+error: self-assignment of `s.b[5 + 4]` to `s.b[9]`
--> $DIR/self_assignment.rs:17:5
|
-LL | s.b[10] = s.b[5 + 5];
- | ^^^^^^^^^^^^^^^^^^^^
+LL | s.b[9] = s.b[5 + 4];
+ | ^^^^^^^^^^^^^^^^^^^
error: self-assignment of `s.c[0][1]` to `s.c[0][1]`
--> $DIR/self_assignment.rs:18:5
diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed
new file mode 100644
index 000000000..653f4533b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed
@@ -0,0 +1,123 @@
+//@run-rustfix
+#![warn(clippy::semicolon_if_nothing_returned)]
+#![allow(clippy::redundant_closure, clippy::uninlined_format_args, clippy::needless_late_init)]
+
+fn get_unit() {}
+
+// the functions below trigger the lint
+fn main() {
+ println!("Hello");
+}
+
+fn hello() {
+ get_unit();
+}
+
+fn basic101(x: i32) {
+ let y: i32;
+ y = x + 1;
+}
+
+#[rustfmt::skip]
+fn closure_error() {
+ let _d = || {
+ hello();
+ };
+}
+
+#[rustfmt::skip]
+fn unsafe_checks_error() {
+ use std::mem::MaybeUninit;
+ use std::ptr;
+
+ let mut s = MaybeUninit::<String>::uninit();
+ let _d = || unsafe {
+ ptr::drop_in_place(s.as_mut_ptr());
+ };
+}
+
+// this is fine
+fn print_sum(a: i32, b: i32) {
+ println!("{}", a + b);
+ assert_eq!(true, false);
+}
+
+fn foo(x: i32) {
+ let y: i32;
+ if x < 1 {
+ y = 4;
+ } else {
+ y = 5;
+ }
+}
+
+fn bar(x: i32) {
+ let y: i32;
+ match x {
+ 1 => y = 4,
+ _ => y = 32,
+ }
+}
+
+fn foobar(x: i32) {
+ let y: i32;
+ 'label: {
+ y = x + 1;
+ }
+}
+
+fn loop_test(x: i32) {
+ let y: i32;
+ for &ext in &["stdout", "stderr", "fixed"] {
+ println!("{}", ext);
+ }
+}
+
+fn closure() {
+ let _d = || hello();
+}
+
+#[rustfmt::skip]
+fn closure_block() {
+ let _d = || { hello() };
+}
+
+unsafe fn some_unsafe_op() {}
+unsafe fn some_other_unsafe_fn() {}
+
+fn do_something() {
+ unsafe { some_unsafe_op() };
+
+ unsafe { some_other_unsafe_fn() };
+}
+
+fn unsafe_checks() {
+ use std::mem::MaybeUninit;
+ use std::ptr;
+
+ let mut s = MaybeUninit::<String>::uninit();
+ let _d = || unsafe { ptr::drop_in_place(s.as_mut_ptr()) };
+}
+
+// Issue #7768
+#[rustfmt::skip]
+fn macro_with_semicolon() {
+ macro_rules! repro {
+ () => {
+ while false {
+ }
+ };
+ }
+ repro!();
+}
+
+fn function_returning_option() -> Option<i32> {
+ Some(1)
+}
+
+// No warning
+fn let_else_stmts() {
+ let Some(x) = function_returning_option() else {
+ return;
+ };
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
index 4ab7dbab5..9db038219 100644
--- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
@@ -1,5 +1,6 @@
+//@run-rustfix
#![warn(clippy::semicolon_if_nothing_returned)]
-#![allow(clippy::redundant_closure, clippy::uninlined_format_args)]
+#![allow(clippy::redundant_closure, clippy::uninlined_format_args, clippy::needless_late_init)]
fn get_unit() {}
@@ -116,5 +117,7 @@ fn function_returning_option() -> Option<i32> {
// No warning
fn let_else_stmts() {
- let Some(x) = function_returning_option() else { return; };
+ let Some(x) = function_returning_option() else {
+ return;
+ };
}
diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
index 8d9a67585..78813e7cc 100644
--- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
+++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
@@ -1,5 +1,5 @@
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:8:5
+ --> $DIR/semicolon_if_nothing_returned.rs:9:5
|
LL | println!("Hello")
| ^^^^^^^^^^^^^^^^^ help: add a `;` here: `println!("Hello");`
@@ -7,25 +7,25 @@ LL | println!("Hello")
= note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings`
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:12:5
+ --> $DIR/semicolon_if_nothing_returned.rs:13:5
|
LL | get_unit()
| ^^^^^^^^^^ help: add a `;` here: `get_unit();`
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:17:5
+ --> $DIR/semicolon_if_nothing_returned.rs:18:5
|
LL | y = x + 1
| ^^^^^^^^^ help: add a `;` here: `y = x + 1;`
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:23:9
+ --> $DIR/semicolon_if_nothing_returned.rs:24:9
|
LL | hello()
| ^^^^^^^ help: add a `;` here: `hello();`
error: consider adding a `;` to the last statement for consistent formatting
- --> $DIR/semicolon_if_nothing_returned.rs:34:9
+ --> $DIR/semicolon_if_nothing_returned.rs:35:9
|
LL | ptr::drop_in_place(s.as_mut_ptr())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `ptr::drop_in_place(s.as_mut_ptr());`
diff --git a/src/tools/clippy/tests/ui/shadow.rs b/src/tools/clippy/tests/ui/shadow.rs
index 9be8c5e59..1b40a43d0 100644
--- a/src/tools/clippy/tests/ui/shadow.rs
+++ b/src/tools/clippy/tests/ui/shadow.rs
@@ -1,7 +1,12 @@
//@aux-build:proc_macro_derive.rs:proc-macro
#![warn(clippy::shadow_same, clippy::shadow_reuse, clippy::shadow_unrelated)]
-#![allow(clippy::let_unit_value, clippy::needless_if)]
+#![allow(
+ clippy::let_unit_value,
+ clippy::needless_if,
+ clippy::redundant_guards,
+ clippy::redundant_locals
+)]
extern crate proc_macro_derive;
diff --git a/src/tools/clippy/tests/ui/shadow.stderr b/src/tools/clippy/tests/ui/shadow.stderr
index 8321f6df2..88b02f53b 100644
--- a/src/tools/clippy/tests/ui/shadow.stderr
+++ b/src/tools/clippy/tests/ui/shadow.stderr
@@ -1,278 +1,278 @@
error: `x` is shadowed by itself in `x`
- --> $DIR/shadow.rs:19:9
+ --> $DIR/shadow.rs:24:9
|
LL | let x = x;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:18:9
+ --> $DIR/shadow.rs:23:9
|
LL | let x = 1;
| ^
= note: `-D clippy::shadow-same` implied by `-D warnings`
error: `mut x` is shadowed by itself in `&x`
- --> $DIR/shadow.rs:20:13
+ --> $DIR/shadow.rs:25:13
|
LL | let mut x = &x;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:19:9
+ --> $DIR/shadow.rs:24:9
|
LL | let x = x;
| ^
error: `x` is shadowed by itself in `&mut x`
- --> $DIR/shadow.rs:21:9
+ --> $DIR/shadow.rs:26:9
|
LL | let x = &mut x;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:20:9
+ --> $DIR/shadow.rs:25:9
|
LL | let mut x = &x;
| ^^^^^
error: `x` is shadowed by itself in `*x`
- --> $DIR/shadow.rs:22:9
+ --> $DIR/shadow.rs:27:9
|
LL | let x = *x;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:21:9
+ --> $DIR/shadow.rs:26:9
|
LL | let x = &mut x;
| ^
error: `x` is shadowed
- --> $DIR/shadow.rs:27:9
+ --> $DIR/shadow.rs:32:9
|
LL | let x = x.0;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:26:9
+ --> $DIR/shadow.rs:31:9
|
LL | let x = ([[0]], ());
| ^
= note: `-D clippy::shadow-reuse` implied by `-D warnings`
error: `x` is shadowed
- --> $DIR/shadow.rs:28:9
+ --> $DIR/shadow.rs:33:9
|
LL | let x = x[0];
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:27:9
+ --> $DIR/shadow.rs:32:9
|
LL | let x = x.0;
| ^
error: `x` is shadowed
- --> $DIR/shadow.rs:29:10
+ --> $DIR/shadow.rs:34:10
|
LL | let [x] = x;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:28:9
+ --> $DIR/shadow.rs:33:9
|
LL | let x = x[0];
| ^
error: `x` is shadowed
- --> $DIR/shadow.rs:30:9
+ --> $DIR/shadow.rs:35:9
|
LL | let x = Some(x);
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:29:10
+ --> $DIR/shadow.rs:34:10
|
LL | let [x] = x;
| ^
error: `x` is shadowed
- --> $DIR/shadow.rs:31:9
+ --> $DIR/shadow.rs:36:9
|
LL | let x = foo(x);
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:30:9
+ --> $DIR/shadow.rs:35:9
|
LL | let x = Some(x);
| ^
error: `x` is shadowed
- --> $DIR/shadow.rs:32:9
+ --> $DIR/shadow.rs:37:9
|
LL | let x = || x;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:31:9
+ --> $DIR/shadow.rs:36:9
|
LL | let x = foo(x);
| ^
error: `x` is shadowed
- --> $DIR/shadow.rs:33:9
+ --> $DIR/shadow.rs:38:9
|
LL | let x = Some(1).map(|_| x)?;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:32:9
+ --> $DIR/shadow.rs:37:9
|
LL | let x = || x;
| ^
error: `y` is shadowed
- --> $DIR/shadow.rs:35:9
+ --> $DIR/shadow.rs:40:9
|
LL | let y = match y {
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:34:9
+ --> $DIR/shadow.rs:39:9
|
LL | let y = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:50:9
+ --> $DIR/shadow.rs:55:9
|
LL | let x = 2;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:49:9
+ --> $DIR/shadow.rs:54:9
|
LL | let x = 1;
| ^
= note: `-D clippy::shadow-unrelated` implied by `-D warnings`
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:55:13
+ --> $DIR/shadow.rs:60:13
|
LL | let x = 1;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:54:10
+ --> $DIR/shadow.rs:59:10
|
LL | fn f(x: u32) {
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:60:14
+ --> $DIR/shadow.rs:65:14
|
LL | Some(x) => {
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:57:9
+ --> $DIR/shadow.rs:62:9
|
LL | let x = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:61:17
+ --> $DIR/shadow.rs:66:17
|
LL | let x = 1;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:60:14
+ --> $DIR/shadow.rs:65:14
|
LL | Some(x) => {
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:65:17
+ --> $DIR/shadow.rs:70:17
|
LL | if let Some(x) = Some(1) {}
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:57:9
+ --> $DIR/shadow.rs:62:9
|
LL | let x = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:66:20
+ --> $DIR/shadow.rs:71:20
|
LL | while let Some(x) = Some(1) {}
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:57:9
+ --> $DIR/shadow.rs:62:9
|
LL | let x = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:67:15
+ --> $DIR/shadow.rs:72:15
|
LL | let _ = |[x]: [u32; 1]| {
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:57:9
+ --> $DIR/shadow.rs:62:9
|
LL | let x = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:68:13
+ --> $DIR/shadow.rs:73:13
|
LL | let x = 1;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:67:15
+ --> $DIR/shadow.rs:72:15
|
LL | let _ = |[x]: [u32; 1]| {
| ^
error: `y` is shadowed
- --> $DIR/shadow.rs:71:17
+ --> $DIR/shadow.rs:76:17
|
LL | if let Some(y) = y {}
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:70:9
+ --> $DIR/shadow.rs:75:9
|
LL | let y = Some(1);
| ^
error: `_b` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:107:9
+ --> $DIR/shadow.rs:112:9
|
LL | let _b = _a;
| ^^
|
note: previous binding is here
- --> $DIR/shadow.rs:106:28
+ --> $DIR/shadow.rs:111:28
|
LL | pub async fn foo2(_a: i32, _b: i64) {
| ^^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:113:21
+ --> $DIR/shadow.rs:118:21
|
LL | if let Some(x) = Some(1) { x } else { 1 }
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:112:13
+ --> $DIR/shadow.rs:117:13
|
LL | let x = 1;
| ^
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
index 8c48b21f1..17df9f88f 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
@@ -7,8 +7,7 @@
use std::num::ParseIntError;
use std::ops::Deref;
use std::sync::atomic::{AtomicU64, Ordering};
-use std::sync::RwLock;
-use std::sync::{Mutex, MutexGuard};
+use std::sync::{Mutex, MutexGuard, RwLock};
struct State {}
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
index 75063a8c9..b56ace200 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
@@ -1,5 +1,5 @@
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:56:11
+ --> $DIR/significant_drop_in_scrutinee.rs:55:11
|
LL | match mutex.lock().unwrap().foo() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -19,7 +19,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:142:11
+ --> $DIR/significant_drop_in_scrutinee.rs:141:11
|
LL | match s.lock_m().get_the_value() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -38,7 +38,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:163:11
+ --> $DIR/significant_drop_in_scrutinee.rs:162:11
|
LL | match s.lock_m_m().get_the_value() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -57,7 +57,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:211:11
+ --> $DIR/significant_drop_in_scrutinee.rs:210:11
|
LL | match counter.temp_increment().len() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:234:16
+ --> $DIR/significant_drop_in_scrutinee.rs:233:16
|
LL | match (mutex1.lock().unwrap().s.len(), true) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -92,7 +92,7 @@ LL ~ match (value, true) {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:243:22
+ --> $DIR/significant_drop_in_scrutinee.rs:242:22
|
LL | match (true, mutex1.lock().unwrap().s.len(), true) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -111,7 +111,7 @@ LL ~ match (true, value, true) {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:253:16
+ --> $DIR/significant_drop_in_scrutinee.rs:252:16
|
LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -132,7 +132,7 @@ LL ~ match (value, true, mutex2.lock().unwrap().s.len()) {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:253:54
+ --> $DIR/significant_drop_in_scrutinee.rs:252:54
|
LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -153,7 +153,7 @@ LL ~ match (mutex1.lock().unwrap().s.len(), true, value) {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:264:15
+ --> $DIR/significant_drop_in_scrutinee.rs:263:15
|
LL | match mutex3.lock().unwrap().s.as_str() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +169,7 @@ LL | };
= note: this might lead to deadlocks or other unexpected behavior
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:274:22
+ --> $DIR/significant_drop_in_scrutinee.rs:273:22
|
LL | match (true, mutex3.lock().unwrap().s.as_str()) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -185,7 +185,7 @@ LL | };
= note: this might lead to deadlocks or other unexpected behavior
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:293:11
+ --> $DIR/significant_drop_in_scrutinee.rs:292:11
|
LL | match mutex.lock().unwrap().s.len() > 1 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -204,7 +204,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:300:11
+ --> $DIR/significant_drop_in_scrutinee.rs:299:11
|
LL | match 1 < mutex.lock().unwrap().s.len() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -223,7 +223,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:318:11
+ --> $DIR/significant_drop_in_scrutinee.rs:317:11
|
LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -244,7 +244,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:329:11
+ --> $DIR/significant_drop_in_scrutinee.rs:328:11
|
LL | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -265,7 +265,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:364:11
+ --> $DIR/significant_drop_in_scrutinee.rs:363:11
|
LL | match get_mutex_guard().s.len() > 1 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -284,7 +284,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:381:11
+ --> $DIR/significant_drop_in_scrutinee.rs:380:11
|
LL | match match i {
| ___________^
@@ -316,7 +316,7 @@ LL ~ match value
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:407:11
+ --> $DIR/significant_drop_in_scrutinee.rs:406:11
|
LL | match if i > 1 {
| ___________^
@@ -349,7 +349,7 @@ LL ~ match value
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:461:11
+ --> $DIR/significant_drop_in_scrutinee.rs:460:11
|
LL | match s.lock().deref().deref() {
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -367,7 +367,7 @@ LL ~ match value {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:489:11
+ --> $DIR/significant_drop_in_scrutinee.rs:488:11
|
LL | match s.lock().deref().deref() {
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -380,7 +380,7 @@ LL | };
= note: this might lead to deadlocks or other unexpected behavior
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:508:11
+ --> $DIR/significant_drop_in_scrutinee.rs:507:11
|
LL | match mutex.lock().unwrap().i = i {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -399,7 +399,7 @@ LL ~ match () {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:514:11
+ --> $DIR/significant_drop_in_scrutinee.rs:513:11
|
LL | match i = mutex.lock().unwrap().i {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -418,7 +418,7 @@ LL ~ match () {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:520:11
+ --> $DIR/significant_drop_in_scrutinee.rs:519:11
|
LL | match mutex.lock().unwrap().i += 1 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -437,7 +437,7 @@ LL ~ match () {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:526:11
+ --> $DIR/significant_drop_in_scrutinee.rs:525:11
|
LL | match i += mutex.lock().unwrap().i {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -456,7 +456,7 @@ LL ~ match () {
|
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:589:11
+ --> $DIR/significant_drop_in_scrutinee.rs:588:11
|
LL | match rwlock.read().unwrap().to_number() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -467,7 +467,7 @@ LL | };
= note: this might lead to deadlocks or other unexpected behavior
error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression
- --> $DIR/significant_drop_in_scrutinee.rs:599:14
+ --> $DIR/significant_drop_in_scrutinee.rs:598:14
|
LL | for s in rwlock.read().unwrap().iter() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -478,7 +478,7 @@ LL | }
= note: this might lead to deadlocks or other unexpected behavior
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
- --> $DIR/significant_drop_in_scrutinee.rs:614:11
+ --> $DIR/significant_drop_in_scrutinee.rs:613:11
|
LL | match mutex.lock().unwrap().foo() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.fixed b/src/tools/clippy/tests/ui/significant_drop_tightening.fixed
index 7b848ead7..8065e9e5f 100644
--- a/src/tools/clippy/tests/ui/significant_drop_tightening.fixed
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.fixed
@@ -28,6 +28,56 @@ pub fn issue_10413() {
}
}
+pub fn issue_11128() {
+ use std::mem::drop as unlock;
+
+ struct Foo {
+ droppable: Option<Vec<i32>>,
+ mutex: Mutex<Vec<i32>>,
+ }
+
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ if let Some(droppable) = self.droppable.take() {
+ let lock = self.mutex.lock().unwrap();
+ let idx_opt = lock.iter().copied().find(|el| Some(el) == droppable.first());
+ if let Some(idx) = idx_opt {
+ let local_droppable = vec![lock.first().copied().unwrap_or_default()];
+ unlock(lock);
+ drop(local_droppable);
+ }
+ }
+ }
+ }
+}
+
+pub fn issue_11160() -> bool {
+ let mutex = Mutex::new(1i32);
+ let lock = mutex.lock().unwrap();
+ let _ = lock.abs();
+ true
+}
+
+pub fn issue_11189() {
+ struct Number {
+ pub value: u32,
+ }
+
+ fn do_something() -> Result<(), ()> {
+ let number = Mutex::new(Number { value: 1 });
+ let number2 = Mutex::new(Number { value: 2 });
+ let number3 = Mutex::new(Number { value: 3 });
+ let mut lock = number.lock().unwrap();
+ let mut lock2 = number2.lock().unwrap();
+ let mut lock3 = number3.lock().unwrap();
+ lock.value += 1;
+ lock2.value += 1;
+ lock3.value += 1;
+ drop((lock, lock2, lock3));
+ Ok(())
+ }
+}
+
pub fn path_return_can_be_ignored() -> i32 {
let mutex = Mutex::new(1);
let lock = mutex.lock().unwrap();
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.rs b/src/tools/clippy/tests/ui/significant_drop_tightening.rs
index 36f77cf1b..1620b7684 100644
--- a/src/tools/clippy/tests/ui/significant_drop_tightening.rs
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.rs
@@ -27,6 +27,56 @@ pub fn issue_10413() {
}
}
+pub fn issue_11128() {
+ use std::mem::drop as unlock;
+
+ struct Foo {
+ droppable: Option<Vec<i32>>,
+ mutex: Mutex<Vec<i32>>,
+ }
+
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ if let Some(droppable) = self.droppable.take() {
+ let lock = self.mutex.lock().unwrap();
+ let idx_opt = lock.iter().copied().find(|el| Some(el) == droppable.first());
+ if let Some(idx) = idx_opt {
+ let local_droppable = vec![lock.first().copied().unwrap_or_default()];
+ unlock(lock);
+ drop(local_droppable);
+ }
+ }
+ }
+ }
+}
+
+pub fn issue_11160() -> bool {
+ let mutex = Mutex::new(1i32);
+ let lock = mutex.lock().unwrap();
+ let _ = lock.abs();
+ true
+}
+
+pub fn issue_11189() {
+ struct Number {
+ pub value: u32,
+ }
+
+ fn do_something() -> Result<(), ()> {
+ let number = Mutex::new(Number { value: 1 });
+ let number2 = Mutex::new(Number { value: 2 });
+ let number3 = Mutex::new(Number { value: 3 });
+ let mut lock = number.lock().unwrap();
+ let mut lock2 = number2.lock().unwrap();
+ let mut lock3 = number3.lock().unwrap();
+ lock.value += 1;
+ lock2.value += 1;
+ lock3.value += 1;
+ drop((lock, lock2, lock3));
+ Ok(())
+ }
+}
+
pub fn path_return_can_be_ignored() -> i32 {
let mutex = Mutex::new(1);
let lock = mutex.lock().unwrap();
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
index 3bdac0b0a..b5cad88ad 100644
--- a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
@@ -23,7 +23,7 @@ LL + drop(lock);
|
error: temporary with significant `Drop` can be early dropped
- --> $DIR/significant_drop_tightening.rs:56:13
+ --> $DIR/significant_drop_tightening.rs:106:13
|
LL | / {
LL | | let mutex = Mutex::new(1i32);
@@ -43,7 +43,7 @@ LL + drop(lock);
|
error: temporary with significant `Drop` can be early dropped
- --> $DIR/significant_drop_tightening.rs:77:13
+ --> $DIR/significant_drop_tightening.rs:127:13
|
LL | / {
LL | | let mutex = Mutex::new(1i32);
@@ -67,7 +67,7 @@ LL +
|
error: temporary with significant `Drop` can be early dropped
- --> $DIR/significant_drop_tightening.rs:83:17
+ --> $DIR/significant_drop_tightening.rs:133:17
|
LL | / {
LL | | let mutex = Mutex::new(vec![1i32]);
diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.fixed b/src/tools/clippy/tests/ui/single_component_path_imports.fixed
index d4d2cbbe5..b6b6b0288 100644
--- a/src/tools/clippy/tests/ui/single_component_path_imports.fixed
+++ b/src/tools/clippy/tests/ui/single_component_path_imports.fixed
@@ -4,8 +4,12 @@
use core;
+
+
use serde as edres;
+
pub use serde;
+
use std;
macro_rules! m {
diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.rs b/src/tools/clippy/tests/ui/single_component_path_imports.rs
index 80d72115f..a8c4d8990 100644
--- a/src/tools/clippy/tests/ui/single_component_path_imports.rs
+++ b/src/tools/clippy/tests/ui/single_component_path_imports.rs
@@ -3,9 +3,13 @@
#![allow(unused_imports)]
use core;
+
use regex;
+
use serde as edres;
+
pub use serde;
+
use std;
macro_rules! m {
diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.stderr b/src/tools/clippy/tests/ui/single_component_path_imports.stderr
index d69a86470..853a2fe0e 100644
--- a/src/tools/clippy/tests/ui/single_component_path_imports.stderr
+++ b/src/tools/clippy/tests/ui/single_component_path_imports.stderr
@@ -1,5 +1,5 @@
error: this import is redundant
- --> $DIR/single_component_path_imports.rs:6:1
+ --> $DIR/single_component_path_imports.rs:7:1
|
LL | use regex;
| ^^^^^^^^^^ help: remove it entirely
@@ -7,7 +7,7 @@ LL | use regex;
= note: `-D clippy::single-component-path-imports` implied by `-D warnings`
error: this import is redundant
- --> $DIR/single_component_path_imports.rs:29:5
+ --> $DIR/single_component_path_imports.rs:33:5
|
LL | use regex;
| ^^^^^^^^^^ help: remove it entirely
diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs
index c75beb747..d6243c19f 100644
--- a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs
+++ b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs
@@ -2,7 +2,9 @@
#![allow(unused_imports)]
use regex;
+
use serde as edres;
+
pub use serde;
fn main() {
diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr
index 330f28520..ff148355e 100644
--- a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr
+++ b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr
@@ -7,7 +7,7 @@ LL | use regex;
= note: `-D clippy::single-component-path-imports` implied by `-D warnings`
error: this import is redundant
- --> $DIR/single_component_path_imports_nested_first.rs:13:10
+ --> $DIR/single_component_path_imports_nested_first.rs:15:10
|
LL | use {regex, serde};
| ^^^^^
@@ -15,7 +15,7 @@ LL | use {regex, serde};
= help: remove this import
error: this import is redundant
- --> $DIR/single_component_path_imports_nested_first.rs:13:17
+ --> $DIR/single_component_path_imports_nested_first.rs:15:17
|
LL | use {regex, serde};
| ^^^^^
diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs b/src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs
index 48e8e5302..5723d480a 100644
--- a/src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs
+++ b/src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs
@@ -2,6 +2,7 @@
#![allow(unused_imports)]
use self::regex::{Regex as xeger, RegexSet as tesxeger};
+#[rustfmt::skip]
pub use self::{
regex::{Regex, RegexSet},
some_mod::SomeType,
diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs b/src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs
index 4fb0cf40b..8a4fbf0dc 100644
--- a/src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs
+++ b/src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs
@@ -4,6 +4,7 @@
use regex;
use self::regex::{Regex as xeger, RegexSet as tesxeger};
+#[rustfmt::skip]
pub use self::{
regex::{Regex, RegexSet},
some_mod::SomeType,
diff --git a/src/tools/clippy/tests/ui/single_match.fixed b/src/tools/clippy/tests/ui/single_match.fixed
index e7b1fd6a8..163ba94af 100644
--- a/src/tools/clippy/tests/ui/single_match.fixed
+++ b/src/tools/clippy/tests/ui/single_match.fixed
@@ -4,6 +4,7 @@
unused,
clippy::uninlined_format_args,
clippy::needless_if,
+ clippy::redundant_guards,
clippy::redundant_pattern_matching
)]
fn dummy() {}
diff --git a/src/tools/clippy/tests/ui/single_match.rs b/src/tools/clippy/tests/ui/single_match.rs
index 1515a7053..0dcdb125f 100644
--- a/src/tools/clippy/tests/ui/single_match.rs
+++ b/src/tools/clippy/tests/ui/single_match.rs
@@ -4,6 +4,7 @@
unused,
clippy::uninlined_format_args,
clippy::needless_if,
+ clippy::redundant_guards,
clippy::redundant_pattern_matching
)]
fn dummy() {}
diff --git a/src/tools/clippy/tests/ui/single_match.stderr b/src/tools/clippy/tests/ui/single_match.stderr
index ef9015132..d35361599 100644
--- a/src/tools/clippy/tests/ui/single_match.stderr
+++ b/src/tools/clippy/tests/ui/single_match.stderr
@@ -1,5 +1,5 @@
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:14:5
+ --> $DIR/single_match.rs:15:5
|
LL | / match x {
LL | | Some(y) => {
@@ -10,7 +10,7 @@ LL | | };
| |_____^
|
= note: `-D clippy::single-match` implied by `-D warnings`
-help: try this
+help: try
|
LL ~ if let Some(y) = x {
LL + println!("{:?}", y);
@@ -18,7 +18,7 @@ LL ~ };
|
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:22:5
+ --> $DIR/single_match.rs:23:5
|
LL | / match x {
LL | | // Note the missing block braces.
@@ -27,136 +27,136 @@ LL | | // is expanded before we can do anything.
LL | | Some(y) => println!("{:?}", y),
LL | | _ => (),
LL | | }
- | |_____^ help: try this: `if let Some(y) = x { println!("{:?}", y) }`
+ | |_____^ help: try: `if let Some(y) = x { println!("{:?}", y) }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:31:5
+ --> $DIR/single_match.rs:32:5
|
LL | / match z {
LL | | (2..=3, 7..=9) => dummy(),
LL | | _ => {},
LL | | };
- | |_____^ help: try this: `if let (2..=3, 7..=9) = z { dummy() }`
+ | |_____^ help: try: `if let (2..=3, 7..=9) = z { dummy() }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:60:5
+ --> $DIR/single_match.rs:61:5
|
LL | / match x {
LL | | Some(y) => dummy(),
LL | | None => (),
LL | | };
- | |_____^ help: try this: `if let Some(y) = x { dummy() }`
+ | |_____^ help: try: `if let Some(y) = x { dummy() }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:65:5
+ --> $DIR/single_match.rs:66:5
|
LL | / match y {
LL | | Ok(y) => dummy(),
LL | | Err(..) => (),
LL | | };
- | |_____^ help: try this: `if let Ok(y) = y { dummy() }`
+ | |_____^ help: try: `if let Ok(y) = y { dummy() }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:72:5
+ --> $DIR/single_match.rs:73:5
|
LL | / match c {
LL | | Cow::Borrowed(..) => dummy(),
LL | | Cow::Owned(..) => (),
LL | | };
- | |_____^ help: try this: `if let Cow::Borrowed(..) = c { dummy() }`
+ | |_____^ help: try: `if let Cow::Borrowed(..) = c { dummy() }`
error: you seem to be trying to use `match` for an equality check. Consider using `if`
- --> $DIR/single_match.rs:93:5
+ --> $DIR/single_match.rs:94:5
|
LL | / match x {
LL | | "test" => println!(),
LL | | _ => (),
LL | | }
- | |_____^ help: try this: `if x == "test" { println!() }`
+ | |_____^ help: try: `if x == "test" { println!() }`
error: you seem to be trying to use `match` for an equality check. Consider using `if`
- --> $DIR/single_match.rs:106:5
+ --> $DIR/single_match.rs:107:5
|
LL | / match x {
LL | | Foo::A => println!(),
LL | | _ => (),
LL | | }
- | |_____^ help: try this: `if x == Foo::A { println!() }`
+ | |_____^ help: try: `if x == Foo::A { println!() }`
error: you seem to be trying to use `match` for an equality check. Consider using `if`
- --> $DIR/single_match.rs:112:5
+ --> $DIR/single_match.rs:113:5
|
LL | / match x {
LL | | FOO_C => println!(),
LL | | _ => (),
LL | | }
- | |_____^ help: try this: `if x == FOO_C { println!() }`
+ | |_____^ help: try: `if x == FOO_C { println!() }`
error: you seem to be trying to use `match` for an equality check. Consider using `if`
- --> $DIR/single_match.rs:117:5
+ --> $DIR/single_match.rs:118:5
|
LL | / match &&x {
LL | | Foo::A => println!(),
LL | | _ => (),
LL | | }
- | |_____^ help: try this: `if x == Foo::A { println!() }`
+ | |_____^ help: try: `if x == Foo::A { println!() }`
error: you seem to be trying to use `match` for an equality check. Consider using `if`
- --> $DIR/single_match.rs:123:5
+ --> $DIR/single_match.rs:124:5
|
LL | / match &x {
LL | | Foo::A => println!(),
LL | | _ => (),
LL | | }
- | |_____^ help: try this: `if x == &Foo::A { println!() }`
+ | |_____^ help: try: `if x == &Foo::A { println!() }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:140:5
+ --> $DIR/single_match.rs:141:5
|
LL | / match x {
LL | | Bar::A => println!(),
LL | | _ => (),
LL | | }
- | |_____^ help: try this: `if let Bar::A = x { println!() }`
+ | |_____^ help: try: `if let Bar::A = x { println!() }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:148:5
+ --> $DIR/single_match.rs:149:5
|
LL | / match x {
LL | | None => println!(),
LL | | _ => (),
LL | | };
- | |_____^ help: try this: `if let None = x { println!() }`
+ | |_____^ help: try: `if let None = x { println!() }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:170:5
+ --> $DIR/single_match.rs:171:5
|
LL | / match x {
LL | | (Some(_), _) => {},
LL | | (None, _) => {},
LL | | }
- | |_____^ help: try this: `if let (Some(_), _) = x {}`
+ | |_____^ help: try: `if let (Some(_), _) = x {}`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:176:5
+ --> $DIR/single_match.rs:177:5
|
LL | / match x {
LL | | (Some(E::V), _) => todo!(),
LL | | (_, _) => {},
LL | | }
- | |_____^ help: try this: `if let (Some(E::V), _) = x { todo!() }`
+ | |_____^ help: try: `if let (Some(E::V), _) = x { todo!() }`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:182:5
+ --> $DIR/single_match.rs:183:5
|
LL | / match (Some(42), Some(E::V), Some(42)) {
LL | | (.., Some(E::V), _) => {},
LL | | (..) => {},
LL | | }
- | |_____^ help: try this: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}`
+ | |_____^ help: try: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}`
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:254:5
+ --> $DIR/single_match.rs:255:5
|
LL | / match bar {
LL | | Some(v) => unsafe {
@@ -167,7 +167,7 @@ LL | | _ => {},
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ if let Some(v) = bar { unsafe {
LL + let r = &v as *const i32;
@@ -176,7 +176,7 @@ LL + } }
|
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
- --> $DIR/single_match.rs:262:5
+ --> $DIR/single_match.rs:263:5
|
LL | / match bar {
LL | | #[rustfmt::skip]
@@ -187,7 +187,7 @@ LL | | _ => {},
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ if let Some(v) = bar {
LL + unsafe {
diff --git a/src/tools/clippy/tests/ui/single_match_else.stderr b/src/tools/clippy/tests/ui/single_match_else.stderr
index 228236f3b..5e7d4062e 100644
--- a/src/tools/clippy/tests/ui/single_match_else.stderr
+++ b/src/tools/clippy/tests/ui/single_match_else.stderr
@@ -12,7 +12,7 @@ LL | | };
| |_____^
|
= note: `-D clippy::single-match-else` implied by `-D warnings`
-help: try this
+help: try
|
LL ~ let _ = if let ExprNode::ExprAddrOf = ExprNode::Butterflies { Some(&NODE) } else {
LL + let x = 5;
@@ -32,7 +32,7 @@ LL | | },
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ if let Some(a) = Some(1) { println!("${:?}", a) } else {
LL + println!("else block");
@@ -52,7 +52,7 @@ LL | | },
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ if let Some(a) = Some(1) { println!("${:?}", a) } else {
LL + println!("else block");
@@ -72,7 +72,7 @@ LL | | }
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ if let Ok(a) = Result::<i32, Infallible>::Ok(1) { println!("${:?}", a) } else {
LL + println!("else block");
@@ -92,7 +92,7 @@ LL | | }
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ if let Cow::Owned(a) = Cow::from("moo") { println!("${:?}", a) } else {
LL + println!("else block");
@@ -112,7 +112,7 @@ LL | | },
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ if let Some(v) = bar { unsafe {
LL + let r = &v as *const i32;
@@ -135,7 +135,7 @@ LL | | },
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ if let Some(v) = bar {
LL + println!("Some");
@@ -159,7 +159,7 @@ LL | | },
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ if let Some(v) = bar { unsafe {
LL + let r = &v as *const i32;
@@ -183,7 +183,7 @@ LL | | },
LL | | }
| |_____^
|
-help: try this
+help: try
|
LL ~ if let Some(v) = bar {
LL + unsafe {
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.rs b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
index 16be9f6d2..cfb856861 100644
--- a/src/tools/clippy/tests/ui/slow_vector_initialization.rs
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
@@ -4,6 +4,7 @@ fn main() {
resize_vector();
extend_vector();
mixed_extend_resize_vector();
+ from_empty_vec();
}
fn extend_vector() {
@@ -59,6 +60,21 @@ fn resize_vector() {
vec1.resize(10, 0);
}
+fn from_empty_vec() {
+ // Resize with constant expression
+ let len = 300;
+ let mut vec1 = Vec::new();
+ vec1.resize(len, 0);
+
+ // Resize with len expression
+ let mut vec3 = Vec::new();
+ vec3.resize(len - 10, 0);
+
+ // Reinitialization should be warned
+ vec1 = Vec::new();
+ vec1.resize(10, 0);
+}
+
fn do_stuff(vec: &mut [u8]) {}
fn extend_vector_with_manipulations_between() {
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
index cb3ce3e95..c88c97a55 100644
--- a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
@@ -1,76 +1,100 @@
error: slow zero-filling initialization
- --> $DIR/slow_vector_initialization.rs:13:5
+ --> $DIR/slow_vector_initialization.rs:14:5
|
LL | let mut vec1 = Vec::with_capacity(len);
- | ----------------------- help: consider replace allocation with: `vec![0; len]`
+ | ----------------------- help: consider replacing this with: `vec![0; len]`
LL | vec1.extend(repeat(0).take(len));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::slow-vector-initialization` implied by `-D warnings`
error: slow zero-filling initialization
- --> $DIR/slow_vector_initialization.rs:17:5
+ --> $DIR/slow_vector_initialization.rs:18:5
|
LL | let mut vec2 = Vec::with_capacity(len - 10);
- | ---------------------------- help: consider replace allocation with: `vec![0; len - 10]`
+ | ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
LL | vec2.extend(repeat(0).take(len - 10));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: slow zero-filling initialization
- --> $DIR/slow_vector_initialization.rs:24:5
+ --> $DIR/slow_vector_initialization.rs:25:5
|
LL | let mut vec4 = Vec::with_capacity(len);
- | ----------------------- help: consider replace allocation with: `vec![0; len]`
+ | ----------------------- help: consider replacing this with: `vec![0; len]`
LL | vec4.extend(repeat(0).take(vec4.capacity()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: slow zero-filling initialization
- --> $DIR/slow_vector_initialization.rs:34:5
+ --> $DIR/slow_vector_initialization.rs:35:5
|
LL | let mut resized_vec = Vec::with_capacity(30);
- | ---------------------- help: consider replace allocation with: `vec![0; 30]`
+ | ---------------------- help: consider replacing this with: `vec![0; 30]`
LL | resized_vec.resize(30, 0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: slow zero-filling initialization
- --> $DIR/slow_vector_initialization.rs:37:5
+ --> $DIR/slow_vector_initialization.rs:38:5
|
LL | let mut extend_vec = Vec::with_capacity(30);
- | ---------------------- help: consider replace allocation with: `vec![0; 30]`
+ | ---------------------- help: consider replacing this with: `vec![0; 30]`
LL | extend_vec.extend(repeat(0).take(30));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: slow zero-filling initialization
- --> $DIR/slow_vector_initialization.rs:44:5
+ --> $DIR/slow_vector_initialization.rs:45:5
|
LL | let mut vec1 = Vec::with_capacity(len);
- | ----------------------- help: consider replace allocation with: `vec![0; len]`
+ | ----------------------- help: consider replacing this with: `vec![0; len]`
LL | vec1.resize(len, 0);
| ^^^^^^^^^^^^^^^^^^^
error: slow zero-filling initialization
- --> $DIR/slow_vector_initialization.rs:52:5
+ --> $DIR/slow_vector_initialization.rs:53:5
|
LL | let mut vec3 = Vec::with_capacity(len - 10);
- | ---------------------------- help: consider replace allocation with: `vec![0; len - 10]`
+ | ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
LL | vec3.resize(len - 10, 0);
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: slow zero-filling initialization
- --> $DIR/slow_vector_initialization.rs:55:5
+ --> $DIR/slow_vector_initialization.rs:56:5
|
LL | let mut vec4 = Vec::with_capacity(len);
- | ----------------------- help: consider replace allocation with: `vec![0; len]`
+ | ----------------------- help: consider replacing this with: `vec![0; len]`
LL | vec4.resize(vec4.capacity(), 0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: slow zero-filling initialization
- --> $DIR/slow_vector_initialization.rs:59:5
+ --> $DIR/slow_vector_initialization.rs:60:5
|
LL | vec1 = Vec::with_capacity(10);
- | ---------------------- help: consider replace allocation with: `vec![0; 10]`
+ | ---------------------- help: consider replacing this with: `vec![0; 10]`
LL | vec1.resize(10, 0);
| ^^^^^^^^^^^^^^^^^^
-error: aborting due to 9 previous errors
+error: slow zero-filling initialization
+ --> $DIR/slow_vector_initialization.rs:67:5
+ |
+LL | let mut vec1 = Vec::new();
+ | ---------- help: consider replacing this with: `vec![0; len]`
+LL | vec1.resize(len, 0);
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+ --> $DIR/slow_vector_initialization.rs:71:5
+ |
+LL | let mut vec3 = Vec::new();
+ | ---------- help: consider replacing this with: `vec![0; len - 10]`
+LL | vec3.resize(len - 10, 0);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+ --> $DIR/slow_vector_initialization.rs:75:5
+ |
+LL | vec1 = Vec::new();
+ | ---------- help: consider replacing this with: `vec![0; 10]`
+LL | vec1.resize(10, 0);
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/string_extend.stderr b/src/tools/clippy/tests/ui/string_extend.stderr
index b35c77fd9..34b432901 100644
--- a/src/tools/clippy/tests/ui/string_extend.stderr
+++ b/src/tools/clippy/tests/ui/string_extend.stderr
@@ -2,7 +2,7 @@ error: calling `.extend(_.chars())`
--> $DIR/string_extend.rs:18:5
|
LL | s.extend(abc.chars());
- | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(abc)`
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str(abc)`
|
= note: `-D clippy::string-extend-chars` implied by `-D warnings`
@@ -10,19 +10,19 @@ error: calling `.extend(_.chars())`
--> $DIR/string_extend.rs:21:5
|
LL | s.extend("abc".chars());
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str("abc")`
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str("abc")`
error: calling `.extend(_.chars())`
--> $DIR/string_extend.rs:24:5
|
LL | s.extend(def.chars());
- | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&def)`
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str(&def)`
error: calling `.extend(_.chars())`
--> $DIR/string_extend.rs:34:5
|
LL | s.extend(abc[0..2].chars());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&abc[0..2])`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str(&abc[0..2])`
error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/string_lit_chars_any.fixed b/src/tools/clippy/tests/ui/string_lit_chars_any.fixed
new file mode 100644
index 000000000..d7ab9c339
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_lit_chars_any.fixed
@@ -0,0 +1,50 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(clippy::eq_op, clippy::needless_raw_string_hashes, clippy::no_effect, unused)]
+#![warn(clippy::string_lit_chars_any)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct NotStringLit;
+
+impl NotStringLit {
+ fn chars(&self) -> impl Iterator<Item = char> {
+ "c".chars()
+ }
+}
+
+fn main() {
+ let c = 'c';
+ matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+ matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+ matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+ matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+ #[rustfmt::skip]
+ matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+ // Do not lint
+ NotStringLit.chars().any(|x| x == c);
+ "\\.+*?()|[]{}^$#&-~".chars().any(|x| {
+ let c = 'c';
+ x == c
+ });
+ "\\.+*?()|[]{}^$#&-~".chars().any(|x| {
+ 1;
+ x == c
+ });
+ "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == x);
+ "\\.+*?()|[]{}^$#&-~".chars().any(|_x| c == c);
+ matches!(
+ c,
+ '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'
+ );
+ external! {
+ let c = 'c';
+ "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+ }
+ with_span! {
+ span
+ let c = 'c';
+ "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+ }
+}
diff --git a/src/tools/clippy/tests/ui/string_lit_chars_any.rs b/src/tools/clippy/tests/ui/string_lit_chars_any.rs
new file mode 100644
index 000000000..9408d7bb2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_lit_chars_any.rs
@@ -0,0 +1,50 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(clippy::eq_op, clippy::needless_raw_string_hashes, clippy::no_effect, unused)]
+#![warn(clippy::string_lit_chars_any)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct NotStringLit;
+
+impl NotStringLit {
+ fn chars(&self) -> impl Iterator<Item = char> {
+ "c".chars()
+ }
+}
+
+fn main() {
+ let c = 'c';
+ "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+ r#"\.+*?()|[]{}^$#&-~"#.chars().any(|x| x == c);
+ "\\.+*?()|[]{}^$#&-~".chars().any(|x| c == x);
+ r#"\.+*?()|[]{}^$#&-~"#.chars().any(|x| c == x);
+ #[rustfmt::skip]
+ "\\.+*?()|[]{}^$#&-~".chars().any(|x| { x == c });
+ // Do not lint
+ NotStringLit.chars().any(|x| x == c);
+ "\\.+*?()|[]{}^$#&-~".chars().any(|x| {
+ let c = 'c';
+ x == c
+ });
+ "\\.+*?()|[]{}^$#&-~".chars().any(|x| {
+ 1;
+ x == c
+ });
+ "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == x);
+ "\\.+*?()|[]{}^$#&-~".chars().any(|_x| c == c);
+ matches!(
+ c,
+ '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'
+ );
+ external! {
+ let c = 'c';
+ "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+ }
+ with_span! {
+ span
+ let c = 'c';
+ "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+ }
+}
diff --git a/src/tools/clippy/tests/ui/string_lit_chars_any.stderr b/src/tools/clippy/tests/ui/string_lit_chars_any.stderr
new file mode 100644
index 000000000..ff951b73d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_lit_chars_any.stderr
@@ -0,0 +1,58 @@
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+ --> $DIR/string_lit_chars_any.rs:19:5
+ |
+LL | "//.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::string-lit-chars-any` implied by `-D warnings`
+help: use `matches!(...)` instead
+ |
+LL | matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+ --> $DIR/string_lit_chars_any.rs:20:5
+ |
+LL | r#"/.+*?()|[]{}^$#&-~"#.chars().any(|x| x == c);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: use `matches!(...)` instead
+ |
+LL | matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+ --> $DIR/string_lit_chars_any.rs:21:5
+ |
+LL | "//.+*?()|[]{}^$#&-~".chars().any(|x| c == x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: use `matches!(...)` instead
+ |
+LL | matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+ --> $DIR/string_lit_chars_any.rs:22:5
+ |
+LL | r#"/.+*?()|[]{}^$#&-~"#.chars().any(|x| c == x);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: use `matches!(...)` instead
+ |
+LL | matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+ --> $DIR/string_lit_chars_any.rs:24:5
+ |
+LL | "//.+*?()|[]{}^$#&-~".chars().any(|x| { x == c });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: use `matches!(...)` instead
+ |
+LL | matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr b/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr
index 296268a5f..fcd17f689 100644
--- a/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr
+++ b/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr
@@ -2,7 +2,7 @@ error: using `libc::strlen` on a `CString` or `CStr` value
--> $DIR/strlen_on_c_strings.rs:15:13
|
LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstring.as_bytes().len()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstring.as_bytes().len()`
|
= note: `-D clippy::strlen-on-c-strings` implied by `-D warnings`
@@ -10,37 +10,37 @@ error: using `libc::strlen` on a `CString` or `CStr` value
--> $DIR/strlen_on_c_strings.rs:19:13
|
LL | let _ = unsafe { libc::strlen(cstr.as_ptr()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstr.to_bytes().len()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstr.to_bytes().len()`
error: using `libc::strlen` on a `CString` or `CStr` value
--> $DIR/strlen_on_c_strings.rs:21:13
|
LL | let _ = unsafe { strlen(cstr.as_ptr()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstr.to_bytes().len()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstr.to_bytes().len()`
error: using `libc::strlen` on a `CString` or `CStr` value
--> $DIR/strlen_on_c_strings.rs:24:22
|
LL | let _ = unsafe { strlen((*pcstr).as_ptr()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*pcstr).to_bytes().len()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*pcstr).to_bytes().len()`
error: using `libc::strlen` on a `CString` or `CStr` value
--> $DIR/strlen_on_c_strings.rs:29:22
|
LL | let _ = unsafe { strlen(unsafe_identity(cstr).as_ptr()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unsafe_identity(cstr).to_bytes().len()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe_identity(cstr).to_bytes().len()`
error: using `libc::strlen` on a `CString` or `CStr` value
--> $DIR/strlen_on_c_strings.rs:30:13
|
LL | let _ = unsafe { strlen(unsafe { unsafe_identity(cstr) }.as_ptr()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unsafe { unsafe_identity(cstr) }.to_bytes().len()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe { unsafe_identity(cstr) }.to_bytes().len()`
error: using `libc::strlen` on a `CString` or `CStr` value
--> $DIR/strlen_on_c_strings.rs:33:22
|
LL | let _ = unsafe { strlen(f(cstr).as_ptr()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `f(cstr).to_bytes().len()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `f(cstr).to_bytes().len()`
error: aborting due to 7 previous errors
diff --git a/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr b/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr
index 8bb3c8fbe..d93a55ba9 100644
--- a/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr
@@ -10,31 +10,31 @@ error: `^` is not the exponentiation operator
--> $DIR/suspicious_xor_used_as_pow.rs:20:13
|
LL | let _ = 2i32 ^ 9i32;
- | ^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(9_i32)`
+ | ^^^^^^^^^^^ help: did you mean to write: `2i32.pow(9i32)`
error: `^` is not the exponentiation operator
--> $DIR/suspicious_xor_used_as_pow.rs:21:13
|
LL | let _ = 2i32 ^ 2i32;
- | ^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(2_i32)`
+ | ^^^^^^^^^^^ help: did you mean to write: `2i32.pow(2i32)`
error: `^` is not the exponentiation operator
--> $DIR/suspicious_xor_used_as_pow.rs:22:13
|
LL | let _ = 50i32 ^ 3i32;
- | ^^^^^^^^^^^^ help: did you mean to write: `50_i32.pow(3_i32)`
+ | ^^^^^^^^^^^^ help: did you mean to write: `50i32.pow(3i32)`
error: `^` is not the exponentiation operator
--> $DIR/suspicious_xor_used_as_pow.rs:23:13
|
LL | let _ = 5i32 ^ 8i32;
- | ^^^^^^^^^^^ help: did you mean to write: `5_i32.pow(8_i32)`
+ | ^^^^^^^^^^^ help: did you mean to write: `5i32.pow(8i32)`
error: `^` is not the exponentiation operator
--> $DIR/suspicious_xor_used_as_pow.rs:24:13
|
LL | let _ = 2i32 ^ 32i32;
- | ^^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(32_i32)`
+ | ^^^^^^^^^^^^ help: did you mean to write: `2i32.pow(32i32)`
error: `^` is not the exponentiation operator
--> $DIR/suspicious_xor_used_as_pow.rs:13:9
diff --git a/src/tools/clippy/tests/ui/swap.fixed b/src/tools/clippy/tests/ui/swap.fixed
index 22f904e3f..7b74a83b6 100644
--- a/src/tools/clippy/tests/ui/swap.fixed
+++ b/src/tools/clippy/tests/ui/swap.fixed
@@ -11,7 +11,8 @@
unused_assignments,
unused_variables,
clippy::let_and_return,
- clippy::useless_vec
+ clippy::useless_vec,
+ clippy::redundant_locals
)]
struct Foo(u32);
diff --git a/src/tools/clippy/tests/ui/swap.rs b/src/tools/clippy/tests/ui/swap.rs
index ada64f89e..93855cd7b 100644
--- a/src/tools/clippy/tests/ui/swap.rs
+++ b/src/tools/clippy/tests/ui/swap.rs
@@ -11,7 +11,8 @@
unused_assignments,
unused_variables,
clippy::let_and_return,
- clippy::useless_vec
+ clippy::useless_vec,
+ clippy::redundant_locals
)]
struct Foo(u32);
diff --git a/src/tools/clippy/tests/ui/swap.stderr b/src/tools/clippy/tests/ui/swap.stderr
index a3b9c2b74..1097b29bb 100644
--- a/src/tools/clippy/tests/ui/swap.stderr
+++ b/src/tools/clippy/tests/ui/swap.stderr
@@ -1,5 +1,5 @@
error: this looks like you are swapping `bar.a` and `bar.b` manually
- --> $DIR/swap.rs:28:5
+ --> $DIR/swap.rs:29:5
|
LL | / let temp = bar.a;
LL | | bar.a = bar.b;
@@ -10,7 +10,7 @@ LL | | bar.b = temp;
= note: `-D clippy::manual-swap` implied by `-D warnings`
error: this looks like you are swapping elements of `foo` manually
- --> $DIR/swap.rs:40:5
+ --> $DIR/swap.rs:41:5
|
LL | / let temp = foo[0];
LL | | foo[0] = foo[1];
@@ -18,7 +18,7 @@ LL | | foo[1] = temp;
| |__________________^ help: try: `foo.swap(0, 1);`
error: this looks like you are swapping elements of `foo` manually
- --> $DIR/swap.rs:49:5
+ --> $DIR/swap.rs:50:5
|
LL | / let temp = foo[0];
LL | | foo[0] = foo[1];
@@ -26,7 +26,7 @@ LL | | foo[1] = temp;
| |__________________^ help: try: `foo.swap(0, 1);`
error: this looks like you are swapping elements of `foo` manually
- --> $DIR/swap.rs:68:5
+ --> $DIR/swap.rs:69:5
|
LL | / let temp = foo[0];
LL | | foo[0] = foo[1];
@@ -34,7 +34,7 @@ LL | | foo[1] = temp;
| |__________________^ help: try: `foo.swap(0, 1);`
error: this looks like you are swapping `a` and `b` manually
- --> $DIR/swap.rs:79:5
+ --> $DIR/swap.rs:80:5
|
LL | / a ^= b;
LL | | b ^= a;
@@ -42,7 +42,7 @@ LL | | a ^= b;
| |___________^ help: try: `std::mem::swap(&mut a, &mut b);`
error: this looks like you are swapping `bar.a` and `bar.b` manually
- --> $DIR/swap.rs:87:5
+ --> $DIR/swap.rs:88:5
|
LL | / bar.a ^= bar.b;
LL | | bar.b ^= bar.a;
@@ -50,7 +50,7 @@ LL | | bar.a ^= bar.b;
| |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);`
error: this looks like you are swapping elements of `foo` manually
- --> $DIR/swap.rs:95:5
+ --> $DIR/swap.rs:96:5
|
LL | / foo[0] ^= foo[1];
LL | | foo[1] ^= foo[0];
@@ -58,7 +58,7 @@ LL | | foo[0] ^= foo[1];
| |_____________________^ help: try: `foo.swap(0, 1);`
error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually
- --> $DIR/swap.rs:124:5
+ --> $DIR/swap.rs:125:5
|
LL | / let temp = foo[0][1];
LL | | foo[0][1] = bar[1][0];
@@ -68,7 +68,7 @@ LL | | bar[1][0] = temp;
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are swapping `a` and `b` manually
- --> $DIR/swap.rs:138:7
+ --> $DIR/swap.rs:139:7
|
LL | ; let t = a;
| _______^
@@ -79,7 +79,7 @@ LL | | b = t;
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are swapping `c.0` and `a` manually
- --> $DIR/swap.rs:147:7
+ --> $DIR/swap.rs:148:7
|
LL | ; let t = c.0;
| _______^
@@ -90,7 +90,7 @@ LL | | a = t;
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are swapping `b` and `a` manually
- --> $DIR/swap.rs:173:5
+ --> $DIR/swap.rs:174:5
|
LL | / let t = b;
LL | | b = a;
@@ -100,7 +100,7 @@ LL | | a = t;
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are trying to swap `a` and `b`
- --> $DIR/swap.rs:135:5
+ --> $DIR/swap.rs:136:5
|
LL | / a = b;
LL | | b = a;
@@ -110,7 +110,7 @@ LL | | b = a;
= note: `-D clippy::almost-swapped` implied by `-D warnings`
error: this looks like you are trying to swap `c.0` and `a`
- --> $DIR/swap.rs:144:5
+ --> $DIR/swap.rs:145:5
|
LL | / c.0 = a;
LL | | a = c.0;
@@ -119,7 +119,7 @@ LL | | a = c.0;
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are trying to swap `a` and `b`
- --> $DIR/swap.rs:151:5
+ --> $DIR/swap.rs:152:5
|
LL | / let a = b;
LL | | let b = a;
@@ -128,7 +128,7 @@ LL | | let b = a;
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are trying to swap `d` and `c`
- --> $DIR/swap.rs:156:5
+ --> $DIR/swap.rs:157:5
|
LL | / d = c;
LL | | c = d;
@@ -137,7 +137,7 @@ LL | | c = d;
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are trying to swap `a` and `b`
- --> $DIR/swap.rs:160:5
+ --> $DIR/swap.rs:161:5
|
LL | / let a = b;
LL | | b = a;
@@ -146,7 +146,7 @@ LL | | b = a;
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are swapping `s.0.x` and `s.0.y` manually
- --> $DIR/swap.rs:208:5
+ --> $DIR/swap.rs:209:5
|
LL | / let t = s.0.x;
LL | | s.0.x = s.0.y;
diff --git a/src/tools/clippy/tests/ui/to_digit_is_some.stderr b/src/tools/clippy/tests/ui/to_digit_is_some.stderr
index 10a1b393a..c4718825d 100644
--- a/src/tools/clippy/tests/ui/to_digit_is_some.stderr
+++ b/src/tools/clippy/tests/ui/to_digit_is_some.stderr
@@ -2,7 +2,7 @@ error: use of `.to_digit(..).is_some()`
--> $DIR/to_digit_is_some.rs:9:13
|
LL | let _ = d.to_digit(8).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `d.is_digit(8)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d.is_digit(8)`
|
= note: `-D clippy::to-digit-is-some` implied by `-D warnings`
@@ -10,7 +10,7 @@ error: use of `.to_digit(..).is_some()`
--> $DIR/to_digit_is_some.rs:10:13
|
LL | let _ = char::to_digit(c, 8).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `char::is_digit(c, 8)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `char::is_digit(c, 8)`
error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
index 486155831..86f5cc937 100644
--- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
+++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
@@ -5,7 +5,8 @@
clippy::disallowed_names,
clippy::needless_lifetimes,
clippy::redundant_field_names,
- clippy::uninlined_format_args
+ clippy::uninlined_format_args,
+ clippy::needless_pass_by_ref_mut
)]
#[derive(Copy, Clone)]
diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
index 8c5cfa8a0..2af668537 100644
--- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
+++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
@@ -1,5 +1,5 @@
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:51:11
+ --> $DIR/trivially_copy_pass_by_ref.rs:52:11
|
LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `u32`
@@ -11,103 +11,103 @@ LL | #![deny(clippy::trivially_copy_pass_by_ref)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:51:20
+ --> $DIR/trivially_copy_pass_by_ref.rs:52:20
|
LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Foo`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:51:29
+ --> $DIR/trivially_copy_pass_by_ref.rs:52:29
|
LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Baz`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:58:12
+ --> $DIR/trivially_copy_pass_by_ref.rs:59:12
|
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
| ^^^^^ help: consider passing by value instead: `self`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:58:22
+ --> $DIR/trivially_copy_pass_by_ref.rs:59:22
|
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `u32`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:58:31
+ --> $DIR/trivially_copy_pass_by_ref.rs:59:31
|
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Foo`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:58:40
+ --> $DIR/trivially_copy_pass_by_ref.rs:59:40
|
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Baz`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:60:16
+ --> $DIR/trivially_copy_pass_by_ref.rs:61:16
|
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `u32`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:60:25
+ --> $DIR/trivially_copy_pass_by_ref.rs:61:25
|
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Foo`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:60:34
+ --> $DIR/trivially_copy_pass_by_ref.rs:61:34
|
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Baz`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:62:35
+ --> $DIR/trivially_copy_pass_by_ref.rs:63:35
|
LL | fn bad_issue7518(self, other: &Self) {}
| ^^^^^ help: consider passing by value instead: `Self`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:74:16
+ --> $DIR/trivially_copy_pass_by_ref.rs:75:16
|
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `u32`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:74:25
+ --> $DIR/trivially_copy_pass_by_ref.rs:75:25
|
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Foo`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:74:34
+ --> $DIR/trivially_copy_pass_by_ref.rs:75:34
|
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
| ^^^^ help: consider passing by value instead: `Baz`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:78:34
+ --> $DIR/trivially_copy_pass_by_ref.rs:79:34
|
LL | fn trait_method(&self, _foo: &Foo);
| ^^^^ help: consider passing by value instead: `Foo`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:110:21
+ --> $DIR/trivially_copy_pass_by_ref.rs:111:21
|
LL | fn foo_never(x: &i32) {
| ^^^^ help: consider passing by value instead: `i32`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:115:15
+ --> $DIR/trivially_copy_pass_by_ref.rs:116:15
|
LL | fn foo(x: &i32) {
| ^^^^ help: consider passing by value instead: `i32`
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:142:37
+ --> $DIR/trivially_copy_pass_by_ref.rs:143:37
|
LL | fn _unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 {
| ^^^^^^^ help: consider passing by value instead: `u32`
diff --git a/src/tools/clippy/tests/ui/try_err.fixed b/src/tools/clippy/tests/ui/try_err.fixed
index 181674087..930489fab 100644
--- a/src/tools/clippy/tests/ui/try_err.fixed
+++ b/src/tools/clippy/tests/ui/try_err.fixed
@@ -2,7 +2,11 @@
//@aux-build:proc_macros.rs:proc-macro
#![deny(clippy::try_err)]
-#![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)]
+#![allow(
+ clippy::unnecessary_wraps,
+ clippy::needless_question_mark,
+ clippy::needless_return_with_question_mark
+)]
extern crate proc_macros;
use proc_macros::{external, inline_macros};
diff --git a/src/tools/clippy/tests/ui/try_err.rs b/src/tools/clippy/tests/ui/try_err.rs
index 0e47c4d02..f5baf3d8f 100644
--- a/src/tools/clippy/tests/ui/try_err.rs
+++ b/src/tools/clippy/tests/ui/try_err.rs
@@ -2,7 +2,11 @@
//@aux-build:proc_macros.rs:proc-macro
#![deny(clippy::try_err)]
-#![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)]
+#![allow(
+ clippy::unnecessary_wraps,
+ clippy::needless_question_mark,
+ clippy::needless_return_with_question_mark
+)]
extern crate proc_macros;
use proc_macros::{external, inline_macros};
diff --git a/src/tools/clippy/tests/ui/try_err.stderr b/src/tools/clippy/tests/ui/try_err.stderr
index 4ad0e2e56..9968b383e 100644
--- a/src/tools/clippy/tests/ui/try_err.stderr
+++ b/src/tools/clippy/tests/ui/try_err.stderr
@@ -1,8 +1,8 @@
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:19:9
+ --> $DIR/try_err.rs:23:9
|
LL | Err(err)?;
- | ^^^^^^^^^ help: try this: `return Err(err)`
+ | ^^^^^^^^^ help: try: `return Err(err)`
|
note: the lint level is defined here
--> $DIR/try_err.rs:4:9
@@ -11,68 +11,68 @@ LL | #![deny(clippy::try_err)]
| ^^^^^^^^^^^^^^^
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:29:9
+ --> $DIR/try_err.rs:33:9
|
LL | Err(err)?;
- | ^^^^^^^^^ help: try this: `return Err(err.into())`
+ | ^^^^^^^^^ help: try: `return Err(err.into())`
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:49:17
+ --> $DIR/try_err.rs:53:17
|
LL | Err(err)?;
- | ^^^^^^^^^ help: try this: `return Err(err)`
+ | ^^^^^^^^^ help: try: `return Err(err)`
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:68:17
+ --> $DIR/try_err.rs:72:17
|
LL | Err(err)?;
- | ^^^^^^^^^ help: try this: `return Err(err.into())`
+ | ^^^^^^^^^ help: try: `return Err(err.into())`
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:88:23
+ --> $DIR/try_err.rs:92:23
|
LL | Err(_) => Err(1)?,
- | ^^^^^^^ help: try this: `return Err(1)`
+ | ^^^^^^^ help: try: `return Err(1)`
|
= note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:95:23
+ --> $DIR/try_err.rs:99:23
|
LL | Err(_) => Err(inline!(1))?,
- | ^^^^^^^^^^^^^^^^ help: try this: `return Err(inline!(1))`
+ | ^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(1))`
|
= note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:122:9
+ --> $DIR/try_err.rs:126:9
|
LL | Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))`
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:129:9
+ --> $DIR/try_err.rs:133:9
|
LL | Err(io::ErrorKind::WriteZero)?
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))`
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:131:9
+ --> $DIR/try_err.rs:135:9
|
LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))?
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))`
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:139:9
+ --> $DIR/try_err.rs:143:9
|
LL | Err(io::ErrorKind::NotFound)?
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))`
error: returning an `Err(_)` with the `?` operator
- --> $DIR/try_err.rs:148:16
+ --> $DIR/try_err.rs:152:16
|
LL | return Err(42)?;
- | ^^^^^^^^ help: try this: `Err(42)`
+ | ^^^^^^^^ help: try: `Err(42)`
error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/tuple_array_conversions.rs b/src/tools/clippy/tests/ui/tuple_array_conversions.rs
index f96a7c97f..569415acb 100644
--- a/src/tools/clippy/tests/ui/tuple_array_conversions.rs
+++ b/src/tools/clippy/tests/ui/tuple_array_conversions.rs
@@ -52,6 +52,36 @@ fn main() {
let v1: Vec<[u32; 2]> = t1.iter().map(|&(a, b)| [a, b]).collect();
let t2: Vec<(u32, u32)> = v1.iter().map(|&[a, b]| (a, b)).collect();
}
+ // FP #11082; needs discussion
+ let (a, b) = (1.0f64, 2.0f64);
+ let _: &[f64] = &[a, b];
+ // FP #11085; impossible to fix
+ let [src, dest]: [_; 2] = [1, 2];
+ (src, dest);
+ // FP #11100
+ fn issue_11100_array_to_tuple(this: [&mut i32; 2]) -> (&i32, &mut i32) {
+ let [input, output] = this;
+ (input, output)
+ }
+
+ fn issue_11100_tuple_to_array<'a>(this: (&'a mut i32, &'a mut i32)) -> [&'a i32; 2] {
+ let (input, output) = this;
+ [input, output]
+ }
+ // FP #11124
+ // tuple=>array
+ let (a, b) = (1, 2);
+ [a, b];
+ let x = a;
+ // array=>tuple
+ let [a, b] = [1, 2];
+ (a, b);
+ let x = a;
+ // FP #11144
+ let (a, (b, c)) = (1, (2, 3));
+ [a, c];
+ let [[a, b], [c, d]] = [[1, 2], [3, 4]];
+ (a, c);
}
#[clippy::msrv = "1.70.0"]
diff --git a/src/tools/clippy/tests/ui/tuple_array_conversions.stderr b/src/tools/clippy/tests/ui/tuple_array_conversions.stderr
index be653e8ef..50bdcf29d 100644
--- a/src/tools/clippy/tests/ui/tuple_array_conversions.stderr
+++ b/src/tools/clippy/tests/ui/tuple_array_conversions.stderr
@@ -15,14 +15,6 @@ LL | let x = [x.0, x.1];
|
= help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed
-error: it looks like you're trying to convert an array to a tuple
- --> $DIR/tuple_array_conversions.rs:13:13
- |
-LL | let x = (x[0], x[1]);
- | ^^^^^^^^^^^^
- |
- = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed
-
error: it looks like you're trying to convert a tuple to an array
--> $DIR/tuple_array_conversions.rs:16:53
|
@@ -55,8 +47,24 @@ LL | t1.iter().for_each(|&(a, b)| _ = [a, b]);
|
= help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed
+error: it looks like you're trying to convert a tuple to an array
+ --> $DIR/tuple_array_conversions.rs:57:22
+ |
+LL | let _: &[f64] = &[a, b];
+ | ^^^^^^
+ |
+ = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed
+
error: it looks like you're trying to convert an array to a tuple
- --> $DIR/tuple_array_conversions.rs:69:13
+ --> $DIR/tuple_array_conversions.rs:60:5
+ |
+LL | (src, dest);
+ | ^^^^^^^^^^^
+ |
+ = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed
+
+error: it looks like you're trying to convert an array to a tuple
+ --> $DIR/tuple_array_conversions.rs:99:13
|
LL | let x = (x[0], x[1]);
| ^^^^^^^^^^^^
@@ -64,20 +72,12 @@ LL | let x = (x[0], x[1]);
= help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed
error: it looks like you're trying to convert a tuple to an array
- --> $DIR/tuple_array_conversions.rs:70:13
+ --> $DIR/tuple_array_conversions.rs:100:13
|
LL | let x = [x.0, x.1];
| ^^^^^^^^^^
|
= help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed
-error: it looks like you're trying to convert an array to a tuple
- --> $DIR/tuple_array_conversions.rs:72:13
- |
-LL | let x = (x[0], x[1]);
- | ^^^^^^^^^^^^
- |
- = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed
-
error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/type_id_on_box.fixed b/src/tools/clippy/tests/ui/type_id_on_box.fixed
new file mode 100644
index 000000000..615d809c8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/type_id_on_box.fixed
@@ -0,0 +1,40 @@
+//@run-rustfix
+
+#![warn(clippy::type_id_on_box)]
+
+use std::any::{Any, TypeId};
+use std::ops::Deref;
+
+type SomeBox = Box<dyn Any>;
+
+struct BadBox(Box<dyn Any>);
+
+impl Deref for BadBox {
+ type Target = Box<dyn Any>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+fn existential() -> impl Any {
+ Box::new(1) as Box<dyn Any>
+}
+
+fn main() {
+ let any_box: Box<dyn Any> = Box::new(0usize);
+ let _ = (*any_box).type_id();
+ let _ = TypeId::of::<Box<dyn Any>>(); // Don't lint. We explicitly say "do this instead" if this is intentional
+ let _ = (*any_box).type_id();
+ let any_box: &Box<dyn Any> = &(Box::new(0usize) as Box<dyn Any>);
+ let _ = (**any_box).type_id(); // 2 derefs are needed here to get to the `dyn Any`
+
+ let b = existential();
+ let _ = b.type_id(); // Don't lint.
+
+ let b: SomeBox = Box::new(0usize);
+ let _ = (*b).type_id();
+
+ let b = BadBox(Box::new(0usize));
+ let _ = b.type_id(); // Don't lint. This is a call to `<BadBox as Any>::type_id`. Not `std::boxed::Box`!
+}
diff --git a/src/tools/clippy/tests/ui/type_id_on_box.rs b/src/tools/clippy/tests/ui/type_id_on_box.rs
new file mode 100644
index 000000000..74b6c74ae
--- /dev/null
+++ b/src/tools/clippy/tests/ui/type_id_on_box.rs
@@ -0,0 +1,40 @@
+//@run-rustfix
+
+#![warn(clippy::type_id_on_box)]
+
+use std::any::{Any, TypeId};
+use std::ops::Deref;
+
+type SomeBox = Box<dyn Any>;
+
+struct BadBox(Box<dyn Any>);
+
+impl Deref for BadBox {
+ type Target = Box<dyn Any>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+fn existential() -> impl Any {
+ Box::new(1) as Box<dyn Any>
+}
+
+fn main() {
+ let any_box: Box<dyn Any> = Box::new(0usize);
+ let _ = any_box.type_id();
+ let _ = TypeId::of::<Box<dyn Any>>(); // Don't lint. We explicitly say "do this instead" if this is intentional
+ let _ = (*any_box).type_id();
+ let any_box: &Box<dyn Any> = &(Box::new(0usize) as Box<dyn Any>);
+ let _ = any_box.type_id(); // 2 derefs are needed here to get to the `dyn Any`
+
+ let b = existential();
+ let _ = b.type_id(); // Don't lint.
+
+ let b: SomeBox = Box::new(0usize);
+ let _ = b.type_id();
+
+ let b = BadBox(Box::new(0usize));
+ let _ = b.type_id(); // Don't lint. This is a call to `<BadBox as Any>::type_id`. Not `std::boxed::Box`!
+}
diff --git a/src/tools/clippy/tests/ui/type_id_on_box.stderr b/src/tools/clippy/tests/ui/type_id_on_box.stderr
new file mode 100644
index 000000000..1525328c0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/type_id_on_box.stderr
@@ -0,0 +1,36 @@
+error: calling `.type_id()` on a `Box<dyn Any>`
+ --> $DIR/type_id_on_box.rs:26:13
+ |
+LL | let _ = any_box.type_id();
+ | -------^^^^^^^^^^
+ | |
+ | help: consider dereferencing first: `(*any_box)`
+ |
+ = note: this returns the type id of the literal type `Box<dyn Any>` instead of the type id of the boxed value, which is most likely not what you want
+ = note: if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, which makes it more clear
+ = note: `-D clippy::type-id-on-box` implied by `-D warnings`
+
+error: calling `.type_id()` on a `Box<dyn Any>`
+ --> $DIR/type_id_on_box.rs:30:13
+ |
+LL | let _ = any_box.type_id(); // 2 derefs are needed here to get to the `dyn Any`
+ | -------^^^^^^^^^^
+ | |
+ | help: consider dereferencing first: `(**any_box)`
+ |
+ = note: this returns the type id of the literal type `Box<dyn Any>` instead of the type id of the boxed value, which is most likely not what you want
+ = note: if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, which makes it more clear
+
+error: calling `.type_id()` on a `Box<dyn Any>`
+ --> $DIR/type_id_on_box.rs:36:13
+ |
+LL | let _ = b.type_id();
+ | -^^^^^^^^^^
+ | |
+ | help: consider dereferencing first: `(*b)`
+ |
+ = note: this returns the type id of the literal type `Box<dyn Any>` instead of the type id of the boxed value, which is most likely not what you want
+ = note: if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, which makes it more clear
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.fixed b/src/tools/clippy/tests/ui/unnecessary_cast.fixed
index 8efd44baf..2bf02f134 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.fixed
@@ -38,6 +38,16 @@ mod fake_libc {
}
}
+fn aaa() -> ::std::primitive::u32 {
+ 0
+}
+
+use std::primitive::u32 as UnsignedThirtyTwoBitInteger;
+
+fn bbb() -> UnsignedThirtyTwoBitInteger {
+ 0
+}
+
#[rustfmt::skip]
fn main() {
// Test cast_unnecessary
@@ -105,6 +115,13 @@ fn main() {
extern_fake_libc::getpid_SAFE_TRUTH() as i32;
let pid = unsafe { fake_libc::getpid() };
pid as i32;
+ aaa();
+ let x = aaa();
+ aaa();
+ // Will not lint currently.
+ bbb() as u32;
+ let x = bbb();
+ bbb() as u32;
let i8_ptr: *const i8 = &1;
let u8_ptr: *const u8 = &1;
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs
index c7723ef51..25b6b0f9b 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs
@@ -38,6 +38,16 @@ mod fake_libc {
}
}
+fn aaa() -> ::std::primitive::u32 {
+ 0
+}
+
+use std::primitive::u32 as UnsignedThirtyTwoBitInteger;
+
+fn bbb() -> UnsignedThirtyTwoBitInteger {
+ 0
+}
+
#[rustfmt::skip]
fn main() {
// Test cast_unnecessary
@@ -105,6 +115,13 @@ fn main() {
extern_fake_libc::getpid_SAFE_TRUTH() as i32;
let pid = unsafe { fake_libc::getpid() };
pid as i32;
+ aaa() as u32;
+ let x = aaa();
+ aaa() as u32;
+ // Will not lint currently.
+ bbb() as u32;
+ let x = bbb();
+ bbb() as u32;
let i8_ptr: *const i8 = &1;
let u8_ptr: *const u8 = &1;
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
index f0443556f..19411a01b 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
@@ -7,226 +7,238 @@ LL | ptr as *const T
= note: `-D clippy::unnecessary-cast` implied by `-D warnings`
error: casting integer literal to `i32` is unnecessary
- --> $DIR/unnecessary_cast.rs:44:5
+ --> $DIR/unnecessary_cast.rs:54:5
|
LL | 1i32 as i32;
| ^^^^^^^^^^^ help: try: `1_i32`
error: casting float literal to `f32` is unnecessary
- --> $DIR/unnecessary_cast.rs:45:5
+ --> $DIR/unnecessary_cast.rs:55:5
|
LL | 1f32 as f32;
| ^^^^^^^^^^^ help: try: `1_f32`
error: casting to the same type is unnecessary (`bool` -> `bool`)
- --> $DIR/unnecessary_cast.rs:46:5
+ --> $DIR/unnecessary_cast.rs:56:5
|
LL | false as bool;
| ^^^^^^^^^^^^^ help: try: `false`
error: casting integer literal to `i32` is unnecessary
- --> $DIR/unnecessary_cast.rs:49:5
+ --> $DIR/unnecessary_cast.rs:59:5
|
LL | -1_i32 as i32;
| ^^^^^^^^^^^^^ help: try: `-1_i32`
error: casting integer literal to `i32` is unnecessary
- --> $DIR/unnecessary_cast.rs:50:5
+ --> $DIR/unnecessary_cast.rs:60:5
|
LL | - 1_i32 as i32;
| ^^^^^^^^^^^^^^ help: try: `- 1_i32`
error: casting float literal to `f32` is unnecessary
- --> $DIR/unnecessary_cast.rs:51:5
+ --> $DIR/unnecessary_cast.rs:61:5
|
LL | -1f32 as f32;
| ^^^^^^^^^^^^ help: try: `-1_f32`
error: casting integer literal to `i32` is unnecessary
- --> $DIR/unnecessary_cast.rs:52:5
+ --> $DIR/unnecessary_cast.rs:62:5
|
LL | 1_i32 as i32;
| ^^^^^^^^^^^^ help: try: `1_i32`
error: casting float literal to `f32` is unnecessary
- --> $DIR/unnecessary_cast.rs:53:5
+ --> $DIR/unnecessary_cast.rs:63:5
|
LL | 1_f32 as f32;
| ^^^^^^^^^^^^ help: try: `1_f32`
error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
- --> $DIR/unnecessary_cast.rs:55:22
+ --> $DIR/unnecessary_cast.rs:65:22
|
LL | let _: *mut u8 = [1u8, 2].as_ptr() as *const u8 as *mut u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()`
error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
- --> $DIR/unnecessary_cast.rs:57:5
+ --> $DIR/unnecessary_cast.rs:67:5
|
LL | [1u8, 2].as_ptr() as *const u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()`
error: casting raw pointers to the same type and constness is unnecessary (`*mut u8` -> `*mut u8`)
- --> $DIR/unnecessary_cast.rs:59:5
+ --> $DIR/unnecessary_cast.rs:69:5
|
LL | [1u8, 2].as_mut_ptr() as *mut u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_mut_ptr()`
error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`)
- --> $DIR/unnecessary_cast.rs:70:5
+ --> $DIR/unnecessary_cast.rs:80:5
|
LL | owo::<u32>([1u32].as_ptr()) as *const u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `owo::<u32>([1u32].as_ptr())`
error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
- --> $DIR/unnecessary_cast.rs:71:5
+ --> $DIR/unnecessary_cast.rs:81:5
|
LL | uwu::<u32, u8>([1u32].as_ptr()) as *const u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::<u32, u8>([1u32].as_ptr())`
error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`)
- --> $DIR/unnecessary_cast.rs:73:5
+ --> $DIR/unnecessary_cast.rs:83:5
|
LL | uwu::<u32, u32>([1u32].as_ptr()) as *const u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::<u32, u32>([1u32].as_ptr())`
+error: casting to the same type is unnecessary (`u32` -> `u32`)
+ --> $DIR/unnecessary_cast.rs:118:5
+ |
+LL | aaa() as u32;
+ | ^^^^^^^^^^^^ help: try: `aaa()`
+
+error: casting to the same type is unnecessary (`u32` -> `u32`)
+ --> $DIR/unnecessary_cast.rs:120:5
+ |
+LL | aaa() as u32;
+ | ^^^^^^^^^^^^ help: try: `aaa()`
+
error: casting integer literal to `f32` is unnecessary
- --> $DIR/unnecessary_cast.rs:139:9
+ --> $DIR/unnecessary_cast.rs:156:9
|
LL | 100 as f32;
| ^^^^^^^^^^ help: try: `100_f32`
error: casting integer literal to `f64` is unnecessary
- --> $DIR/unnecessary_cast.rs:140:9
+ --> $DIR/unnecessary_cast.rs:157:9
|
LL | 100 as f64;
| ^^^^^^^^^^ help: try: `100_f64`
error: casting integer literal to `f64` is unnecessary
- --> $DIR/unnecessary_cast.rs:141:9
+ --> $DIR/unnecessary_cast.rs:158:9
|
LL | 100_i32 as f64;
| ^^^^^^^^^^^^^^ help: try: `100_f64`
error: casting integer literal to `f32` is unnecessary
- --> $DIR/unnecessary_cast.rs:142:17
+ --> $DIR/unnecessary_cast.rs:159:17
|
LL | let _ = -100 as f32;
| ^^^^^^^^^^^ help: try: `-100_f32`
error: casting integer literal to `f64` is unnecessary
- --> $DIR/unnecessary_cast.rs:143:17
+ --> $DIR/unnecessary_cast.rs:160:17
|
LL | let _ = -100 as f64;
| ^^^^^^^^^^^ help: try: `-100_f64`
error: casting integer literal to `f64` is unnecessary
- --> $DIR/unnecessary_cast.rs:144:17
+ --> $DIR/unnecessary_cast.rs:161:17
|
LL | let _ = -100_i32 as f64;
| ^^^^^^^^^^^^^^^ help: try: `-100_f64`
error: casting float literal to `f32` is unnecessary
- --> $DIR/unnecessary_cast.rs:145:9
+ --> $DIR/unnecessary_cast.rs:162:9
|
LL | 100. as f32;
| ^^^^^^^^^^^ help: try: `100_f32`
error: casting float literal to `f64` is unnecessary
- --> $DIR/unnecessary_cast.rs:146:9
+ --> $DIR/unnecessary_cast.rs:163:9
|
LL | 100. as f64;
| ^^^^^^^^^^^ help: try: `100_f64`
error: casting integer literal to `u32` is unnecessary
- --> $DIR/unnecessary_cast.rs:158:9
+ --> $DIR/unnecessary_cast.rs:175:9
|
LL | 1 as u32;
| ^^^^^^^^ help: try: `1_u32`
error: casting integer literal to `i32` is unnecessary
- --> $DIR/unnecessary_cast.rs:159:9
+ --> $DIR/unnecessary_cast.rs:176:9
|
LL | 0x10 as i32;
| ^^^^^^^^^^^ help: try: `0x10_i32`
error: casting integer literal to `usize` is unnecessary
- --> $DIR/unnecessary_cast.rs:160:9
+ --> $DIR/unnecessary_cast.rs:177:9
|
LL | 0b10 as usize;
| ^^^^^^^^^^^^^ help: try: `0b10_usize`
error: casting integer literal to `u16` is unnecessary
- --> $DIR/unnecessary_cast.rs:161:9
+ --> $DIR/unnecessary_cast.rs:178:9
|
LL | 0o73 as u16;
| ^^^^^^^^^^^ help: try: `0o73_u16`
error: casting integer literal to `u32` is unnecessary
- --> $DIR/unnecessary_cast.rs:162:9
+ --> $DIR/unnecessary_cast.rs:179:9
|
LL | 1_000_000_000 as u32;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32`
error: casting float literal to `f64` is unnecessary
- --> $DIR/unnecessary_cast.rs:164:9
+ --> $DIR/unnecessary_cast.rs:181:9
|
LL | 1.0 as f64;
| ^^^^^^^^^^ help: try: `1.0_f64`
error: casting float literal to `f32` is unnecessary
- --> $DIR/unnecessary_cast.rs:165:9
+ --> $DIR/unnecessary_cast.rs:182:9
|
LL | 0.5 as f32;
| ^^^^^^^^^^ help: try: `0.5_f32`
error: casting integer literal to `i32` is unnecessary
- --> $DIR/unnecessary_cast.rs:169:17
+ --> $DIR/unnecessary_cast.rs:186:17
|
LL | let _ = -1 as i32;
| ^^^^^^^^^ help: try: `-1_i32`
error: casting float literal to `f32` is unnecessary
- --> $DIR/unnecessary_cast.rs:170:17
+ --> $DIR/unnecessary_cast.rs:187:17
|
LL | let _ = -1.0 as f32;
| ^^^^^^^^^^^ help: try: `-1.0_f32`
error: casting to the same type is unnecessary (`i32` -> `i32`)
- --> $DIR/unnecessary_cast.rs:176:18
+ --> $DIR/unnecessary_cast.rs:193:18
|
LL | let _ = &(x as i32);
| ^^^^^^^^^^ help: try: `{ x }`
error: casting integer literal to `i32` is unnecessary
- --> $DIR/unnecessary_cast.rs:182:22
+ --> $DIR/unnecessary_cast.rs:199:22
|
LL | let _: i32 = -(1) as i32;
| ^^^^^^^^^^^ help: try: `-1_i32`
error: casting integer literal to `i64` is unnecessary
- --> $DIR/unnecessary_cast.rs:184:22
+ --> $DIR/unnecessary_cast.rs:201:22
|
LL | let _: i64 = -(1) as i64;
| ^^^^^^^^^^^ help: try: `-1_i64`
error: casting float literal to `f64` is unnecessary
- --> $DIR/unnecessary_cast.rs:191:22
+ --> $DIR/unnecessary_cast.rs:208:22
|
LL | let _: f64 = (-8.0 as f64).exp();
| ^^^^^^^^^^^^^ help: try: `(-8.0_f64)`
error: casting float literal to `f64` is unnecessary
- --> $DIR/unnecessary_cast.rs:193:23
+ --> $DIR/unnecessary_cast.rs:210:23
|
LL | let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior
| ^^^^^^^^^^^^ help: try: `8.0_f64`
error: casting to the same type is unnecessary (`f32` -> `f32`)
- --> $DIR/unnecessary_cast.rs:201:20
+ --> $DIR/unnecessary_cast.rs:218:20
|
LL | let _num = foo() as f32;
| ^^^^^^^^^^^^ help: try: `foo()`
-error: aborting due to 38 previous errors
+error: aborting due to 40 previous errors
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.rs b/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.rs
new file mode 100644
index 000000000..0e027f604
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.rs
@@ -0,0 +1,22 @@
+#![warn(clippy::unnecessary_cast)]
+
+fn main() {
+ let _ = std::ptr::null() as *const u8;
+}
+
+mod issue11113 {
+ #[repr(C)]
+ struct Vtbl {
+ query: unsafe extern "system" fn(),
+ }
+
+ struct TearOff {
+ object: *mut std::ffi::c_void,
+ }
+
+ impl TearOff {
+ unsafe fn query(&self) {
+ ((*(*(self.object as *mut *mut _) as *mut Vtbl)).query)()
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr
new file mode 100644
index 000000000..eecf24568
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr
@@ -0,0 +1,16 @@
+error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
+ --> $DIR/unnecessary_cast_unfixable.rs:4:13
+ |
+LL | let _ = std::ptr::null() as *const u8;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::null()`
+ |
+ = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
+
+error: casting raw pointers to the same type and constness is unnecessary (`*mut issue11113::Vtbl` -> `*mut issue11113::Vtbl`)
+ --> $DIR/unnecessary_cast_unfixable.rs:19:16
+ |
+LL | ((*(*(self.object as *mut *mut _) as *mut Vtbl)).query)()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `*(self.object as *mut *mut _)`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.stderr b/src/tools/clippy/tests/ui/unnecessary_clone.stderr
index 5686ab6b4..23639f6d4 100644
--- a/src/tools/clippy/tests/ui/unnecessary_clone.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_clone.stderr
@@ -2,7 +2,7 @@ error: using `.clone()` on a ref-counted pointer
--> $DIR/unnecessary_clone.rs:23:5
|
LL | rc.clone();
- | ^^^^^^^^^^ help: try this: `Rc::<bool>::clone(&rc)`
+ | ^^^^^^^^^^ help: try: `Rc::<bool>::clone(&rc)`
|
= note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings`
@@ -10,25 +10,25 @@ error: using `.clone()` on a ref-counted pointer
--> $DIR/unnecessary_clone.rs:26:5
|
LL | arc.clone();
- | ^^^^^^^^^^^ help: try this: `Arc::<bool>::clone(&arc)`
+ | ^^^^^^^^^^^ help: try: `Arc::<bool>::clone(&arc)`
error: using `.clone()` on a ref-counted pointer
--> $DIR/unnecessary_clone.rs:29:5
|
LL | rcweak.clone();
- | ^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&rcweak)`
+ | ^^^^^^^^^^^^^^ help: try: `Weak::<bool>::clone(&rcweak)`
error: using `.clone()` on a ref-counted pointer
--> $DIR/unnecessary_clone.rs:32:5
|
LL | arc_weak.clone();
- | ^^^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&arc_weak)`
+ | ^^^^^^^^^^^^^^^^ help: try: `Weak::<bool>::clone(&arc_weak)`
error: using `.clone()` on a ref-counted pointer
--> $DIR/unnecessary_clone.rs:36:33
|
LL | let _: Arc<dyn SomeTrait> = x.clone();
- | ^^^^^^^^^ help: try this: `Arc::<SomeImpl>::clone(&x)`
+ | ^^^^^^^^^ help: try: `Arc::<SomeImpl>::clone(&x)`
error: using `clone` on type `T` which implements the `Copy` trait
--> $DIR/unnecessary_clone.rs:40:5
@@ -54,7 +54,7 @@ error: using `.clone()` on a ref-counted pointer
--> $DIR/unnecessary_clone.rs:95:14
|
LL | Some(try_opt!(Some(rc)).clone())
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Rc::<u8>::clone(&try_opt!(Some(rc)))`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Rc::<u8>::clone(&try_opt!(Some(rc)))`
error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/unnecessary_filter_map.rs b/src/tools/clippy/tests/ui/unnecessary_filter_map.rs
index 8e01c2674..3c8c6ec94 100644
--- a/src/tools/clippy/tests/ui/unnecessary_filter_map.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_filter_map.rs
@@ -148,3 +148,9 @@ mod comment_1052978898 {
})
}
}
+
+fn issue11260() {
+ // #11260 is about unnecessary_find_map, but the fix also kind of applies to
+ // unnecessary_filter_map
+ let _x = std::iter::once(1).filter_map(|n| (n > 1).then_some(n));
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr b/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr
index 5585b10ab..2d5403ce3 100644
--- a/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr
@@ -34,5 +34,11 @@ error: this `.filter_map` can be written more simply using `.map`
LL | let _ = (0..4).filter_map(|x| Some(x + 1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 4 previous errors
+error: this `.filter_map` can be written more simply using `.filter`
+ --> $DIR/unnecessary_filter_map.rs:155:14
+ |
+LL | let _x = std::iter::once(1).filter_map(|n| (n > 1).then_some(n));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/unnecessary_find_map.rs b/src/tools/clippy/tests/ui/unnecessary_find_map.rs
index a52390861..2c228fbbc 100644
--- a/src/tools/clippy/tests/ui/unnecessary_find_map.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_find_map.rs
@@ -21,3 +21,9 @@ fn main() {
fn find_map_none_changes_item_type() -> Option<bool> {
"".chars().find_map(|_| None)
}
+
+fn issue11260() {
+ let y = Some(1);
+ let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n));
+ let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(y)); // different option, so can't be just `.find()`
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_find_map.stderr b/src/tools/clippy/tests/ui/unnecessary_find_map.stderr
index fb33c122f..3a995b41b 100644
--- a/src/tools/clippy/tests/ui/unnecessary_find_map.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_find_map.stderr
@@ -34,5 +34,11 @@ error: this `.find_map` can be written more simply using `.map(..).next()`
LL | let _ = (0..4).find_map(|x| Some(x + 1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 4 previous errors
+error: this `.find_map` can be written more simply using `.find`
+ --> $DIR/unnecessary_find_map.rs:27:14
+ |
+LL | let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed
index 44530d8b1..72d52c623 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed
@@ -79,6 +79,26 @@ fn unwrap_methods_result() {
1;
}
+fn unwrap_from_binding() {
+ macro_rules! from_macro {
+ () => {
+ Some("")
+ };
+ }
+ let val = from_macro!();
+ let _ = val.unwrap_or("");
+}
+
+fn unwrap_unchecked() {
+ let _ = 1;
+ let _ = unsafe { 1 + *(&1 as *const i32) }; // needs to keep the unsafe block
+ let _ = 1 + 1;
+ let _ = 1;
+ let _ = unsafe { 1 + *(&1 as *const i32) };
+ let _ = 1 + 1;
+ let _ = 123;
+}
+
fn main() {
unwrap_option_some();
unwrap_option_none();
@@ -86,4 +106,5 @@ fn main() {
unwrap_result_err();
unwrap_methods_option();
unwrap_methods_result();
+ unwrap_unchecked();
}
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs
index b43e4d3a3..7d713ea20 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs
@@ -79,6 +79,26 @@ fn unwrap_methods_result() {
Ok::<_, ()>(1).unwrap_or_else(|_| 2);
}
+fn unwrap_from_binding() {
+ macro_rules! from_macro {
+ () => {
+ Some("")
+ };
+ }
+ let val = from_macro!();
+ let _ = val.unwrap_or("");
+}
+
+fn unwrap_unchecked() {
+ let _ = unsafe { Some(1).unwrap_unchecked() };
+ let _ = unsafe { Some(1).unwrap_unchecked() + *(&1 as *const i32) }; // needs to keep the unsafe block
+ let _ = unsafe { Some(1).unwrap_unchecked() } + 1;
+ let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() };
+ let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() + *(&1 as *const i32) };
+ let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1;
+ let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() };
+}
+
fn main() {
unwrap_option_some();
unwrap_option_none();
@@ -86,4 +106,5 @@ fn main() {
unwrap_result_err();
unwrap_methods_option();
unwrap_methods_result();
+ unwrap_unchecked();
}
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
index 905384bc8..7f603d6ef 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
@@ -517,5 +517,89 @@ LL - Ok::<_, ()>(1).unwrap_or_else(|_| 2);
LL + 1;
|
-error: aborting due to 46 previous errors
+error: used `unwrap_unchecked()` on `Some` value
+ --> $DIR/unnecessary_literal_unwrap.rs:93:22
+ |
+LL | let _ = unsafe { Some(1).unwrap_unchecked() };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: remove the `Some` and `unwrap_unchecked()`
+ |
+LL - let _ = unsafe { Some(1).unwrap_unchecked() };
+LL + let _ = 1;
+ |
+
+error: used `unwrap_unchecked()` on `Some` value
+ --> $DIR/unnecessary_literal_unwrap.rs:94:22
+ |
+LL | let _ = unsafe { Some(1).unwrap_unchecked() + *(&1 as *const i32) }; // needs to keep the unsafe block
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: remove the `Some` and `unwrap_unchecked()`
+ |
+LL - let _ = unsafe { Some(1).unwrap_unchecked() + *(&1 as *const i32) }; // needs to keep the unsafe block
+LL + let _ = unsafe { 1 + *(&1 as *const i32) }; // needs to keep the unsafe block
+ |
+
+error: used `unwrap_unchecked()` on `Some` value
+ --> $DIR/unnecessary_literal_unwrap.rs:95:22
+ |
+LL | let _ = unsafe { Some(1).unwrap_unchecked() } + 1;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: remove the `Some` and `unwrap_unchecked()`
+ |
+LL - let _ = unsafe { Some(1).unwrap_unchecked() } + 1;
+LL + let _ = 1 + 1;
+ |
+
+error: used `unwrap_unchecked()` on `Ok` value
+ --> $DIR/unnecessary_literal_unwrap.rs:96:22
+ |
+LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: remove the `Ok` and `unwrap_unchecked()`
+ |
+LL - let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() };
+LL + let _ = 1;
+ |
+
+error: used `unwrap_unchecked()` on `Ok` value
+ --> $DIR/unnecessary_literal_unwrap.rs:97:22
+ |
+LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() + *(&1 as *const i32) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: remove the `Ok` and `unwrap_unchecked()`
+ |
+LL - let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() + *(&1 as *const i32) };
+LL + let _ = unsafe { 1 + *(&1 as *const i32) };
+ |
+
+error: used `unwrap_unchecked()` on `Ok` value
+ --> $DIR/unnecessary_literal_unwrap.rs:98:22
+ |
+LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: remove the `Ok` and `unwrap_unchecked()`
+ |
+LL - let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1;
+LL + let _ = 1 + 1;
+ |
+
+error: used `unwrap_err_unchecked()` on `Err` value
+ --> $DIR/unnecessary_literal_unwrap.rs:99:22
+ |
+LL | let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: remove the `Err` and `unwrap_err_unchecked()`
+ |
+LL - let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() };
+LL + let _ = 123;
+ |
+
+error: aborting due to 53 previous errors
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
index 592a53f3a..cb7562351 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
@@ -477,7 +477,8 @@ mod issue_10021 {
mod issue_10033 {
#![allow(dead_code)]
- use std::{fmt::Display, ops::Deref};
+ use std::fmt::Display;
+ use std::ops::Deref;
fn _main() {
let f = Foo;
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
index f2e48b1c4..f82ddb2d2 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
@@ -477,7 +477,8 @@ mod issue_10021 {
mod issue_10033 {
#![allow(dead_code)]
- use std::{fmt::Display, ops::Deref};
+ use std::fmt::Display;
+ use std::ops::Deref;
fn _main() {
let f = Foo;
diff --git a/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs b/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs
index d29888ac6..04f6ef29a 100644
--- a/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs
+++ b/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs
@@ -8,9 +8,13 @@ use std::cell::UnsafeCell as TotallySafeCellAgain;
// Shouldn't error
use std::cell::RefCell as ProbablyNotUnsafe;
+
use std::cell::RefCell as RefCellThatCantBeUnsafe;
+
use std::cell::UnsafeCell as SuperDangerousUnsafeCell;
+
use std::cell::UnsafeCell as Dangerunsafe;
+
use std::cell::UnsafeCell as Bombsawayunsafe;
mod mod_with_some_unsafe_things {
@@ -20,8 +24,12 @@ mod mod_with_some_unsafe_things {
use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety;
+// merged imports
+use mod_with_some_unsafe_things::{Unsafe as A, Unsafe as B};
+
// Shouldn't error
use mod_with_some_unsafe_things::Safe as IPromiseItsSafeThisTime;
+
use mod_with_some_unsafe_things::Unsafe as SuperUnsafeModThing;
#[allow(clippy::unsafe_removed_from_name)]
diff --git a/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr b/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr
index 4f871cbe4..090d917bd 100644
--- a/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr
+++ b/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr
@@ -13,10 +13,22 @@ LL | use std::cell::UnsafeCell as TotallySafeCellAgain;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: removed `unsafe` from the name of `Unsafe` in use as `LieAboutModSafety`
- --> $DIR/unsafe_removed_from_name.rs:21:1
+ --> $DIR/unsafe_removed_from_name.rs:25:1
|
LL | use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 3 previous errors
+error: removed `unsafe` from the name of `Unsafe` in use as `A`
+ --> $DIR/unsafe_removed_from_name.rs:28:1
+ |
+LL | use mod_with_some_unsafe_things::{Unsafe as A, Unsafe as B};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: removed `unsafe` from the name of `Unsafe` in use as `B`
+ --> $DIR/unsafe_removed_from_name.rs:28:1
+ |
+LL | use mod_with_some_unsafe_things::{Unsafe as A, Unsafe as B};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs
index 69e46ab47..1d188025e 100644
--- a/src/tools/clippy/tests/ui/unused_async.rs
+++ b/src/tools/clippy/tests/ui/unused_async.rs
@@ -37,6 +37,23 @@ mod issue10459 {
}
}
+mod issue9695 {
+ use std::future::Future;
+
+ async fn f() {}
+ async fn f2() {}
+ async fn f3() {}
+
+ fn needs_async_fn<F: Future<Output = ()>>(_: fn() -> F) {}
+
+ fn test() {
+ let x = f;
+ needs_async_fn(x); // async needed in f
+ needs_async_fn(f2); // async needed in f2
+ f3(); // async not needed in f3
+ }
+}
+
async fn foo() -> i32 {
4
}
diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr
index ffae8366b..8d9b72c48 100644
--- a/src/tools/clippy/tests/ui/unused_async.stderr
+++ b/src/tools/clippy/tests/ui/unused_async.stderr
@@ -17,7 +17,15 @@ LL | ready(()).await;
= note: `-D clippy::unused-async` implied by `-D warnings`
error: unused `async` for function with no await statements
- --> $DIR/unused_async.rs:40:1
+ --> $DIR/unused_async.rs:45:5
+ |
+LL | async fn f3() {}
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: consider removing the `async` from this function
+
+error: unused `async` for function with no await statements
+ --> $DIR/unused_async.rs:57:1
|
LL | / async fn foo() -> i32 {
LL | | 4
@@ -27,7 +35,7 @@ LL | | }
= help: consider removing the `async` from this function
error: unused `async` for function with no await statements
- --> $DIR/unused_async.rs:51:5
+ --> $DIR/unused_async.rs:68:5
|
LL | / async fn unused(&self) -> i32 {
LL | | 1
@@ -36,5 +44,5 @@ LL | | }
|
= help: consider removing the `async` from this function
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/unused_io_amount.rs b/src/tools/clippy/tests/ui/unused_io_amount.rs
index 8d3e094b7..e9d1eeb31 100644
--- a/src/tools/clippy/tests/ui/unused_io_amount.rs
+++ b/src/tools/clippy/tests/ui/unused_io_amount.rs
@@ -1,4 +1,4 @@
-#![allow(dead_code)]
+#![allow(dead_code, clippy::needless_pass_by_ref_mut)]
#![warn(clippy::unused_io_amount)]
extern crate futures;
diff --git a/src/tools/clippy/tests/ui/unused_peekable.rs b/src/tools/clippy/tests/ui/unused_peekable.rs
index 7374dfdf9..b227f8660 100644
--- a/src/tools/clippy/tests/ui/unused_peekable.rs
+++ b/src/tools/clippy/tests/ui/unused_peekable.rs
@@ -1,8 +1,7 @@
#![warn(clippy::unused_peekable)]
#![allow(clippy::no_effect)]
-use std::iter::Empty;
-use std::iter::Peekable;
+use std::iter::{Empty, Peekable};
fn main() {
invalid();
diff --git a/src/tools/clippy/tests/ui/unused_peekable.stderr b/src/tools/clippy/tests/ui/unused_peekable.stderr
index 54788f2fa..d969232fd 100644
--- a/src/tools/clippy/tests/ui/unused_peekable.stderr
+++ b/src/tools/clippy/tests/ui/unused_peekable.stderr
@@ -1,5 +1,5 @@
error: `peek` never called on `Peekable` iterator
- --> $DIR/unused_peekable.rs:14:9
+ --> $DIR/unused_peekable.rs:13:9
|
LL | let peekable = std::iter::empty::<u32>().peekable();
| ^^^^^^^^
@@ -8,7 +8,7 @@ LL | let peekable = std::iter::empty::<u32>().peekable();
= note: `-D clippy::unused-peekable` implied by `-D warnings`
error: `peek` never called on `Peekable` iterator
- --> $DIR/unused_peekable.rs:18:9
+ --> $DIR/unused_peekable.rs:17:9
|
LL | let new_local = old_local;
| ^^^^^^^^^
@@ -16,7 +16,7 @@ LL | let new_local = old_local;
= help: consider removing the call to `peekable`
error: `peek` never called on `Peekable` iterator
- --> $DIR/unused_peekable.rs:22:9
+ --> $DIR/unused_peekable.rs:21:9
|
LL | let by_mut_ref = &mut by_mut_ref_test;
| ^^^^^^^^^^
@@ -24,7 +24,7 @@ LL | let by_mut_ref = &mut by_mut_ref_test;
= help: consider removing the call to `peekable`
error: `peek` never called on `Peekable` iterator
- --> $DIR/unused_peekable.rs:29:9
+ --> $DIR/unused_peekable.rs:28:9
|
LL | let peekable_from_fn = returns_peekable();
| ^^^^^^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL | let peekable_from_fn = returns_peekable();
= help: consider removing the call to `peekable`
error: `peek` never called on `Peekable` iterator
- --> $DIR/unused_peekable.rs:32:13
+ --> $DIR/unused_peekable.rs:31:13
|
LL | let mut peekable_using_iterator_method = std::iter::empty::<u32>().peekable();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +40,7 @@ LL | let mut peekable_using_iterator_method = std::iter::empty::<u32>().peek
= help: consider removing the call to `peekable`
error: `peek` never called on `Peekable` iterator
- --> $DIR/unused_peekable.rs:37:9
+ --> $DIR/unused_peekable.rs:36:9
|
LL | let passed_along_ref = std::iter::empty::<u32>().peekable();
| ^^^^^^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL | let passed_along_ref = std::iter::empty::<u32>().peekable();
= help: consider removing the call to `peekable`
error: `peek` never called on `Peekable` iterator
- --> $DIR/unused_peekable.rs:42:9
+ --> $DIR/unused_peekable.rs:41:9
|
LL | let _by_ref = by_ref_test.by_ref();
| ^^^^^^^
@@ -56,7 +56,7 @@ LL | let _by_ref = by_ref_test.by_ref();
= help: consider removing the call to `peekable`
error: `peek` never called on `Peekable` iterator
- --> $DIR/unused_peekable.rs:44:13
+ --> $DIR/unused_peekable.rs:43:13
|
LL | let mut peekable_in_for_loop = std::iter::empty::<u32>().peekable();
| ^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/unwrap.stderr b/src/tools/clippy/tests/ui/unwrap.stderr
index 3796d942f..41db819f6 100644
--- a/src/tools/clippy/tests/ui/unwrap.stderr
+++ b/src/tools/clippy/tests/ui/unwrap.stderr
@@ -4,7 +4,8 @@ error: used `unwrap()` on an `Option` value
LL | let _ = opt.unwrap();
| ^^^^^^^^^^^^
|
- = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is `None`, it will panic
+ = help: consider using `expect()` to provide a better panic message
= note: `-D clippy::unwrap-used` implied by `-D warnings`
error: used `unwrap()` on a `Result` value
@@ -13,7 +14,8 @@ error: used `unwrap()` on a `Result` value
LL | let _ = res.unwrap();
| ^^^^^^^^^^^^
|
- = help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message
+ = note: if this value is an `Err`, it will panic
+ = help: consider using `expect()` to provide a better panic message
error: used `unwrap_err()` on a `Result` value
--> $DIR/unwrap.rs:12:13
@@ -21,7 +23,8 @@ error: used `unwrap_err()` on a `Result` value
LL | let _ = res.unwrap_err();
| ^^^^^^^^^^^^^^^^
|
- = help: if you don't want to handle the `Ok` case gracefully, consider using `expect_err()` to provide a better panic message
+ = note: if this value is an `Ok`, it will panic
+ = help: consider using `expect_err()` to provide a better panic message
error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.rs b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
index 7f57efc53..26f92ccde 100644
--- a/src/tools/clippy/tests/ui/unwrap_expect_used.rs
+++ b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
@@ -1,5 +1,8 @@
#![warn(clippy::unwrap_used, clippy::expect_used)]
#![allow(clippy::unnecessary_literal_unwrap)]
+#![feature(never_type)]
+
+use std::convert::Infallible;
trait OptionExt {
type Item;
@@ -28,6 +31,14 @@ fn main() {
Some(3).unwrap_err();
Some(3).expect_err("Hellow none!");
+ // Issue #11245: The `Err` variant can never be constructed so do not lint this.
+ let x: Result<(), !> = Ok(());
+ x.unwrap();
+ x.expect("is `!` (never)");
+ let x: Result<(), Infallible> = Ok(());
+ x.unwrap();
+ x.expect("is never-like (0 variants)");
+
let a: Result<i32, i32> = Ok(3);
a.unwrap();
a.expect("Hello world!");
diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.stderr b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr
index 1a551ab5a..f66e47612 100644
--- a/src/tools/clippy/tests/ui/unwrap_expect_used.stderr
+++ b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr
@@ -1,52 +1,52 @@
error: used `unwrap()` on an `Option` value
- --> $DIR/unwrap_expect_used.rs:24:5
+ --> $DIR/unwrap_expect_used.rs:27:5
|
LL | Some(3).unwrap();
| ^^^^^^^^^^^^^^^^
|
- = help: if this value is `None`, it will panic
+ = note: if this value is `None`, it will panic
= note: `-D clippy::unwrap-used` implied by `-D warnings`
error: used `expect()` on an `Option` value
- --> $DIR/unwrap_expect_used.rs:25:5
+ --> $DIR/unwrap_expect_used.rs:28:5
|
LL | Some(3).expect("Hello world!");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if this value is `None`, it will panic
+ = note: if this value is `None`, it will panic
= note: `-D clippy::expect-used` implied by `-D warnings`
error: used `unwrap()` on a `Result` value
- --> $DIR/unwrap_expect_used.rs:32:5
+ --> $DIR/unwrap_expect_used.rs:43:5
|
LL | a.unwrap();
| ^^^^^^^^^^
|
- = help: if this value is an `Err`, it will panic
+ = note: if this value is an `Err`, it will panic
error: used `expect()` on a `Result` value
- --> $DIR/unwrap_expect_used.rs:33:5
+ --> $DIR/unwrap_expect_used.rs:44:5
|
LL | a.expect("Hello world!");
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if this value is an `Err`, it will panic
+ = note: if this value is an `Err`, it will panic
error: used `unwrap_err()` on a `Result` value
- --> $DIR/unwrap_expect_used.rs:34:5
+ --> $DIR/unwrap_expect_used.rs:45:5
|
LL | a.unwrap_err();
| ^^^^^^^^^^^^^^
|
- = help: if this value is an `Ok`, it will panic
+ = note: if this value is an `Ok`, it will panic
error: used `expect_err()` on a `Result` value
- --> $DIR/unwrap_expect_used.rs:35:5
+ --> $DIR/unwrap_expect_used.rs:46:5
|
LL | a.expect_err("Hello error!");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: if this value is an `Ok`, it will panic
+ = note: if this value is an `Ok`, it will panic
error: aborting due to 6 previous errors
diff --git a/src/tools/clippy/tests/ui/unwrap_or.stderr b/src/tools/clippy/tests/ui/unwrap_or.stderr
index cf720eaaf..e384bbbb0 100644
--- a/src/tools/clippy/tests/ui/unwrap_or.stderr
+++ b/src/tools/clippy/tests/ui/unwrap_or.stderr
@@ -2,7 +2,7 @@ error: use of `unwrap_or` followed by a function call
--> $DIR/unwrap_or.rs:5:47
|
LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| "Fail".to_string())`
|
= note: `-D clippy::or-fun-call` implied by `-D warnings`
@@ -10,7 +10,7 @@ error: use of `unwrap_or` followed by a function call
--> $DIR/unwrap_or.rs:9:47
|
LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| "Fail".to_string())`
error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed b/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed
index 08b89a18b..acdb96942 100644
--- a/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed
+++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed
@@ -1,10 +1,10 @@
//@run-rustfix
-#![warn(clippy::unwrap_or_else_default)]
+#![warn(clippy::unwrap_or_default)]
#![allow(dead_code)]
#![allow(clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)]
-/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint.
+/// Checks implementation of the `UNWRAP_OR_DEFAULT` lint.
fn unwrap_or_else_default() {
struct Foo;
@@ -74,4 +74,62 @@ fn unwrap_or_else_default() {
empty_string.unwrap_or_default();
}
+fn type_certainty(option: Option<Vec<u64>>) {
+ option.unwrap_or_default().push(1);
+
+ let option: std::option::Option<std::vec::Vec<u64>> = None;
+ option.unwrap_or_default().push(1);
+
+ let option: Option<Vec<u64>> = None;
+ option.unwrap_or_default().push(1);
+
+ let option = std::option::Option::<std::vec::Vec<u64>>::None;
+ option.unwrap_or_default().push(1);
+
+ let option = Option::<Vec<u64>>::None;
+ option.unwrap_or_default().push(1);
+
+ let option = std::option::Option::None::<std::vec::Vec<u64>>;
+ option.unwrap_or_default().push(1);
+
+ let option = Option::None::<Vec<u64>>;
+ option.unwrap_or_default().push(1);
+
+ let option = None::<Vec<u64>>;
+ option.unwrap_or_default().push(1);
+
+ // should not be changed: type annotation with infer, unconcretized initializer
+ let option: Option<Vec<_>> = None;
+ option.unwrap_or_else(Vec::new).push(1);
+
+ // should not be changed: no type annotation, unconcretized initializer
+ let option = Option::None;
+ option.unwrap_or_else(Vec::new).push(1);
+
+ // should not be changed: no type annotation, unconcretized initializer
+ let option = None;
+ option.unwrap_or_else(Vec::new).push(1);
+
+ type Alias = Option<Vec<u32>>;
+ let option: Alias = Option::<Vec<u32>>::Some(Vec::new());
+ option.unwrap_or_default().push(1);
+}
+
+fn method_call_with_deref() {
+ use std::cell::RefCell;
+ use std::collections::HashMap;
+
+ let cell = RefCell::new(HashMap::<u64, HashMap<u64, String>>::new());
+
+ let mut outer_map = cell.borrow_mut();
+
+ #[allow(unused_assignments)]
+ let mut option = None;
+ option = Some(0);
+
+ let inner_map = outer_map.get_mut(&option.unwrap()).unwrap();
+
+ let _ = inner_map.entry(0).or_default();
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.rs b/src/tools/clippy/tests/ui/unwrap_or_else_default.rs
index ad2a74490..55ccd00e1 100644
--- a/src/tools/clippy/tests/ui/unwrap_or_else_default.rs
+++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.rs
@@ -1,10 +1,10 @@
//@run-rustfix
-#![warn(clippy::unwrap_or_else_default)]
+#![warn(clippy::unwrap_or_default)]
#![allow(dead_code)]
#![allow(clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)]
-/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint.
+/// Checks implementation of the `UNWRAP_OR_DEFAULT` lint.
fn unwrap_or_else_default() {
struct Foo;
@@ -74,4 +74,62 @@ fn unwrap_or_else_default() {
empty_string.unwrap_or_else(|| "".to_string());
}
+fn type_certainty(option: Option<Vec<u64>>) {
+ option.unwrap_or_else(Vec::new).push(1);
+
+ let option: std::option::Option<std::vec::Vec<u64>> = None;
+ option.unwrap_or_else(Vec::new).push(1);
+
+ let option: Option<Vec<u64>> = None;
+ option.unwrap_or_else(Vec::new).push(1);
+
+ let option = std::option::Option::<std::vec::Vec<u64>>::None;
+ option.unwrap_or_else(Vec::new).push(1);
+
+ let option = Option::<Vec<u64>>::None;
+ option.unwrap_or_else(Vec::new).push(1);
+
+ let option = std::option::Option::None::<std::vec::Vec<u64>>;
+ option.unwrap_or_else(Vec::new).push(1);
+
+ let option = Option::None::<Vec<u64>>;
+ option.unwrap_or_else(Vec::new).push(1);
+
+ let option = None::<Vec<u64>>;
+ option.unwrap_or_else(Vec::new).push(1);
+
+ // should not be changed: type annotation with infer, unconcretized initializer
+ let option: Option<Vec<_>> = None;
+ option.unwrap_or_else(Vec::new).push(1);
+
+ // should not be changed: no type annotation, unconcretized initializer
+ let option = Option::None;
+ option.unwrap_or_else(Vec::new).push(1);
+
+ // should not be changed: no type annotation, unconcretized initializer
+ let option = None;
+ option.unwrap_or_else(Vec::new).push(1);
+
+ type Alias = Option<Vec<u32>>;
+ let option: Alias = Option::<Vec<u32>>::Some(Vec::new());
+ option.unwrap_or_else(Vec::new).push(1);
+}
+
+fn method_call_with_deref() {
+ use std::cell::RefCell;
+ use std::collections::HashMap;
+
+ let cell = RefCell::new(HashMap::<u64, HashMap<u64, String>>::new());
+
+ let mut outer_map = cell.borrow_mut();
+
+ #[allow(unused_assignments)]
+ let mut option = None;
+ option = Some(0);
+
+ let inner_map = outer_map.get_mut(&option.unwrap()).unwrap();
+
+ let _ = inner_map.entry(0).or_insert_with(Default::default);
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr b/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr
index d2b921222..af662c6de 100644
--- a/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr
+++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr
@@ -1,40 +1,100 @@
-error: use of `.unwrap_or_else(..)` to construct default value
- --> $DIR/unwrap_or_else_default.rs:48:5
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:48:14
|
LL | with_new.unwrap_or_else(Vec::new);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_new.unwrap_or_default()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
|
- = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings`
+ = note: `-D clippy::unwrap-or-default` implied by `-D warnings`
-error: use of `.unwrap_or_else(..)` to construct default value
- --> $DIR/unwrap_or_else_default.rs:62:5
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:62:23
|
LL | with_real_default.unwrap_or_else(<HasDefaultAndDuplicate as Default>::default);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_real_default.unwrap_or_default()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-error: use of `.unwrap_or_else(..)` to construct default value
- --> $DIR/unwrap_or_else_default.rs:65:5
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:65:24
|
LL | with_default_trait.unwrap_or_else(Default::default);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_trait.unwrap_or_default()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-error: use of `.unwrap_or_else(..)` to construct default value
- --> $DIR/unwrap_or_else_default.rs:68:5
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:68:23
|
LL | with_default_type.unwrap_or_else(u64::default);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-error: use of `.unwrap_or_else(..)` to construct default value
- --> $DIR/unwrap_or_else_default.rs:71:5
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:71:23
|
LL | with_default_type.unwrap_or_else(Vec::new);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-error: use of `.unwrap_or_else(..)` to construct default value
- --> $DIR/unwrap_or_else_default.rs:74:5
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:74:18
|
LL | empty_string.unwrap_or_else(|| "".to_string());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `empty_string.unwrap_or_default()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-error: aborting due to 6 previous errors
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:78:12
+ |
+LL | option.unwrap_or_else(Vec::new).push(1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:81:12
+ |
+LL | option.unwrap_or_else(Vec::new).push(1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:84:12
+ |
+LL | option.unwrap_or_else(Vec::new).push(1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:87:12
+ |
+LL | option.unwrap_or_else(Vec::new).push(1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:90:12
+ |
+LL | option.unwrap_or_else(Vec::new).push(1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:93:12
+ |
+LL | option.unwrap_or_else(Vec::new).push(1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:96:12
+ |
+LL | option.unwrap_or_else(Vec::new).push(1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:99:12
+ |
+LL | option.unwrap_or_else(Vec::new).push(1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:115:12
+ |
+LL | option.unwrap_or_else(Vec::new).push(1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `or_insert_with` to construct default value
+ --> $DIR/unwrap_or_else_default.rs:132:32
+ |
+LL | let _ = inner_map.entry(0).or_insert_with(Default::default);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+
+error: aborting due to 16 previous errors
diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed
index 490d36ae6..e42731f9b 100644
--- a/src/tools/clippy/tests/ui/useless_asref.fixed
+++ b/src/tools/clippy/tests/ui/useless_asref.fixed
@@ -1,6 +1,10 @@
//@run-rustfix
#![deny(clippy::useless_asref)]
-#![allow(clippy::explicit_auto_deref, clippy::uninlined_format_args)]
+#![allow(
+ clippy::explicit_auto_deref,
+ clippy::uninlined_format_args,
+ clippy::needless_pass_by_ref_mut
+)]
use std::fmt::Debug;
diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs
index f2681af92..50c9990bb 100644
--- a/src/tools/clippy/tests/ui/useless_asref.rs
+++ b/src/tools/clippy/tests/ui/useless_asref.rs
@@ -1,6 +1,10 @@
//@run-rustfix
#![deny(clippy::useless_asref)]
-#![allow(clippy::explicit_auto_deref, clippy::uninlined_format_args)]
+#![allow(
+ clippy::explicit_auto_deref,
+ clippy::uninlined_format_args,
+ clippy::needless_pass_by_ref_mut
+)]
use std::fmt::Debug;
diff --git a/src/tools/clippy/tests/ui/useless_asref.stderr b/src/tools/clippy/tests/ui/useless_asref.stderr
index 67ce8b64e..c97851ac6 100644
--- a/src/tools/clippy/tests/ui/useless_asref.stderr
+++ b/src/tools/clippy/tests/ui/useless_asref.stderr
@@ -1,8 +1,8 @@
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:43:18
+ --> $DIR/useless_asref.rs:47:18
|
LL | foo_rstr(rstr.as_ref());
- | ^^^^^^^^^^^^^ help: try this: `rstr`
+ | ^^^^^^^^^^^^^ help: try: `rstr`
|
note: the lint level is defined here
--> $DIR/useless_asref.rs:2:9
@@ -11,64 +11,64 @@ LL | #![deny(clippy::useless_asref)]
| ^^^^^^^^^^^^^^^^^^^^^
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:45:20
+ --> $DIR/useless_asref.rs:49:20
|
LL | foo_rslice(rslice.as_ref());
- | ^^^^^^^^^^^^^^^ help: try this: `rslice`
+ | ^^^^^^^^^^^^^^^ help: try: `rslice`
error: this call to `as_mut` does nothing
- --> $DIR/useless_asref.rs:49:21
+ --> $DIR/useless_asref.rs:53:21
|
LL | foo_mrslice(mrslice.as_mut());
- | ^^^^^^^^^^^^^^^^ help: try this: `mrslice`
+ | ^^^^^^^^^^^^^^^^ help: try: `mrslice`
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:51:20
+ --> $DIR/useless_asref.rs:55:20
|
LL | foo_rslice(mrslice.as_ref());
- | ^^^^^^^^^^^^^^^^ help: try this: `mrslice`
+ | ^^^^^^^^^^^^^^^^ help: try: `mrslice`
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:58:20
+ --> $DIR/useless_asref.rs:62:20
|
LL | foo_rslice(rrrrrslice.as_ref());
- | ^^^^^^^^^^^^^^^^^^^ help: try this: `rrrrrslice`
+ | ^^^^^^^^^^^^^^^^^^^ help: try: `rrrrrslice`
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:60:18
+ --> $DIR/useless_asref.rs:64:18
|
LL | foo_rstr(rrrrrstr.as_ref());
- | ^^^^^^^^^^^^^^^^^ help: try this: `rrrrrstr`
+ | ^^^^^^^^^^^^^^^^^ help: try: `rrrrrstr`
error: this call to `as_mut` does nothing
- --> $DIR/useless_asref.rs:65:21
+ --> $DIR/useless_asref.rs:69:21
|
LL | foo_mrslice(mrrrrrslice.as_mut());
- | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice`
+ | ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice`
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:67:20
+ --> $DIR/useless_asref.rs:71:20
|
LL | foo_rslice(mrrrrrslice.as_ref());
- | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice`
+ | ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice`
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:71:16
+ --> $DIR/useless_asref.rs:75:16
|
LL | foo_rrrrmr((&&&&MoreRef).as_ref());
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(&&&&MoreRef)`
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&&&&MoreRef)`
error: this call to `as_mut` does nothing
- --> $DIR/useless_asref.rs:121:13
+ --> $DIR/useless_asref.rs:125:13
|
LL | foo_mrt(mrt.as_mut());
- | ^^^^^^^^^^^^ help: try this: `mrt`
+ | ^^^^^^^^^^^^ help: try: `mrt`
error: this call to `as_ref` does nothing
- --> $DIR/useless_asref.rs:123:12
+ --> $DIR/useless_asref.rs:127:12
|
LL | foo_rt(mrt.as_ref());
- | ^^^^^^^^^^^^ help: try this: `mrt`
+ | ^^^^^^^^^^^^ help: try: `mrt`
error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/vec.fixed b/src/tools/clippy/tests/ui/vec.fixed
index fcdc917c1..7a7d0026f 100644
--- a/src/tools/clippy/tests/ui/vec.fixed
+++ b/src/tools/clippy/tests/ui/vec.fixed
@@ -115,6 +115,46 @@ fn main() {
let _x = vec![1; 201];
}
+fn issue11075() {
+ macro_rules! repro {
+ ($e:expr) => {
+ stringify!($e)
+ };
+ }
+ for _string in [repro!(true), repro!(null)] {
+ unimplemented!();
+ }
+
+ macro_rules! in_macro {
+ ($e:expr, $vec:expr, $vec2:expr) => {{
+ vec![1; 2].fill(3);
+ vec![1, 2].fill(3);
+ for _ in vec![1, 2] {}
+ for _ in vec![1; 2] {}
+ for _ in vec![$e, $e] {}
+ for _ in vec![$e; 2] {}
+ for _ in $vec {}
+ for _ in $vec2 {}
+ }};
+ }
+
+ in_macro!(1, [1, 2], [1; 2]);
+
+ macro_rules! from_macro {
+ () => {
+ vec![1, 2, 3]
+ };
+ }
+ macro_rules! from_macro_repeat {
+ () => {
+ vec![1; 3]
+ };
+ }
+
+ for _ in from_macro!() {}
+ for _ in from_macro_repeat!() {}
+}
+
#[clippy::msrv = "1.53"]
fn above() {
for a in [1, 2, 3] {
diff --git a/src/tools/clippy/tests/ui/vec.rs b/src/tools/clippy/tests/ui/vec.rs
index 0404d8cdb..cbe7685b4 100644
--- a/src/tools/clippy/tests/ui/vec.rs
+++ b/src/tools/clippy/tests/ui/vec.rs
@@ -115,6 +115,46 @@ fn main() {
let _x = vec![1; 201];
}
+fn issue11075() {
+ macro_rules! repro {
+ ($e:expr) => {
+ stringify!($e)
+ };
+ }
+ for _string in vec![repro!(true), repro!(null)] {
+ unimplemented!();
+ }
+
+ macro_rules! in_macro {
+ ($e:expr, $vec:expr, $vec2:expr) => {{
+ vec![1; 2].fill(3);
+ vec![1, 2].fill(3);
+ for _ in vec![1, 2] {}
+ for _ in vec![1; 2] {}
+ for _ in vec![$e, $e] {}
+ for _ in vec![$e; 2] {}
+ for _ in $vec {}
+ for _ in $vec2 {}
+ }};
+ }
+
+ in_macro!(1, vec![1, 2], vec![1; 2]);
+
+ macro_rules! from_macro {
+ () => {
+ vec![1, 2, 3]
+ };
+ }
+ macro_rules! from_macro_repeat {
+ () => {
+ vec![1; 3]
+ };
+ }
+
+ for _ in from_macro!() {}
+ for _ in from_macro_repeat!() {}
+}
+
#[clippy::msrv = "1.53"]
fn above() {
for a in vec![1, 2, 3] {
diff --git a/src/tools/clippy/tests/ui/vec.stderr b/src/tools/clippy/tests/ui/vec.stderr
index 33d565b2d..8f6d2a1df 100644
--- a/src/tools/clippy/tests/ui/vec.stderr
+++ b/src/tools/clippy/tests/ui/vec.stderr
@@ -85,16 +85,34 @@ LL | for _ in vec![1, 2, 3] {}
| ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
error: useless use of `vec!`
- --> $DIR/vec.rs:120:14
+ --> $DIR/vec.rs:124:20
+ |
+LL | for _string in vec![repro!(true), repro!(null)] {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[repro!(true), repro!(null)]`
+
+error: useless use of `vec!`
+ --> $DIR/vec.rs:141:18
+ |
+LL | in_macro!(1, vec![1, 2], vec![1; 2]);
+ | ^^^^^^^^^^ help: you can use an array directly: `[1, 2]`
+
+error: useless use of `vec!`
+ --> $DIR/vec.rs:141:30
+ |
+LL | in_macro!(1, vec![1, 2], vec![1; 2]);
+ | ^^^^^^^^^^ help: you can use an array directly: `[1; 2]`
+
+error: useless use of `vec!`
+ --> $DIR/vec.rs:160:14
|
LL | for a in vec![1, 2, 3] {
| ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]`
error: useless use of `vec!`
- --> $DIR/vec.rs:124:14
+ --> $DIR/vec.rs:164:14
|
LL | for a in vec![String::new(), String::new()] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[String::new(), String::new()]`
-error: aborting due to 16 previous errors
+error: aborting due to 19 previous errors
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
index 30d29aa4e..5b88ae4ab 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
@@ -2,7 +2,7 @@ error: wildcard match will also match any future added variants
--> $DIR/wildcard_enum_match_arm.rs:40:9
|
LL | _ => eprintln!("Not red"),
- | ^ help: try this: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan`
+ | ^ help: try: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan`
|
note: the lint level is defined here
--> $DIR/wildcard_enum_match_arm.rs:3:9
@@ -14,31 +14,31 @@ error: wildcard match will also match any future added variants
--> $DIR/wildcard_enum_match_arm.rs:44:9
|
LL | _not_red => eprintln!("Not red"),
- | ^^^^^^^^ help: try this: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan`
+ | ^^^^^^^^ help: try: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan`
error: wildcard match will also match any future added variants
--> $DIR/wildcard_enum_match_arm.rs:48:9
|
LL | not_red => format!("{:?}", not_red),
- | ^^^^^^^ help: try this: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan`
+ | ^^^^^^^ help: try: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan`
error: wildcard match will also match any future added variants
--> $DIR/wildcard_enum_match_arm.rs:64:9
|
LL | _ => "No red",
- | ^ help: try this: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan`
+ | ^ help: try: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan`
error: wildcard matches known variants and will also match future added variants
--> $DIR/wildcard_enum_match_arm.rs:81:9
|
LL | _ => {},
- | ^ help: try this: `ErrorKind::PermissionDenied | _`
+ | ^ help: try: `ErrorKind::PermissionDenied | _`
error: wildcard match will also match any future added variants
--> $DIR/wildcard_enum_match_arm.rs:99:13
|
LL | _ => (),
- | ^ help: try this: `Enum::B | Enum::__Private`
+ | ^ help: try: `Enum::B | Enum::__Private`
error: aborting due to 6 previous errors
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed
index 2961b062e..67173f406 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed
@@ -112,6 +112,7 @@ mod in_fn_test {
}
fn test_inner_nested() {
+ #[rustfmt::skip]
use self::{inner::inner_foo, inner2::inner_bar};
inner_foo();
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.rs b/src/tools/clippy/tests/ui/wildcard_imports.rs
index 28508a253..8223b6930 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.rs
+++ b/src/tools/clippy/tests/ui/wildcard_imports.rs
@@ -112,6 +112,7 @@ mod in_fn_test {
}
fn test_inner_nested() {
+ #[rustfmt::skip]
use self::{inner::*, inner2::*};
inner_foo();
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr
index c96b3041a..f7baf234c 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr
@@ -55,37 +55,37 @@ LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:115:20
+ --> $DIR/wildcard_imports.rs:116:20
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^ help: try: `inner::inner_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:115:30
+ --> $DIR/wildcard_imports.rs:116:30
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^^ help: try: `inner2::inner_bar`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:122:13
+ --> $DIR/wildcard_imports.rs:123:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:151:9
+ --> $DIR/wildcard_imports.rs:152:9
|
LL | use crate::in_fn_test::*;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:160:9
+ --> $DIR/wildcard_imports.rs:161:9
|
LL | use crate:: in_fn_test:: * ;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:161:9
+ --> $DIR/wildcard_imports.rs:162:9
|
LL | use crate:: fn_mod::
| _________^
@@ -93,37 +93,37 @@ LL | | *;
| |_________^ help: try: `crate:: fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:172:13
+ --> $DIR/wildcard_imports.rs:173:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:207:17
+ --> $DIR/wildcard_imports.rs:208:17
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::insidefoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:215:13
+ --> $DIR/wildcard_imports.rs:216:13
|
LL | use crate::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:224:17
+ --> $DIR/wildcard_imports.rs:225:17
|
LL | use super::super::*;
| ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:233:13
+ --> $DIR/wildcard_imports.rs:234:13
|
LL | use super::super::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:241:13
+ --> $DIR/wildcard_imports.rs:242:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
index 3aea013fb..8a6337567 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
@@ -106,6 +106,7 @@ mod in_fn_test {
}
fn test_inner_nested() {
+ #[rustfmt::skip]
use self::{inner::inner_foo, inner2::inner_bar};
inner_foo();
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
index acca9f651..af9ae6e78 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
@@ -55,37 +55,37 @@ LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:109:20
+ --> $DIR/wildcard_imports_2021.rs:110:20
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^ help: try: `inner::inner_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:109:30
+ --> $DIR/wildcard_imports_2021.rs:110:30
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^^ help: try: `inner2::inner_bar`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:116:13
+ --> $DIR/wildcard_imports_2021.rs:117:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:145:9
+ --> $DIR/wildcard_imports_2021.rs:146:9
|
LL | use crate::in_fn_test::*;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:154:9
+ --> $DIR/wildcard_imports_2021.rs:155:9
|
LL | use crate:: in_fn_test:: * ;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:155:9
+ --> $DIR/wildcard_imports_2021.rs:156:9
|
LL | use crate:: fn_mod::
| _________^
@@ -93,37 +93,37 @@ LL | | *;
| |_________^ help: try: `crate:: fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:166:13
+ --> $DIR/wildcard_imports_2021.rs:167:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:201:17
+ --> $DIR/wildcard_imports_2021.rs:202:17
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::insidefoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:209:13
+ --> $DIR/wildcard_imports_2021.rs:210:13
|
LL | use crate::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:218:17
+ --> $DIR/wildcard_imports_2021.rs:219:17
|
LL | use super::super::*;
| ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:227:13
+ --> $DIR/wildcard_imports_2021.rs:228:13
|
LL | use super::super::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:235:13
+ --> $DIR/wildcard_imports_2021.rs:236:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
index 3aea013fb..8a6337567 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
@@ -106,6 +106,7 @@ mod in_fn_test {
}
fn test_inner_nested() {
+ #[rustfmt::skip]
use self::{inner::inner_foo, inner2::inner_bar};
inner_foo();
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
index acca9f651..af9ae6e78 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
@@ -55,37 +55,37 @@ LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:109:20
+ --> $DIR/wildcard_imports_2021.rs:110:20
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^ help: try: `inner::inner_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:109:30
+ --> $DIR/wildcard_imports_2021.rs:110:30
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^^ help: try: `inner2::inner_bar`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:116:13
+ --> $DIR/wildcard_imports_2021.rs:117:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:145:9
+ --> $DIR/wildcard_imports_2021.rs:146:9
|
LL | use crate::in_fn_test::*;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:154:9
+ --> $DIR/wildcard_imports_2021.rs:155:9
|
LL | use crate:: in_fn_test:: * ;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:155:9
+ --> $DIR/wildcard_imports_2021.rs:156:9
|
LL | use crate:: fn_mod::
| _________^
@@ -93,37 +93,37 @@ LL | | *;
| |_________^ help: try: `crate:: fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:166:13
+ --> $DIR/wildcard_imports_2021.rs:167:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:201:17
+ --> $DIR/wildcard_imports_2021.rs:202:17
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::insidefoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:209:13
+ --> $DIR/wildcard_imports_2021.rs:210:13
|
LL | use crate::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:218:17
+ --> $DIR/wildcard_imports_2021.rs:219:17
|
LL | use super::super::*;
| ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:227:13
+ --> $DIR/wildcard_imports_2021.rs:228:13
|
LL | use super::super::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:235:13
+ --> $DIR/wildcard_imports_2021.rs:236:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
index 40c2d0752..52cd2c828 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
@@ -106,6 +106,7 @@ mod in_fn_test {
}
fn test_inner_nested() {
+ #[rustfmt::skip]
use self::{inner::*, inner2::*};
inner_foo();
diff --git a/src/tools/clippy/tests/ui/write_literal.stderr b/src/tools/clippy/tests/ui/write_literal.stderr
index 1e306ae28..8b72c8bd2 100644
--- a/src/tools/clippy/tests/ui/write_literal.stderr
+++ b/src/tools/clippy/tests/ui/write_literal.stderr
@@ -5,7 +5,7 @@ LL | write!(v, "Hello {}", "world");
| ^^^^^^^
|
= note: `-D clippy::write-literal` implied by `-D warnings`
-help: try this
+help: try
|
LL - write!(v, "Hello {}", "world");
LL + write!(v, "Hello world");
@@ -17,7 +17,7 @@ error: literal with an empty format string
LL | writeln!(v, "Hello {} {}", world, "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "Hello {} {}", world, "world");
LL + writeln!(v, "Hello {} world", world);
@@ -29,7 +29,7 @@ error: literal with an empty format string
LL | writeln!(v, "Hello {}", "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "Hello {}", "world");
LL + writeln!(v, "Hello world");
@@ -41,7 +41,7 @@ error: literal with an empty format string
LL | writeln!(v, "{} {:.4}", "a literal", 5);
| ^^^^^^^^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "{} {:.4}", "a literal", 5);
LL + writeln!(v, "a literal {:.4}", 5);
@@ -53,7 +53,7 @@ error: literal with an empty format string
LL | writeln!(v, "{0} {1}", "hello", "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "{0} {1}", "hello", "world");
LL + writeln!(v, "hello {1}", "world");
@@ -65,7 +65,7 @@ error: literal with an empty format string
LL | writeln!(v, "{0} {1}", "hello", "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "{0} {1}", "hello", "world");
LL + writeln!(v, "{0} world", "hello");
@@ -77,7 +77,7 @@ error: literal with an empty format string
LL | writeln!(v, "{1} {0}", "hello", "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "{1} {0}", "hello", "world");
LL + writeln!(v, "world {0}", "hello");
@@ -89,7 +89,7 @@ error: literal with an empty format string
LL | writeln!(v, "{1} {0}", "hello", "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "{1} {0}", "hello", "world");
LL + writeln!(v, "{1} hello", "world");
@@ -101,7 +101,7 @@ error: literal with an empty format string
LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
LL + writeln!(v, "hello {bar}", bar = "world");
@@ -113,7 +113,7 @@ error: literal with an empty format string
LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
LL + writeln!(v, "{foo} world", foo = "hello");
@@ -125,7 +125,7 @@ error: literal with an empty format string
LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
LL + writeln!(v, "world {foo}", foo = "hello");
@@ -137,7 +137,7 @@ error: literal with an empty format string
LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
| ^^^^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
LL + writeln!(v, "{bar} hello", bar = "world");
diff --git a/src/tools/clippy/tests/ui/write_literal_2.stderr b/src/tools/clippy/tests/ui/write_literal_2.stderr
index 18591250a..c30ec385b 100644
--- a/src/tools/clippy/tests/ui/write_literal_2.stderr
+++ b/src/tools/clippy/tests/ui/write_literal_2.stderr
@@ -13,7 +13,7 @@ LL | writeln!(v, "{}", "{hello}");
| ^^^^^^^^^
|
= note: `-D clippy::write-literal` implied by `-D warnings`
-help: try this
+help: try
|
LL - writeln!(v, "{}", "{hello}");
LL + writeln!(v, "{{hello}}");
@@ -25,7 +25,7 @@ error: literal with an empty format string
LL | writeln!(v, r"{}", r"{hello}");
| ^^^^^^^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, r"{}", r"{hello}");
LL + writeln!(v, r"{{hello}}");
@@ -37,7 +37,7 @@ error: literal with an empty format string
LL | writeln!(v, "{}", '/'');
| ^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "{}", '/'');
LL + writeln!(v, "'");
@@ -49,7 +49,7 @@ error: literal with an empty format string
LL | writeln!(v, "{}", '"');
| ^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "{}", '"');
LL + writeln!(v, "/"");
@@ -67,7 +67,7 @@ error: literal with an empty format string
LL | writeln!(v, r"{}", '/'');
| ^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, r"{}", '/'');
LL + writeln!(v, r"'");
@@ -80,7 +80,7 @@ LL | / "hello /
LL | | world!"
| |_______________^
|
-help: try this
+help: try
|
LL ~ "some hello /
LL ~ world!"
@@ -92,7 +92,7 @@ error: literal with an empty format string
LL | "1", "2", "3",
| ^^^
|
-help: try this
+help: try
|
LL ~ "some 1/
LL ~ {} // {}", "2", "3",
@@ -104,7 +104,7 @@ error: literal with an empty format string
LL | "1", "2", "3",
| ^^^
|
-help: try this
+help: try
|
LL ~ 2 // {}",
LL ~ "1", "3",
@@ -116,7 +116,7 @@ error: literal with an empty format string
LL | "1", "2", "3",
| ^^^
|
-help: try this
+help: try
|
LL ~ {} // 3",
LL ~ "1", "2",
@@ -128,7 +128,7 @@ error: literal with an empty format string
LL | writeln!(v, "{}", "//");
| ^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "{}", "//");
LL + writeln!(v, "//");
@@ -140,7 +140,7 @@ error: literal with an empty format string
LL | writeln!(v, r"{}", "//");
| ^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, r"{}", "//");
LL + writeln!(v, r"/");
@@ -152,7 +152,7 @@ error: literal with an empty format string
LL | writeln!(v, r#"{}"#, "//");
| ^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, r#"{}"#, "//");
LL + writeln!(v, r#"/"#);
@@ -164,7 +164,7 @@ error: literal with an empty format string
LL | writeln!(v, "{}", r"/");
| ^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "{}", r"/");
LL + writeln!(v, "//");
@@ -176,7 +176,7 @@ error: literal with an empty format string
LL | writeln!(v, "{}", "/r");
| ^^^^
|
-help: try this
+help: try
|
LL - writeln!(v, "{}", "/r");
LL + writeln!(v, "/r");
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index c40b71f6c..6856bb0ab 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -9,6 +9,9 @@ allow-unauthenticated = [
# See https://github.com/rust-lang/triagebot/wiki/Shortcuts
[shortcut]
+# Have rustbot inform users about the *No Merge Policy*
+[no-merges]
+
[autolabel."S-waiting-on-review"]
new_pr = true
@@ -27,4 +30,6 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB
"@Alexendoo",
"@dswij",
"@Jarcho",
+ "@blyxyas",
+ "@Centri3",
]
diff --git a/src/tools/clippy/util/fetch_prs_between.sh b/src/tools/clippy/util/fetch_prs_between.sh
index 6865abf97..fa7560b69 100755
--- a/src/tools/clippy/util/fetch_prs_between.sh
+++ b/src/tools/clippy/util/fetch_prs_between.sh
@@ -6,15 +6,20 @@
# If you want to use this to update the Clippy changelog, be sure to manually
# exclude the non-user facing changes like 'rustup' PRs, typo fixes, etc.
-first=$1
-last=$2
+set -e
IFS='
'
-for pr in $(git log --oneline --grep "Merge #" --grep "Merge pull request" --grep "Auto merge of" --grep "Rollup merge of" "$first...$last" | sort -rn | uniq); do
+for pr in $(git log --oneline --merges --first-parent "$1...$2"); do
id=$(echo "$pr" | rg -o '#[0-9]{3,5}' | cut -c 2-)
commit=$(echo "$pr" | cut -d' ' -f 1)
message=$(git --no-pager show --pretty=medium "$commit")
+
+ if [[ -z "$newest_pr" ]]; then
+ newest_pr="$id"
+ fi
+ oldest_pr="$id"
+
if [[ -n $(echo "$message" | rg "^[\s]{4}changelog: [nN]one\.*$") ]]; then
continue
fi
@@ -25,3 +30,14 @@ for pr in $(git log --oneline --grep "Merge #" --grep "Merge pull request" --gre
echo "---------------------------------------------------------"
echo
done
+
+newest_merged_at="$(gh pr view -R rust-lang/rust-clippy --json mergedAt $newest_pr -q .mergedAt)"
+oldest_merged_at="$(gh pr view -R rust-lang/rust-clippy --json mergedAt $oldest_pr -q .mergedAt)"
+
+query="merged:$oldest_merged_at..$newest_merged_at base:master"
+encoded_query="$(echo $query | sed 's/ /+/g; s/:/%3A/g')"
+
+pr_link="https://github.com/rust-lang/rust-clippy/pulls?q=$encoded_query"
+count="$(gh api -X GET search/issues -f "q=$query repo:rust-lang/rust-clippy" -q .total_count)"
+
+echo "[View all $count merged pull requests]($pr_link)"