From c9a43b18f11219fa70fe632b29518581fcd589c8 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 1 Dec 2023 18:21:58 +0100 Subject: [PATCH] Merge commit 'f0cdee4a3f094416189261481eae374b76792af1' into clippy-subtree-sync --- .github/workflows/deploy.yml | 4 +- CHANGELOG.md | 5 + book/src/development/adding_lints.md | 4 +- book/src/development/type_checking.md | 2 +- book/src/lint_configuration.md | 14 + clippy_config/src/conf.rs | 6 +- clippy_config/src/msrvs.rs | 1 + clippy_dev/src/new_lint.rs | 4 +- clippy_lints/src/absolute_paths.rs | 2 +- clippy_lints/src/allow_attributes.rs | 2 +- clippy_lints/src/almost_complete_range.rs | 2 +- clippy_lints/src/approx_const.rs | 2 +- clippy_lints/src/arc_with_non_send_sync.rs | 2 +- clippy_lints/src/as_conversions.rs | 2 +- clippy_lints/src/asm_syntax.rs | 2 +- clippy_lints/src/assertions_on_constants.rs | 2 +- .../src/assertions_on_result_states.rs | 2 +- clippy_lints/src/async_yields_async.rs | 2 +- clippy_lints/src/attrs.rs | 39 +- clippy_lints/src/await_holding_invalid.rs | 2 +- clippy_lints/src/blocks_in_if_conditions.rs | 2 +- clippy_lints/src/bool_assert_comparison.rs | 2 +- clippy_lints/src/bool_to_int_with_if.rs | 2 +- clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/borrow_deref_ref.rs | 2 +- clippy_lints/src/box_default.rs | 12 +- clippy_lints/src/cargo/mod.rs | 2 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/checked_conversions.rs | 2 +- clippy_lints/src/cognitive_complexity.rs | 2 +- clippy_lints/src/collapsible_if.rs | 2 +- clippy_lints/src/collection_is_never_read.rs | 2 +- clippy_lints/src/comparison_chain.rs | 2 +- clippy_lints/src/copies.rs | 2 +- clippy_lints/src/copy_iterator.rs | 2 +- clippy_lints/src/crate_in_macro_def.rs | 2 +- clippy_lints/src/create_dir.rs | 2 +- clippy_lints/src/dbg_macro.rs | 2 +- clippy_lints/src/declared_lints.rs | 4 + clippy_lints/src/default.rs | 2 +- .../src/default_constructed_unit_structs.rs | 2 +- .../src/default_instead_of_iter_empty.rs | 2 +- clippy_lints/src/default_numeric_fallback.rs | 2 +- .../src/default_union_representation.rs | 2 +- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/derivable_impls.rs | 2 +- clippy_lints/src/derive.rs | 2 +- clippy_lints/src/disallowed_macros.rs | 2 +- clippy_lints/src/disallowed_methods.rs | 2 +- clippy_lints/src/disallowed_names.rs | 2 +- clippy_lints/src/disallowed_script_idents.rs | 2 +- clippy_lints/src/disallowed_types.rs | 2 +- clippy_lints/src/doc/link_with_quotes.rs | 20 + clippy_lints/src/doc/markdown.rs | 109 +++++ clippy_lints/src/doc/missing_headers.rs | 86 ++++ clippy_lints/src/{doc.rs => doc/mod.rs} | 454 +++++------------- clippy_lints/src/doc/needless_doctest_main.rs | 135 ++++++ .../src/doc/suspicious_doc_comments.rs | 48 ++ clippy_lints/src/double_parens.rs | 2 +- clippy_lints/src/drop_forget_ref.rs | 2 +- clippy_lints/src/duplicate_mod.rs | 2 +- clippy_lints/src/else_if_without_else.rs | 2 +- clippy_lints/src/empty_drop.rs | 2 +- clippy_lints/src/empty_enum.rs | 2 +- .../src/empty_structs_with_brackets.rs | 2 +- clippy_lints/src/endian_bytes.rs | 2 +- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/equatable_if_let.rs | 11 +- clippy_lints/src/error_impl_error.rs | 2 +- clippy_lints/src/escape.rs | 2 +- clippy_lints/src/eta_reduction.rs | 5 +- clippy_lints/src/excessive_bools.rs | 2 +- clippy_lints/src/excessive_nesting.rs | 2 +- clippy_lints/src/exhaustive_items.rs | 2 +- clippy_lints/src/exit.rs | 2 +- clippy_lints/src/explicit_write.rs | 2 +- .../src/extra_unused_type_parameters.rs | 2 +- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/float_literal.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 10 +- clippy_lints/src/format.rs | 2 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/format_impl.rs | 2 +- clippy_lints/src/format_push_string.rs | 2 +- clippy_lints/src/formatting.rs | 2 +- clippy_lints/src/four_forward_slashes.rs | 2 +- clippy_lints/src/from_over_into.rs | 2 +- clippy_lints/src/from_raw_with_void_ptr.rs | 2 +- clippy_lints/src/from_str_radix_10.rs | 2 +- clippy_lints/src/functions/mod.rs | 2 +- clippy_lints/src/future_not_send.rs | 2 +- clippy_lints/src/if_let_mutex.rs | 2 +- clippy_lints/src/if_not_else.rs | 2 +- clippy_lints/src/if_then_some_else_none.rs | 2 +- clippy_lints/src/ignored_unit_patterns.rs | 2 +- .../impl_hash_with_borrow_str_and_bytes.rs | 106 ++++ clippy_lints/src/implicit_hasher.rs | 2 +- clippy_lints/src/implicit_return.rs | 2 +- clippy_lints/src/implicit_saturating_add.rs | 2 +- clippy_lints/src/implicit_saturating_sub.rs | 2 +- clippy_lints/src/implied_bounds_in_impls.rs | 4 +- .../src/inconsistent_struct_constructor.rs | 2 +- clippy_lints/src/index_refutable_slice.rs | 2 +- clippy_lints/src/indexing_slicing.rs | 2 +- clippy_lints/src/infinite_iter.rs | 2 +- clippy_lints/src/inherent_impl.rs | 2 +- clippy_lints/src/inherent_to_string.rs | 2 +- clippy_lints/src/init_numbered_fields.rs | 2 +- clippy_lints/src/inline_fn_without_body.rs | 2 +- clippy_lints/src/instant_subtraction.rs | 2 +- clippy_lints/src/int_plus_one.rs | 2 +- .../src/invalid_upcast_comparisons.rs | 2 +- clippy_lints/src/item_name_repetitions.rs | 2 +- clippy_lints/src/items_after_statements.rs | 2 +- clippy_lints/src/items_after_test_module.rs | 2 +- .../src/iter_not_returning_iterator.rs | 2 +- clippy_lints/src/iter_over_hash_type.rs | 2 +- clippy_lints/src/iter_without_into_iter.rs | 2 +- clippy_lints/src/large_const_arrays.rs | 2 +- clippy_lints/src/large_enum_variant.rs | 2 +- clippy_lints/src/large_futures.rs | 2 +- clippy_lints/src/large_include_file.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 2 +- clippy_lints/src/large_stack_frames.rs | 2 +- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/let_if_seq.rs | 2 +- clippy_lints/src/let_underscore.rs | 2 +- clippy_lints/src/let_with_type_underscore.rs | 2 +- clippy_lints/src/lib.rs | 5 +- clippy_lints/src/lifetimes.rs | 2 +- clippy_lints/src/lines_filter_map_ok.rs | 62 +-- clippy_lints/src/literal_representation.rs | 2 +- clippy_lints/src/loops/mod.rs | 2 +- clippy_lints/src/loops/single_element_loop.rs | 35 +- clippy_lints/src/macro_use.rs | 27 +- clippy_lints/src/main_recursion.rs | 2 +- clippy_lints/src/manual_assert.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 17 +- clippy_lints/src/manual_bits.rs | 2 +- clippy_lints/src/manual_clamp.rs | 2 +- clippy_lints/src/manual_float_methods.rs | 2 +- clippy_lints/src/manual_hash_one.rs | 2 +- clippy_lints/src/manual_is_ascii_check.rs | 2 +- clippy_lints/src/manual_let_else.rs | 2 +- clippy_lints/src/manual_main_separator_str.rs | 2 +- clippy_lints/src/manual_non_exhaustive.rs | 6 +- clippy_lints/src/manual_range_patterns.rs | 2 +- clippy_lints/src/manual_rem_euclid.rs | 2 +- clippy_lints/src/manual_retain.rs | 2 +- .../src/manual_slice_size_calculation.rs | 2 +- clippy_lints/src/manual_string_new.rs | 2 +- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/map_unit_fn.rs | 2 +- clippy_lints/src/match_result_ok.rs | 2 +- clippy_lints/src/matches/match_same_arms.rs | 13 +- clippy_lints/src/matches/mod.rs | 2 +- clippy_lints/src/matches/redundant_guards.rs | 102 +++- clippy_lints/src/mem_replace.rs | 2 +- clippy_lints/src/methods/iter_kv_map.rs | 5 + .../src/methods/join_absolute_paths.rs | 52 ++ clippy_lints/src/methods/manual_try_fold.rs | 5 +- clippy_lints/src/methods/map_unwrap_or.rs | 6 +- clippy_lints/src/methods/mod.rs | 88 +++- clippy_lints/src/methods/needless_collect.rs | 5 +- .../src/methods/option_as_ref_deref.rs | 5 +- .../src/methods/option_map_or_err_ok.rs | 41 ++ .../src/methods/option_map_or_none.rs | 9 +- .../src/methods/option_map_unwrap_or.rs | 5 +- .../src/methods/result_map_or_else_none.rs | 42 ++ clippy_lints/src/min_ident_chars.rs | 2 +- clippy_lints/src/minmax.rs | 2 +- clippy_lints/src/misc.rs | 2 +- clippy_lints/src/misc_early/mod.rs | 2 +- .../src/mismatching_type_param_order.rs | 2 +- clippy_lints/src/missing_assert_message.rs | 2 +- .../src/missing_asserts_for_indexing.rs | 8 +- clippy_lints/src/missing_const_for_fn.rs | 2 +- clippy_lints/src/missing_doc.rs | 2 +- .../src/missing_enforced_import_rename.rs | 2 +- clippy_lints/src/missing_fields_in_debug.rs | 2 +- clippy_lints/src/missing_inline.rs | 2 +- clippy_lints/src/missing_trait_methods.rs | 2 +- .../src/mixed_read_write_in_expression.rs | 2 +- clippy_lints/src/module_style.rs | 2 +- clippy_lints/src/multi_assignments.rs | 2 +- .../src/multiple_unsafe_ops_per_block.rs | 2 +- clippy_lints/src/mut_key.rs | 8 +- clippy_lints/src/mut_mut.rs | 2 +- clippy_lints/src/mut_reference.rs | 2 +- clippy_lints/src/mutable_debug_assertion.rs | 2 +- clippy_lints/src/mutex_atomic.rs | 2 +- .../src/needless_arbitrary_self_type.rs | 2 +- clippy_lints/src/needless_bool.rs | 2 +- clippy_lints/src/needless_borrowed_ref.rs | 2 +- .../src/needless_borrows_for_generic_args.rs | 2 +- clippy_lints/src/needless_continue.rs | 2 +- clippy_lints/src/needless_else.rs | 2 +- clippy_lints/src/needless_for_each.rs | 2 +- clippy_lints/src/needless_if.rs | 2 +- clippy_lints/src/needless_late_init.rs | 2 +- .../src/needless_parens_on_range_literals.rs | 2 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/needless_question_mark.rs | 2 +- clippy_lints/src/needless_update.rs | 2 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 2 +- clippy_lints/src/neg_multiply.rs | 2 +- clippy_lints/src/new_without_default.rs | 2 +- clippy_lints/src/no_effect.rs | 2 +- clippy_lints/src/no_mangle_with_rust_abi.rs | 2 +- clippy_lints/src/non_canonical_impls.rs | 2 +- clippy_lints/src/non_copy_const.rs | 2 +- clippy_lints/src/non_expressive_names.rs | 2 +- .../src/non_octal_unix_permissions.rs | 2 +- .../src/non_send_fields_in_send_ty.rs | 2 +- clippy_lints/src/nonstandard_macro_braces.rs | 2 +- clippy_lints/src/octal_escapes.rs | 2 +- clippy_lints/src/only_used_in_recursion.rs | 2 +- clippy_lints/src/operators/eq_op.rs | 2 +- .../src/operators/misrefactored_assign_op.rs | 2 +- clippy_lints/src/operators/mod.rs | 2 +- clippy_lints/src/option_env_unwrap.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 23 +- .../src/overflow_check_conditional.rs | 2 +- clippy_lints/src/panic_in_result_fn.rs | 2 +- clippy_lints/src/panic_unimplemented.rs | 2 +- clippy_lints/src/partial_pub_fields.rs | 2 +- clippy_lints/src/partialeq_ne_impl.rs | 2 +- clippy_lints/src/partialeq_to_none.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 2 +- clippy_lints/src/pattern_type_mismatch.rs | 2 +- .../src/permissions_set_readonly_false.rs | 2 +- clippy_lints/src/precedence.rs | 2 +- clippy_lints/src/ptr.rs | 42 +- clippy_lints/src/ptr_offset_with_cast.rs | 2 +- clippy_lints/src/pub_use.rs | 2 +- clippy_lints/src/question_mark.rs | 2 +- clippy_lints/src/question_mark_used.rs | 2 +- clippy_lints/src/ranges.rs | 2 +- clippy_lints/src/raw_strings.rs | 2 +- clippy_lints/src/rc_clone_in_vec_init.rs | 2 +- clippy_lints/src/read_zero_byte_vec.rs | 2 +- clippy_lints/src/redundant_async_block.rs | 2 +- clippy_lints/src/redundant_clone.rs | 2 +- clippy_lints/src/redundant_closure_call.rs | 37 +- clippy_lints/src/redundant_else.rs | 2 +- clippy_lints/src/redundant_field_names.rs | 2 +- clippy_lints/src/redundant_locals.rs | 2 +- clippy_lints/src/redundant_pub_crate.rs | 2 +- clippy_lints/src/redundant_slicing.rs | 2 +- .../src/redundant_static_lifetimes.rs | 2 +- .../src/redundant_type_annotations.rs | 2 +- clippy_lints/src/ref_option_ref.rs | 2 +- clippy_lints/src/ref_patterns.rs | 2 +- clippy_lints/src/reference.rs | 2 +- clippy_lints/src/regex.rs | 2 +- .../src/reserve_after_initialization.rs | 2 +- clippy_lints/src/return_self_not_must_use.rs | 2 +- clippy_lints/src/returns.rs | 23 +- clippy_lints/src/same_name_method.rs | 2 +- clippy_lints/src/self_named_constructors.rs | 2 +- clippy_lints/src/semicolon_block.rs | 2 +- .../src/semicolon_if_nothing_returned.rs | 2 +- clippy_lints/src/serde_api.rs | 2 +- clippy_lints/src/shadow.rs | 2 +- .../src/significant_drop_tightening.rs | 2 +- clippy_lints/src/single_call_fn.rs | 2 +- .../src/single_char_lifetime_names.rs | 2 +- .../src/single_component_path_imports.rs | 2 +- clippy_lints/src/single_range_in_vec_init.rs | 2 +- clippy_lints/src/size_of_in_element_count.rs | 2 +- clippy_lints/src/size_of_ref.rs | 2 +- .../src/slow_vector_initialization.rs | 2 +- clippy_lints/src/std_instead_of_core.rs | 2 +- clippy_lints/src/strings.rs | 2 +- clippy_lints/src/strlen_on_c_strings.rs | 2 +- .../src/suspicious_operation_groupings.rs | 2 +- clippy_lints/src/suspicious_trait_impl.rs | 2 +- .../src/suspicious_xor_used_as_pow.rs | 2 +- clippy_lints/src/swap.rs | 2 +- clippy_lints/src/swap_ptr_to_ref.rs | 2 +- clippy_lints/src/tabs_in_doc_comments.rs | 2 +- clippy_lints/src/temporary_assignment.rs | 2 +- clippy_lints/src/tests_outside_test_module.rs | 2 +- clippy_lints/src/to_digit_is_some.rs | 2 +- clippy_lints/src/trailing_empty_array.rs | 2 +- clippy_lints/src/trait_bounds.rs | 2 +- clippy_lints/src/transmute/mod.rs | 2 +- clippy_lints/src/tuple_array_conversions.rs | 2 +- clippy_lints/src/types/mod.rs | 2 +- .../src/undocumented_unsafe_blocks.rs | 2 +- clippy_lints/src/unicode.rs | 2 +- clippy_lints/src/uninit_vec.rs | 2 +- clippy_lints/src/unit_return_expecting_ord.rs | 10 +- clippy_lints/src/unit_types/mod.rs | 2 +- clippy_lints/src/unnamed_address.rs | 2 +- clippy_lints/src/unnecessary_box_returns.rs | 2 +- .../src/unnecessary_map_on_constructor.rs | 15 +- .../src/unnecessary_owned_empty_strings.rs | 2 +- clippy_lints/src/unnecessary_self_imports.rs | 2 +- .../src/unnecessary_struct_initialization.rs | 2 +- clippy_lints/src/unnecessary_wraps.rs | 2 +- clippy_lints/src/unnested_or_patterns.rs | 2 +- clippy_lints/src/unsafe_removed_from_name.rs | 2 +- clippy_lints/src/unused_async.rs | 2 +- clippy_lints/src/unused_io_amount.rs | 2 +- clippy_lints/src/unused_peekable.rs | 2 +- clippy_lints/src/unused_rounding.rs | 2 +- clippy_lints/src/unused_self.rs | 2 +- clippy_lints/src/unused_unit.rs | 2 +- clippy_lints/src/unwrap.rs | 2 +- clippy_lints/src/unwrap_in_result.rs | 2 +- clippy_lints/src/upper_case_acronyms.rs | 33 +- clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/useless_conversion.rs | 2 +- .../almost_standard_lint_formulation.rs | 2 +- .../utils/internal_lints/collapsible_calls.rs | 2 +- .../internal_lints/compiler_lint_functions.rs | 2 +- .../interning_defined_symbol.rs | 2 +- .../src/utils/internal_lints/invalid_paths.rs | 2 +- .../internal_lints/lint_without_lint_pass.rs | 2 +- .../internal_lints/metadata_collector.rs | 8 +- .../utils/internal_lints/msrv_attr_impl.rs | 2 +- .../internal_lints/outer_expn_data_pass.rs | 2 +- .../src/utils/internal_lints/produce_ice.rs | 2 +- .../internal_lints/unnecessary_def_path.rs | 2 +- .../unsorted_clippy_utils_paths.rs | 2 +- clippy_lints/src/vec.rs | 4 +- clippy_lints/src/vec_init_then_push.rs | 2 +- clippy_lints/src/visibility.rs | 2 +- clippy_lints/src/wildcard_imports.rs | 2 +- clippy_lints/src/write.rs | 2 +- clippy_lints/src/zero_div_zero.rs | 2 +- clippy_lints/src/zero_sized_map_values.rs | 2 +- clippy_utils/src/consts.rs | 132 ++++- clippy_utils/src/eager_or_lazy.rs | 52 +- clippy_utils/src/hir_utils.rs | 3 +- clippy_utils/src/lib.rs | 3 +- clippy_utils/src/sugg.rs | 7 +- clippy_utils/src/ty/type_certainty/mod.rs | 25 +- declare_clippy_lint/src/lib.rs | 2 +- lintcheck/src/main.rs | 4 +- rust-toolchain | 2 +- tests/ui-toml/private-doc-errors/clippy.toml | 1 + tests/ui-toml/private-doc-errors/doc_lints.rs | 54 +++ .../private-doc-errors/doc_lints.stderr | 64 +++ .../toml_unknown_key/conf_unknown_key.stderr | 2 + tests/ui/attrs.rs | 3 + tests/ui/box_default.fixed | 14 + tests/ui/box_default.rs | 14 + tests/ui/cfg_features.fixed | 20 +- tests/ui/cfg_features.rs | 20 +- tests/ui/cfg_features.stderr | 42 +- tests/ui/doc_link_with_quotes.rs | 6 + tests/ui/doc_link_with_quotes.stderr | 8 +- tests/ui/floating_point_mul_add.fixed | 18 + tests/ui/floating_point_mul_add.rs | 18 + .../ui/impl_hash_with_borrow_str_and_bytes.rs | 136 ++++++ ...impl_hash_with_borrow_str_and_bytes.stderr | 41 ++ tests/ui/iter_kv_map.fixed | 43 ++ tests/ui/iter_kv_map.rs | 43 ++ tests/ui/iter_kv_map.stderr | 62 ++- tests/ui/join_absolute_paths.rs | 30 ++ tests/ui/join_absolute_paths.stderr | 68 +++ tests/ui/lines_filter_map_ok.fixed | 6 + tests/ui/lines_filter_map_ok.rs | 6 + tests/ui/lines_filter_map_ok.stderr | 38 +- tests/ui/macro_use_imports.stderr | 12 +- tests/ui/manual_non_exhaustive_enum.rs | 2 +- tests/ui/manual_non_exhaustive_enum.stderr | 23 +- tests/ui/manual_non_exhaustive_struct.stderr | 22 +- tests/ui/manual_ok_or.stderr | 11 +- tests/ui/manual_try_fold.rs | 30 ++ tests/ui/map_unwrap_or.stderr | 30 +- tests/ui/map_unwrap_or_fixable.stderr | 4 +- .../missing_asserts_for_indexing_unfixable.rs | 22 + ...sing_asserts_for_indexing_unfixable.stderr | 21 +- tests/ui/needless_pass_by_ref_mut.rs | 7 +- tests/ui/needless_pass_by_ref_mut.stderr | 42 +- .../needless_return_with_question_mark.fixed | 18 + .../ui/needless_return_with_question_mark.rs | 18 + .../needless_return_with_question_mark.stderr | 10 +- tests/ui/option_as_ref_deref.stderr | 36 +- tests/ui/option_if_let_else.fixed | 26 +- tests/ui/option_if_let_else.rs | 34 +- tests/ui/option_if_let_else.stderr | 48 +- tests/ui/option_map_or_err_ok.fixed | 7 + tests/ui/option_map_or_err_ok.rs | 7 + tests/ui/option_map_or_err_ok.stderr | 11 + tests/ui/option_map_or_none.stderr | 10 +- tests/ui/ptr_arg.rs | 6 + tests/ui/ptr_arg.stderr | 50 +- tests/ui/redundant_closure_call_fixable.fixed | 18 + tests/ui/redundant_closure_call_fixable.rs | 18 + .../ui/redundant_closure_call_fixable.stderr | 20 +- tests/ui/redundant_guards.fixed | 57 +++ tests/ui/redundant_guards.rs | 57 +++ tests/ui/redundant_guards.stderr | 86 +++- tests/ui/result_map_or_into_option.fixed | 7 + tests/ui/result_map_or_into_option.rs | 7 + tests/ui/result_map_or_into_option.stderr | 16 +- tests/ui/single_element_loop.fixed | 12 +- tests/ui/single_element_loop.stderr | 72 +-- tests/ui/test_attr_in_doctest.rs | 51 ++ tests/ui/test_attr_in_doctest.stderr | 29 ++ tests/ui/transmute_ptr_to_ptr.fixed | 3 + tests/ui/transmute_ptr_to_ptr.rs | 3 + tests/ui/transmute_ptr_to_ptr.stderr | 8 +- tests/ui/transmute_ref_to_ref.rs | 18 + tests/ui/transmute_ref_to_ref.stderr | 26 + tests/ui/unnecessary_lazy_eval.fixed | 78 +++ tests/ui/unnecessary_lazy_eval.rs | 78 +++ tests/ui/unnecessary_lazy_eval.stderr | 266 ++++++++-- tests/ui/upper_case_acronyms.fixed | 8 + tests/ui/upper_case_acronyms.rs | 8 + tests/ui/upper_case_acronyms.stderr | 8 +- 417 files changed, 3662 insertions(+), 1176 deletions(-) create mode 100644 clippy_lints/src/doc/link_with_quotes.rs create mode 100644 clippy_lints/src/doc/markdown.rs create mode 100644 clippy_lints/src/doc/missing_headers.rs rename clippy_lints/src/{doc.rs => doc/mod.rs} (60%) create mode 100644 clippy_lints/src/doc/needless_doctest_main.rs create mode 100644 clippy_lints/src/doc/suspicious_doc_comments.rs create mode 100644 clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs create mode 100644 clippy_lints/src/methods/join_absolute_paths.rs create mode 100644 clippy_lints/src/methods/option_map_or_err_ok.rs create mode 100644 clippy_lints/src/methods/result_map_or_else_none.rs create mode 100644 tests/ui-toml/private-doc-errors/clippy.toml create mode 100644 tests/ui-toml/private-doc-errors/doc_lints.rs create mode 100644 tests/ui-toml/private-doc-errors/doc_lints.stderr create mode 100644 tests/ui/impl_hash_with_borrow_str_and_bytes.rs create mode 100644 tests/ui/impl_hash_with_borrow_str_and_bytes.stderr create mode 100644 tests/ui/join_absolute_paths.rs create mode 100644 tests/ui/join_absolute_paths.stderr create mode 100644 tests/ui/option_map_or_err_ok.fixed create mode 100644 tests/ui/option_map_or_err_ok.rs create mode 100644 tests/ui/option_map_or_err_ok.stderr create mode 100644 tests/ui/test_attr_in_doctest.rs create mode 100644 tests/ui/test_attr_in_doctest.stderr create mode 100644 tests/ui/transmute_ref_to_ref.rs create mode 100644 tests/ui/transmute_ref_to_ref.stderr diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f42928c2cd1..999ee7acfe7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -52,7 +52,9 @@ jobs: run: cargo generate-lockfile - name: Cache - uses: Swatinem/rust-cache@v1.3.0 + uses: Swatinem/rust-cache@v2.7.0 + with: + save-if: ${{ github.ref == 'refs/heads/master' }} - name: cargo collect-metadata run: cargo collect-metadata diff --git a/CHANGELOG.md b/CHANGELOG.md index e74df808e06..2e9b755caa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5128,6 +5128,7 @@ Released 2018-09-13 [`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_hash_borrow_with_str_and_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_hash_borrow_with_str_and_bytes [`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 @@ -5189,6 +5190,7 @@ Released 2018-09-13 [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain [`iter_without_into_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_without_into_iter [`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero +[`join_absolute_paths`]: https://rust-lang.github.io/rust-clippy/master/index.html#join_absolute_paths [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits [`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays [`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups @@ -5380,6 +5382,7 @@ Released 2018-09-13 [`option_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_expect_used [`option_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_filter_map [`option_if_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else +[`option_map_or_err_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_err_ok [`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none [`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn [`option_map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or @@ -5542,6 +5545,7 @@ Released 2018-09-13 [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr +[`test_attr_in_doctest`]: https://rust-lang.github.io/rust-clippy/master/index.html#test_attr_in_doctest [`tests_outside_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#tests_outside_test_module [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some [`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display @@ -5738,4 +5742,5 @@ Released 2018-09-13 [`absolute-paths-allowed-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-allowed-crates [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles [`enforce-iter-loop-reborrow`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforce-iter-loop-reborrow +[`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 1803fc2d2f3..e30a5f9fe10 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -202,7 +202,7 @@ is. This file has already imported some initial things we will need: ```rust use rustc_lint::{EarlyLintPass, EarlyContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_ast::ast::*; ``` @@ -518,6 +518,8 @@ define_Conf! { [`clippy_config::msrvs`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_config/msrvs/index.html +Afterwards update the documentation for the book as described in [Adding configuration to a lint](#adding-configuration-to-a-lint). + ## Author lint If you have trouble implementing your lint, there is also the internal `author` diff --git a/book/src/development/type_checking.md b/book/src/development/type_checking.md index d7c2775b896..a8c9660da4c 100644 --- a/book/src/development/type_checking.md +++ b/book/src/development/type_checking.md @@ -119,7 +119,7 @@ an `u32`. As far as `hir::Ty` is concerned those might be different types. But a understands that they're the same type, in-depth lifetimes, etc... To get from a `hir::Ty` to a `ty::Ty`, you can use the [`hir_ty_to_ty`][hir_ty_to_ty] function outside of bodies or -outside of bodies the [`TypeckResults::node_type()`][node_type] method. +the [`TypeckResults::node_type()`][node_type] method inside of bodies. > **Warning**: Don't use `hir_ty_to_ty` inside of bodies, because this can cause ICEs. diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 841a5b6d007..2bb89321cef 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -150,6 +150,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) * [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold) * [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one) +* [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map) ## `cognitive-complexity-threshold` @@ -791,3 +792,16 @@ for _ in &mut *rmvec {} * [`explicit_iter_loop`](https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop) +## `check-private-items` + + +**Default Value:** `false` + +--- +**Affected lints:** +* [`missing_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc) +* [`unnecessary_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc) +* [`missing_panics_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc) +* [`missing_errors_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc) + + diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 47259776921..88611eb7087 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -249,7 +249,7 @@ define_Conf! { /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP. /// /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` #[default_text = ""] @@ -543,6 +543,10 @@ define_Conf! { /// for _ in &mut *rmvec {} /// ``` (enforce_iter_loop_reborrow: bool = false), + /// Lint: MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC, MISSING_PANICS_DOC, MISSING_ERRORS_DOC + /// + /// Whether to also run the listed lints on private items. + (check_private_items: bool = false), } /// Search for the configuration file. diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index 011d54629d4..b3ef666e306 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -23,6 +23,7 @@ msrv_aliases! { 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY } 1,55,0 { SEEK_REWIND } + 1,54,0 { INTO_KEYS } 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index ddc20f7f37f..31a42734c13 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -283,7 +283,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { use clippy_utils::msrvs::{{self, Msrv}}; {pass_import} use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; - use rustc_session::{{declare_tool_lint, impl_lint_pass}}; + use rustc_session::impl_lint_pass; "# ) @@ -292,7 +292,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { r#" {pass_import} use rustc_lint::{{{context_import}, {pass_type}}}; - use rustc_session::{{declare_lint_pass, declare_tool_lint}}; + use rustc_session::declare_lint_pass; "# ) diff --git a/clippy_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs index 582423603eb..83d15c0c425 100644 --- a/clippy_lints/src/absolute_paths.rs +++ b/clippy_lints/src/absolute_paths.rs @@ -5,7 +5,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::{HirId, ItemKind, Node, Path}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; declare_clippy_lint! { diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs index 98299e1e4bd..39fc49dee37 100644 --- a/clippy_lints/src/allow_attributes.rs +++ b/clippy_lints/src/allow_attributes.rs @@ -5,7 +5,7 @@ use rustc_ast as ast; use rustc_errors::Applicability; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs index e85878eb570..57a5cd8fba8 100644 --- a/clippy_lints/src/almost_complete_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -5,7 +5,7 @@ use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimit use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index b4f778f12b9..409ae0c85ac 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol; use std::f64::consts as f64; diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index 9799e703afe..657d52d0e9e 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -6,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::GenericArgKind; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index b9dda49ca41..e052d36f115 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -3,7 +3,7 @@ use clippy_utils::is_from_proc_macro; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs index 9717aa9e981..feb6437ee26 100644 --- a/clippy_lints/src/asm_syntax.rs +++ b/clippy_lints/src/asm_syntax.rs @@ -3,7 +3,7 @@ use std::fmt; use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions}; use rustc_lint::{EarlyContext, EarlyLintPass, Lint}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; #[derive(Clone, Copy, PartialEq, Eq)] enum AsmStyle { diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index b90914e936a..a15ec199a28 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index 71ec87a8874..aec22965b1b 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -9,7 +9,7 @@ use rustc_hir::def::Res; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index ec2447dae96..3e5a01c45df 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 2dcaf1f0167..da38422874b 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -17,7 +17,7 @@ use rustc_hir::{ use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; +use rustc_session::{declare_lint_pass, impl_lint_pass}; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span, DUMMY_SP}; use semver::Version; @@ -120,7 +120,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for `#[deprecated]` annotations with a `since` - /// field that is not a valid semantic version. + /// field that is not a valid semantic version. Also allows "TBD" to signal + /// future deprecation. /// /// ### Why is this bad? /// For checking the version of the deprecation, it must be @@ -405,20 +406,26 @@ declare_clippy_lint! { /// Checks for `#[cfg(features = "...")]` and suggests to replace it with /// `#[cfg(feature = "...")]`. /// + /// It also checks if `cfg(test)` was misspelled. + /// /// ### Why is this bad? - /// Misspelling `feature` as `features` can be sometimes hard to spot. It + /// Misspelling `feature` as `features` or `test` as `tests` can be sometimes hard to spot. It /// may cause conditional compilation not work quietly. /// /// ### Example /// ```no_run /// #[cfg(features = "some-feature")] /// fn conditional() { } + /// #[cfg(tests)] + /// mod tests { } /// ``` /// /// Use instead: /// ```no_run /// #[cfg(feature = "some-feature")] /// fn conditional() { } + /// #[cfg(test)] + /// mod tests { } /// ``` #[clippy::version = "1.69.0"] pub MAYBE_MISUSED_CFG, @@ -473,7 +480,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { && let MetaItemKind::NameValue(lit) = &mi.kind && mi.has_name(sym::since) { - check_semver(cx, item.span(), lit); + check_deprecated_since(cx, item.span(), lit); } } } @@ -754,9 +761,9 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribut } } -fn check_semver(cx: &LateContext<'_>, span: Span, lit: &MetaItemLit) { +fn check_deprecated_since(cx: &LateContext<'_>, span: Span, lit: &MetaItemLit) { if let LitKind::Str(is, _) = lit.kind { - if Version::parse(is.as_str()).is_ok() { + if is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok() { return; } } @@ -923,21 +930,35 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { for item in items { if let NestedMetaItem::MetaItem(meta) = item { - if meta.has_name(sym!(features)) + if let Some(ident) = meta.ident() + && ident.name.as_str() == "features" && let Some(val) = meta.value_str() { span_lint_and_sugg( cx, MAYBE_MISUSED_CFG, meta.span, - "feature may misspelled as features", - "use", + "'feature' may be misspelled as 'features'", + "did you mean", format!("feature = \"{val}\""), Applicability::MaybeIncorrect, ); } if let MetaItemKind::List(list) = &meta.kind { check_nested_misused_cfg(cx, list); + // If this is not a list, then we check for `cfg(test)`. + } else if let Some(ident) = meta.ident() + && matches!(ident.name.as_str(), "tests" | "Test") + { + span_lint_and_sugg( + cx, + MAYBE_MISUSED_CFG, + meta.span, + &format!("'test' may be misspelled as '{}'", ident.name.as_str()), + "did you mean", + "test".to_string(), + Applicability::MaybeIncorrect, + ); } } } diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 06b74b972b7..9894a163961 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Body, CoroutineKind, CoroutineSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 28bd3fc7011..692309629b7 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index 665dbd6f708..74201e9cc30 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Lit}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Ident; declare_clippy_lint! { diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs index 156cb34df9c..cfb76cab6dc 100644 --- a/clippy_lints/src/bool_to_int_with_if.rs +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -2,7 +2,7 @@ use clippy_utils::higher::If; use rustc_ast::LitKind; use rustc_hir::{Block, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::Sugg; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 2cb599964d2..e11f83f2260 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; use rustc_lint::{LateContext, LateLintPass, Level}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 789cd3b6c21..d3d4f3c41c8 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -8,7 +8,7 @@ use rustc_hir::{ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::Mutability; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index 9c78c6e532d..ef12fe344e4 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::IsSuggestable; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { @@ -45,7 +45,7 @@ impl LateLintPass<'_> for BoxDefault { && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_new.kind && let ExprKind::Call(arg_path, ..) = arg.kind && !in_external_macro(cx.sess(), expr.span) - && (expr.span.eq_ctxt(arg.span) || is_vec_expn(cx, arg)) + && (expr.span.eq_ctxt(arg.span) || is_local_vec_expn(cx, arg, expr)) && seg.ident.name == sym::new && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box()) && is_default_equivalent(cx, arg) @@ -81,10 +81,10 @@ fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool { } } -fn is_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - macro_backtrace(expr.span) - .next() - .map_or(false, |call| cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id)) +fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) -> bool { + macro_backtrace(expr.span).next().map_or(false, |call| { + cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id) && call.span.eq_ctxt(ref_expr.span) + }) } #[derive(Default)] diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index 3a872e54c9a..fea6924d89e 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -8,7 +8,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_lint_allowed; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_lint::{LateContext, LateLintPass, Lint}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::DUMMY_SP; declare_clippy_lint! { diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 49a90a2f3c2..e05b8f66d86 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -27,7 +27,7 @@ use clippy_utils::is_hir_ty_cfg_dependant; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 69fa0821e3f..92810ea2aa0 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 74ecaa60c7c..60f436dc5d2 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -10,7 +10,7 @@ use rustc_ast::ast::Attribute; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, BytePos, Span}; diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index e5aaf88ab6c..07b02c98df1 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -18,7 +18,7 @@ use clippy_utils::sugg::Sugg; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index 1dfc2e251d9..d0c989cfff3 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -5,7 +5,7 @@ use clippy_utils::{get_enclosing_block, get_parent_node, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir::{Block, ExprKind, HirId, LangItem, Local, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; use rustc_span::Symbol; diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 0fe973b49a3..2c23c0b4f15 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::implements_trait; use clippy_utils::{if_sequence, in_constant, is_else_clause, SpanlessEq}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 3b6d4886ba3..d91af76f5e0 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -13,7 +13,7 @@ use rustc_hir::def_id::DefIdSet; use rustc_hir::{intravisit, BinOpKind, Block, Expr, ExprKind, HirId, HirIdSet, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::query::Key; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Span, Symbol}; diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs index db850edd640..50fd76a3a47 100644 --- a/clippy_lints/src/copy_iterator.rs +++ b/clippy_lints/src/copy_iterator.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::ty::is_copy; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index 637d5aae1be..d4828778be2 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -4,7 +4,7 @@ use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 97b736dfd8f..7a3d5a07091 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index 4774917c7b5..9424a9103db 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -5,7 +5,7 @@ use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 85854a0dfb7..b440e267efe 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -140,6 +140,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::doc::MISSING_SAFETY_DOC_INFO, crate::doc::NEEDLESS_DOCTEST_MAIN_INFO, crate::doc::SUSPICIOUS_DOC_COMMENTS_INFO, + crate::doc::TEST_ATTR_IN_DOCTEST_INFO, crate::doc::UNNECESSARY_SAFETY_DOC_INFO, crate::double_parens::DOUBLE_PARENS_INFO, crate::drop_forget_ref::DROP_NON_DROP_INFO, @@ -204,6 +205,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::if_not_else::IF_NOT_ELSE_INFO, crate::if_then_some_else_none::IF_THEN_SOME_ELSE_NONE_INFO, crate::ignored_unit_patterns::IGNORED_UNIT_PATTERNS_INFO, + crate::impl_hash_with_borrow_str_and_bytes::IMPL_HASH_BORROW_WITH_STR_AND_BYTES_INFO, crate::implicit_hasher::IMPLICIT_HASHER_INFO, crate::implicit_return::IMPLICIT_RETURN_INFO, crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO, @@ -376,6 +378,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::ITER_SKIP_NEXT_INFO, crate::methods::ITER_SKIP_ZERO_INFO, crate::methods::ITER_WITH_DRAIN_INFO, + crate::methods::JOIN_ABSOLUTE_PATHS_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, crate::methods::MANUAL_NEXT_BACK_INFO, @@ -403,6 +406,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::OK_EXPECT_INFO, crate::methods::OPTION_AS_REF_DEREF_INFO, crate::methods::OPTION_FILTER_MAP_INFO, + crate::methods::OPTION_MAP_OR_ERR_OK_INFO, crate::methods::OPTION_MAP_OR_NONE_INFO, crate::methods::OR_FUN_CALL_INFO, crate::methods::OR_THEN_UNWRAP_INFO, diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index b325449c5a3..d8a070b785d 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -9,7 +9,7 @@ use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index b90d01b765a..9ce5acfbcc2 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index 553b670fdb7..2472e2ee76f 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, SyntaxContext}; declare_clippy_lint! { diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index fb29703957d..64a924a776a 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -8,7 +8,7 @@ use rustc_hir::{Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::iter; declare_clippy_lint! { diff --git a/clippy_lints/src/default_union_representation.rs b/clippy_lints/src/default_union_representation.rs index 8c6749a95fa..db01ff2cd22 100644 --- a/clippy_lints/src/default_union_representation.rs +++ b/clippy_lints/src/default_union_representation.rs @@ -3,7 +3,7 @@ use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, FieldDef, GenericArg, List}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index cbeb0050be0..854324f845b 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -17,7 +17,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt, TypeckResults}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 9db56fa8ad0..53ef6d7e387 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -10,7 +10,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, PointerCoercion}; use rustc_middle::ty::{self, Adt, AdtDef, GenericArgsRef, Ty, TypeckResults}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 64573ac4d53..61faaa10b8a 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{ self, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate, TraitPredicate, Ty, TyCtxt, }; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index 324b5e0798e..656b3d9bfaf 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{ExpnId, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index d23aeebb5a8..1868d3cd391 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -4,7 +4,7 @@ use clippy_utils::{fn_def_id, get_parent_expr, path_def_id}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/disallowed_names.rs b/clippy_lints/src/disallowed_names.rs index a1dd4805b9c..09dad5554ad 100644 --- a/clippy_lints/src/disallowed_names.rs +++ b/clippy_lints/src/disallowed_names.rs @@ -3,7 +3,7 @@ use clippy_utils::is_test_module_or_function; use rustc_data_structures::fx::FxHashSet; use rustc_hir::{Item, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index 96a7f0e4fde..d5205e65cef 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use unicode_script::{Script, UnicodeScript}; declare_clippy_lint! { diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index 3578fb640fc..130f56b698f 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -5,7 +5,7 @@ use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/doc/link_with_quotes.rs b/clippy_lints/src/doc/link_with_quotes.rs new file mode 100644 index 00000000000..01191e811b0 --- /dev/null +++ b/clippy_lints/src/doc/link_with_quotes.rs @@ -0,0 +1,20 @@ +use std::ops::Range; + +use clippy_utils::diagnostics::span_lint; +use rustc_lint::LateContext; + +use super::{Fragments, DOC_LINK_WITH_QUOTES}; + +pub fn check(cx: &LateContext<'_>, trimmed_text: &str, range: Range, fragments: Fragments<'_>) { + if ((trimmed_text.starts_with('\'') && trimmed_text.ends_with('\'')) + || (trimmed_text.starts_with('"') && trimmed_text.ends_with('"'))) + && let Some(span) = fragments.span(cx, range) + { + span_lint( + cx, + DOC_LINK_WITH_QUOTES, + span, + "possible intra-doc link using quotes instead of backticks", + ); + } +} diff --git a/clippy_lints/src/doc/markdown.rs b/clippy_lints/src/doc/markdown.rs new file mode 100644 index 00000000000..c0b11eb0dd1 --- /dev/null +++ b/clippy_lints/src/doc/markdown.rs @@ -0,0 +1,109 @@ +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::source::snippet_with_applicability; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_lint::LateContext; +use rustc_span::{BytePos, Pos, Span}; +use url::Url; + +use crate::doc::DOC_MARKDOWN; + +pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet, text: &str, span: Span) { + for word in text.split(|c: char| c.is_whitespace() || c == '\'') { + // Trim punctuation as in `some comment (see foo::bar).` + // ^^ + // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix. + let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':'); + + // Remove leading or trailing single `:` which may be part of a sentence. + if word.starts_with(':') && !word.starts_with("::") { + word = word.trim_start_matches(':'); + } + if word.ends_with(':') && !word.ends_with("::") { + word = word.trim_end_matches(':'); + } + + if valid_idents.contains(word) || word.chars().all(|c| c == ':') { + continue; + } + + // Adjust for the current word + let offset = word.as_ptr() as usize - text.as_ptr() as usize; + let span = Span::new( + span.lo() + BytePos::from_usize(offset), + span.lo() + BytePos::from_usize(offset + word.len()), + span.ctxt(), + span.parent(), + ); + + check_word(cx, word, span); + } +} + +fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { + /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and + /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case + /// letter (`NASA` is ok). + /// Plurals are also excluded (`IDs` is ok). + fn is_camel_case(s: &str) -> bool { + if s.starts_with(|c: char| c.is_ascii_digit() | c.is_ascii_lowercase()) { + return false; + } + + let s = s.strip_suffix('s').unwrap_or(s); + + s.chars().all(char::is_alphanumeric) + && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 + && s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0 + } + + fn has_underscore(s: &str) -> bool { + s != "_" && !s.contains("\\_") && s.contains('_') + } + + fn has_hyphen(s: &str) -> bool { + s != "-" && s.contains('-') + } + + if let Ok(url) = Url::parse(word) { + // try to get around the fact that `foo::bar` parses as a valid URL + if !url.cannot_be_a_base() { + span_lint( + cx, + DOC_MARKDOWN, + span, + "you should put bare URLs between `<`/`>` or make a proper Markdown link", + ); + + return; + } + } + + // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343) + if has_underscore(word) && has_hyphen(word) { + return; + } + + if has_underscore(word) || word.contains("::") || is_camel_case(word) { + let mut applicability = Applicability::MachineApplicable; + + span_lint_and_then( + cx, + DOC_MARKDOWN, + span, + "item in documentation is missing backticks", + |diag| { + let snippet = snippet_with_applicability(cx, span, "..", &mut applicability); + diag.span_suggestion_with_style( + span, + "try", + format!("`{snippet}`"), + applicability, + // always show the suggestion in a separate line, since the + // inline presentation adds another pair of backticks + SuggestionStyle::ShowAlways, + ); + }, + ); + } +} diff --git a/clippy_lints/src/doc/missing_headers.rs b/clippy_lints/src/doc/missing_headers.rs new file mode 100644 index 00000000000..4cbfa97a8a3 --- /dev/null +++ b/clippy_lints/src/doc/missing_headers.rs @@ -0,0 +1,86 @@ +use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::{is_doc_hidden, return_ty}; +use rustc_hir::{BodyId, FnSig, OwnerId, Unsafety}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::{sym, Span}; + +use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC}; + +pub fn check( + cx: &LateContext<'_>, + owner_id: OwnerId, + sig: &FnSig<'_>, + headers: DocHeaders, + body_id: Option, + panic_span: Option, + check_private_items: bool, +) { + if !check_private_items && !cx.effective_visibilities.is_exported(owner_id.def_id) { + return; // Private functions do not require doc comments + } + + // do not lint if any parent has `#[doc(hidden)]` attribute (#7347) + if !check_private_items + && cx + .tcx + .hir() + .parent_iter(owner_id.into()) + .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id))) + { + return; + } + + let span = cx.tcx.def_span(owner_id); + match (headers.safety, sig.header.unsafety) { + (false, Unsafety::Unsafe) => span_lint( + cx, + MISSING_SAFETY_DOC, + span, + "unsafe function's docs miss `# Safety` section", + ), + (true, Unsafety::Normal) => span_lint( + cx, + UNNECESSARY_SAFETY_DOC, + span, + "safe function's docs have unnecessary `# Safety` section", + ), + _ => (), + } + if !headers.panics && panic_span.is_some() { + span_lint_and_note( + cx, + MISSING_PANICS_DOC, + span, + "docs for function which may panic missing `# Panics` section", + panic_span, + "first possible panic found here", + ); + } + if !headers.errors { + if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) { + span_lint( + cx, + MISSING_ERRORS_DOC, + span, + "docs for function returning `Result` missing `# Errors` section", + ); + } else if let Some(body_id) = body_id + && let Some(future) = cx.tcx.lang_items().future_trait() + && let typeck = cx.tcx.typeck_body(body_id) + && let body = cx.tcx.hir().body(body_id) + && let ret_ty = typeck.expr_ty(body.value) + && implements_trait(cx, ret_ty, future, &[]) + && let ty::Coroutine(_, subs, _) = ret_ty.kind() + && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result) + { + span_lint( + cx, + MISSING_ERRORS_DOC, + span, + "docs for function returning `Result` missing `# Errors` section", + ); + } + } +} diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc/mod.rs similarity index 60% rename from clippy_lints/src/doc.rs rename to clippy_lints/src/doc/mod.rs index ca277e7eded..ba452775015 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc/mod.rs @@ -1,21 +1,16 @@ use clippy_utils::attrs::is_doc_hidden; -use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::visitors::Visitable; +use clippy_utils::{is_entrypoint_fn, method_chain_args}; use pulldown_cmark::Event::{ Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text, }; use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph}; use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options}; -use rustc_ast::ast::{Async, Attribute, Fn, FnRetTy, ItemKind}; -use rustc_ast::token::CommentKind; -use rustc_ast::{AttrKind, AttrStyle}; +use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sync::Lrc; -use rustc_errors::emitter::EmitterWriter; -use rustc_errors::{Applicability, Handler, SuggestionStyle}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AnonConst, Expr}; @@ -23,20 +18,21 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_parse::maybe_new_parser_from_source_str; -use rustc_parse::parser::ForceCollect; use rustc_resolve::rustdoc::{ add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, DocFragment, }; -use rustc_session::parse::ParseSess; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; -use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::{sym, BytePos, FileName, Pos, Span}; +use rustc_span::{sym, Span}; use std::ops::Range; -use std::{io, thread}; use url::Url; +mod link_with_quotes; +mod markdown; +mod missing_headers; +mod needless_doctest_main; +mod suspicious_doc_comments; + declare_clippy_lint! { /// ### What it does /// Checks for the presence of `_`, `::` or camel-case words @@ -203,6 +199,39 @@ declare_clippy_lint! { "presence of `fn main() {` in code examples" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `#[test]` in doctests unless they are marked with + /// either `ignore`, `no_run` or `compile_fail`. + /// + /// ### Why is this bad? + /// Code in examples marked as `#[test]` will somewhat + /// surprisingly not be run by `cargo test`. If you really want + /// to show how to test stuff in an example, mark it `no_run` to + /// make the intent clear. + /// + /// ### Examples + /// ```no_run + /// /// An example of a doctest with a `main()` function + /// /// + /// /// # Examples + /// /// + /// /// ``` + /// /// #[test] + /// /// fn equality_works() { + /// /// assert_eq!(1_u8, 1); + /// /// } + /// /// ``` + /// fn test_attr_in_doctest() { + /// unimplemented!(); + /// } + /// ``` + #[clippy::version = "1.40.0"] + pub TEST_ATTR_IN_DOCTEST, + suspicious, + "presence of `#[test]` in code examples" +} + declare_clippy_lint! { /// ### What it does /// Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks) @@ -309,34 +338,36 @@ declare_clippy_lint! { "suspicious usage of (outer) doc comments" } -#[expect(clippy::module_name_repetitions)] #[derive(Clone)] -pub struct DocMarkdown { +pub struct Documentation { valid_idents: FxHashSet, in_trait_impl: bool, + check_private_items: bool, } -impl DocMarkdown { - pub fn new(valid_idents: &[String]) -> Self { +impl Documentation { + pub fn new(valid_idents: &[String], check_private_items: bool) -> Self { Self { valid_idents: valid_idents.iter().cloned().collect(), in_trait_impl: false, + check_private_items, } } } -impl_lint_pass!(DocMarkdown => [ +impl_lint_pass!(Documentation => [ DOC_LINK_WITH_QUOTES, DOC_MARKDOWN, MISSING_SAFETY_DOC, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, NEEDLESS_DOCTEST_MAIN, + TEST_ATTR_IN_DOCTEST, UNNECESSARY_SAFETY_DOC, SUSPICIOUS_DOC_COMMENTS ]); -impl<'tcx> LateLintPass<'tcx> for DocMarkdown { +impl<'tcx> LateLintPass<'tcx> for Documentation { fn check_crate(&mut self, cx: &LateContext<'tcx>) { let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID); check_attrs(cx, &self.valid_idents, attrs); @@ -351,13 +382,17 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { hir::ItemKind::Fn(ref sig, _, body_id) => { if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) { let body = cx.tcx.hir().body(body_id); - let mut fpu = FindPanicUnwrap { + + let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); + missing_headers::check( cx, - typeck_results: cx.tcx.typeck(item.owner_id.def_id), - panic_span: None, - }; - fpu.visit_expr(body.value); - lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span); + item.owner_id, + sig, + headers, + Some(body_id), + panic_span, + self.check_private_items, + ); } }, hir::ItemKind::Impl(impl_) => { @@ -395,7 +430,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { }; if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind { if !in_external_macro(cx.tcx.sess, item.span) { - lint_for_missing_headers(cx, item.owner_id, sig, headers, None, None); + missing_headers::check(cx, item.owner_id, sig, headers, None, None, self.check_private_items); } } } @@ -410,87 +445,16 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { } if let hir::ImplItemKind::Fn(ref sig, body_id) = item.kind { let body = cx.tcx.hir().body(body_id); - let mut fpu = FindPanicUnwrap { - cx, - typeck_results: cx.tcx.typeck(item.owner_id.def_id), - panic_span: None, - }; - fpu.visit_expr(body.value); - lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span); - } - } -} -fn lint_for_missing_headers( - cx: &LateContext<'_>, - owner_id: hir::OwnerId, - sig: &hir::FnSig<'_>, - headers: DocHeaders, - body_id: Option, - panic_span: Option, -) { - if !cx.effective_visibilities.is_exported(owner_id.def_id) { - return; // Private functions do not require doc comments - } - - // do not lint if any parent has `#[doc(hidden)]` attribute (#7347) - if cx - .tcx - .hir() - .parent_iter(owner_id.into()) - .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id))) - { - return; - } - - let span = cx.tcx.def_span(owner_id); - match (headers.safety, sig.header.unsafety) { - (false, hir::Unsafety::Unsafe) => span_lint( - cx, - MISSING_SAFETY_DOC, - span, - "unsafe function's docs miss `# Safety` section", - ), - (true, hir::Unsafety::Normal) => span_lint( - cx, - UNNECESSARY_SAFETY_DOC, - span, - "safe function's docs have unnecessary `# Safety` section", - ), - _ => (), - } - if !headers.panics && panic_span.is_some() { - span_lint_and_note( - cx, - MISSING_PANICS_DOC, - span, - "docs for function which may panic missing `# Panics` section", - panic_span, - "first possible panic found here", - ); - } - if !headers.errors { - if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) { - span_lint( + let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); + missing_headers::check( cx, - MISSING_ERRORS_DOC, - span, - "docs for function returning `Result` missing `# Errors` section", - ); - } else if let Some(body_id) = body_id - && let Some(future) = cx.tcx.lang_items().future_trait() - && let typeck = cx.tcx.typeck_body(body_id) - && let body = cx.tcx.hir().body(body_id) - && let ret_ty = typeck.expr_ty(body.value) - && implements_trait(cx, ret_ty, future, &[]) - && let ty::Coroutine(_, subs, _) = ret_ty.kind() - && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result) - { - span_lint( - cx, - MISSING_ERRORS_DOC, - span, - "docs for function returning `Result` missing `# Errors` section", + item.owner_id, + sig, + headers, + Some(body_id), + panic_span, + self.check_private_items, ); } } @@ -515,6 +479,13 @@ struct DocHeaders { panics: bool, } +/// Does some pre-processing on raw, desugared `#[doc]` attributes such as parsing them and +/// then delegates to `check_doc`. +/// Some lints are already checked here if they can work with attributes directly and don't need +/// to work with markdown. +/// Others are checked elsewhere, e.g. in `check_doc` if they need access to markdown, or +/// back in the various late lint pass methods if they need the final doc headers, like "Safety" or +/// "Panics" sections. fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[Attribute]) -> Option { /// We don't want the parser to choke on intra doc links. Since we don't /// actually care about rendering them, just pretend that all broken links @@ -528,7 +499,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ return None; } - check_almost_inner_doc(cx, attrs); + suspicious_doc_comments::check(cx, attrs); let (fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true); let mut doc = String::new(); @@ -558,45 +529,12 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ )) } -/// Looks for `///!` and `/**!` comments, which were probably meant to be `//!` and `/*!` -fn check_almost_inner_doc(cx: &LateContext<'_>, attrs: &[Attribute]) { - let replacements: Vec<_> = attrs - .iter() - .filter_map(|attr| { - if let AttrKind::DocComment(com_kind, sym) = attr.kind - && let AttrStyle::Outer = attr.style - && let Some(com) = sym.as_str().strip_prefix('!') - { - let sugg = match com_kind { - CommentKind::Line => format!("//!{com}"), - CommentKind::Block => format!("/*!{com}*/"), - }; - Some((attr.span, sugg)) - } else { - None - } - }) - .collect(); - - if let Some((&(lo_span, _), &(hi_span, _))) = replacements.first().zip(replacements.last()) { - span_lint_and_then( - cx, - SUSPICIOUS_DOC_COMMENTS, - lo_span.to(hi_span), - "this is an outer doc comment and does not apply to the parent module or crate", - |diag| { - diag.multipart_suggestion( - "use an inner doc comment to document the parent module or crate", - replacements, - Applicability::MaybeIncorrect, - ); - }, - ); - } -} - const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"]; +/// Checks parsed documentation. +/// This walks the "events" (think sections of markdown) produced by `pulldown_cmark`, +/// so lints here will generally access that information. +/// Returns documentation headers -- whether a "Safety", "Errors", "Panic" section was found #[allow(clippy::too_many_lines)] // Only a big match statement fn check_doc<'a, Events: Iterator, Range)>>( cx: &LateContext<'_>, @@ -611,6 +549,7 @@ fn check_doc<'a, Events: Iterator, Range, Range)> = Vec::new(); @@ -626,6 +565,8 @@ fn check_doc<'a, Events: Iterator, Range, Range { in_code = false; is_rust = false; + ignore = false; }, Start(Link(_, url, _)) => in_link = Some(url), End(Link(..)) => in_link = None, @@ -665,7 +607,7 @@ fn check_doc<'a, Events: Iterator, Range, Range, Range, trimmed_text: &str, range: Range, fragments: Fragments<'_>) { - if trimmed_text.starts_with('\'') - && trimmed_text.ends_with('\'') - && let Some(span) = fragments.span(cx, range) - { - span_lint( - cx, - DOC_LINK_WITH_QUOTES, - span, - "possible intra-doc link using quotes instead of backticks", - ); - } -} - -fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range, fragments: Fragments<'_>) { - fn has_needless_main(code: String, edition: Edition) -> bool { - rustc_driver::catch_fatal_errors(|| { - rustc_span::create_session_globals_then(edition, || { - let filename = FileName::anon_source_code(&code); - - let fallback_bundle = - rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false); - let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle); - let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings(); - #[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_span_handler - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sess = ParseSess::with_span_handler(handler, sm); - - let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) { - Ok(p) => p, - Err(errs) => { - drop(errs); - return false; - }, - }; - - let mut relevant_main_found = false; - loop { - match parser.parse_item(ForceCollect::No) { - Ok(Some(item)) => match &item.kind { - ItemKind::Fn(box Fn { - sig, body: Some(block), .. - }) if item.ident.name == sym::main => { - let is_async = matches!(sig.header.asyncness, Async::Yes { .. }); - let returns_nothing = match &sig.decl.output { - FnRetTy::Default(..) => true, - FnRetTy::Ty(ty) if ty.kind.is_unit() => true, - FnRetTy::Ty(_) => false, - }; - - if returns_nothing && !is_async && !block.stmts.is_empty() { - // This main function should be linted, but only if there are no other functions - relevant_main_found = true; - } else { - // This main function should not be linted, we're done - return false; - } - }, - // Tests with one of these items are ignored - ItemKind::Static(..) - | ItemKind::Const(..) - | ItemKind::ExternCrate(..) - | ItemKind::ForeignMod(..) - // Another function was found; this case is ignored - | ItemKind::Fn(..) => return false, - _ => {}, - }, - Ok(None) => break, - Err(e) => { - e.cancel(); - return false; - }, - } - } - - relevant_main_found - }) - }) - .ok() - .unwrap_or_default() - } - - let trailing_whitespace = text.len() - text.trim_end().len(); - - // Because of the global session, we need to create a new session in a different thread with - // the edition we need. - let text = text.to_owned(); - if thread::spawn(move || has_needless_main(text, edition)) - .join() - .expect("thread::spawn failed") - && let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace) - { - span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest"); - } -} - -fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet, text: &str, span: Span) { - for word in text.split(|c: char| c.is_whitespace() || c == '\'') { - // Trim punctuation as in `some comment (see foo::bar).` - // ^^ - // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix. - let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':'); - - // Remove leading or trailing single `:` which may be part of a sentence. - if word.starts_with(':') && !word.starts_with("::") { - word = word.trim_start_matches(':'); - } - if word.ends_with(':') && !word.ends_with("::") { - word = word.trim_end_matches(':'); - } - - if valid_idents.contains(word) || word.chars().all(|c| c == ':') { - continue; - } - - // Adjust for the current word - let offset = word.as_ptr() as usize - text.as_ptr() as usize; - let span = Span::new( - span.lo() + BytePos::from_usize(offset), - span.lo() + BytePos::from_usize(offset + word.len()), - span.ctxt(), - span.parent(), - ); - - check_word(cx, word, span); - } -} - -fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { - /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and - /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case - /// letter (`NASA` is ok). - /// Plurals are also excluded (`IDs` is ok). - fn is_camel_case(s: &str) -> bool { - if s.starts_with(|c: char| c.is_ascii_digit() | c.is_ascii_lowercase()) { - return false; - } - - let s = s.strip_suffix('s').unwrap_or(s); - - s.chars().all(char::is_alphanumeric) - && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 - && s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0 - } - - fn has_underscore(s: &str) -> bool { - s != "_" && !s.contains("\\_") && s.contains('_') - } - - fn has_hyphen(s: &str) -> bool { - s != "-" && s.contains('-') - } - - if let Ok(url) = Url::parse(word) { - // try to get around the fact that `foo::bar` parses as a valid URL - if !url.cannot_be_a_base() { - span_lint( - cx, - DOC_MARKDOWN, - span, - "you should put bare URLs between `<`/`>` or make a proper Markdown link", - ); - - return; - } - } - - // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343) - if has_underscore(word) && has_hyphen(word) { - return; - } - - if has_underscore(word) || word.contains("::") || is_camel_case(word) { - let mut applicability = Applicability::MachineApplicable; - - span_lint_and_then( - cx, - DOC_MARKDOWN, - span, - "item in documentation is missing backticks", - |diag| { - let snippet = snippet_with_applicability(cx, span, "..", &mut applicability); - diag.span_suggestion_with_style( - span, - "try", - format!("`{snippet}`"), - applicability, - // always show the suggestion in a separate line, since the - // inline presentation adds another pair of backticks - SuggestionStyle::ShowAlways, - ); - }, - ); - } -} - struct FindPanicUnwrap<'a, 'tcx> { cx: &'a LateContext<'tcx>, panic_span: Option, typeck_results: &'tcx ty::TypeckResults<'tcx>, } +impl<'a, 'tcx> FindPanicUnwrap<'a, 'tcx> { + pub fn find_span( + cx: &'a LateContext<'tcx>, + typeck_results: &'tcx ty::TypeckResults<'tcx>, + body: impl Visitable<'tcx>, + ) -> Option { + let mut vis = Self { + cx, + panic_span: None, + typeck_results, + }; + body.visit(&mut vis); + vis.panic_span + } +} + impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; diff --git a/clippy_lints/src/doc/needless_doctest_main.rs b/clippy_lints/src/doc/needless_doctest_main.rs new file mode 100644 index 00000000000..e50e83834c1 --- /dev/null +++ b/clippy_lints/src/doc/needless_doctest_main.rs @@ -0,0 +1,135 @@ +use std::ops::Range; +use std::{io, thread}; + +use crate::doc::{NEEDLESS_DOCTEST_MAIN, TEST_ATTR_IN_DOCTEST}; +use clippy_utils::diagnostics::span_lint; +use rustc_ast::{Async, Fn, FnRetTy, Item, ItemKind}; +use rustc_data_structures::sync::Lrc; +use rustc_errors::emitter::EmitterWriter; +use rustc_errors::Handler; +use rustc_lint::LateContext; +use rustc_parse::maybe_new_parser_from_source_str; +use rustc_parse::parser::ForceCollect; +use rustc_session::parse::ParseSess; +use rustc_span::edition::Edition; +use rustc_span::source_map::{FilePathMapping, SourceMap}; +use rustc_span::{sym, FileName, Pos}; + +use super::Fragments; + +fn get_test_spans(item: &Item, test_attr_spans: &mut Vec>) { + test_attr_spans.extend( + item.attrs + .iter() + .find(|attr| attr.has_name(sym::test)) + .map(|attr| attr.span.lo().to_usize()..item.ident.span.hi().to_usize()), + ); +} + +pub fn check( + cx: &LateContext<'_>, + text: &str, + edition: Edition, + range: Range, + fragments: Fragments<'_>, + ignore: bool, +) { + // return whether the code contains a needless `fn main` plus a vector of byte position ranges + // of all `#[test]` attributes in not ignored code examples + fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec>) { + rustc_driver::catch_fatal_errors(|| { + rustc_span::create_session_globals_then(edition, || { + let mut test_attr_spans = vec![]; + let filename = FileName::anon_source_code(&code); + + let fallback_bundle = + rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false); + let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle); + let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings(); + #[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_span_handler + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sess = ParseSess::with_span_handler(handler, sm); + + let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) { + Ok(p) => p, + Err(errs) => { + drop(errs); + return (false, test_attr_spans); + }, + }; + + let mut relevant_main_found = false; + let mut eligible = true; + loop { + match parser.parse_item(ForceCollect::No) { + Ok(Some(item)) => match &item.kind { + ItemKind::Fn(box Fn { + sig, body: Some(block), .. + }) if item.ident.name == sym::main => { + if !ignore { + get_test_spans(&item, &mut test_attr_spans); + } + let is_async = matches!(sig.header.asyncness, Async::Yes { .. }); + let returns_nothing = match &sig.decl.output { + FnRetTy::Default(..) => true, + FnRetTy::Ty(ty) if ty.kind.is_unit() => true, + FnRetTy::Ty(_) => false, + }; + + if returns_nothing && !is_async && !block.stmts.is_empty() { + // This main function should be linted, but only if there are no other functions + relevant_main_found = true; + } else { + // This main function should not be linted, we're done + eligible = false; + } + }, + // Another function was found; this case is ignored for needless_doctest_main + ItemKind::Fn(box Fn { .. }) => { + eligible = false; + if !ignore { + get_test_spans(&item, &mut test_attr_spans); + } + }, + // Tests with one of these items are ignored + ItemKind::Static(..) + | ItemKind::Const(..) + | ItemKind::ExternCrate(..) + | ItemKind::ForeignMod(..) => { + eligible = false; + }, + _ => {}, + }, + Ok(None) => break, + Err(e) => { + e.cancel(); + return (false, test_attr_spans); + }, + } + } + + (relevant_main_found & eligible, test_attr_spans) + }) + }) + .ok() + .unwrap_or_default() + } + + let trailing_whitespace = text.len() - text.trim_end().len(); + + // Because of the global session, we need to create a new session in a different thread with + // the edition we need. + let text = text.to_owned(); + let (has_main, test_attr_spans) = thread::spawn(move || check_code_sample(text, edition, ignore)) + .join() + .expect("thread::spawn failed"); + if has_main && let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace) { + span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest"); + } + for span in test_attr_spans { + let span = (range.start + span.start)..(range.start + span.end); + if let Some(span) = fragments.span(cx, span) { + span_lint(cx, TEST_ATTR_IN_DOCTEST, span, "unit tests in doctest are not executed"); + } + } +} diff --git a/clippy_lints/src/doc/suspicious_doc_comments.rs b/clippy_lints/src/doc/suspicious_doc_comments.rs new file mode 100644 index 00000000000..d7ad30efec3 --- /dev/null +++ b/clippy_lints/src/doc/suspicious_doc_comments.rs @@ -0,0 +1,48 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_ast::token::CommentKind; +use rustc_ast::{AttrKind, AttrStyle, Attribute}; +use rustc_errors::Applicability; +use rustc_lint::LateContext; +use rustc_span::Span; + +use super::SUSPICIOUS_DOC_COMMENTS; + +pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) { + let replacements: Vec<_> = collect_doc_replacements(attrs); + + if let Some((&(lo_span, _), &(hi_span, _))) = replacements.first().zip(replacements.last()) { + span_lint_and_then( + cx, + SUSPICIOUS_DOC_COMMENTS, + lo_span.to(hi_span), + "this is an outer doc comment and does not apply to the parent module or crate", + |diag| { + diag.multipart_suggestion( + "use an inner doc comment to document the parent module or crate", + replacements, + Applicability::MaybeIncorrect, + ); + }, + ); + } +} + +fn collect_doc_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> { + attrs + .iter() + .filter_map(|attr| { + if let AttrKind::DocComment(com_kind, sym) = attr.kind + && let AttrStyle::Outer = attr.style + && let Some(com) = sym.as_str().strip_prefix('!') + { + let sugg = match com_kind { + CommentKind::Line => format!("//!{com}"), + CommentKind::Block => format!("/*!{com}*/"), + }; + Some((attr.span, sugg)) + } else { + None + } + }) + .collect() +} diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 63f32173b05..b51bb7951b7 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 177e04dfa6b..124d78fc4ff 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item}; use clippy_utils::{get_parent_node, is_must_use_func_call}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use std::borrow::Cow; diff --git a/clippy_lints/src/duplicate_mod.rs b/clippy_lints/src/duplicate_mod.rs index 7ff7068f0b0..471335c098f 100644 --- a/clippy_lints/src/duplicate_mod.rs +++ b/clippy_lints/src/duplicate_mod.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Crate, Inline, Item, ItemKind, ModKind}; use rustc_errors::MultiSpan; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{FileName, Span}; use std::collections::BTreeMap; use std::path::PathBuf; diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index 61db1c1abd1..47780cab9ed 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/empty_drop.rs b/clippy_lints/src/empty_drop.rs index 17be95780cc..e97030cc8b6 100644 --- a/clippy_lints/src/empty_drop.rs +++ b/clippy_lints/src/empty_drop.rs @@ -3,7 +3,7 @@ use clippy_utils::peel_blocks; use rustc_errors::Applicability; use rustc_hir::{Body, ExprKind, Impl, ImplItemKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs index a5699727b5b..420888b6ccb 100644 --- a/clippy_lints/src/empty_enum.rs +++ b/clippy_lints/src/empty_enum.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/empty_structs_with_brackets.rs b/clippy_lints/src/empty_structs_with_brackets.rs index 4e2a8b73c0a..3cf67b3ecbf 100644 --- a/clippy_lints/src/empty_structs_with_brackets.rs +++ b/clippy_lints/src/empty_structs_with_brackets.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{Item, ItemKind, VariantData}; use rustc_errors::Applicability; use rustc_lexer::TokenKind; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs index 6f5a0cb8801..b8a817e21b1 100644 --- a/clippy_lints/src/endian_bytes.rs +++ b/clippy_lints/src/endian_bytes.rs @@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Symbol; use std::borrow::Cow; diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 3e3c62e85d0..ce0a1dfdc61 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -10,7 +10,7 @@ use rustc_hir::hir_id::HirIdSet; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Block, Expr, ExprKind, Guard, HirId, Let, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{Span, SyntaxContext, DUMMY_SP}; declare_clippy_lint! { diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 003b5fc7261..30eb643c42e 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -7,7 +7,7 @@ use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, IntTy, UintTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index 630df9a84f5..3c435294252 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -6,7 +6,7 @@ use rustc_hir::{Expr, ExprKind, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does @@ -46,9 +46,12 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { pats.iter().all(unary_pattern) } match &pat.kind { - PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Never | PatKind::Or(_) => { - false - }, + PatKind::Slice(_, _, _) + | PatKind::Range(_, _, _) + | PatKind::Binding(..) + | PatKind::Wild + | PatKind::Never + | PatKind::Or(_) => false, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), diff --git a/clippy_lints/src/error_impl_error.rs b/clippy_lints/src/error_impl_error.rs index 35b1d3f9bab..8dbb47fadc5 100644 --- a/clippy_lints/src/error_impl_error.rs +++ b/clippy_lints/src/error_impl_error.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Visibility; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index af2d1c27d43..ae1e69a4f23 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -6,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, TraitRef, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; use rustc_span::Span; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index e0df87e08da..450cee4007c 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::{ self, Binder, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, GenericArgsRef, ImplPolarity, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults, }; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; @@ -220,7 +220,8 @@ fn check_inputs( params.len() == self_arg.map_or(0, |_| 1) + args.len() && params.iter().zip(self_arg.into_iter().chain(args)).all(|(p, arg)| { matches!( - p.pat.kind,PatKind::Binding(BindingAnnotation::NONE, id, _, None) + p.pat.kind, + PatKind::Binding(BindingAnnotation::NONE, id, _, None) if path_to_local_id(arg, id) ) // Only allow adjustments which change regions (i.e. re-borrowing). diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 713957bff51..c5f7212c4c0 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -3,7 +3,7 @@ use clippy_utils::{get_parent_as_impl, has_repr_attr, is_bool}; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_target::spec::abi::Abi; diff --git a/clippy_lints/src/excessive_nesting.rs b/clippy_lints/src/excessive_nesting.rs index 83480fc5eeb..4b0d11c5d1b 100644 --- a/clippy_lints/src/excessive_nesting.rs +++ b/clippy_lints/src/excessive_nesting.rs @@ -5,7 +5,7 @@ use rustc_ast::visit::{walk_block, walk_item, Visitor}; use rustc_ast::{Block, Crate, Inline, Item, ItemKind, ModKind, NodeId}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/exhaustive_items.rs b/clippy_lints/src/exhaustive_items.rs index b7e62e082e4..3a621d967f4 100644 --- a/clippy_lints/src/exhaustive_items.rs +++ b/clippy_lints/src/exhaustive_items.rs @@ -3,7 +3,7 @@ use clippy_utils::source::indent_of; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/exit.rs b/clippy_lints/src/exit.rs index 07d025f68c3..a974c10bc7d 100644 --- a/clippy_lints/src/exit.rs +++ b/clippy_lints/src/exit.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_entrypoint_fn; use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 08cb2114a2b..4e2e1d1724a 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, ExpnId}; declare_clippy_lint! { diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index d6c746901fc..538d29eb43d 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -10,7 +10,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 753f75d83a8..0446943321a 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -5,7 +5,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 663c33e8cee..38a16c5c8b0 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, FloatTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::fmt; declare_clippy_lint! { diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index d522873472b..c8b87e510ed 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_ast::ast; @@ -496,9 +496,13 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { if let BinOpKind::Sub = op { -sugg } else { sugg } }; - let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) { + let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) + && cx.typeck_results().expr_ty(rhs).is_floating_point() + { (inner_lhs, Sugg::hir(cx, inner_rhs, ".."), maybe_neg_sugg(rhs)) - } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) { + } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) + && cx.typeck_results().expr_ty(lhs).is_floating_point() + { (inner_lhs, maybe_neg_sugg(inner_rhs), Sugg::hir(cx, lhs, "..")) } else { return; diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 18ed05c1ca6..8a0cd155d21 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index c9868255dcf..8af321e4d55 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -19,7 +19,7 @@ use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::DefId; use rustc_span::edition::Edition::Edition2021; use rustc_span::{sym, Span, Symbol}; diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index ec87629a344..9360eb1fa91 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -5,7 +5,7 @@ use rustc_ast::{FormatArgsPiece, FormatTrait}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{sym, Span, Symbol}; diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index ac45f5aedfa..3901dd984f9 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_lang_item; use clippy_utils::{higher, match_def_path, paths}; use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 2ab04682f1d..c3ef6f180c9 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_opt; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/four_forward_slashes.rs b/clippy_lints/src/four_forward_slashes.rs index 69bc0b726fc..0599e08e6c0 100644 --- a/clippy_lints/src/four_forward_slashes.rs +++ b/clippy_lints/src/four_forward_slashes.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::Item; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 5477532bb95..fa1f98ba013 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -12,7 +12,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::{kw, sym}; use rustc_span::{Span, Symbol}; diff --git a/clippy_lints/src/from_raw_with_void_ptr.rs b/clippy_lints/src/from_raw_with_void_ptr.rs index d9138d48b2c..c8d10dc4b92 100644 --- a/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/clippy_lints/src/from_raw_with_void_ptr.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{RawPtr, TypeAndMut}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 18d11ccc0b5..633ed96d6a6 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index bfd73debd76..96da2ec2a1a 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -9,7 +9,7 @@ mod too_many_lines; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index ded90f5f911..9fb59a320d4 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -5,7 +5,7 @@ use rustc_hir::{Body, FnDecl}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 644b9cdaeb2..5e354209cbf 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -5,7 +5,7 @@ use rustc_errors::Diagnostic; use rustc_hir::intravisit::{self as visit, Visitor}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index cae561f7802..4dc1ff83771 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -6,7 +6,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_else_clause; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 66c10ab228f..cd6c46a71a8 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -9,7 +9,7 @@ use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/ignored_unit_patterns.rs b/clippy_lints/src/ignored_unit_patterns.rs index 76bdfb94eb8..0a2fd0c663e 100644 --- a/clippy_lints/src/ignored_unit_patterns.rs +++ b/clippy_lints/src/ignored_unit_patterns.rs @@ -3,7 +3,7 @@ use hir::{Node, PatKind}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs b/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs new file mode 100644 index 00000000000..940adbae428 --- /dev/null +++ b/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs @@ -0,0 +1,106 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::implements_trait; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Item, ItemKind, Path, TraitRef}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::sym; + +declare_clippy_lint! { + /// ### What it does + /// + /// This lint is concerned with the semantics of `Borrow` and `Hash` for a + /// type that implements all three of `Hash`, `Borrow` and `Borrow<[u8]>` + /// as it is impossible to satisfy the semantics of Borrow and `Hash` for + /// both `Borrow` and `Borrow<[u8]>`. + /// + /// ### Why is this bad? + /// + /// When providing implementations for `Borrow`, one should consider whether the different + /// implementations should act as facets or representations of the underlying type. Generic code + /// typically uses `Borrow` when it relies on the identical behavior of these additional trait + /// implementations. These traits will likely appear as additional trait bounds. + /// + /// In particular `Eq`, `Ord` and `Hash` must be equivalent for borrowed and owned values: + /// `x.borrow() == y.borrow()` should give the same result as `x == y`. + /// It follows then that the following equivalence must hold: + /// `hash(x) == hash((x as Borrow<[u8]>).borrow()) == hash((x as Borrow).borrow())` + /// + /// Unfortunately it doesn't hold as `hash("abc") != hash("abc".as_bytes())`. + /// This happens because the `Hash` impl for str passes an additional `0xFF` byte to + /// the hasher to avoid collisions. For example, given the tuples `("a", "bc")`, and `("ab", "c")`, + /// the two tuples would have the same hash value if the `0xFF` byte was not added. + /// + /// ### Example + /// + /// ``` + /// use std::borrow::Borrow; + /// use std::hash::{Hash, Hasher}; + /// + /// struct ExampleType { + /// data: String + /// } + /// + /// impl Hash for ExampleType { + /// fn hash(&self, state: &mut H) { + /// self.data.hash(state); + /// } + /// } + /// + /// impl Borrow for ExampleType { + /// fn borrow(&self) -> &str { + /// &self.data + /// } + /// } + /// + /// impl Borrow<[u8]> for ExampleType { + /// fn borrow(&self) -> &[u8] { + /// self.data.as_bytes() + /// } + /// } + /// ``` + /// As a consequence, hashing a `&ExampleType` and hashing the result of the two + /// borrows will result in different values. + /// + #[clippy::version = "1.76.0"] + pub IMPL_HASH_BORROW_WITH_STR_AND_BYTES, + correctness, + "ensures that the semantics of `Borrow` for `Hash` are satisfied when `Borrow` and `Borrow<[u8]>` are implemented" +} + +declare_lint_pass!(ImplHashWithBorrowStrBytes => [IMPL_HASH_BORROW_WITH_STR_AND_BYTES]); + +impl LateLintPass<'_> for ImplHashWithBorrowStrBytes { + /// We are emitting this lint at the Hash impl of a type that implements all + /// three of `Hash`, `Borrow` and `Borrow<[u8]>`. + fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + if let ItemKind::Impl(imp) = item.kind + && let Some(TraitRef {path: Path {span, res, ..}, ..}) = imp.of_trait + && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() + && let Some(hash_id) = cx.tcx.get_diagnostic_item(sym::Hash) + && Res::Def(DefKind::Trait, hash_id) == *res + && let Some(borrow_id) = cx.tcx.get_diagnostic_item(sym::Borrow) + // since we are in the `Hash` impl, we don't need to check for that. + // we need only to check for `Borrow` and `Borrow<[u8]>` + && implements_trait(cx, ty, borrow_id, &[cx.tcx.types.str_.into()]) + && implements_trait(cx, ty, borrow_id, &[Ty::new_slice(cx.tcx, cx.tcx.types.u8).into()]) + { + span_lint_and_then( + cx, + IMPL_HASH_BORROW_WITH_STR_AND_BYTES, + *span, + "the semantics of `Borrow` around `Hash` can't be satisfied when both `Borrow` and `Borrow<[u8]>` are implemented", + |diag| { + diag.note("the `Borrow` semantics require that `Hash` must behave the same for all implementations of Borrow"); + diag.note( + "however, the hash implementations of a string (`str`) and the bytes of a string `[u8]` do not behave the same ..." + ); + diag.note("... as (`hash(\"abc\") != hash(\"abc\".as_bytes())`"); + diag.help("consider either removing one of the `Borrow` implementations (`Borrow` or `Borrow<[u8]>`) ..."); + diag.help("... or not implementing `Hash` for this type"); + }, + ); + } + } +} diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 6594636d884..43eb6a9b838 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -9,7 +9,7 @@ use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{Ty, TypeckResults}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index c6bcf3ba40c..d68c5c4bac6 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -8,7 +8,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, SyntaxContext}; diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs index f2fac9a29cb..cc74844f294 100644 --- a/clippy_lints/src/implicit_saturating_add.rs +++ b/clippy_lints/src/implicit_saturating_add.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Int, IntTy, Ty, Uint, UintTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index fc66f86ae86..81df1a889c7 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index 232d8eeb11b..9a66cbde53c 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -10,7 +10,7 @@ use rustc_hir::{ use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, ClauseKind, Generics, Ty, TyCtxt}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { @@ -45,7 +45,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.74.0"] pub IMPLIED_BOUNDS_IN_IMPLS, - nursery, + complexity, "specifying bounds that are implied by other bounds in `impl Trait` type" } declare_lint_pass!(ImpliedBoundsInImpls => [IMPLIED_BOUNDS_IN_IMPLS]); diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index f6e1281a291..1075975f0a2 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{self as hir, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; use std::fmt::{self, Write as _}; diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index fa6536db796..b6f9d8b81f8 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; use rustc_span::Span; diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 1ce7d85d382..0ae03d101ab 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -7,7 +7,7 @@ use rustc_ast::ast::RangeLimits; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index e9c53671a93..9ad02735878 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -3,7 +3,7 @@ use clippy_utils::higher; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_hir::{BorrowKind, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::{sym, Symbol}; declare_clippy_lint! { diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index aa732980b1f..5c926133c42 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; use rustc_hir::{Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; use std::collections::hash_map::Entry; diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index fe5eb5ccac5..ca2ac60306b 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::{implements_trait, is_type_lang_item}; use clippy_utils::{return_ty, trait_ref_of_method}; use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem, Unsafety}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use rustc_target::spec::abi::Abi; diff --git a/clippy_lints/src/init_numbered_fields.rs b/clippy_lints/src/init_numbered_fields.rs index 269311a67d6..e486563808a 100644 --- a/clippy_lints/src/init_numbered_fields.rs +++ b/clippy_lints/src/init_numbered_fields.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::borrow::Cow; use std::cmp::Reverse; use std::collections::BinaryHeap; diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index 899126565f7..bc236c5c71f 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::Attribute; use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Symbol}; declare_clippy_lint! { diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 8e84c73666f..655f4b82aa4 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -6,7 +6,7 @@ use clippy_utils::ty; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::sym; diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 9ffcee07d28..b8e0eef7c7e 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs index de82935e66b..8bcd9b532bd 100644 --- a/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/clippy_lints/src/invalid_upcast_comparisons.rs @@ -2,7 +2,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, IntTy, UintTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; use clippy_utils::comparisons; diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 2b131d27b7b..b6aacba2517 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -6,7 +6,7 @@ use clippy_utils::source::is_present_in_source; use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case}; use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Symbol; use rustc_span::Span; diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 9605d76fbf0..39223c20470 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_hir; use rustc_hir::{Block, ItemKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index 35e01862cee..3614fb8cc96 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -4,7 +4,7 @@ use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro}; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::{HirId, Item, ItemKind, Mod}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::hygiene::AstPass; use rustc_span::{sym, ExpnKind}; diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index fce3b0e18b7..b9fad726511 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::implements_trait; use rustc_hir::def_id::LocalDefId; use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/iter_over_hash_type.rs b/clippy_lints/src/iter_over_hash_type.rs index 7755adc4c1d..8110c1970d9 100644 --- a/clippy_lints/src/iter_over_hash_type.rs +++ b/clippy_lints/src/iter_over_hash_type.rs @@ -7,7 +7,7 @@ use clippy_utils::paths::{ }; use clippy_utils::ty::is_type_diagnostic_item; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 3c291f25590..3a5756482a1 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Symbol}; use std::iter; diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs index 7db088f986f..b561054b582 100644 --- a/clippy_lints/src/large_const_arrays.rs +++ b/clippy_lints/src/large_const_arrays.rs @@ -4,7 +4,7 @@ use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Pos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index 0bf9b8718cd..6feb1885576 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -8,7 +8,7 @@ use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{Adt, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs index 26a7278524e..eb7570e9b44 100644 --- a/clippy_lints/src/large_futures.rs +++ b/clippy_lints/src/large_futures.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_target::abi::Size; declare_clippy_lint! { diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index 902b72ba5e4..1b5981ecc28 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -4,7 +4,7 @@ use clippy_utils::macros::root_macro_call_first_node; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 5e312ab7240..fd33ba91bfd 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -4,7 +4,7 @@ use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ConstKind}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index 33636eb687f..b397180a69c 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 8c6ef81cced..e121da776b2 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -13,7 +13,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index da269ec61ff..270162ae771 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{BindingAnnotation, Mutability}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 04f23a213f2..606c2ed72be 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -5,7 +5,7 @@ use rustc_hir::{Local, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{GenericArgKind, IsSuggestable}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index d4f410de957..5f3f9b43f45 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_hir::{Local, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c462c933082..1c59b2df853 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -144,6 +144,7 @@ mod if_let_mutex; mod if_not_else; mod if_then_some_else_none; mod ignored_unit_patterns; +mod impl_hash_with_borrow_str_and_bytes; mod implicit_hasher; mod implicit_return; mod implicit_saturating_add; @@ -562,6 +563,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { vec_box_size_threshold, verbose_bit_mask_threshold, warn_on_all_wildcard_imports, + check_private_items, blacklisted_names: _, cyclomatic_complexity_threshold: _, @@ -745,7 +747,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { avoid_breaking_exported_api, )) }); - store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents))); + store.register_late_pass(move |_| Box::new(doc::Documentation::new(doc_valid_idents, check_private_items))); store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply)); store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq)); store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence)); @@ -1066,6 +1068,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(msrv()))); store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter)); store.register_late_pass(|_| Box::new(iter_over_hash_type::IterOverHashType)); + store.register_late_pass(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index bb0edec3373..17ca48683b3 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -18,7 +18,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter as middle_nested_filter; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs index 0a5f5a80cb7..8a0955147bb 100644 --- a/clippy_lints/src/lines_filter_map_ok.rs +++ b/clippy_lints/src/lines_filter_map_ok.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_diag_item_method, is_trait_method, match_def_path, path_to use rustc_errors::Applicability; use rustc_hir::{Body, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { @@ -53,18 +53,45 @@ declare_clippy_lint! { #[clippy::version = "1.70.0"] pub LINES_FILTER_MAP_OK, suspicious, - "filtering `std::io::Lines` with `filter_map()` or `flat_map()` might cause an infinite loop" + "filtering `std::io::Lines` with `filter_map()`, `flat_map()`, or `flatten()` might cause an infinite loop" } declare_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]); impl LateLintPass<'_> for LinesFilterMapOk { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind + if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind && is_trait_method(cx, expr, sym::Iterator) - && (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map") + && let fm_method_str = fm_method.ident.as_str() + && matches!(fm_method_str, "filter_map" | "flat_map" | "flatten") && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines) + && should_lint(cx, fm_args, fm_method_str) { - let lint = match &fm_arg.kind { + span_lint_and_then( + cx, + LINES_FILTER_MAP_OK, + fm_span, + &format!("`{fm_method_str}()` will run forever if the iterator repeatedly produces an `Err`",), + |diag| { + diag.span_note( + fm_receiver.span, + "this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error"); + diag.span_suggestion( + fm_span, + "replace with", + "map_while(Result::ok)", + Applicability::MaybeIncorrect, + ); + }, + ); + } + } +} + +fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> bool { + match args { + [] => method_str == "flatten", + [fm_arg] => { + match &fm_arg.kind { // Detect `Result::ok` ExprKind::Path(qpath) => cx .qpath_res(qpath, fm_arg.hir_id) @@ -86,29 +113,8 @@ impl LateLintPass<'_> for LinesFilterMapOk { } }, _ => false, - }; - if lint { - span_lint_and_then( - cx, - LINES_FILTER_MAP_OK, - fm_span, - &format!( - "`{}()` will run forever if the iterator repeatedly produces an `Err`", - fm_method.ident - ), - |diag| { - diag.span_note( - fm_receiver.span, - "this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error"); - diag.span_suggestion( - fm_span, - "replace with", - "map_while(Result::ok)", - Applicability::MaybeIncorrect, - ); - }, - ); } - } + }, + _ => false, } } diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 8f34a9b1fed..f33151cf4c5 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -9,7 +9,7 @@ use rustc_ast::token; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; use std::iter; diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 67c80fb8387..892336878c7 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -24,7 +24,7 @@ use clippy_config::msrvs::Msrv; use clippy_utils::higher; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor}; diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index d860b297a02..4773a1454b7 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -1,6 +1,6 @@ use super::SINGLE_ELEMENT_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, snippet_with_applicability}; +use clippy_utils::source::{indent_of, snippet, snippet_with_applicability}; use clippy_utils::visitors::contains_break_or_continue; use rustc_ast::util::parser::PREC_PREFIX; use rustc_ast::Mutability; @@ -87,14 +87,29 @@ pub(super) fn check<'tcx>( arg_snip = format!("({arg_snip})").into(); } - span_lint_and_sugg( - cx, - SINGLE_ELEMENT_LOOP, - expr.span, - "for loop over a single element", - "try", - format!("{{\n{indent}let {pat_snip} = {prefix}{arg_snip};{block_str}}}"), - applicability, - ); + if clippy_utils::higher::Range::hir(arg_expression).is_some() { + let range_expr = snippet(cx, arg_expression.span, "?").to_string(); + + let sugg = snippet(cx, arg_expression.span, ".."); + span_lint_and_sugg( + cx, + SINGLE_ELEMENT_LOOP, + arg.span, + format!("this loops only once with `{pat_snip}` being `{range_expr}`").as_str(), + "did you mean to iterate over the range instead?", + sugg.to_string(), + Applicability::Unspecified, + ); + } else { + span_lint_and_sugg( + cx, + SINGLE_ELEMENT_LOOP, + expr.span, + "for loop over a single element", + "try", + format!("{{\n{indent}let {pat_snip} = {prefix}{arg_snip};{block_str}}}"), + applicability, + ); + } } } diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index 9b2e02058a6..8d3e7520a54 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -2,13 +2,14 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use hir::def::{DefKind, Res}; use rustc_ast::ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; use rustc_span::{sym, Span}; +use std::collections::BTreeMap; declare_clippy_lint! { /// ### What it does @@ -136,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { } } fn check_crate_post(&mut self, cx: &LateContext<'_>) { - let mut used = FxHashMap::default(); + let mut used = BTreeMap::new(); let mut check_dup = vec![]; for (import, span, hir_id) in &self.imports { let found_idx = self.mac_refs.iter().position(|mac| import.ends_with(&mac.name)); @@ -185,20 +186,16 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { } } - let mut suggestions = vec![]; - for ((root, span, hir_id), path) in used { - if path.len() == 1 { - suggestions.push((span, format!("{root}::{}", path[0]), hir_id)); - } else { - suggestions.push((span, format!("{root}::{{{}}}", path.join(", ")), hir_id)); - } - } - // If mac_refs is not empty we have encountered an import we could not handle // such as `std::prelude::v1::foo` or some other macro that expands to an import. if self.mac_refs.is_empty() { - for (span, import, hir_id) in suggestions { - let help = format!("use {import};"); + for ((root, span, hir_id), path) in used { + let import = if let [single] = &path[..] { + format!("{root}::{single}") + } else { + format!("{root}::{{{}}}", path.join(", ")) + }; + span_lint_hir_and_then( cx, MACRO_USE_IMPORTS, @@ -209,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { diag.span_suggestion( *span, "remove the attribute and import the macro directly, try", - help, + format!("use {import};"), Applicability::MaybeIncorrect, ); }, diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs index ea1d25d80e1..a381b35cf2e 100644 --- a/clippy_lints/src/main_recursion.rs +++ b/clippy_lints/src/main_recursion.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use clippy_utils::{is_entrypoint_fn, is_no_std_crate}; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs index 9a3da975f83..4f6a2cf017c 100644 --- a/clippy_lints/src/manual_assert.rs +++ b/clippy_lints/src/manual_assert.rs @@ -5,7 +5,7 @@ use clippy_utils::{is_else_clause, peel_blocks_with_stmt, span_extract_comment, use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index a5d91c949bc..ee053ffe4ec 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -7,7 +7,7 @@ use rustc_hir::{ ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; @@ -187,14 +187,11 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) } fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, String)> { - match output.kind { - TyKind::Tup(tys) if tys.is_empty() => { - let sugg = "remove the return type"; - Some((sugg, String::new())) - }, - _ => { - let sugg = "return the output of the future directly"; - snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {snip}"))) - }, + if let TyKind::Tup([]) = output.kind { + let sugg = "remove the return type"; + Some((sugg, String::new())) + } else { + let sugg = "return the output of the future directly"; + snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {snip}"))) } } diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 69c65cf305c..96c652283da 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -8,7 +8,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_clamp.rs b/clippy_lints/src/manual_clamp.rs index 09c90e38e11..385fe387a31 100644 --- a/clippy_lints/src/manual_clamp.rs +++ b/clippy_lints/src/manual_clamp.rs @@ -14,7 +14,7 @@ use rustc_hir::def::Res; use rustc_hir::{Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; use std::ops::Deref; diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 0c4101ceb6b..31cfb41640d 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Constness, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index 472b4eb9006..252b3a83a18 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -6,7 +6,7 @@ use clippy_utils::{is_trait_method, path_to_local_id}; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, ExprKind, Local, Node, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 468f4170732..e433c5a3b32 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -8,7 +8,7 @@ use rustc_ast::LitKind::{Byte, Char}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::DefId; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 01eccb56a0a..92dc4d57ab1 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -11,7 +11,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::declare_tool_lint; + use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use std::slice; diff --git a/clippy_lints/src/manual_main_separator_str.rs b/clippy_lints/src/manual_main_separator_str.rs index 23f47c86fcc..5732bdda7f2 100644 --- a/clippy_lints/src/manual_main_separator_str.rs +++ b/clippy_lints/src/manual_main_separator_str.rs @@ -6,7 +6,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, Mutability, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 79cc98bfb7f..545b122930e 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::{self as hir, Expr, ExprKind, QPath}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{sym, Span}; @@ -118,7 +118,6 @@ impl EarlyLintPass for ManualNonExhaustiveStruct { if let Some(Ok(field)) = iter.next() && iter.next().is_none() && field.ty.kind.is_unit() - && field.ident.map_or(true, |name| name.as_str().starts_with('_')) { span_lint_and_then( cx, @@ -158,7 +157,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { { let mut iter = def.variants.iter().filter_map(|v| { (matches!(v.data, hir::VariantData::Unit(_, _)) - && v.ident.as_str().starts_with('_') && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)) && !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive)) .then_some((v.def_id, v.span)) @@ -173,9 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if let ExprKind::Path(QPath::Resolved(None, p)) = &e.kind - && let [.., name] = p.segments && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), id) = p.res - && name.ident.as_str().starts_with('_') { let variant_id = cx.tcx.parent(id); let enum_id = cx.tcx.parent(variant_id); diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index d24bfe18224..d585290f777 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{Span, DUMMY_SP}; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index bc8372fbd41..e006df7d666 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 2f8682d0418..1fe247dacb9 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::ExprKind::Assign; use rustc_lint::{LateContext, LateLintPass}; use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; const ACCEPTABLE_METHODS: [&[&str]; 5] = [ diff --git a/clippy_lints/src/manual_slice_size_calculation.rs b/clippy_lints/src/manual_slice_size_calculation.rs index 3b97d165998..1de686dbcb5 100644 --- a/clippy_lints/src/manual_slice_size_calculation.rs +++ b/clippy_lints/src/manual_slice_size_calculation.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_string_new.rs b/clippy_lints/src/manual_string_new.rs index f8afae0e1f5..737c70496c2 100644 --- a/clippy_lints/src/manual_string_new.rs +++ b/clippy_lints/src/manual_string_new.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability::MachineApplicable; use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, symbol, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index b41bf2d767e..7b04fd28b89 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -10,7 +10,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::Span; diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 147e72ea894..3b82c50a84e 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs index bf035969477..62cedc8847b 100644 --- a/clippy_lints/src/match_result_ok.rs +++ b/clippy_lints/src/match_result_ok.rs @@ -5,7 +5,7 @@ use clippy_utils::{higher, is_res_lang_ctor}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index cbf478620ec..c823d07e2bd 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use clippy_utils::{is_lint_allowed, path_to_local, search_same, SpanlessEq, SpanlessHash}; use core::cmp::Ordering; @@ -104,9 +104,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { if !cx.tcx.features().non_exhaustive_omitted_patterns_lint || is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id) { - span_lint_and_then( + span_lint_hir_and_then( cx, MATCH_SAME_ARMS, + arm1.hir_id, arm1.span, "this match arm has an identical body to the `_` wildcard arm", |diag| { @@ -124,9 +125,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { (arm2, arm1) }; - span_lint_and_then( + span_lint_hir_and_then( cx, MATCH_SAME_ARMS, + keep_arm.hir_id, keep_arm.span, "this match arm has an identical body to another arm", |diag| { @@ -222,7 +224,7 @@ fn iter_matching_struct_fields<'a>( Iter(left.iter(), right.iter()) } -#[expect(clippy::similar_names)] +#[expect(clippy::similar_names, clippy::too_many_lines)] impl<'a> NormalizedPat<'a> { fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self { match pat.kind { @@ -334,8 +336,7 @@ impl<'a> NormalizedPat<'a> { /// type. fn has_overlapping_values(&self, other: &Self) -> bool { match (*self, *other) { - (Self::Wild, _) | (_, Self::Wild) => true, - (Self::Never, Self::Never) => true, + (Self::Wild, _) | (_, Self::Wild) | (Self::Never, Self::Never) => true, (Self::Or(pats), ref other) | (ref other, Self::Or(pats)) => { pats.iter().any(|pat| pat.has_overlapping_values(other)) }, diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index dea46d4d360..4c7568f39b4 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -31,7 +31,7 @@ use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; use rustc_lexer::TokenKind; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{Span, SpanData, SyntaxContext}; declare_clippy_lint! { diff --git a/clippy_lints/src/matches/redundant_guards.rs b/clippy_lints/src/matches/redundant_guards.rs index 4a44d596a46..f57b22374c8 100644 --- a/clippy_lints/src/matches/redundant_guards.rs +++ b/clippy_lints/src/matches/redundant_guards.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::path_to_local; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet; use clippy_utils::visitors::{for_each_expr, is_local_used}; use rustc_ast::{BorrowKind, LitKind}; use rustc_errors::Applicability; @@ -8,7 +8,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, Guard, MatchSource, Node, Pat, PatKind}; use rustc_lint::LateContext; use rustc_span::symbol::Ident; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; +use std::borrow::Cow; use std::ops::ControlFlow; use super::REDUNDANT_GUARDS; @@ -41,7 +42,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (PatKind::Ref(..), None) | (_, Some(_)) => continue, _ => arm.pat.span, }; - emit_redundant_guards(cx, outer_arm, if_expr.span, pat_span, &binding, arm.guard); + emit_redundant_guards( + cx, + outer_arm, + if_expr.span, + snippet(cx, pat_span, ""), + &binding, + arm.guard, + ); } // `Some(x) if let Some(2) = x` else if let Guard::IfLet(let_expr) = guard @@ -52,7 +60,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (PatKind::Ref(..), None) | (_, Some(_)) => continue, _ => let_expr.pat.span, }; - emit_redundant_guards(cx, outer_arm, let_expr.span, pat_span, &binding, None); + emit_redundant_guards( + cx, + outer_arm, + let_expr.span, + snippet(cx, pat_span, ""), + &binding, + None, + ); } // `Some(x) if x == Some(2)` // `Some(x) if Some(2) == x` @@ -78,11 +93,76 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { (ExprKind::AddrOf(..), None) | (_, Some(_)) => continue, _ => pat.span, }; - emit_redundant_guards(cx, outer_arm, if_expr.span, pat_span, &binding, None); + emit_redundant_guards( + cx, + outer_arm, + if_expr.span, + snippet(cx, pat_span, ""), + &binding, + None, + ); + } else if let Guard::If(if_expr) = guard + && let ExprKind::MethodCall(path, recv, args, ..) = if_expr.kind + && let Some(binding) = get_pat_binding(cx, recv, outer_arm) + { + check_method_calls(cx, outer_arm, path.ident.name, recv, args, if_expr, &binding); } } } +fn check_method_calls<'tcx>( + cx: &LateContext<'tcx>, + arm: &Arm<'tcx>, + method: Symbol, + recv: &Expr<'_>, + args: &[Expr<'_>], + if_expr: &Expr<'_>, + binding: &PatBindingInfo, +) { + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + let slice_like = ty.is_slice() || ty.is_array(); + + let sugg = if method == sym!(is_empty) { + // `s if s.is_empty()` becomes "" + // `arr if arr.is_empty()` becomes [] + + if ty.is_str() { + r#""""#.into() + } else if slice_like { + "[]".into() + } else { + return; + } + } else if slice_like + && let Some(needle) = args.first() + && let ExprKind::AddrOf(.., needle) = needle.kind + && let ExprKind::Array(needles) = needle.kind + && needles.iter().all(|needle| expr_can_be_pat(cx, needle)) + { + // `arr if arr.starts_with(&[123])` becomes [123, ..] + // `arr if arr.ends_with(&[123])` becomes [.., 123] + // `arr if arr.starts_with(&[])` becomes [..] (why would anyone write this?) + + let mut sugg = snippet(cx, needle.span, "").into_owned(); + + if needles.is_empty() { + sugg.insert_str(1, ".."); + } else if method == sym!(starts_with) { + sugg.insert_str(sugg.len() - 1, ", .."); + } else if method == sym!(ends_with) { + sugg.insert_str(1, ".., "); + } else { + return; + } + + sugg.into() + } else { + return; + }; + + emit_redundant_guards(cx, arm, if_expr.span, sugg, binding, None); +} + struct PatBindingInfo { span: Span, byref_ident: Option, @@ -134,19 +214,16 @@ fn emit_redundant_guards<'tcx>( cx: &LateContext<'tcx>, outer_arm: &Arm<'tcx>, guard_span: Span, - pat_span: Span, + binding_replacement: Cow<'static, str>, pat_binding: &PatBindingInfo, inner_guard: Option>, ) { - let mut app = Applicability::MaybeIncorrect; - span_lint_and_then( cx, REDUNDANT_GUARDS, guard_span.source_callsite(), "redundant guard", |diag| { - let binding_replacement = snippet_with_applicability(cx, pat_span, "", &mut app); let suggestion_span = match *pat_binding { PatBindingInfo { span, @@ -170,14 +247,11 @@ fn emit_redundant_guards<'tcx>( Guard::IfLet(l) => ("if let", l.span), }; - format!( - " {prefix} {}", - snippet_with_applicability(cx, span, "", &mut app), - ) + format!(" {prefix} {}", snippet(cx, span, "")) }), ), ], - app, + Applicability::MaybeIncorrect, ); }, ); diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 1517223ab9a..c22f76484d0 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -9,7 +9,7 @@ use rustc_hir::LangItem::OptionNone; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index c5dbb6ad98b..e1b934d36ea 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -1,6 +1,7 @@ #![allow(unused_imports)] use super::ITER_KV_MAP; +use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::ty::is_type_diagnostic_item; @@ -21,7 +22,11 @@ pub(super) fn check<'tcx>( expr: &'tcx Expr<'tcx>, // .iter().map(|(_, v_| v)) recv: &'tcx Expr<'tcx>, // hashmap m_arg: &'tcx Expr<'tcx>, // |(_, v)| v + msrv: &Msrv, ) { + if map_type == "into_iter" && !msrv.meets(msrvs::INTO_KEYS) { + return; + } if !expr.span.from_expansion() && let ExprKind::Closure(c) = m_arg.kind && let Body { diff --git a/clippy_lints/src/methods/join_absolute_paths.rs b/clippy_lints/src/methods/join_absolute_paths.rs new file mode 100644 index 00000000000..02f28779cf6 --- /dev/null +++ b/clippy_lints/src/methods/join_absolute_paths.rs @@ -0,0 +1,52 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::expr_or_init; +use clippy_utils::source::snippet_opt; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; +use rustc_span::Span; + +use super::JOIN_ABSOLUTE_PATHS; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx Expr<'tcx>, join_arg: &'tcx Expr<'tcx>, expr_span: Span) { + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + if (is_type_diagnostic_item(cx, ty, sym::Path) || is_type_diagnostic_item(cx, ty, sym::PathBuf)) + && let ExprKind::Lit(spanned) = expr_or_init(cx, join_arg).kind + && let LitKind::Str(symbol, _) = spanned.node + && let sym_str = symbol.as_str() + && sym_str.starts_with(['/', '\\']) + { + span_lint_and_then( + cx, + JOIN_ABSOLUTE_PATHS, + join_arg.span, + "argument to `Path::join` starts with a path separator", + |diag| { + let arg_str = snippet_opt(cx, spanned.span).unwrap_or_else(|| "..".to_string()); + + let no_separator = if sym_str.starts_with('/') { + arg_str.replacen('/', "", 1) + } else { + arg_str.replacen('\\', "", 1) + }; + + diag.note("joining a path starting with separator will replace the path instead") + .span_suggestion( + spanned.span, + "if this is unintentional, try removing the starting separator", + no_separator, + Applicability::Unspecified, + ) + .span_suggestion( + expr_span, + "if this is intentional, try using `Path::new` instead", + format!("PathBuf::from({arg_str})"), + Applicability::Unspecified, + ); + }, + ); + } +} diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index 51145afda7f..f93edded729 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -1,14 +1,14 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_from_proc_macro; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; +use clippy_utils::{is_from_proc_macro, is_trait_method}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_span::Span; +use rustc_span::{sym, Span}; use super::MANUAL_TRY_FOLD; @@ -22,6 +22,7 @@ pub(super) fn check<'tcx>( ) { if !in_external_macro(cx.sess(), fold_span) && msrv.meets(msrvs::ITERATOR_TRY_FOLD) + && is_trait_method(cx, expr, sym::Iterator) && let init_ty = cx.typeck_results().expr_ty(init) && let Some(try_trait) = cx.tcx.lang_items().try_trait() && implements_trait(cx, init_ty, try_trait, &[]) diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index cb81b3919bf..52ea584a2c8 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -44,11 +44,9 @@ pub(super) fn check<'tcx>( // lint message let msg = if is_option { - "called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling \ - `map_or_else(, )` instead" + "called `map().unwrap_or_else()` on an `Option` value" } else { - "called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling \ - `.map_or_else(, )` instead" + "called `map().unwrap_or_else()` on a `Result` value" }; // get snippets for args to map() and unwrap_or_else() let map_snippet = snippet(cx, map_arg.span, ".."); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 31d44bc1b3f..25c681bb9d9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -49,6 +49,7 @@ mod iter_skip_next; mod iter_skip_zero; mod iter_with_drain; mod iterator_step_by_zero; +mod join_absolute_paths; mod manual_next_back; mod manual_ok_or; mod manual_saturating_arithmetic; @@ -69,6 +70,7 @@ mod obfuscated_if_else; mod ok_expect; mod open_options; mod option_as_ref_deref; +mod option_map_or_err_ok; mod option_map_or_none; mod option_map_unwrap_or; mod or_fun_call; @@ -80,6 +82,7 @@ mod read_line_without_trim; mod readonly_write_lock; mod redundant_as_str; mod repeat_once; +mod result_map_or_else_none; mod search_is_some; mod seek_from_current; mod seek_to_start_instead_of_rewind; @@ -130,7 +133,7 @@ use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -3609,7 +3612,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `as_str()` on a `String`` chained with a method available on the `String` itself. + /// Checks for usage of `as_str()` on a `String` chained with a method available on the `String` itself. /// /// ### Why is this bad? /// The `as_str()` conversion is pointless and can be removed for simplicity and cleanliness. @@ -3618,14 +3621,16 @@ declare_clippy_lint! { /// ```no_run /// # #![allow(unused)] /// let owned_string = "This is a string".to_owned(); - /// owned_string.as_str().as_bytes(); + /// owned_string.as_str().as_bytes() + /// # ; /// ``` /// /// Use instead: /// ```no_run /// # #![allow(unused)] /// let owned_string = "This is a string".to_owned(); - /// owned_string.as_bytes(); + /// owned_string.as_bytes() + /// # ; /// ``` #[clippy::version = "1.74.0"] pub REDUNDANT_AS_STR, @@ -3682,6 +3687,71 @@ declare_clippy_lint! { "calling the `try_from` and `try_into` trait methods when `From`/`Into` is implemented" } +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `Path::join` that start with a path separator (`\\` or `/`). + /// + /// ### Why is this bad? + /// If the argument to `Path::join` starts with a separator, it will overwrite + /// the original path. If this is intentional, prefer using `Path::new` instead. + /// + /// Note the behavior is platform dependent. A leading `\\` will be accepted + /// on unix systems as part of the file name + /// + /// See [`Path::join`](https://doc.rust-lang.org/std/path/struct.Path.html#method.join) + /// + /// ### Example + /// ```rust + /// # use std::path::{Path, PathBuf}; + /// let path = Path::new("/bin"); + /// let joined_path = path.join("/sh"); + /// assert_eq!(joined_path, PathBuf::from("/sh")); + /// ``` + /// + /// Use instead; + /// ```rust + /// # use std::path::{Path, PathBuf}; + /// let path = Path::new("/bin"); + /// + /// // If this was unintentional, remove the leading separator + /// let joined_path = path.join("sh"); + /// assert_eq!(joined_path, PathBuf::from("/bin/sh")); + /// + /// // If this was intentional, create a new path instead + /// let new = Path::new("/sh"); + /// assert_eq!(new, PathBuf::from("/sh")); + /// ``` + #[clippy::version = "1.76.0"] + pub JOIN_ABSOLUTE_PATHS, + suspicious, + "calls to `Path::join` which will overwrite the original path" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `_.map_or(Err(_), Ok)`. + /// + /// ### Why is this bad? + /// Readability, this can be written more concisely as + /// `_.ok_or(_)`. + /// + /// ### Example + /// ```no_run + /// # let opt = Some(1); + /// opt.map_or(Err("error"), Ok); + /// ``` + /// + /// Use instead: + /// ```no_run + /// # let opt = Some(1); + /// opt.ok_or("error"); + /// ``` + #[clippy::version = "1.76.0"] + pub OPTION_MAP_OR_ERR_OK, + style, + "using `Option.map_or(Err(_), Ok)`, which is more succinctly expressed as `Option.ok_or(_)`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3831,6 +3901,8 @@ impl_lint_pass!(Methods => [ REDUNDANT_AS_STR, WAKER_CLONE_WAKE, UNNECESSARY_FALLIBLE_CONVERSIONS, + JOIN_ABSOLUTE_PATHS, + OPTION_MAP_OR_ERR_OK, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4233,6 +4305,8 @@ impl Methods { ("join", [join_arg]) => { if let Some(("collect", _, _, span, _)) = method_call(recv) { unnecessary_join::check(cx, expr, recv, join_arg, span); + } else { + join_absolute_paths::check(cx, recv, join_arg, expr.span); } }, ("last", []) => { @@ -4255,7 +4329,7 @@ impl Methods { map_clone::check(cx, expr, recv, m_arg, &self.msrv); match method_call(recv) { Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => { - iter_kv_map::check(cx, map_name, expr, recv2, m_arg); + iter_kv_map::check(cx, map_name, expr, recv2, m_arg, &self.msrv); }, Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( cx, @@ -4288,6 +4362,10 @@ impl Methods { ("map_or", [def, map]) => { option_map_or_none::check(cx, expr, recv, def, map); manual_ok_or::check(cx, expr, recv, def, map); + option_map_or_err_ok::check(cx, expr, recv, def, map); + }, + ("map_or_else", [def, map]) => { + result_map_or_else_none::check(cx, expr, recv, def, map); }, ("next", []) => { if let Some((name2, recv2, args2, _, _)) = method_call(recv) { diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 79ed5515ea2..293b4981c55 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -225,7 +225,10 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - && let sig = cx.tcx.fn_sig(id).instantiate_identity() && sig.skip_binder().output().is_bool() && let [_, search_ty] = *sig.skip_binder().inputs() - && let ty::Ref(_, search_ty, Mutability::Not) = *cx.tcx.instantiate_bound_regions_with_erased(sig.rebind(search_ty)).kind() + && let ty::Ref(_, search_ty, Mutability::Not) = *cx + .tcx + .instantiate_bound_regions_with_erased(sig.rebind(search_ty)) + .kind() && let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) && let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_name_and_kind( cx.tcx, diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 15111006133..756dbe62d84 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -99,10 +99,7 @@ pub(super) fn check( let hint = format!("{}.{method_hint}()", snippet(cx, as_ref_recv.span, "..")); let suggestion = format!("try using {method_hint} instead"); - let msg = format!( - "called `{current_method}` on an Option value. This can be done more directly \ - by calling `{hint}` instead" - ); + let msg = format!("called `{current_method}` on an `Option` value"); span_lint_and_sugg( cx, OPTION_AS_REF_DEREF, diff --git a/clippy_lints/src/methods/option_map_or_err_ok.rs b/clippy_lints/src/methods/option_map_or_err_ok.rs new file mode 100644 index 00000000000..91e39d5a1cd --- /dev/null +++ b/clippy_lints/src/methods/option_map_or_err_ok.rs @@ -0,0 +1,41 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_res_lang_ctor, path_res}; +use rustc_errors::Applicability; +use rustc_hir::LangItem::{ResultErr, ResultOk}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::OPTION_MAP_OR_ERR_OK; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + recv: &'tcx Expr<'_>, + or_expr: &'tcx Expr<'_>, + map_expr: &'tcx Expr<'_>, +) { + // We check that it's called on an `Option` type. + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option) + // We check that first we pass an `Err`. + && let ExprKind::Call(call, &[arg]) = or_expr.kind + && is_res_lang_ctor(cx, path_res(cx, call), ResultErr) + // And finally we check that it is mapped as `Ok`. + && is_res_lang_ctor(cx, path_res(cx, map_expr), ResultOk) + { + let msg = "called `map_or(Err(_), Ok)` on an `Option` value"; + let self_snippet = snippet(cx, recv.span, ".."); + let err_snippet = snippet(cx, arg.span, ".."); + span_lint_and_sugg( + cx, + OPTION_MAP_OR_ERR_OK, + expr.span, + msg, + "try using `ok_or` instead", + format!("{self_snippet}.ok_or({err_snippet})"), + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 418e6a7d6a0..ff4d8cc9e3e 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -66,8 +66,7 @@ pub(super) fn check<'tcx>( && Some(id) == cx.tcx.lang_items().option_some_variant() { let func_snippet = snippet(cx, arg_char.span, ".."); - let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ - `map(..)` instead"; + let msg = "called `map_or(None, ..)` on an `Option` value"; return span_lint_and_sugg( cx, OPTION_MAP_OR_NONE, @@ -80,8 +79,7 @@ pub(super) fn check<'tcx>( } let func_snippet = snippet(cx, map_arg.span, ".."); - let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ - `and_then(..)` instead"; + let msg = "called `map_or(None, ..)` on an `Option` value"; span_lint_and_sugg( cx, OPTION_MAP_OR_NONE, @@ -92,8 +90,7 @@ pub(super) fn check<'tcx>( Applicability::MachineApplicable, ); } else if f_arg_is_some { - let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \ - `ok()` instead"; + let msg = "called `map_or(None, Some)` on a `Result` value"; let self_snippet = snippet(cx, recv.span, ".."); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index c78f8b71c78..575c2d8f157 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -97,10 +97,7 @@ pub(super) fn check<'tcx>( } else { "map_or(, )" }; - let msg = &format!( - "called `map().unwrap_or({arg})` on an `Option` value. \ - This can be done more directly by calling `{suggest}` instead" - ); + let msg = &format!("called `map().unwrap_or({arg})` on an `Option` value"); span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| { let map_arg_span = map_arg.span; diff --git a/clippy_lints/src/methods/result_map_or_else_none.rs b/clippy_lints/src/methods/result_map_or_else_none.rs new file mode 100644 index 00000000000..bc16a112816 --- /dev/null +++ b/clippy_lints/src/methods/result_map_or_else_none.rs @@ -0,0 +1,42 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::LangItem::{OptionNone, OptionSome}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::RESULT_MAP_OR_INTO_OPTION; + +/// lint use of `_.map_or_else(|_| None, Some)` for `Result`s +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, + def_arg: &'tcx hir::Expr<'_>, + map_arg: &'tcx hir::Expr<'_>, +) { + // lint if the caller of `map_or_else()` is a `Result` + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) + // We check that it is mapped as `Some`. + && is_res_lang_ctor(cx, path_res(cx, map_arg), OptionSome) + && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = def_arg.kind + && let body = cx.tcx.hir().body(body) + // And finally we check that we return a `None` in the "else case". + && is_res_lang_ctor(cx, path_res(cx, peel_blocks(body.value)), OptionNone) + { + let msg = "called `map_or_else(|_| None, Some)` on a `Result` value"; + let self_snippet = snippet(cx, recv.span, ".."); + span_lint_and_sugg( + cx, + RESULT_MAP_OR_INTO_OPTION, + expr.span, + msg, + "try using `ok` instead", + format!("{self_snippet}.ok()"), + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs index 4ad12e899fe..f5b749c7f80 100644 --- a/clippy_lints/src/min_ident_chars.rs +++ b/clippy_lints/src/min_ident_chars.rs @@ -6,7 +6,7 @@ use rustc_hir::intravisit::{walk_item, Visitor}; use rustc_hir::{GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; use std::borrow::Cow; diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index e0904f17b8d..fca626fa5c3 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_trait_method; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use std::cmp::Ordering; diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 814fc3303b0..b9784a58596 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -13,7 +13,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index df0dd9e4e39..abe5b00e888 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -16,7 +16,7 @@ use rustc_ast::visit::FnKind; use rustc_data_structures::fx::FxHashMap; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index c74d0d623df..0739b49fe19 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -4,7 +4,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{GenericArg, Item, ItemKind, QPath, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::GenericParamDefKind; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/missing_assert_message.rs b/clippy_lints/src/missing_assert_message.rs index 4e00215c5cb..04df7b7a7e5 100644 --- a/clippy_lints/src/missing_assert_message.rs +++ b/clippy_lints/src/missing_assert_message.rs @@ -3,7 +3,7 @@ use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_cal use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index ff2792faf57..8f2a5390781 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -9,9 +9,9 @@ use clippy_utils::{eq_expr_value, hash_expr, higher}; use rustc_ast::{LitKind, RangeLimits}; use rustc_data_structures::unhash::UnhashMap; use rustc_errors::{Applicability, Diagnostic}; -use rustc_hir::{BinOp, Block, Expr, ExprKind, UnOp}; +use rustc_hir::{BinOp, Block, Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::{sym, Span}; @@ -390,10 +390,10 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap> } impl LateLintPass<'_> for MissingAssertsForIndexing { - fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) { + fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) { let mut map = UnhashMap::default(); - for_each_expr(block, |expr| { + for_each_expr(body.value, |expr| { check_index(cx, expr, &mut map); check_assert(cx, expr, &mut map); ControlFlow::::Continue(()) diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 496bae583f1..5f736898159 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -9,7 +9,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index b5a884f7c8b..bf4af7946f4 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -13,7 +13,7 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::Visibility; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index f7e42815104..c1f6c71a63e 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -7,7 +7,7 @@ use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::{Item, ItemKind, UseKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Symbol; declare_clippy_lint! { diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 95f9df4e42a..8be45b8c2f3 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -12,7 +12,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Ty, TypeckResults}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span, Symbol}; declare_clippy_lint! { diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index b815da79b69..07bcbfc4ff4 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast; use rustc_hir as hir; use rustc_lint::{self, LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/missing_trait_methods.rs b/clippy_lints/src/missing_trait_methods.rs index ad5f45a3280..6bbf18d52d1 100644 --- a/clippy_lints/src/missing_trait_methods.rs +++ b/clippy_lints/src/missing_trait_methods.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::DefIdMap; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::AssocItem; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index e5ebdc14510..cd180754113 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -4,7 +4,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index cd45467407e..0226b31dd19 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{FileName, SourceFile, Span, SyntaxContext}; use std::ffi::OsStr; diff --git a/clippy_lints/src/multi_assignments.rs b/clippy_lints/src/multi_assignments.rs index b42dce7a13a..9a6b1dfc52b 100644 --- a/clippy_lints/src/multi_assignments.rs +++ b/clippy_lints/src/multi_assignments.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index d4f8008aece..049f44f3246 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{DesugaringKind, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 454fc6f5642..04d2ced6abf 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::query::Key; use rustc_middle::ty::{Adt, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; use rustc_span::Span; @@ -143,7 +143,11 @@ impl MutableKeyType { for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) { self.check_ty_(cx, hir_ty.span, *ty); } - self.check_ty_(cx, decl.output.span(), cx.tcx.instantiate_bound_regions_with_erased(fn_sig.output())); + self.check_ty_( + cx, + decl.output.span(), + cx.tcx.instantiate_bound_regions_with_erased(fn_sig.output()), + ); } // We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 6989504a4a9..72a2cca1e40 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -5,7 +5,7 @@ use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 4f8e244222d..f905a4e5b64 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::iter; declare_clippy_lint! { diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index dea432fdbd5..96cd81ecdf3 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -5,7 +5,7 @@ use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 9d8c06cd077..a23e12f7a18 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -7,7 +7,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 1712262ff3e..2ab83f733cb 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::ast::{BindingAnnotation, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::kw; use rustc_span::Span; diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 02c177c9227..218ca5e80f3 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -13,7 +13,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::Span; diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index fdb91f0dc0d..4710a69443b 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, Mutability, Node, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index f25475aaa8e..85166b0dd95 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -15,7 +15,7 @@ use rustc_middle::mir::{Rvalue, StatementKind}; use rustc_middle::ty::{ self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, List, ParamTy, ProjectionPredicate, Ty, }; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{Obligation, ObligationCause}; diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 6803034f475..4b9ab50e4fd 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -37,7 +37,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{indent_of, snippet, snippet_block}; use rustc_ast::ast; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index d881c13f84a..b6aad69d166 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_opt, trim_span}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 70571d18e78..84a07df1bb0 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -2,7 +2,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span, Symbol}; use clippy_utils::diagnostics::span_lint_and_then; diff --git a/clippy_lints/src/needless_if.rs b/clippy_lints/src/needless_if.rs index 1ed7ea6b325..41d05d72284 100644 --- a/clippy_lints/src/needless_if.rs +++ b/clippy_lints/src/needless_if.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 0a95678d31a..3e63c0a1d36 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -10,7 +10,7 @@ use rustc_hir::{ StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/needless_parens_on_range_literals.rs b/clippy_lints/src/needless_parens_on_range_literals.rs index 490c3f9c1ab..8a62106377c 100644 --- a/clippy_lints/src/needless_parens_on_range_literals.rs +++ b/clippy_lints/src/needless_parens_on_range_literals.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index f4ccd26631f..13b736cd9ad 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -17,7 +17,7 @@ use rustc_middle::hir::map::associated_body; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarId, UpvarPath}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; use rustc_span::Span; diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 5442463bbf5..27da44812eb 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -17,7 +17,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 7ec0879ba38..a4d3aaf0de9 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index f8888d36878..6a2893cefbd 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 30aed8cc04a..f7621822b66 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::implements_trait; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index a6adb7c8a5f..f84d9fadb85 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -6,7 +6,7 @@ use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 2f6aebae4f5..9de6ad42137 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_hir::HirIdSet; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index de8bb123e9b..6e65dd628a4 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -10,7 +10,7 @@ use rustc_hir::{ use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::ops::Deref; declare_clippy_lint! { diff --git a/clippy_lints/src/no_mangle_with_rust_abi.rs b/clippy_lints/src/no_mangle_with_rust_abi.rs index 04d75014892..8d5a523fd8f 100644 --- a/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Pos}; use rustc_target::spec::abi::Abi; diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index 9689f63a013..63050080ac6 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::EarlyBinder; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use rustc_span::symbol::kw; diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 3059eb25d29..4f8922aea17 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -18,7 +18,7 @@ use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; use rustc_middle::query::Key; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, InnerSpan, Span}; use rustc_target::abi::VariantIdx; diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 649a23565a9..70b7ef1a5ea 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -5,7 +5,7 @@ use rustc_ast::ast::{ use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{sym, Span}; use std::cmp::Ordering; diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 6cfcc81025d..49e9e2c00cc 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -4,7 +4,7 @@ use clippy_utils::{match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs index d07a9da55a2..352540d70b5 100644 --- a/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -8,7 +8,7 @@ use rustc_hir::{FieldDef, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, GenericArgKind, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 1c6a8e16ae2..1c6069e9c65 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::Span; diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 0faf4ce3d3e..8822dfeeddd 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -4,7 +4,7 @@ use rustc_ast::token::{Lit, LitKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; use std::fmt::Write; diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index ef7b367649f..d621051ef16 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -8,7 +8,7 @@ use rustc_hir::hir_id::HirIdMap; use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, ConstKind, EarlyBinder, GenericArgKind, GenericArgsRef}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; use std::iter; diff --git a/clippy_lints/src/operators/eq_op.rs b/clippy_lints/src/operators/eq_op.rs index fd3502ad878..01dd418c38b 100644 --- a/clippy_lints/src/operators/eq_op.rs +++ b/clippy_lints/src/operators/eq_op.rs @@ -36,7 +36,7 @@ pub(crate) fn check<'tcx>( left: &'tcx Expr<'_>, right: &'tcx Expr<'_>, ) { - if is_useless_with_eq_exprs(op.into()) && eq_expr_value(cx, left, right) && !is_in_test_function(cx.tcx, e.hir_id) { + if is_useless_with_eq_exprs(op) && eq_expr_value(cx, left, right) && !is_in_test_function(cx.tcx, e.hir_id) { span_lint_and_then( cx, EQ_OP, diff --git a/clippy_lints/src/operators/misrefactored_assign_op.rs b/clippy_lints/src/operators/misrefactored_assign_op.rs index 5eabb349ec1..fecc5a8578e 100644 --- a/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -46,7 +46,7 @@ fn lint_misrefactored_assign_op( if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) { let a = &sugg::Sugg::hir(cx, assignee, ".."); let r = &sugg::Sugg::hir(cx, rhs, ".."); - let long = format!("{snip_a} = {}", sugg::make_binop(op.into(), a, r)); + let long = format!("{snip_a} = {}", sugg::make_binop(op, a, r)); diag.span_suggestion( expr.span, format!( diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index ee79ea27689..4c09c4eea58 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -25,7 +25,7 @@ pub(crate) mod arithmetic_side_effects; use rustc_hir::{Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs index 7792efe6acd..4bfb26209d2 100644 --- a/clippy_lints/src/option_env_unwrap.rs +++ b/clippy_lints/src/option_env_unwrap.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_direct_expn_of; use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 6e4e0c98d29..89e4e3c740d 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -9,7 +9,7 @@ use rustc_hir::def::Res; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::SyntaxContext; declare_clippy_lint! { @@ -239,21 +239,24 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> if_then, if_else: Some(if_else), }) = higher::IfLet::hir(cx, expr) + && !cx.typeck_results().expr_ty(expr).is_unit() + && !is_else_clause(cx.tcx, expr) { - if !is_else_clause(cx.tcx, expr) { - return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, let_expr, if_then, if_else); - } + try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, let_expr, if_then, if_else) + } else { + None } - None } fn detect_option_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { - if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind { - if let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) { - return try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, ex, if_then, if_else); - } + if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind + && !cx.typeck_results().expr_ty(expr).is_unit() + && let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) + { + try_get_option_occurrence(cx, expr.span.ctxt(), let_pat, ex, if_then, if_else) + } else { + None } - None } fn try_convert_match<'tcx>( diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index e661bfbb96c..de789879331 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::SpanlessEq; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index f4dc80d744a..f821a4efee7 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -7,7 +7,7 @@ use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index f4f1f6ddb3f..ef51a9a9a1c 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/partial_pub_fields.rs b/clippy_lints/src/partial_pub_fields.rs index 99ba55b6b31..ffa403e27ca 100644 --- a/clippy_lints/src/partial_pub_fields.rs +++ b/clippy_lints/src/partial_pub_fields.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Item, ItemKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index 1b06762415d..18e6aad9c9a 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/partialeq_to_none.rs b/clippy_lints/src/partialeq_to_none.rs index 11e9a2bc394..6d4216970cc 100644 --- a/clippy_lints/src/partialeq_to_none.rs +++ b/clippy_lints/src/partialeq_to_none.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_res_lang_ctor, path_res, peel_hir_expr_refs, peel_ref_oper use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 98d284d0340..57d37067e8f 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, PointerCoercion}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, RegionKind}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index dcd1e7af0c2..60ced9c1208 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -3,7 +3,7 @@ use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, Let, LocalSource, Muta use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/clippy_lints/src/permissions_set_readonly_false.rs b/clippy_lints/src/permissions_set_readonly_false.rs index b98005d5922..704acdc103e 100644 --- a/clippy_lints/src/permissions_set_readonly_false.rs +++ b/clippy_lints/src/permissions_set_readonly_false.rs @@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 52cec437378..ff83725da69 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{BinOpKind, Expr, ExprKind, MethodCall, UnOp}; use rustc_ast::token; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; const ALLOWED_ODD_FUNCTIONS: [&str; 14] = [ diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 621a32d79bf..2587b3881bb 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -20,7 +20,7 @@ use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; @@ -28,6 +28,8 @@ use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use std::{fmt, iter}; +use crate::vec::is_allowed_vec_method; + declare_clippy_lint! { /// ### What it does /// This lint checks for function arguments of type `&String`, `&Vec`, @@ -660,7 +662,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: }, // If the types match check for methods which exist on both types. e.g. `Vec::len` and // `slice::len` - ty::Adt(def, _) if def.did() == args.ty_did => { + ty::Adt(def, _) if def.did() == args.ty_did && !is_allowed_vec_method(self.cx, e) => { set_skip_flag(); }, _ => (), @@ -712,23 +714,25 @@ fn matches_preds<'tcx>( preds: &'tcx [ty::PolyExistentialPredicate<'tcx>], ) -> bool { let infcx = cx.tcx.infer_ctxt().build(); - preds.iter().all(|&p| match cx.tcx.instantiate_bound_regions_with_erased(p) { - ExistentialPredicate::Trait(p) => infcx - .type_implements_trait(p.def_id, [ty.into()].into_iter().chain(p.args.iter()), cx.param_env) - .must_apply_modulo_regions(), - ExistentialPredicate::Projection(p) => infcx.predicate_must_hold_modulo_regions(&Obligation::new( - cx.tcx, - ObligationCause::dummy(), - cx.param_env, - cx.tcx - .mk_predicate(Binder::dummy(PredicateKind::Clause(ClauseKind::Projection( - p.with_self_ty(cx.tcx, ty), - )))), - )), - ExistentialPredicate::AutoTrait(p) => infcx - .type_implements_trait(p, [ty], cx.param_env) - .must_apply_modulo_regions(), - }) + preds + .iter() + .all(|&p| match cx.tcx.instantiate_bound_regions_with_erased(p) { + ExistentialPredicate::Trait(p) => infcx + .type_implements_trait(p.def_id, [ty.into()].into_iter().chain(p.args.iter()), cx.param_env) + .must_apply_modulo_regions(), + ExistentialPredicate::Projection(p) => infcx.predicate_must_hold_modulo_regions(&Obligation::new( + cx.tcx, + ObligationCause::dummy(), + cx.param_env, + cx.tcx + .mk_predicate(Binder::dummy(PredicateKind::Clause(ClauseKind::Projection( + p.with_self_ty(cx.tcx, ty), + )))), + )), + ExistentialPredicate::AutoTrait(p) => infcx + .type_implements_trait(p, [ty], cx.param_env) + .must_apply_modulo_regions(), + }) } fn get_ref_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> { diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 66d869bc45a..ff8ec2ad57c 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; use std::fmt; diff --git a/clippy_lints/src/pub_use.rs b/clippy_lints/src/pub_use.rs index 316a72988aa..c0e999e76ef 100644 --- a/clippy_lints/src/pub_use.rs +++ b/clippy_lints/src/pub_use.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Item, ItemKind, VisibilityKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 5c395143b9a..fc5835408a9 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -18,7 +18,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; use rustc_span::symbol::Symbol; diff --git a/clippy_lints/src/question_mark_used.rs b/clippy_lints/src/question_mark_used.rs index d0de33e3c4f..ddfc53083c4 100644 --- a/clippy_lints/src/question_mark_used.rs +++ b/clippy_lints/src/question_mark_used.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::macros::span_is_local; use rustc_hir::{Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index fd9de76bacf..6b54258dd61 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::Span; use std::cmp::Ordering; diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index 98f5a07da0d..ac29d27303c 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -8,7 +8,7 @@ use rustc_ast::token::LitKind; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Pos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index b99af44655d..d0b45b59526 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span, Symbol}; declare_clippy_lint! { diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index b27d4cc6e4f..62f3c09aa7e 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -7,7 +7,7 @@ use hir::{Expr, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 90297ca8bb6..19d9d64b31e 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -9,7 +9,7 @@ use rustc_hir::{Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSo use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 698af9fb192..c62c351e716 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -9,7 +9,7 @@ use rustc_hir::{def_id, Body, FnDecl, LangItem}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, BytePos, Span}; diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index f2a006ebdfc..8bac2e40e01 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -4,13 +4,13 @@ use clippy_utils::get_parent_expr; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::intravisit as hir_visit; use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; +use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does @@ -60,11 +60,14 @@ impl<'tcx> Visitor<'tcx> for ReturnVisitor { } } -/// Checks if the body is owned by an async closure -fn is_async_closure(body: &hir::Body<'_>) -> bool { - if let hir::ExprKind::Closure(closure) = body.value.kind - && let [resume_ty] = closure.fn_decl.inputs - && let hir::TyKind::Path(hir::QPath::LangItem(hir::LangItem::ResumeTy, ..)) = resume_ty.kind +/// Checks if the body is owned by an async closure. +/// Returns true for `async || whatever_expression`, but false for `|| async { whatever_expression +/// }`. +fn is_async_closure(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool { + if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind + && let desugared_inner_closure_body = cx.tcx.hir().body(innermost_closure_generated_by_desugar.body) + // checks whether it is `async || whatever_expression` + && let Some(CoroutineKind::Async(CoroutineSource::Closure)) = desugared_inner_closure_body.coroutine_kind { true } else { @@ -100,7 +103,7 @@ fn find_innermost_closure<'tcx>( data = Some(( body.value, closure.fn_decl, - if is_async_closure(body) { + if is_async_closure(cx, body) { ty::Asyncness::Yes } else { ty::Asyncness::No @@ -173,12 +176,18 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { hint = hint.asyncify(); } - diag.span_suggestion( - full_expr.span, - "try doing something like", - hint.maybe_par(), - applicability, - ); + let is_in_fn_call_arg = + clippy_utils::get_parent_node(cx.tcx, expr.hir_id).is_some_and(|x| match x { + Node::Expr(expr) => matches!(expr.kind, hir::ExprKind::Call(_, _)), + _ => false, + }); + + // avoid clippy::double_parens + if !is_in_fn_call_arg { + hint = hint.maybe_par(); + }; + + diag.span_suggestion(full_expr.span, "try doing something like", hint, applicability); } }, ); diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs index 221aa317e5d..1168e79bb0d 100644 --- a/clippy_lints/src/redundant_else.rs +++ b/clippy_lints/src/redundant_else.rs @@ -3,7 +3,7 @@ use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_ast::visit::{walk_expr, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index b8e606df737..fb000cd7184 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs index 15b784039b6..8c374d7d6db 100644 --- a/clippy_lints/src/redundant_locals.rs +++ b/clippy_lints/src/redundant_locals.rs @@ -6,7 +6,7 @@ use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Ident; use rustc_span::DesugaringKind; diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 32e0c3749ab..0e43e4a7ee5 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -4,7 +4,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::hygiene::MacroKind; diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index c9fc65653c2..c99b657c23a 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -8,7 +8,7 @@ use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{GenericArg, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index a70b831a80c..07b604f2326 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; declare_clippy_lint! { diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs index f6af9cac3de..07fcb69afbc 100644 --- a/clippy_lints/src/redundant_type_annotations.rs +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -5,7 +5,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index 0ba898e75a1..19ce08bde10 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::{GenericArg, GenericArgsParentheses, Mutability, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/ref_patterns.rs b/clippy_lints/src/ref_patterns.rs index 8b3dabde9be..a4be78b310b 100644 --- a/clippy_lints/src/ref_patterns.rs +++ b/clippy_lints/src/ref_patterns.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{BindingAnnotation, Pat, PatKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 69818db7c82..16086ba6637 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_opt, snippet_with_applicability}; use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::BytePos; declare_clippy_lint! { diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index ae8be006781..687bad35a36 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -8,7 +8,7 @@ use rustc_ast::ast::{LitKind, StrStyle}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs index b4842e7d48a..ca7a0c7c87b 100644 --- a/clippy_lints/src/reserve_after_initialization.rs +++ b/clippy_lints/src/reserve_after_initialization.rs @@ -7,7 +7,7 @@ use rustc_hir::def::Res; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/return_self_not_must_use.rs b/clippy_lints/src/return_self_not_must_use.rs index 1a23757f7d6..5962e8be959 100644 --- a/clippy_lints/src/return_self_not_must_use.rs +++ b/clippy_lints/src/return_self_not_must_use.rs @@ -6,7 +6,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 14c103e7047..2293b53b42b 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -7,12 +7,14 @@ use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Block, Body, Expr, ExprKind, FnDecl, ItemKind, LangItem, MatchSource, OwnerNode, PatKind, QPath, Stmt, StmtKind, + Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt, + StmtKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, GenericArgKind, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{BytePos, Pos, Span}; use std::borrow::Cow; @@ -158,6 +160,22 @@ impl<'tcx> ToString for RetReplacement<'tcx> { declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN, NEEDLESS_RETURN_WITH_QUESTION_MARK]); +/// Checks if a return statement is "needed" in the middle of a block, or if it can be removed. This +/// is the case when the enclosing block expression is coerced to some other type, which only works +/// because of the never-ness of `return` expressions +fn stmt_needs_never_type(cx: &LateContext<'_>, stmt_hir_id: HirId) -> bool { + cx.tcx + .hir() + .parent_iter(stmt_hir_id) + .find_map(|(_, node)| if let Node::Expr(expr) = node { Some(expr) } else { None }) + .is_some_and(|e| { + cx.typeck_results() + .expr_adjustments(e) + .iter() + .any(|adjust| adjust.target != cx.tcx.types.unit && matches!(adjust.kind, Adjust::NeverToAny)) + }) +} + impl<'tcx> LateLintPass<'tcx> for Return { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if !in_external_macro(cx.sess(), stmt.span) @@ -173,6 +191,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { && let [.., final_stmt] = block.stmts && final_stmt.hir_id != stmt.hir_id && !is_from_proc_macro(cx, expr) + && !stmt_needs_never_type(cx, stmt.hir_id) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 4f53cceeecf..74193e0199f 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -4,7 +4,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::AssocKind; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; use rustc_span::Span; use std::collections::{BTreeMap, BTreeSet}; diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs index 36cb2edf723..935dd4a3630 100644 --- a/clippy_lints/src/self_named_constructors.rs +++ b/clippy_lints/src/self_named_constructors.rs @@ -3,7 +3,7 @@ use clippy_utils::return_ty; use clippy_utils::ty::contains_adt_constructor; use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index b0601bba4af..0b3adfb7a4b 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs index 3aabcadaa1f..2cd3e57f885 100644 --- a/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/serde_api.rs b/clippy_lints/src/serde_api.rs index fc1c2af9257..90834d784a5 100644 --- a/clippy_lints/src/serde_api.rs +++ b/clippy_lints/src/serde_api.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::{get_trait_def_id, paths}; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 41c10b34a42..c74364d89d6 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -7,7 +7,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::hir_id::ItemLocalId; use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{Span, Symbol}; declare_clippy_lint! { diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index 57bcee1a871..6c99ccda7ea 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -8,7 +8,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{self as hir}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, DUMMY_SP}; use std::borrow::Cow; diff --git a/clippy_lints/src/single_call_fn.rs b/clippy_lints/src/single_call_fn.rs index ae81e1198af..396d2717a13 100644 --- a/clippy_lints/src/single_call_fn.rs +++ b/clippy_lints/src/single_call_fn.rs @@ -7,7 +7,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/single_char_lifetime_names.rs b/clippy_lints/src/single_char_lifetime_names.rs index 74ee8ce2de7..42f1564db35 100644 --- a/clippy_lints/src/single_char_lifetime_names.rs +++ b/clippy_lints/src/single_char_lifetime_names.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{GenericParam, GenericParamKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index 9c21d70c82c..18fbbdb4079 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -5,7 +5,7 @@ use rustc_ast::visit::{walk_expr, Visitor}; use rustc_ast::{Crate, Expr, ExprKind, Item, ItemKind, MacroDef, ModKind, Ty, TyKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; use rustc_span::symbol::kw; use rustc_span::{Span, Symbol}; diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index 099743d229d..95b4a11a783 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -8,7 +8,7 @@ use rustc_ast::{LitIntType, LitKind, UintTy}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::fmt::{self, Display, Formatter}; declare_clippy_lint! { diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index 0385f1a98e5..756e47cbdf0 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -5,7 +5,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty, TypeAndMut}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/size_of_ref.rs b/clippy_lints/src/size_of_ref.rs index 7de029b7b94..14ca7a3f004 100644 --- a/clippy_lints/src/size_of_ref.rs +++ b/clippy_lints/src/size_of_ref.rs @@ -3,7 +3,7 @@ use clippy_utils::path_def_id; use clippy_utils::ty::peel_mid_ty_refs; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 733da790441..c4a5e48e855 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -9,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index d07a44770cc..38fd54a0f1e 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{HirId, Path, PathSegment}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index baa9750cc01..13ae1ff52dd 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -11,7 +11,7 @@ use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::sym; diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 644664b104d..8cf4715eeb8 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -6,7 +6,7 @@ use clippy_utils::{get_parent_node, match_libc_symbol}; use rustc_errors::Applicability; use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index b332309a552..8b9d9bade91 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::{BinOpKind, Expr, ExprKind, StmtKind}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; use rustc_span::Span; diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index 3244933a124..268c0c1b2df 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -4,7 +4,7 @@ use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TR use core::ops::ControlFlow; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/suspicious_xor_used_as_pow.rs b/clippy_lints/src/suspicious_xor_used_as_pow.rs index 4340c23f830..1cc27670fa8 100644 --- a/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 285f2f4f6f9..daa6fe8715c 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -8,7 +8,7 @@ use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, SyntaxContext}; diff --git a/clippy_lints/src/swap_ptr_to_ref.rs b/clippy_lints/src/swap_ptr_to_ref.rs index 6a6c94425d1..20e9608a15d 100644 --- a/clippy_lints/src/swap_ptr_to_ref.rs +++ b/clippy_lints/src/swap_ptr_to_ref.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span, SyntaxContext}; declare_clippy_lint! { diff --git a/clippy_lints/src/tabs_in_doc_comments.rs b/clippy_lints/src/tabs_in_doc_comments.rs index dcf1fac023a..af9e13dba36 100644 --- a/clippy_lints/src/tabs_in_doc_comments.rs +++ b/clippy_lints/src/tabs_in_doc_comments.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/temporary_assignment.rs b/clippy_lints/src/temporary_assignment.rs index c717ccc35a6..8151dd8f2cf 100644 --- a/clippy_lints/src/temporary_assignment.rs +++ b/clippy_lints/src/temporary_assignment.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::is_adjusted; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/tests_outside_test_module.rs b/clippy_lints/src/tests_outside_test_module.rs index 9481c78a505..da557582647 100644 --- a/clippy_lints/src/tests_outside_test_module.rs +++ b/clippy_lints/src/tests_outside_test_module.rs @@ -3,7 +3,7 @@ use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index 1dca523a966..dafe9e38818 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs index 7eef02b3c65..cbdf31c9336 100644 --- a/clippy_lints/src/trailing_empty_array.rs +++ b/clippy_lints/src/trailing_empty_array.rs @@ -3,7 +3,7 @@ use clippy_utils::has_repr_attr; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Const; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index e624bbe5ff1..e4054393d0a 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -13,7 +13,7 @@ use rustc_hir::{ TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Span}; use std::collections::hash_map::Entry; diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index a3a50acb609..95a92afea66 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -21,7 +21,7 @@ use clippy_config::msrvs::Msrv; use clippy_utils::in_constant; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/tuple_array_conversions.rs b/clippy_lints/src/tuple_array_conversions.rs index 642e39e8270..e1cd82e18d5 100644 --- a/clippy_lints/src/tuple_array_conversions.rs +++ b/clippy_lints/src/tuple_array_conversions.rs @@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use std::iter::once; use std::ops::ControlFlow; diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 4037808d34f..8e890b4df88 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -16,7 +16,7 @@ use rustc_hir::{ TraitItemKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::Span; diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 41c4d3359f4..7a6549a7c54 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -11,7 +11,7 @@ use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource}; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Pos, RelativeBytePos, Span, SyntaxContext}; declare_clippy_lint! { diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index b824deac2c8..3d319b9fe76 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -6,7 +6,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; use unicode_normalization::UnicodeNormalization; diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index a7119434517..fc8519d5628 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -6,7 +6,7 @@ use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKi use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; // TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index bfd30cec3dd..729972de6e6 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -4,7 +4,7 @@ use rustc_hir::{Closure, Expr, ExprKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::{ClauseKind, GenericPredicates, ProjectionPredicate, TraitPredicate}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { @@ -44,7 +44,9 @@ fn get_trait_predicates_for_trait_id<'tcx>( let mut preds = Vec::new(); for (pred, _) in generics.predicates { if let ClauseKind::Trait(poly_trait_pred) = pred.kind().skip_binder() - && let trait_pred = cx.tcx.instantiate_bound_regions_with_erased(pred.kind().rebind(poly_trait_pred)) + && let trait_pred = cx + .tcx + .instantiate_bound_regions_with_erased(pred.kind().rebind(poly_trait_pred)) && let Some(trait_def_id) = trait_id && trait_def_id == trait_pred.trait_ref.def_id { @@ -61,7 +63,9 @@ fn get_projection_pred<'tcx>( ) -> Option> { generics.predicates.iter().find_map(|(proj_pred, _)| { if let ClauseKind::Projection(pred) = proj_pred.kind().skip_binder() { - let projection_pred = cx.tcx.instantiate_bound_regions_with_erased(proj_pred.kind().rebind(pred)); + let projection_pred = cx + .tcx + .instantiate_bound_regions_with_erased(proj_pred.kind().rebind(pred)); if projection_pred.projection_ty.args == trait_pred.trait_ref.args { return Some(projection_pred); } diff --git a/clippy_lints/src/unit_types/mod.rs b/clippy_lints/src/unit_types/mod.rs index 884c6ca4d31..0abd48e6423 100644 --- a/clippy_lints/src/unit_types/mod.rs +++ b/clippy_lints/src/unit_types/mod.rs @@ -5,7 +5,7 @@ mod utils; use rustc_hir::{Expr, Local}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index 2223cbcb060..41e13e13e56 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index 9bd7167db25..f5af540fa14 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::{FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Symbol; declare_clippy_lint! { diff --git a/clippy_lints/src/unnecessary_map_on_constructor.rs b/clippy_lints/src/unnecessary_map_on_constructor.rs index 25a9db36d5c..9979e02297e 100644 --- a/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -4,24 +4,27 @@ use clippy_utils::ty::get_type_diagnostic_name; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Suggest removing the use of a may (or map_err) method when an Option or Result is being constructed. + /// Suggests removing the use of a `map()` (or `map_err()`) method when an `Option` or `Result` + /// is being constructed. /// /// ### Why is this bad? - /// It introduces unnecessary complexity. In this case the function can be used directly and - /// construct the Option or Result from the output. + /// It introduces unnecessary complexity. Instead, the function can be called before + /// constructing the `Option` or `Result` from its return value. /// /// ### Example /// ```no_run - /// Some(4).map(i32::swap_bytes); + /// Some(4).map(i32::swap_bytes) + /// # ; /// ``` /// Use instead: /// ```no_run - /// Some(i32::swap_bytes(4)); + /// Some(i32::swap_bytes(4)) + /// # ; /// ``` #[clippy::version = "1.74.0"] pub UNNECESSARY_MAP_ON_CONSTRUCTOR, diff --git a/clippy_lints/src/unnecessary_owned_empty_strings.rs b/clippy_lints/src/unnecessary_owned_empty_strings.rs index 14694bb3a28..6b5e6c6ab20 100644 --- a/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/unnecessary_self_imports.rs b/clippy_lints/src/unnecessary_self_imports.rs index 1e2b20469ef..ddee06b59ca 100644 --- a/clippy_lints/src/unnecessary_self_imports.rs +++ b/clippy_lints/src/unnecessary_self_imports.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::{Item, ItemKind, UseTreeKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::kw; declare_clippy_lint! { diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs index c35a2afab48..ed4d87ef8f8 100644 --- a/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/clippy_lints/src/unnecessary_struct_initialization.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::is_copy; use clippy_utils::{get_parent_expr, path_to_local}; use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 0d551639ea9..446160f8e0f 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -8,7 +8,7 @@ use rustc_hir::LangItem::{OptionSome, ResultOk}; use rustc_hir::{Body, ExprKind, FnDecl, Impl, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; use rustc_span::Span; diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 952c0dc72b1..65600009c1d 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -11,7 +11,7 @@ use rustc_ast::{self as ast, Mutability, Pat, PatKind, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::DUMMY_SP; use std::cell::Cell; use std::mem; diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index a7b2d2148e9..3f2f765f751 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Ident; use rustc_span::Span; diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index 780ece3677d..9c8c44c0a16 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -5,7 +5,7 @@ use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::def_id::{LocalDefId, LocalDefIdSet}; use rustc_span::Span; diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 0fcb62017c6..1de9adfcb96 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::{is_trait_method, is_try, match_trait_method, paths}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index 0473ecaabeb..ba72b3450b9 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -6,7 +6,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter::OnlyBodies; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index fbb36bea068..d5ca844b9e2 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/unused_self.rs b/clippy_lints/src/unused_self.rs index 532207310bc..a67f53f00ae 100644 --- a/clippy_lints/src/unused_self.rs +++ b/clippy_lints/src/unused_self.rs @@ -3,7 +3,7 @@ use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::visitors::is_local_used; use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use std::ops::ControlFlow; declare_clippy_lint! { diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index 9627f4c7454..0a73da202ec 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -4,7 +4,7 @@ use rustc_ast::visit::FnKind; use rustc_ast::{ast, ClosureBinder}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index 6e1d0e09fe2..ae2ac38cffe 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -12,7 +12,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index df4b42133f8..a615ef11691 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -6,7 +6,7 @@ use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::ImplItemKind; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::{sym, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index de6a75b79fc..d2a1d42f279 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -1,10 +1,10 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_hir_and_then; use itertools::Itertools; use rustc_errors::Applicability; -use rustc_hir::{Item, ItemKind}; +use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; declare_clippy_lint! { @@ -77,7 +77,7 @@ fn correct_ident(ident: &str) -> String { ident } -fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) { +fn check_ident(cx: &LateContext<'_>, ident: &Ident, hir_id: HirId, be_aggressive: bool) { let span = ident.span; let ident = ident.as_str(); let corrected = correct_ident(ident); @@ -89,14 +89,20 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) { // upper-case-acronyms-aggressive config option enabled || (be_aggressive && ident != corrected) { - span_lint_and_sugg( + span_lint_hir_and_then( cx, UPPER_CASE_ACRONYMS, + hir_id, span, &format!("name `{ident}` contains a capitalized acronym"), - "consider making the acronym lowercase, except the initial letter", - corrected, - Applicability::MaybeIncorrect, + |diag| { + diag.span_suggestion( + span, + "consider making the acronym lowercase, except the initial letter", + corrected, + Applicability::MaybeIncorrect, + ); + }, ); } } @@ -111,16 +117,15 @@ impl LateLintPass<'_> for UpperCaseAcronyms { } match it.kind { ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..) => { - check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive); + check_ident(cx, &it.ident, it.hir_id(), self.upper_case_acronyms_aggressive); }, ItemKind::Enum(ref enumdef, _) => { - check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive); + check_ident(cx, &it.ident, it.hir_id(), self.upper_case_acronyms_aggressive); // check enum variants separately because again we only want to lint on private enums and // the fn check_variant does not know about the vis of the enum of its variants - enumdef - .variants - .iter() - .for_each(|variant| check_ident(cx, &variant.ident, self.upper_case_acronyms_aggressive)); + enumdef.variants.iter().for_each(|variant| { + check_ident(cx, &variant.ident, variant.hir_id, self.upper_case_acronyms_aggressive); + }); }, _ => {}, } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index ac1d9acc70b..fa033838ef3 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -13,7 +13,7 @@ use rustc_hir::{ }; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 7aed1d6e30b..2ab24f70ae0 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -11,7 +11,7 @@ use rustc_infer::traits::Obligation; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; diff --git a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs index d78f67c05f0..5ddedb24b15 100644 --- a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs +++ b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs @@ -4,7 +4,7 @@ use regex::Regex; use rustc_ast as ast; use rustc_hir::{Item, ItemKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs index f514f166cff..7c70d3f45db 100644 --- a/clippy_lints/src/utils/internal_lints/collapsible_calls.rs +++ b/clippy_lints/src/utils/internal_lints/collapsible_calls.rs @@ -5,7 +5,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use std::borrow::{Borrow, Cow}; diff --git a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs index 5aa1417cfb4..5059712d69c 100644 --- a/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs +++ b/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_lint_allowed, paths}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs index 16d0636b834..07879e81fc2 100644 --- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs +++ b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs @@ -11,7 +11,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::ConstValue; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::sym; use rustc_span::symbol::Symbol; diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs index 66d32087fcd..4fb615e1d57 100644 --- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs +++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs @@ -7,7 +7,7 @@ use rustc_hir::Item; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::FloatTy; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; declare_clippy_lint! { diff --git a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 486e8220484..370ed430bcf 100644 --- a/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -11,7 +11,7 @@ use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 8ecdba47f89..373b076f92c 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -20,9 +20,9 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, intravisit, Closure, ExprKind, Item, ItemKind, Mutability, QPath}; -use rustc_lint::{CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId}; +use rustc_lint::{unerased_lint_store, CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId}; use rustc_middle::hir::nested_filter; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; use rustc_span::{sym, Loc, Span, Symbol}; use serde::ser::SerializeStruct; @@ -714,7 +714,7 @@ fn get_lint_group_and_level_or_lint( lint_name: &str, item: &Item<'_>, ) -> Option<(String, &'static str)> { - let result = cx.lint_store.check_lint_name( + let result = unerased_lint_store(cx.tcx.sess).check_lint_name( lint_name, Some(sym::clippy), &std::iter::once(Ident::with_dummy_span(sym::clippy)).collect(), @@ -746,7 +746,7 @@ fn get_lint_group_and_level_or_lint( } fn get_lint_group(cx: &LateContext<'_>, lint_id: LintId) -> Option { - for (group_name, lints, _) in cx.lint_store.get_lint_groups() { + for (group_name, lints, _) in unerased_lint_store(cx.tcx.sess).get_lint_groups() { if IGNORED_LINT_GROUPS.contains(&group_name) { continue; } diff --git a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs index 86b1a0ae624..6d5240db832 100644 --- a/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs +++ b/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs @@ -6,7 +6,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{self, EarlyBinder, GenericArgKind}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs b/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs index 77b95e51f62..326e1721461 100644 --- a/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs +++ b/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs @@ -4,7 +4,7 @@ use clippy_utils::{is_lint_allowed, method_calls, paths}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; declare_clippy_lint! { diff --git a/clippy_lints/src/utils/internal_lints/produce_ice.rs b/clippy_lints/src/utils/internal_lints/produce_ice.rs index 5899b94e16b..9169e2968eb 100644 --- a/clippy_lints/src/utils/internal_lints/produce_ice.rs +++ b/clippy_lints/src/utils/internal_lints/produce_ice.rs @@ -1,7 +1,7 @@ use rustc_ast::ast::NodeId; use rustc_ast::visit::FnKind; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::Span; declare_clippy_lint! { diff --git a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs index 9aa23b6efe3..70ca1b206b4 100644 --- a/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs +++ b/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs @@ -12,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::interpret::{Allocation, GlobalAlloc}; use rustc_middle::mir::ConstValue; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::Symbol; use rustc_span::Span; diff --git a/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs b/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs index fd51bca9e5b..a5c4bf474f7 100644 --- a/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs +++ b/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::ast::{Crate, ItemKind, ModKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index f58641289f8..ba958c5b392 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -12,7 +12,7 @@ use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, Span}; #[expect(clippy::module_name_repetitions)] @@ -57,7 +57,7 @@ fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { /// Checks if the given expression is a method call to a `Vec` method /// that also exists on slices. If this returns true, it means that /// this expression does not actually require a `Vec` and could just work with an array. -fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { +pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { const ALLOWED_METHOD_NAMES: &[&str] = &["len", "as_ptr", "is_empty"]; if let ExprKind::MethodCall(path, ..) = e.kind { diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index c8b9402f1ae..ac3b2bdaf65 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -11,7 +11,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{Span, Symbol}; declare_clippy_lint! { diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index 8abcc964b89..83369c66367 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{Item, VisibilityKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::symbol::kw; use rustc_span::Span; diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 5c1bea74486..9b0dac6af25 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -6,7 +6,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind, PathSegment, UseKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{sym, BytePos}; diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index b6f942a90d3..be16d2e5cc3 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -10,7 +10,7 @@ use rustc_ast::{ use rustc_errors::Applicability; use rustc_hir::{Expr, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::impl_lint_pass; use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 1d6217d186c..d3623d6fda4 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -2,7 +2,7 @@ use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index 41c1757fde8..fba3808261a 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -5,7 +5,7 @@ use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{Adt, Ty, TypeVisitableExt}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_lint_pass; use rustc_span::sym; declare_clippy_lint! { diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index dcfce45fc9a..35a8a7920a9 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -10,7 +10,7 @@ use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir::interpret::{alloc_range, Scalar}; -use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, List, ScalarInt, Ty, TyCtxt}; +use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List, ScalarInt, Ty, TyCtxt, UintTy}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::SyntaxContext; @@ -51,6 +51,63 @@ pub enum Constant<'tcx> { Err, } +trait IntTypeBounds: Sized { + type Output: PartialOrd; + + fn min_max(self) -> Option<(Self::Output, Self::Output)>; + fn bits(self) -> Self::Output; + fn ensure_fits(self, val: Self::Output) -> Option { + let (min, max) = self.min_max()?; + (min <= val && val <= max).then_some(val) + } +} +impl IntTypeBounds for UintTy { + type Output = u128; + fn min_max(self) -> Option<(Self::Output, Self::Output)> { + Some(match self { + UintTy::U8 => (u8::MIN.into(), u8::MAX.into()), + UintTy::U16 => (u16::MIN.into(), u16::MAX.into()), + UintTy::U32 => (u32::MIN.into(), u32::MAX.into()), + UintTy::U64 => (u64::MIN.into(), u64::MAX.into()), + UintTy::U128 => (u128::MIN, u128::MAX), + UintTy::Usize => (usize::MIN.try_into().ok()?, usize::MAX.try_into().ok()?), + }) + } + fn bits(self) -> Self::Output { + match self { + UintTy::U8 => 8, + UintTy::U16 => 16, + UintTy::U32 => 32, + UintTy::U64 => 64, + UintTy::U128 => 128, + UintTy::Usize => usize::BITS.into(), + } + } +} +impl IntTypeBounds for IntTy { + type Output = i128; + fn min_max(self) -> Option<(Self::Output, Self::Output)> { + Some(match self { + IntTy::I8 => (i8::MIN.into(), i8::MAX.into()), + IntTy::I16 => (i16::MIN.into(), i16::MAX.into()), + IntTy::I32 => (i32::MIN.into(), i32::MAX.into()), + IntTy::I64 => (i64::MIN.into(), i64::MAX.into()), + IntTy::I128 => (i128::MIN, i128::MAX), + IntTy::Isize => (isize::MIN.try_into().ok()?, isize::MAX.try_into().ok()?), + }) + } + fn bits(self) -> Self::Output { + match self { + IntTy::I8 => 8, + IntTy::I16 => 16, + IntTy::I32 => 32, + IntTy::I64 => 64, + IntTy::I128 => 128, + IntTy::Isize => isize::BITS.into(), + } + } +} + impl<'tcx> PartialEq for Constant<'tcx> { fn eq(&self, other: &Self) -> bool { match (self, other) { @@ -433,8 +490,15 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { match *o { Int(value) => { let ty::Int(ity) = *ty.kind() else { return None }; + let (min, _) = ity.min_max()?; // sign extend let value = sext(self.lcx.tcx, value, ity); + + // Applying unary - to the most negative value of any signed integer type panics. + if value == min { + return None; + } + let value = value.checked_neg()?; // clear unused bits Some(Int(unsext(self.lcx.tcx, value, ity))) @@ -570,17 +634,33 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { match (l, r) { (Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck_results.expr_ty_opt(left)?.kind() { ty::Int(ity) => { + let (ty_min_value, _) = ity.min_max()?; + let bits = ity.bits(); let l = sext(self.lcx.tcx, l, ity); let r = sext(self.lcx.tcx, r, ity); + + // Using / or %, where the left-hand argument is the smallest integer of a signed integer type and + // the right-hand argument is -1 always panics, even with overflow-checks disabled + if let BinOpKind::Div | BinOpKind::Rem = op.node + && l == ty_min_value + && r == -1 + { + return None; + } + let zext = |n: i128| Constant::Int(unsext(self.lcx.tcx, n, ity)); match op.node { - BinOpKind::Add => l.checked_add(r).map(zext), - BinOpKind::Sub => l.checked_sub(r).map(zext), - BinOpKind::Mul => l.checked_mul(r).map(zext), + // When +, * or binary - create a value greater than the maximum value, or less than + // the minimum value that can be stored, it panics. + BinOpKind::Add => l.checked_add(r).and_then(|n| ity.ensure_fits(n)).map(zext), + BinOpKind::Sub => l.checked_sub(r).and_then(|n| ity.ensure_fits(n)).map(zext), + BinOpKind::Mul => l.checked_mul(r).and_then(|n| ity.ensure_fits(n)).map(zext), BinOpKind::Div if r != 0 => l.checked_div(r).map(zext), BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext), - BinOpKind::Shr => l.checked_shr(r.try_into().ok()?).map(zext), - BinOpKind::Shl => l.checked_shl(r.try_into().ok()?).map(zext), + // Using << or >> where the right-hand argument is greater than or equal to the number of bits + // in the type of the left-hand argument, or is negative panics. + BinOpKind::Shr if r < bits && !r.is_negative() => l.checked_shr(r.try_into().ok()?).map(zext), + BinOpKind::Shl if r < bits && !r.is_negative() => l.checked_shl(r.try_into().ok()?).map(zext), BinOpKind::BitXor => Some(zext(l ^ r)), BinOpKind::BitOr => Some(zext(l | r)), BinOpKind::BitAnd => Some(zext(l & r)), @@ -593,24 +673,28 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { _ => None, } }, - ty::Uint(_) => match op.node { - BinOpKind::Add => l.checked_add(r).map(Constant::Int), - BinOpKind::Sub => l.checked_sub(r).map(Constant::Int), - BinOpKind::Mul => l.checked_mul(r).map(Constant::Int), - BinOpKind::Div => l.checked_div(r).map(Constant::Int), - BinOpKind::Rem => l.checked_rem(r).map(Constant::Int), - BinOpKind::Shr => l.checked_shr(r.try_into().ok()?).map(Constant::Int), - BinOpKind::Shl => l.checked_shl(r.try_into().ok()?).map(Constant::Int), - BinOpKind::BitXor => Some(Constant::Int(l ^ r)), - BinOpKind::BitOr => Some(Constant::Int(l | r)), - BinOpKind::BitAnd => Some(Constant::Int(l & r)), - BinOpKind::Eq => Some(Constant::Bool(l == r)), - BinOpKind::Ne => Some(Constant::Bool(l != r)), - BinOpKind::Lt => Some(Constant::Bool(l < r)), - BinOpKind::Le => Some(Constant::Bool(l <= r)), - BinOpKind::Ge => Some(Constant::Bool(l >= r)), - BinOpKind::Gt => Some(Constant::Bool(l > r)), - _ => None, + ty::Uint(ity) => { + let bits = ity.bits(); + + match op.node { + BinOpKind::Add => l.checked_add(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int), + BinOpKind::Sub => l.checked_sub(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int), + BinOpKind::Mul => l.checked_mul(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int), + BinOpKind::Div => l.checked_div(r).map(Constant::Int), + BinOpKind::Rem => l.checked_rem(r).map(Constant::Int), + BinOpKind::Shr if r < bits => l.checked_shr(r.try_into().ok()?).map(Constant::Int), + BinOpKind::Shl if r < bits => l.checked_shl(r.try_into().ok()?).map(Constant::Int), + BinOpKind::BitXor => Some(Constant::Int(l ^ r)), + BinOpKind::BitOr => Some(Constant::Int(l | r)), + BinOpKind::BitAnd => Some(Constant::Int(l & r)), + BinOpKind::Eq => Some(Constant::Bool(l == r)), + BinOpKind::Ne => Some(Constant::Bool(l != r)), + BinOpKind::Lt => Some(Constant::Bool(l < r)), + BinOpKind::Le => Some(Constant::Bool(l <= r)), + BinOpKind::Ge => Some(Constant::Bool(l >= r)), + BinOpKind::Gt => Some(Constant::Bool(l > r)), + _ => None, + } }, _ => None, }, diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 0bcefba75a7..4e71c6483e6 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -9,12 +9,13 @@ //! - or-fun-call //! - option-if-let-else +use crate::consts::{constant, FullInt}; 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::{Block, Expr, ExprKind, QPath, UnOp}; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_middle::ty::adjustment::Adjust; @@ -193,6 +194,12 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS self.eagerness = Lazy; } }, + + // `-i32::MIN` panics with overflow checks + ExprKind::Unary(UnOp::Neg, right) if constant(self.cx, self.cx.typeck_results(), right).is_none() => { + self.eagerness |= NoChange; + }, + // Custom `Deref` impl might have side effects ExprKind::Unary(UnOp::Deref, e) if self.cx.typeck_results().expr_ty(e).builtin_deref(true).is_none() => @@ -207,6 +214,49 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS self.cx.typeck_results().expr_ty(e).kind(), ty::Bool | ty::Int(_) | ty::Uint(_), ) => {}, + + // `>>` and `<<` panic when the right-hand side is greater than or equal to the number of bits in the + // type of the left-hand side, or is negative. + // We intentionally only check if the right-hand isn't a constant, because even if the suggestion would + // overflow with constants, the compiler emits an error for it and the programmer will have to fix it. + // Thus, we would realistically only delay the lint. + ExprKind::Binary(op, _, right) + if matches!(op.node, BinOpKind::Shl | BinOpKind::Shr) + && constant(self.cx, self.cx.typeck_results(), right).is_none() => + { + self.eagerness |= NoChange; + }, + + ExprKind::Binary(op, left, right) + if matches!(op.node, BinOpKind::Div | BinOpKind::Rem) + && let right_ty = self.cx.typeck_results().expr_ty(right) + && let left = constant(self.cx, self.cx.typeck_results(), left) + && let right = constant(self.cx, self.cx.typeck_results(), right) + .and_then(|c| c.int_value(self.cx, right_ty)) + && matches!( + (left, right), + // `1 / x`: x might be zero + (_, None) + // `x / -1`: x might be T::MIN + | (None, Some(FullInt::S(-1))) + ) => + { + self.eagerness |= NoChange; + }, + + // Similar to `>>` and `<<`, we only want to avoid linting entirely if either side is unknown and the + // compiler can't emit an error for an overflowing expression. + // Suggesting eagerness for `true.then(|| i32::MAX + 1)` is okay because the compiler will emit an + // error and it's good to have the eagerness warning up front when the user fixes the logic error. + ExprKind::Binary(op, left, right) + if matches!(op.node, BinOpKind::Add | BinOpKind::Sub | BinOpKind::Mul) + && !self.cx.typeck_results().expr_ty(e).is_floating_point() + && (constant(self.cx, self.cx.typeck_results(), left).is_none() + || constant(self.cx, self.cx.typeck_results(), right).is_none()) => + { + self.eagerness |= NoChange; + }, + ExprKind::Binary(_, lhs, rhs) if self.cx.typeck_results().expr_ty(lhs).is_primitive() && self.cx.typeck_results().expr_ty(rhs).is_primitive() => {}, diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 34ec83709ff..e610ed93050 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1017,8 +1017,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } e.hash(&mut self.s); }, - PatKind::Never => {}, - PatKind::Wild => {}, + PatKind::Never | PatKind::Wild => {}, } } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index fd37713fc60..f3b63f1cdcf 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1706,8 +1706,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { } match pat.kind { - PatKind::Wild => false, - PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. + PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)), PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), PatKind::Lit(..) | PatKind::Range(..) => true, diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index f143163152e..9b2bc8df1f3 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -159,7 +159,7 @@ impl<'a> Sugg<'a> { Sugg::BinOp(hirbinop2assignop(op), get_snippet(lhs.span), get_snippet(rhs.span)) }, hir::ExprKind::Binary(op, lhs, rhs) => Sugg::BinOp( - AssocOp::from_ast_binop(op.node.into()), + AssocOp::from_ast_binop(op.node), get_snippet(lhs.span), get_snippet(rhs.span), ), @@ -380,10 +380,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String { | AssocOp::NotEqual | AssocOp::Greater | AssocOp::GreaterEqual => { - format!( - "{lhs} {} {rhs}", - op.to_ast_binop().expect("Those are AST ops").as_str() - ) + format!("{lhs} {} {rhs}", op.to_ast_binop().expect("Those are AST ops").as_str()) }, AssocOp::Assign => format!("{lhs} = {rhs}"), AssocOp::AssignOp(op) => { diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs index c325e4eae21..da71fc3aaa8 100644 --- a/clippy_utils/src/ty/type_certainty/mod.rs +++ b/clippy_utils/src/ty/type_certainty/mod.rs @@ -170,19 +170,18 @@ fn qpath_certainty(cx: &LateContext<'_>, qpath: &QPath<'_>, resolves_to_type: bo 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 - } - }) - }, + 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 diff --git a/declare_clippy_lint/src/lib.rs b/declare_clippy_lint/src/lib.rs index dc3037f6669..25b2fc9395c 100644 --- a/declare_clippy_lint/src/lib.rs +++ b/declare_clippy_lint/src/lib.rs @@ -148,7 +148,7 @@ pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { let category_variant = format_ident!("{category}"); let output = quote! { - declare_tool_lint! { + rustc_session::declare_tool_lint! { #(#attrs)* pub clippy::#name, #level, diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index 58cb42316fd..841b605f5fb 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -309,7 +309,7 @@ impl Crate { target_dir_index: &AtomicUsize, total_crates_to_lint: usize, config: &LintcheckConfig, - lint_filter: &Vec, + lint_filter: &[String], server: &Option, ) -> Vec { // advance the atomic index by one @@ -728,7 +728,7 @@ fn read_stats_from_file(file_path: &Path) -> HashMap { } /// print how lint counts changed between runs -fn print_stats(old_stats: HashMap, new_stats: HashMap<&String, usize>, lint_filter: &Vec) { +fn print_stats(old_stats: HashMap, new_stats: HashMap<&String, usize>, lint_filter: &[String]) { let same_in_both_hashmaps = old_stats .iter() .filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val)) diff --git a/rust-toolchain b/rust-toolchain index d40e176b4b0..684cf4574b9 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-11-16" +channel = "nightly-2023-12-01" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/tests/ui-toml/private-doc-errors/clippy.toml b/tests/ui-toml/private-doc-errors/clippy.toml new file mode 100644 index 00000000000..8483b87c650 --- /dev/null +++ b/tests/ui-toml/private-doc-errors/clippy.toml @@ -0,0 +1 @@ +check-private-items = true diff --git a/tests/ui-toml/private-doc-errors/doc_lints.rs b/tests/ui-toml/private-doc-errors/doc_lints.rs new file mode 100644 index 00000000000..ae4c3f84c29 --- /dev/null +++ b/tests/ui-toml/private-doc-errors/doc_lints.rs @@ -0,0 +1,54 @@ +#![deny( + clippy::unnecessary_safety_doc, + clippy::missing_errors_doc, + clippy::missing_panics_doc +)] + +/// This is a private function, skip to match behavior with `missing_safety_doc`. +/// +/// # Safety +/// +/// Boo! +fn you_dont_see_me() { + //~^ ERROR: safe function's docs have unnecessary `# Safety` section + unimplemented!(); +} + +mod private_mod { + /// This is public but unexported function. + /// + /// # Safety + /// + /// Very safe! + pub fn only_crate_wide_accessible() -> Result<(), ()> { + //~^ ERROR: safe function's docs have unnecessary `# Safety` section + //~| ERROR: docs for function returning `Result` missing `# Errors` section + unimplemented!(); + } +} + +pub struct S; + +impl S { + /// Private, fine again to stay consistent with `missing_safety_doc`. + /// + /// # Safety + /// + /// Unnecessary! + fn private(&self) { + //~^ ERROR: safe function's docs have unnecessary `# Safety` section + //~| ERROR: docs for function which may panic missing `# Panics` section + panic!(); + } +} + +#[doc(hidden)] +pub mod __macro { + pub struct T; + impl T { + pub unsafe fn f() {} + //~^ ERROR: unsafe function's docs miss `# Safety` section + } +} + +fn main() {} diff --git a/tests/ui-toml/private-doc-errors/doc_lints.stderr b/tests/ui-toml/private-doc-errors/doc_lints.stderr new file mode 100644 index 00000000000..85336748049 --- /dev/null +++ b/tests/ui-toml/private-doc-errors/doc_lints.stderr @@ -0,0 +1,64 @@ +error: safe function's docs have unnecessary `# Safety` section + --> $DIR/doc_lints.rs:12:1 + | +LL | fn you_dont_see_me() { + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/doc_lints.rs:2:5 + | +LL | clippy::unnecessary_safety_doc, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: safe function's docs have unnecessary `# Safety` section + --> $DIR/doc_lints.rs:23:5 + | +LL | pub fn only_crate_wide_accessible() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: docs for function returning `Result` missing `# Errors` section + --> $DIR/doc_lints.rs:23:5 + | +LL | pub fn only_crate_wide_accessible() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/doc_lints.rs:3:5 + | +LL | clippy::missing_errors_doc, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: safe function's docs have unnecessary `# Safety` section + --> $DIR/doc_lints.rs:38:5 + | +LL | fn private(&self) { + | ^^^^^^^^^^^^^^^^^ + +error: docs for function which may panic missing `# Panics` section + --> $DIR/doc_lints.rs:38:5 + | +LL | fn private(&self) { + | ^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> $DIR/doc_lints.rs:41:9 + | +LL | panic!(); + | ^^^^^^^^ +note: the lint level is defined here + --> $DIR/doc_lints.rs:4:5 + | +LL | clippy::missing_panics_doc + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unsafe function's docs miss `# Safety` section + --> $DIR/doc_lints.rs:49:9 + | +LL | pub unsafe fn f() {} + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::missing-safety-doc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_safety_doc)]` + +error: aborting due to 6 previous errors + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 2f9eaa5178c..12828cf9dec 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -21,6 +21,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect await-holding-invalid-types blacklisted-names cargo-ignore-publish + check-private-items cognitive-complexity-threshold cyclomatic-complexity-threshold disallowed-macros @@ -95,6 +96,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect await-holding-invalid-types blacklisted-names cargo-ignore-publish + check-private-items cognitive-complexity-threshold cyclomatic-complexity-threshold disallowed-macros diff --git a/tests/ui/attrs.rs b/tests/ui/attrs.rs index 05ee48d17b1..da96eabede1 100644 --- a/tests/ui/attrs.rs +++ b/tests/ui/attrs.rs @@ -36,6 +36,9 @@ pub const ANOTHER_CONST: u8 = 23; #[deprecated(since = "0.1.1")] pub const YET_ANOTHER_CONST: u8 = 0; +#[deprecated(since = "TBD")] +pub const GONNA_DEPRECATE_THIS_LATER: u8 = 0; + fn main() { test_attr_lint(); if false { diff --git a/tests/ui/box_default.fixed b/tests/ui/box_default.fixed index 69cabcb32d3..48408e19125 100644 --- a/tests/ui/box_default.fixed +++ b/tests/ui/box_default.fixed @@ -90,3 +90,17 @@ fn issue_10381() { assert!(maybe_get_bar(2).is_some()); } + +#[allow(unused)] +fn issue_11868() { + fn foo(_: &mut Vec) {} + + macro_rules! bar { + ($baz:expr) => { + Box::leak(Box::new($baz)) + }; + } + + foo(bar!(vec![])); + foo(bar!(vec![1])); +} diff --git a/tests/ui/box_default.rs b/tests/ui/box_default.rs index 48fa8bc33bc..58b91270747 100644 --- a/tests/ui/box_default.rs +++ b/tests/ui/box_default.rs @@ -90,3 +90,17 @@ fn issue_10381() { assert!(maybe_get_bar(2).is_some()); } + +#[allow(unused)] +fn issue_11868() { + fn foo(_: &mut Vec) {} + + macro_rules! bar { + ($baz:expr) => { + Box::leak(Box::new($baz)) + }; + } + + foo(bar!(vec![])); + foo(bar!(vec![1])); +} diff --git a/tests/ui/cfg_features.fixed b/tests/ui/cfg_features.fixed index 3d52f2382ea..0fe38f169f9 100644 --- a/tests/ui/cfg_features.fixed +++ b/tests/ui/cfg_features.fixed @@ -2,16 +2,28 @@ fn main() { #[cfg(feature = "not-really-a-feature")] - //~^ ERROR: feature may misspelled as features + //~^ ERROR: 'feature' may be misspelled as 'features' //~| NOTE: `-D clippy::maybe-misused-cfg` implied by `-D warnings` let _ = 1 + 2; #[cfg(all(feature = "right", feature = "wrong"))] - //~^ ERROR: feature may misspelled as features + //~^ ERROR: 'feature' may be misspelled as 'features' let _ = 1 + 2; #[cfg(all(feature = "wrong1", any(feature = "right", feature = "wrong2", feature, features)))] - //~^ ERROR: feature may misspelled as features - //~| ERROR: feature may misspelled as features + //~^ ERROR: 'feature' may be misspelled as 'features' + //~| ERROR: 'feature' may be misspelled as 'features' let _ = 1 + 2; + + #[cfg(test)] + //~^ ERROR: 'test' may be misspelled as 'tests' + let _ = 2; + #[cfg(test)] + //~^ ERROR: 'test' may be misspelled as 'Test' + let _ = 2; + + #[cfg(all(test, test))] + //~^ ERROR: 'test' may be misspelled as 'tests' + //~| ERROR: 'test' may be misspelled as 'Test' + let _ = 2; } diff --git a/tests/ui/cfg_features.rs b/tests/ui/cfg_features.rs index a0344a00447..9c0db035eac 100644 --- a/tests/ui/cfg_features.rs +++ b/tests/ui/cfg_features.rs @@ -2,16 +2,28 @@ fn main() { #[cfg(features = "not-really-a-feature")] - //~^ ERROR: feature may misspelled as features + //~^ ERROR: 'feature' may be misspelled as 'features' //~| NOTE: `-D clippy::maybe-misused-cfg` implied by `-D warnings` let _ = 1 + 2; #[cfg(all(feature = "right", features = "wrong"))] - //~^ ERROR: feature may misspelled as features + //~^ ERROR: 'feature' may be misspelled as 'features' let _ = 1 + 2; #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] - //~^ ERROR: feature may misspelled as features - //~| ERROR: feature may misspelled as features + //~^ ERROR: 'feature' may be misspelled as 'features' + //~| ERROR: 'feature' may be misspelled as 'features' let _ = 1 + 2; + + #[cfg(tests)] + //~^ ERROR: 'test' may be misspelled as 'tests' + let _ = 2; + #[cfg(Test)] + //~^ ERROR: 'test' may be misspelled as 'Test' + let _ = 2; + + #[cfg(all(tests, Test))] + //~^ ERROR: 'test' may be misspelled as 'tests' + //~| ERROR: 'test' may be misspelled as 'Test' + let _ = 2; } diff --git a/tests/ui/cfg_features.stderr b/tests/ui/cfg_features.stderr index 401c3e92ed9..e1593e2071b 100644 --- a/tests/ui/cfg_features.stderr +++ b/tests/ui/cfg_features.stderr @@ -1,29 +1,53 @@ -error: feature may misspelled as features +error: 'feature' may be misspelled as 'features' --> $DIR/cfg_features.rs:4:11 | LL | #[cfg(features = "not-really-a-feature")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `feature = "not-really-a-feature"` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "not-really-a-feature"` | = note: `-D clippy::maybe-misused-cfg` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::maybe_misused_cfg)]` -error: feature may misspelled as features +error: 'feature' may be misspelled as 'features' --> $DIR/cfg_features.rs:9:34 | LL | #[cfg(all(feature = "right", features = "wrong"))] - | ^^^^^^^^^^^^^^^^^^ help: use: `feature = "wrong"` + | ^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "wrong"` -error: feature may misspelled as features +error: 'feature' may be misspelled as 'features' --> $DIR/cfg_features.rs:13:15 | LL | #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] - | ^^^^^^^^^^^^^^^^^^^ help: use: `feature = "wrong1"` + | ^^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "wrong1"` -error: feature may misspelled as features +error: 'feature' may be misspelled as 'features' --> $DIR/cfg_features.rs:13:59 | LL | #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] - | ^^^^^^^^^^^^^^^^^^^ help: use: `feature = "wrong2"` + | ^^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "wrong2"` -error: aborting due to 4 previous errors +error: 'test' may be misspelled as 'tests' + --> $DIR/cfg_features.rs:18:11 + | +LL | #[cfg(tests)] + | ^^^^^ help: did you mean: `test` + +error: 'test' may be misspelled as 'Test' + --> $DIR/cfg_features.rs:21:11 + | +LL | #[cfg(Test)] + | ^^^^ help: did you mean: `test` + +error: 'test' may be misspelled as 'tests' + --> $DIR/cfg_features.rs:25:15 + | +LL | #[cfg(all(tests, Test))] + | ^^^^^ help: did you mean: `test` + +error: 'test' may be misspelled as 'Test' + --> $DIR/cfg_features.rs:25:22 + | +LL | #[cfg(all(tests, Test))] + | ^^^^ help: did you mean: `test` + +error: aborting due to 8 previous errors diff --git a/tests/ui/doc_link_with_quotes.rs b/tests/ui/doc_link_with_quotes.rs index 37d0d135957..48e1b1819c6 100644 --- a/tests/ui/doc_link_with_quotes.rs +++ b/tests/ui/doc_link_with_quotes.rs @@ -11,6 +11,12 @@ pub fn foo() { bar() } +/// Calls ["bar"] uselessly +//~^ ERROR: possible intra-doc link using quotes instead of backticks +pub fn foo2() { + bar() +} + /// # Examples /// This demonstrates issue \#8961 /// ``` diff --git a/tests/ui/doc_link_with_quotes.stderr b/tests/ui/doc_link_with_quotes.stderr index e1883f349b0..cd4f87c56b4 100644 --- a/tests/ui/doc_link_with_quotes.stderr +++ b/tests/ui/doc_link_with_quotes.stderr @@ -7,5 +7,11 @@ LL | /// Calls ['bar'] uselessly = note: `-D clippy::doc-link-with-quotes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::doc_link_with_quotes)]` -error: aborting due to 1 previous error +error: possible intra-doc link using quotes instead of backticks + --> $DIR/doc_link_with_quotes.rs:14:12 + | +LL | /// Calls ["bar"] uselessly + | ^^^^^ + +error: aborting due to 2 previous errors diff --git a/tests/ui/floating_point_mul_add.fixed b/tests/ui/floating_point_mul_add.fixed index a4d6d49e57c..3ce2edf2c71 100644 --- a/tests/ui/floating_point_mul_add.fixed +++ b/tests/ui/floating_point_mul_add.fixed @@ -39,3 +39,21 @@ fn main() { // Cases where the lint shouldn't be applied let _ = (a * a + b * b).sqrt(); } + +fn _issue11831() { + struct NotAFloat; + + impl std::ops::Add for NotAFloat { + type Output = Self; + + fn add(self, _: f64) -> Self { + NotAFloat + } + } + + let a = NotAFloat; + let b = 1.0_f64; + let c = 1.0; + + let _ = a + b * c; +} diff --git a/tests/ui/floating_point_mul_add.rs b/tests/ui/floating_point_mul_add.rs index 262a20f0f55..b5e4a8db4db 100644 --- a/tests/ui/floating_point_mul_add.rs +++ b/tests/ui/floating_point_mul_add.rs @@ -39,3 +39,21 @@ fn main() { // Cases where the lint shouldn't be applied let _ = (a * a + b * b).sqrt(); } + +fn _issue11831() { + struct NotAFloat; + + impl std::ops::Add for NotAFloat { + type Output = Self; + + fn add(self, _: f64) -> Self { + NotAFloat + } + } + + let a = NotAFloat; + let b = 1.0_f64; + let c = 1.0; + + let _ = a + b * c; +} diff --git a/tests/ui/impl_hash_with_borrow_str_and_bytes.rs b/tests/ui/impl_hash_with_borrow_str_and_bytes.rs new file mode 100644 index 00000000000..f6ce6153e01 --- /dev/null +++ b/tests/ui/impl_hash_with_borrow_str_and_bytes.rs @@ -0,0 +1,136 @@ +#![warn(clippy::impl_hash_borrow_with_str_and_bytes)] + +use std::borrow::Borrow; +use std::hash::{Hash, Hasher}; + +struct ExampleType { + data: String, +} + +impl Hash for ExampleType { + //~^ ERROR: can't + fn hash(&self, state: &mut H) { + self.data.hash(state); + } +} + +impl Borrow for ExampleType { + fn borrow(&self) -> &str { + &self.data + } +} + +impl Borrow<[u8]> for ExampleType { + fn borrow(&self) -> &[u8] { + self.data.as_bytes() + } +} + +struct ShouldNotRaiseForHash {} +impl Hash for ShouldNotRaiseForHash { + fn hash(&self, state: &mut H) { + todo!(); + } +} + +struct ShouldNotRaiseForBorrow {} +impl Borrow for ShouldNotRaiseForBorrow { + fn borrow(&self) -> &str { + todo!(); + } +} +impl Borrow<[u8]> for ShouldNotRaiseForBorrow { + fn borrow(&self) -> &[u8] { + todo!(); + } +} + +struct ShouldNotRaiseForHashBorrowStr {} +impl Hash for ShouldNotRaiseForHashBorrowStr { + fn hash(&self, state: &mut H) { + todo!(); + } +} +impl Borrow for ShouldNotRaiseForHashBorrowStr { + fn borrow(&self) -> &str { + todo!(); + } +} + +struct ShouldNotRaiseForHashBorrowSlice {} +impl Hash for ShouldNotRaiseForHashBorrowSlice { + fn hash(&self, state: &mut H) { + todo!(); + } +} + +impl Borrow<[u8]> for ShouldNotRaiseForHashBorrowSlice { + fn borrow(&self) -> &[u8] { + todo!(); + } +} + +#[derive(Hash)] +//~^ ERROR: can't +struct Derived { + data: String, +} + +impl Borrow for Derived { + fn borrow(&self) -> &str { + self.data.as_str() + } +} + +impl Borrow<[u8]> for Derived { + fn borrow(&self) -> &[u8] { + self.data.as_bytes() + } +} + +struct GenericExampleType { + data: T, +} + +impl Hash for GenericExampleType { + fn hash(&self, state: &mut H) { + self.data.hash(state); + } +} + +impl Borrow for GenericExampleType { + fn borrow(&self) -> &str { + &self.data + } +} + +impl Borrow<[u8]> for GenericExampleType<&'static [u8]> { + fn borrow(&self) -> &[u8] { + self.data + } +} + +struct GenericExampleType2 { + data: T, +} + +impl Hash for GenericExampleType2 { + //~^ ERROR: can't + // this is correctly throwing an error for generic with concrete impl + // for all 3 types + fn hash(&self, state: &mut H) { + self.data.hash(state); + } +} + +impl Borrow for GenericExampleType2 { + fn borrow(&self) -> &str { + &self.data + } +} + +impl Borrow<[u8]> for GenericExampleType2 { + fn borrow(&self) -> &[u8] { + self.data.as_bytes() + } +} diff --git a/tests/ui/impl_hash_with_borrow_str_and_bytes.stderr b/tests/ui/impl_hash_with_borrow_str_and_bytes.stderr new file mode 100644 index 00000000000..afc35ef9845 --- /dev/null +++ b/tests/ui/impl_hash_with_borrow_str_and_bytes.stderr @@ -0,0 +1,41 @@ +error: the semantics of `Borrow` around `Hash` can't be satisfied when both `Borrow` and `Borrow<[u8]>` are implemented + --> $DIR/impl_hash_with_borrow_str_and_bytes.rs:10:6 + | +LL | impl Hash for ExampleType { + | ^^^^ + | + = note: the `Borrow` semantics require that `Hash` must behave the same for all implementations of Borrow + = note: however, the hash implementations of a string (`str`) and the bytes of a string `[u8]` do not behave the same ... + = note: ... as (`hash("abc") != hash("abc".as_bytes())` + = help: consider either removing one of the `Borrow` implementations (`Borrow` or `Borrow<[u8]>`) ... + = help: ... or not implementing `Hash` for this type + = note: `-D clippy::impl-hash-borrow-with-str-and-bytes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::impl_hash_borrow_with_str_and_bytes)]` + +error: the semantics of `Borrow` around `Hash` can't be satisfied when both `Borrow` and `Borrow<[u8]>` are implemented + --> $DIR/impl_hash_with_borrow_str_and_bytes.rs:73:10 + | +LL | #[derive(Hash)] + | ^^^^ + | + = note: the `Borrow` semantics require that `Hash` must behave the same for all implementations of Borrow + = note: however, the hash implementations of a string (`str`) and the bytes of a string `[u8]` do not behave the same ... + = note: ... as (`hash("abc") != hash("abc".as_bytes())` + = help: consider either removing one of the `Borrow` implementations (`Borrow` or `Borrow<[u8]>`) ... + = help: ... or not implementing `Hash` for this type + = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: the semantics of `Borrow` around `Hash` can't be satisfied when both `Borrow` and `Borrow<[u8]>` are implemented + --> $DIR/impl_hash_with_borrow_str_and_bytes.rs:117:6 + | +LL | impl Hash for GenericExampleType2 { + | ^^^^ + | + = note: the `Borrow` semantics require that `Hash` must behave the same for all implementations of Borrow + = note: however, the hash implementations of a string (`str`) and the bytes of a string `[u8]` do not behave the same ... + = note: ... as (`hash("abc") != hash("abc".as_bytes())` + = help: consider either removing one of the `Borrow` implementations (`Borrow` or `Borrow<[u8]>`) ... + = help: ... or not implementing `Hash` for this type + +error: aborting due to 3 previous errors + diff --git a/tests/ui/iter_kv_map.fixed b/tests/ui/iter_kv_map.fixed index 566a5b690d8..2cbf972fca5 100644 --- a/tests/ui/iter_kv_map.fixed +++ b/tests/ui/iter_kv_map.fixed @@ -89,3 +89,46 @@ fn main() { // Don't let a mut interfere. let _ = map.clone().into_values().count(); } + +#[clippy::msrv = "1.53"] +fn msrv_1_53() { + let map: HashMap = HashMap::new(); + + // Don't lint because into_iter is not supported + let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + + let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + + // Lint + let _ = map.keys().collect::>(); + //~^ ERROR: iterating on a map's keys + let _ = map.values().collect::>(); + //~^ ERROR: iterating on a map's values + let _ = map.values().map(|v| v + 2).collect::>(); + //~^ ERROR: iterating on a map's values +} + +#[clippy::msrv = "1.54"] +fn msrv_1_54() { + // Lint all + let map: HashMap = HashMap::new(); + + let _ = map.clone().into_keys().collect::>(); + //~^ ERROR: iterating on a map's keys + let _ = map.clone().into_keys().map(|key| key + 2).collect::>(); + //~^ ERROR: iterating on a map's keys + + let _ = map.clone().into_values().collect::>(); + //~^ ERROR: iterating on a map's values + let _ = map.clone().into_values().map(|val| val + 2).collect::>(); + //~^ ERROR: iterating on a map's values + + let _ = map.keys().collect::>(); + //~^ ERROR: iterating on a map's keys + let _ = map.values().collect::>(); + //~^ ERROR: iterating on a map's values + let _ = map.values().map(|v| v + 2).collect::>(); + //~^ ERROR: iterating on a map's values +} diff --git a/tests/ui/iter_kv_map.rs b/tests/ui/iter_kv_map.rs index d85e501da48..6a9a4267a76 100644 --- a/tests/ui/iter_kv_map.rs +++ b/tests/ui/iter_kv_map.rs @@ -93,3 +93,46 @@ fn main() { // Don't let a mut interfere. let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); } + +#[clippy::msrv = "1.53"] +fn msrv_1_53() { + let map: HashMap = HashMap::new(); + + // Don't lint because into_iter is not supported + let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + + let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + + // Lint + let _ = map.iter().map(|(key, _)| key).collect::>(); + //~^ ERROR: iterating on a map's keys + let _ = map.iter().map(|(_, value)| value).collect::>(); + //~^ ERROR: iterating on a map's values + let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + //~^ ERROR: iterating on a map's values +} + +#[clippy::msrv = "1.54"] +fn msrv_1_54() { + // Lint all + let map: HashMap = HashMap::new(); + + let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + //~^ ERROR: iterating on a map's keys + let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + //~^ ERROR: iterating on a map's keys + + let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + //~^ ERROR: iterating on a map's values + let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + //~^ ERROR: iterating on a map's values + + let _ = map.iter().map(|(key, _)| key).collect::>(); + //~^ ERROR: iterating on a map's keys + let _ = map.iter().map(|(_, value)| value).collect::>(); + //~^ ERROR: iterating on a map's values + let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + //~^ ERROR: iterating on a map's values +} diff --git a/tests/ui/iter_kv_map.stderr b/tests/ui/iter_kv_map.stderr index 62155b7f838..471615978e1 100644 --- a/tests/ui/iter_kv_map.stderr +++ b/tests/ui/iter_kv_map.stderr @@ -201,5 +201,65 @@ error: iterating on a map's values LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` -error: aborting due to 28 previous errors +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:109:13 + | +LL | let _ = map.iter().map(|(key, _)| key).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:111:13 + | +LL | let _ = map.iter().map(|(_, value)| value).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:113:13 + | +LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:122:13 + | +LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:124:13 + | +LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:127:13 + | +LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:129:13 + | +LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` + +error: iterating on a map's keys + --> $DIR/iter_kv_map.rs:132:13 + | +LL | let _ = map.iter().map(|(key, _)| key).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:134:13 + | +LL | let _ = map.iter().map(|(_, value)| value).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` + +error: iterating on a map's values + --> $DIR/iter_kv_map.rs:136:13 + | +LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` + +error: aborting due to 38 previous errors diff --git a/tests/ui/join_absolute_paths.rs b/tests/ui/join_absolute_paths.rs new file mode 100644 index 00000000000..efa77a0492e --- /dev/null +++ b/tests/ui/join_absolute_paths.rs @@ -0,0 +1,30 @@ +//@no-rustfix + +#![allow(clippy::needless_raw_string_hashes)] +#![warn(clippy::join_absolute_paths)] + +use std::path::{Path, PathBuf}; + +fn main() { + let path = Path::new("/bin"); + path.join("/sh"); + //~^ ERROR: argument to `Path::join` starts with a path separator + + let path = Path::new("C:\\Users"); + path.join("\\user"); + //~^ ERROR: argument to `Path::join` starts with a path separator + + let path = PathBuf::from("/bin"); + path.join("/sh"); + //~^ ERROR: argument to `Path::join` starts with a path separator + + let path = PathBuf::from("/bin"); + path.join(r#"/sh"#); + //~^ ERROR: argument to `Path::join` starts with a path separator + + let path: &[&str] = &["/bin"]; + path.join("/sh"); + + let path = Path::new("/bin"); + path.join("sh"); +} diff --git a/tests/ui/join_absolute_paths.stderr b/tests/ui/join_absolute_paths.stderr new file mode 100644 index 00000000000..0c2f89d9978 --- /dev/null +++ b/tests/ui/join_absolute_paths.stderr @@ -0,0 +1,68 @@ +error: argument to `Path::join` starts with a path separator + --> $DIR/join_absolute_paths.rs:10:15 + | +LL | path.join("/sh"); + | ^^^^^ + | + = note: joining a path starting with separator will replace the path instead + = note: `-D clippy::join-absolute-paths` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::join_absolute_paths)]` +help: if this is unintentional, try removing the starting separator + | +LL | path.join("sh"); + | ~~~~ +help: if this is intentional, try using `Path::new` instead + | +LL | PathBuf::from("/sh"); + | ~~~~~~~~~~~~~~~~~~~~ + +error: argument to `Path::join` starts with a path separator + --> $DIR/join_absolute_paths.rs:14:15 + | +LL | path.join("\\user"); + | ^^^^^^^^ + | + = note: joining a path starting with separator will replace the path instead +help: if this is unintentional, try removing the starting separator + | +LL | path.join("\user"); + | ~~~~~~~ +help: if this is intentional, try using `Path::new` instead + | +LL | PathBuf::from("\\user"); + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error: argument to `Path::join` starts with a path separator + --> $DIR/join_absolute_paths.rs:18:15 + | +LL | path.join("/sh"); + | ^^^^^ + | + = note: joining a path starting with separator will replace the path instead +help: if this is unintentional, try removing the starting separator + | +LL | path.join("sh"); + | ~~~~ +help: if this is intentional, try using `Path::new` instead + | +LL | PathBuf::from("/sh"); + | ~~~~~~~~~~~~~~~~~~~~ + +error: argument to `Path::join` starts with a path separator + --> $DIR/join_absolute_paths.rs:22:15 + | +LL | path.join(r#"/sh"#); + | ^^^^^^^^ + | + = note: joining a path starting with separator will replace the path instead +help: if this is unintentional, try removing the starting separator + | +LL | path.join(r#"sh"#); + | ~~~~~~~ +help: if this is intentional, try using `Path::new` instead + | +LL | PathBuf::from(r#"/sh"#); + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lines_filter_map_ok.fixed b/tests/ui/lines_filter_map_ok.fixed index 74ef6f72957..621115cc132 100644 --- a/tests/ui/lines_filter_map_ok.fixed +++ b/tests/ui/lines_filter_map_ok.fixed @@ -10,11 +10,17 @@ fn main() -> io::Result<()> { // Lint let f = std::fs::File::open("/")?; BufReader::new(f).lines().map_while(Result::ok).for_each(|_| ()); + // Lint + let f = std::fs::File::open("/")?; + BufReader::new(f).lines().map_while(Result::ok).for_each(|_| ()); + let s = "foo\nbar\nbaz\n"; // Lint io::stdin().lines().map_while(Result::ok).for_each(|_| ()); // Lint io::stdin().lines().map_while(Result::ok).for_each(|_| ()); + // Lint + io::stdin().lines().map_while(Result::ok).for_each(|_| ()); // Do not lint (not a `Lines` iterator) io::stdin() .lines() diff --git a/tests/ui/lines_filter_map_ok.rs b/tests/ui/lines_filter_map_ok.rs index 345f4dc5f30..a86efbd6686 100644 --- a/tests/ui/lines_filter_map_ok.rs +++ b/tests/ui/lines_filter_map_ok.rs @@ -10,11 +10,17 @@ fn main() -> io::Result<()> { // Lint let f = std::fs::File::open("/")?; BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ()); + // Lint + let f = std::fs::File::open("/")?; + BufReader::new(f).lines().flatten().for_each(|_| ()); + let s = "foo\nbar\nbaz\n"; // Lint io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); // Lint io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); + // Lint + io::stdin().lines().flatten().for_each(|_| ()); // Do not lint (not a `Lines` iterator) io::stdin() .lines() diff --git a/tests/ui/lines_filter_map_ok.stderr b/tests/ui/lines_filter_map_ok.stderr index fa2ba0a9a46..9833ab16473 100644 --- a/tests/ui/lines_filter_map_ok.stderr +++ b/tests/ui/lines_filter_map_ok.stderr @@ -24,29 +24,53 @@ note: this expression returning a `std::io::Lines` may produce an infinite numbe LL | BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `filter_map()` will run forever if the iterator repeatedly produces an `Err` - --> $DIR/lines_filter_map_ok.rs:15:25 +error: `flatten()` will run forever if the iterator repeatedly produces an `Err` + --> $DIR/lines_filter_map_ok.rs:15:31 | -LL | io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); - | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` +LL | BufReader::new(f).lines().flatten().for_each(|_| ()); + | ^^^^^^^^^ help: replace with: `map_while(Result::ok)` | note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error --> $DIR/lines_filter_map_ok.rs:15:5 | +LL | BufReader::new(f).lines().flatten().for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `filter_map()` will run forever if the iterator repeatedly produces an `Err` + --> $DIR/lines_filter_map_ok.rs:19:25 + | +LL | io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` + | +note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error + --> $DIR/lines_filter_map_ok.rs:19:5 + | LL | io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^ error: `filter_map()` will run forever if the iterator repeatedly produces an `Err` - --> $DIR/lines_filter_map_ok.rs:17:25 + --> $DIR/lines_filter_map_ok.rs:21:25 | LL | io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` | note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error - --> $DIR/lines_filter_map_ok.rs:17:5 + --> $DIR/lines_filter_map_ok.rs:21:5 | LL | io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: `flatten()` will run forever if the iterator repeatedly produces an `Err` + --> $DIR/lines_filter_map_ok.rs:23:25 + | +LL | io::stdin().lines().flatten().for_each(|_| ()); + | ^^^^^^^^^ help: replace with: `map_while(Result::ok)` + | +note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error + --> $DIR/lines_filter_map_ok.rs:23:5 + | +LL | io::stdin().lines().flatten().for_each(|_| ()); + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/tests/ui/macro_use_imports.stderr b/tests/ui/macro_use_imports.stderr index bafe8cfddb4..5524e7e5642 100644 --- a/tests/ui/macro_use_imports.stderr +++ b/tests/ui/macro_use_imports.stderr @@ -1,17 +1,17 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:23:5 + --> $DIR/macro_use_imports.rs:19:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::mut_mut, inner::try_err};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};` | = note: `-D clippy::macro-use-imports` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::macro_use_imports)]` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:21:5 + --> $DIR/macro_use_imports.rs:23:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::mut_mut, inner::try_err};` error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:25:5 @@ -20,10 +20,10 @@ LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:19:5 + --> $DIR/macro_use_imports.rs:21:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` error: aborting due to 4 previous errors diff --git a/tests/ui/manual_non_exhaustive_enum.rs b/tests/ui/manual_non_exhaustive_enum.rs index e32ba863176..eb387532031 100644 --- a/tests/ui/manual_non_exhaustive_enum.rs +++ b/tests/ui/manual_non_exhaustive_enum.rs @@ -26,7 +26,7 @@ enum NoDocHidden { _C, } -// name of variant with doc hidden does not start with underscore, should be ignored +// name of variant with doc hidden does not start with underscore enum NoUnderscore { A, B, diff --git a/tests/ui/manual_non_exhaustive_enum.stderr b/tests/ui/manual_non_exhaustive_enum.stderr index d2922af99bf..c4b13a577a9 100644 --- a/tests/ui/manual_non_exhaustive_enum.stderr +++ b/tests/ui/manual_non_exhaustive_enum.stderr @@ -22,5 +22,26 @@ LL | _C, = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]` -error: aborting due to 1 previous error +error: this seems like a manual implementation of the non-exhaustive pattern + --> $DIR/manual_non_exhaustive_enum.rs:30:1 + | +LL | enum NoUnderscore { + | ^---------------- + | | + | _help: add the attribute: `#[non_exhaustive] enum NoUnderscore` + | | +LL | | A, +LL | | B, +LL | | #[doc(hidden)] +LL | | C, +LL | | } + | |_^ + | +help: remove this variant + --> $DIR/manual_non_exhaustive_enum.rs:34:5 + | +LL | C, + | ^ + +error: aborting due to 2 previous errors diff --git a/tests/ui/manual_non_exhaustive_struct.stderr b/tests/ui/manual_non_exhaustive_struct.stderr index 028b8ff7639..0b88b19691e 100644 --- a/tests/ui/manual_non_exhaustive_struct.stderr +++ b/tests/ui/manual_non_exhaustive_struct.stderr @@ -38,6 +38,26 @@ help: remove this field LL | _c: (), | ^^^^^^ +error: this seems like a manual implementation of the non-exhaustive pattern + --> $DIR/manual_non_exhaustive_struct.rs:29:5 + | +LL | struct NoUnderscore { + | ^------------------ + | | + | _____help: add the attribute: `#[non_exhaustive] struct NoUnderscore` + | | +LL | | pub a: i32, +LL | | pub b: i32, +LL | | c: (), +LL | | } + | |_____^ + | +help: remove this field + --> $DIR/manual_non_exhaustive_struct.rs:32:9 + | +LL | c: (), + | ^^^^^ + error: this seems like a manual implementation of the non-exhaustive pattern --> $DIR/manual_non_exhaustive_struct.rs:56:5 | @@ -64,5 +84,5 @@ help: remove this field LL | struct Tp(pub i32, pub i32, ()); | ^^ -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/manual_ok_or.stderr b/tests/ui/manual_ok_or.stderr index ddb2cf261e4..b277d22e59b 100644 --- a/tests/ui/manual_ok_or.stderr +++ b/tests/ui/manual_ok_or.stderr @@ -13,6 +13,15 @@ error: this pattern reimplements `Option::ok_or` LL | foo.map_or(Err("error"), Ok); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `foo.ok_or("error")` +error: called `map_or(Err(_), Ok)` on an `Option` value + --> $DIR/manual_ok_or.rs:14:5 + | +LL | foo.map_or(Err("error"), Ok); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok_or` instead: `foo.ok_or("error")` + | + = note: `-D clippy::option-map-or-err-ok` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::option_map_or_err_ok)]` + error: this pattern reimplements `Option::ok_or` --> $DIR/manual_ok_or.rs:17:5 | @@ -38,5 +47,5 @@ LL + "{}{}{}{}{}{}{}", LL ~ "Alice", "Bob", "Sarah", "Marc", "Sandra", "Eric", "Jenifer")); | -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/manual_try_fold.rs b/tests/ui/manual_try_fold.rs index bddf03ac3f1..7299d7cf986 100644 --- a/tests/ui/manual_try_fold.rs +++ b/tests/ui/manual_try_fold.rs @@ -96,3 +96,33 @@ fn msrv_juust_right() { .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) .unwrap(); } + +mod issue11876 { + struct Foo; + + impl Bar for Foo { + type Output = u32; + } + + trait Bar: Sized { + type Output; + fn fold(self, init: A, func: F) -> Fold + where + A: Clone, + F: Fn(A, Self::Output) -> A, + { + Fold { this: self, init, func } + } + } + + #[allow(dead_code)] + struct Fold { + this: S, + init: A, + func: F, + } + + fn main() { + Foo.fold(Some(0), |acc, entry| Some(acc? + entry)); + } +} diff --git a/tests/ui/map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr index 7b7eeb322a5..54ddd1402e3 100644 --- a/tests/ui/map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -1,4 +1,4 @@ -error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead +error: called `map().unwrap_or()` on an `Option` value --> $DIR/map_unwrap_or.rs:17:13 | LL | let _ = opt.map(|x| x + 1) @@ -15,7 +15,7 @@ LL - let _ = opt.map(|x| x + 1) LL + let _ = opt.map_or(0, |x| x + 1); | -error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead +error: called `map().unwrap_or()` on an `Option` value --> $DIR/map_unwrap_or.rs:21:13 | LL | let _ = opt.map(|x| { @@ -33,7 +33,7 @@ LL | } LL ~ ); | -error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead +error: called `map().unwrap_or()` on an `Option` value --> $DIR/map_unwrap_or.rs:25:13 | LL | let _ = opt.map(|x| x + 1) @@ -50,7 +50,7 @@ LL + 0 LL ~ }, |x| x + 1); | -error: called `map().unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then()` instead +error: called `map().unwrap_or(None)` on an `Option` value --> $DIR/map_unwrap_or.rs:30:13 | LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); @@ -62,7 +62,7 @@ LL - let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); LL + let _ = opt.and_then(|x| Some(x + 1)); | -error: called `map().unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then()` instead +error: called `map().unwrap_or(None)` on an `Option` value --> $DIR/map_unwrap_or.rs:32:13 | LL | let _ = opt.map(|x| { @@ -80,7 +80,7 @@ LL | } LL ~ ); | -error: called `map().unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then()` instead +error: called `map().unwrap_or(None)` on an `Option` value --> $DIR/map_unwrap_or.rs:36:13 | LL | let _ = opt @@ -95,7 +95,7 @@ LL - .map(|x| Some(x + 1)) LL + .and_then(|x| Some(x + 1)); | -error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead +error: called `map().unwrap_or()` on an `Option` value --> $DIR/map_unwrap_or.rs:47:13 | LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); @@ -107,7 +107,7 @@ LL - let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); LL + let _ = Some("prefix").map_or(id, |p| format!("{}.", p)); | -error: called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead +error: called `map().unwrap_or_else()` on an `Option` value --> $DIR/map_unwrap_or.rs:51:13 | LL | let _ = opt.map(|x| { @@ -117,7 +117,7 @@ LL | | } LL | | ).unwrap_or_else(|| 0); | |__________________________^ -error: called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead +error: called `map().unwrap_or_else()` on an `Option` value --> $DIR/map_unwrap_or.rs:55:13 | LL | let _ = opt.map(|x| x + 1) @@ -127,7 +127,7 @@ LL | | 0 LL | | ); | |_________^ -error: called `map().unwrap_or(false)` on an `Option` value. This can be done more directly by calling `is_some_and()` instead +error: called `map().unwrap_or(false)` on an `Option` value --> $DIR/map_unwrap_or.rs:61:13 | LL | let _ = opt.map(|x| x > 5).unwrap_or(false); @@ -139,7 +139,7 @@ LL - let _ = opt.map(|x| x > 5).unwrap_or(false); LL + let _ = opt.is_some_and(|x| x > 5); | -error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead +error: called `map().unwrap_or_else()` on a `Result` value --> $DIR/map_unwrap_or.rs:71:13 | LL | let _ = res.map(|x| { @@ -149,7 +149,7 @@ LL | | } LL | | ).unwrap_or_else(|_e| 0); | |____________________________^ -error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead +error: called `map().unwrap_or_else()` on a `Result` value --> $DIR/map_unwrap_or.rs:75:13 | LL | let _ = res.map(|x| x + 1) @@ -159,13 +159,13 @@ LL | | 0 LL | | }); | |__________^ -error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead +error: called `map().unwrap_or_else()` on a `Result` value --> $DIR/map_unwrap_or.rs:99:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)` -error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead +error: called `map().unwrap_or()` on an `Option` value --> $DIR/map_unwrap_or.rs:106:13 | LL | let _ = opt.map(|x| x > 5).unwrap_or(false); @@ -177,7 +177,7 @@ LL - let _ = opt.map(|x| x > 5).unwrap_or(false); LL + let _ = opt.map_or(false, |x| x > 5); | -error: called `map().unwrap_or(false)` on an `Option` value. This can be done more directly by calling `is_some_and()` instead +error: called `map().unwrap_or(false)` on an `Option` value --> $DIR/map_unwrap_or.rs:113:13 | LL | let _ = opt.map(|x| x > 5).unwrap_or(false); diff --git a/tests/ui/map_unwrap_or_fixable.stderr b/tests/ui/map_unwrap_or_fixable.stderr index ca611ac9d7f..d1a9fdd6ecf 100644 --- a/tests/ui/map_unwrap_or_fixable.stderr +++ b/tests/ui/map_unwrap_or_fixable.stderr @@ -1,4 +1,4 @@ -error: called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead +error: called `map().unwrap_or_else()` on an `Option` value --> $DIR/map_unwrap_or_fixable.rs:16:13 | LL | let _ = opt.map(|x| x + 1) @@ -10,7 +10,7 @@ LL | | .unwrap_or_else(|| 0); = note: `-D clippy::map-unwrap-or` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::map_unwrap_or)]` -error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead +error: called `map().unwrap_or_else()` on a `Result` value --> $DIR/map_unwrap_or_fixable.rs:46:13 | LL | let _ = res.map(|x| x + 1) diff --git a/tests/ui/missing_asserts_for_indexing_unfixable.rs b/tests/ui/missing_asserts_for_indexing_unfixable.rs index 4346ed892f2..de53079a476 100644 --- a/tests/ui/missing_asserts_for_indexing_unfixable.rs +++ b/tests/ui/missing_asserts_for_indexing_unfixable.rs @@ -46,4 +46,26 @@ fn index_struct_different_fields(f: &Foo<'_>) { let _ = f.v[0] + f.v2[1]; } +fn shadowing() { + let x: &[i32] = &[1]; + assert!(x.len() > 1); + + let x: &[i32] = &[1]; + let _ = x[0] + x[1]; + //~^ ERROR: indexing into a slice multiple times without an `assert` +} + +pub fn issue11856(values: &[i32]) -> usize { + let mut ascending = Vec::new(); + for w in values.windows(2) { + assert!(w.len() > 1); + if w[0] < w[1] { + ascending.push((w[0], w[1])); + } else { + ascending.push((w[1], w[0])); + } + } + ascending.len() +} + fn main() {} diff --git a/tests/ui/missing_asserts_for_indexing_unfixable.stderr b/tests/ui/missing_asserts_for_indexing_unfixable.stderr index 12c9eed5d66..12e05422798 100644 --- a/tests/ui/missing_asserts_for_indexing_unfixable.stderr +++ b/tests/ui/missing_asserts_for_indexing_unfixable.stderr @@ -160,5 +160,24 @@ LL | let _ = f.v[0] + f.v[1]; | ^^^^^^ = note: asserting the length before indexing will elide bounds checks -error: aborting due to 7 previous errors +error: indexing into a slice multiple times without an `assert` + --> $DIR/missing_asserts_for_indexing_unfixable.rs:54:13 + | +LL | let _ = x[0] + x[1]; + | ^^^^^^^^^^^ + | + = help: consider asserting the length before indexing: `assert!(x.len() > 1);` +note: slice indexed here + --> $DIR/missing_asserts_for_indexing_unfixable.rs:54:13 + | +LL | let _ = x[0] + x[1]; + | ^^^^ +note: slice indexed here + --> $DIR/missing_asserts_for_indexing_unfixable.rs:54:20 + | +LL | let _ = x[0] + x[1]; + | ^^^^ + = note: asserting the length before indexing will elide bounds checks + +error: aborting due to 8 previous errors diff --git a/tests/ui/needless_pass_by_ref_mut.rs b/tests/ui/needless_pass_by_ref_mut.rs index ea5e74c4c00..25a02bdd2f2 100644 --- a/tests/ui/needless_pass_by_ref_mut.rs +++ b/tests/ui/needless_pass_by_ref_mut.rs @@ -1,4 +1,9 @@ -#![allow(clippy::if_same_then_else, clippy::no_effect, clippy::redundant_closure_call)] +#![allow( + clippy::if_same_then_else, + clippy::no_effect, + clippy::redundant_closure_call, + clippy::ptr_arg +)] #![warn(clippy::needless_pass_by_ref_mut)] #![feature(lint_reasons)] //@no-rustfix diff --git a/tests/ui/needless_pass_by_ref_mut.stderr b/tests/ui/needless_pass_by_ref_mut.stderr index aa937c3f6af..92b753276ac 100644 --- a/tests/ui/needless_pass_by_ref_mut.stderr +++ b/tests/ui/needless_pass_by_ref_mut.stderr @@ -1,5 +1,5 @@ error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:7:11 + --> $DIR/needless_pass_by_ref_mut.rs:12:11 | LL | fn foo(s: &mut Vec, b: &u32, x: &mut u32) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` @@ -8,79 +8,79 @@ LL | fn foo(s: &mut Vec, b: &u32, x: &mut u32) { = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:32:12 + --> $DIR/needless_pass_by_ref_mut.rs:37:12 | LL | fn foo6(s: &mut Vec) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:45:29 + --> $DIR/needless_pass_by_ref_mut.rs:50:29 | LL | fn mushroom(&self, vec: &mut Vec) -> usize { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:50:31 + --> $DIR/needless_pass_by_ref_mut.rs:55:31 | LL | fn badger(&mut self, vec: &mut Vec) -> usize { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:127:16 + --> $DIR/needless_pass_by_ref_mut.rs:132: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:131:16 + --> $DIR/needless_pass_by_ref_mut.rs:136: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:135:16 + --> $DIR/needless_pass_by_ref_mut.rs:140: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:139:16 + --> $DIR/needless_pass_by_ref_mut.rs:144: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:143:24 + --> $DIR/needless_pass_by_ref_mut.rs:148: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:147:24 + --> $DIR/needless_pass_by_ref_mut.rs:152: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:151:32 + --> $DIR/needless_pass_by_ref_mut.rs:156: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:155:24 + --> $DIR/needless_pass_by_ref_mut.rs:160: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:155:45 + --> $DIR/needless_pass_by_ref_mut.rs:160: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:189:16 + --> $DIR/needless_pass_by_ref_mut.rs:194:16 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -88,7 +88,7 @@ LL | fn cfg_warn(s: &mut 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:195:20 + --> $DIR/needless_pass_by_ref_mut.rs:200:20 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -96,19 +96,19 @@ LL | fn cfg_warn(s: &mut 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:209:39 + --> $DIR/needless_pass_by_ref_mut.rs:214: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:217:26 + --> $DIR/needless_pass_by_ref_mut.rs:222:26 | LL | async fn inner_async3(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:236:34 + --> $DIR/needless_pass_by_ref_mut.rs:241:34 | LL | pub async fn call_in_closure1(n: &mut str) { | ^^^^^^^^ help: consider changing to: `&str` @@ -116,7 +116,7 @@ LL | pub async fn call_in_closure1(n: &mut str) { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:248:25 + --> $DIR/needless_pass_by_ref_mut.rs:253:25 | LL | pub async fn closure(n: &mut usize) -> impl '_ + FnMut() { | ^^^^^^^^^^ help: consider changing to: `&usize` @@ -124,7 +124,7 @@ LL | pub async fn closure(n: &mut usize) -> impl '_ + FnMut() { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:255:20 + --> $DIR/needless_pass_by_ref_mut.rs:260:20 | LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { | ^^^^^^^^^^ help: consider changing to: `&usize` @@ -132,7 +132,7 @@ LL | pub fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { = warning: changing this function will impact semver compatibility error: this argument is a mutable reference, but not used mutably - --> $DIR/needless_pass_by_ref_mut.rs:266:26 + --> $DIR/needless_pass_by_ref_mut.rs:271:26 | LL | pub async fn closure4(n: &mut usize) { | ^^^^^^^^^^ help: consider changing to: `&usize` diff --git a/tests/ui/needless_return_with_question_mark.fixed b/tests/ui/needless_return_with_question_mark.fixed index d5932ebcf12..0147c73a94b 100644 --- a/tests/ui/needless_return_with_question_mark.fixed +++ b/tests/ui/needless_return_with_question_mark.fixed @@ -5,6 +5,7 @@ clippy::unit_arg, clippy::useless_conversion, clippy::diverging_sub_expression, + clippy::let_unit_value, unused )] @@ -59,3 +60,20 @@ fn main() -> Result<(), ()> { Err(()) } + +fn issue11616() -> Result<(), ()> { + let _x: String = { + return Err(())?; + }; + let _x: () = { + Err(())?; + //~^ ERROR: unneeded `return` statement with `?` operator + }; + let _x = match 1 { + 1 => vec![1, 2], + _ => { + return Err(())?; + }, + }; + Ok(()) +} diff --git a/tests/ui/needless_return_with_question_mark.rs b/tests/ui/needless_return_with_question_mark.rs index 2485e25f05c..66e1f438f8c 100644 --- a/tests/ui/needless_return_with_question_mark.rs +++ b/tests/ui/needless_return_with_question_mark.rs @@ -5,6 +5,7 @@ clippy::unit_arg, clippy::useless_conversion, clippy::diverging_sub_expression, + clippy::let_unit_value, unused )] @@ -59,3 +60,20 @@ fn main() -> Result<(), ()> { Err(()) } + +fn issue11616() -> Result<(), ()> { + let _x: String = { + return Err(())?; + }; + let _x: () = { + return Err(())?; + //~^ ERROR: unneeded `return` statement with `?` operator + }; + let _x = match 1 { + 1 => vec![1, 2], + _ => { + return Err(())?; + }, + }; + Ok(()) +} diff --git a/tests/ui/needless_return_with_question_mark.stderr b/tests/ui/needless_return_with_question_mark.stderr index 707f1c25327..17aa212ae8d 100644 --- a/tests/ui/needless_return_with_question_mark.stderr +++ b/tests/ui/needless_return_with_question_mark.stderr @@ -1,5 +1,5 @@ error: unneeded `return` statement with `?` operator - --> $DIR/needless_return_with_question_mark.rs:28:5 + --> $DIR/needless_return_with_question_mark.rs:29:5 | LL | return Err(())?; | ^^^^^^^ help: remove it @@ -7,5 +7,11 @@ LL | return Err(())?; = note: `-D clippy::needless-return-with-question-mark` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_return_with_question_mark)]` -error: aborting due to 1 previous error +error: unneeded `return` statement with `?` operator + --> $DIR/needless_return_with_question_mark.rs:69:9 + | +LL | return Err(())?; + | ^^^^^^^ help: remove it + +error: aborting due to 2 previous errors diff --git a/tests/ui/option_as_ref_deref.stderr b/tests/ui/option_as_ref_deref.stderr index eb0661c523a..9d173e409ab 100644 --- a/tests/ui/option_as_ref_deref.stderr +++ b/tests/ui/option_as_ref_deref.stderr @@ -1,4 +1,4 @@ -error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead +error: called `.as_ref().map(Deref::deref)` on an `Option` value --> $DIR/option_as_ref_deref.rs:11:13 | LL | let _ = opt.clone().as_ref().map(Deref::deref).map(str::len); @@ -7,7 +7,7 @@ LL | let _ = opt.clone().as_ref().map(Deref::deref).map(str::len); = note: `-D clippy::option-as-ref-deref` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::option_as_ref_deref)]` -error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead +error: called `.as_ref().map(Deref::deref)` on an `Option` value --> $DIR/option_as_ref_deref.rs:14:13 | LL | let _ = opt.clone() @@ -17,97 +17,97 @@ LL | | Deref::deref LL | | ) | |_________^ help: try using as_deref instead: `opt.clone().as_deref()` -error: called `.as_mut().map(DerefMut::deref_mut)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead +error: called `.as_mut().map(DerefMut::deref_mut)` on an `Option` value --> $DIR/option_as_ref_deref.rs:20:13 | LL | let _ = opt.as_mut().map(DerefMut::deref_mut); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` -error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(String::as_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:22:13 | LL | let _ = opt.as_ref().map(String::as_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_ref().map(|x| x.as_str())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(|x| x.as_str())` on an `Option` value --> $DIR/option_as_ref_deref.rs:23:13 | LL | let _ = opt.as_ref().map(|x| x.as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_mut().map(String::as_mut_str)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead +error: called `.as_mut().map(String::as_mut_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:24:13 | LL | let _ = opt.as_mut().map(String::as_mut_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` -error: called `.as_mut().map(|x| x.as_mut_str())` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead +error: called `.as_mut().map(|x| x.as_mut_str())` on an `Option` value --> $DIR/option_as_ref_deref.rs:25:13 | LL | let _ = opt.as_mut().map(|x| x.as_mut_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` -error: called `.as_ref().map(CString::as_c_str)` on an Option value. This can be done more directly by calling `Some(CString::new(vec![]).unwrap()).as_deref()` instead +error: called `.as_ref().map(CString::as_c_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:26:13 | LL | let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(CString::new(vec![]).unwrap()).as_deref()` -error: called `.as_ref().map(OsString::as_os_str)` on an Option value. This can be done more directly by calling `Some(OsString::new()).as_deref()` instead +error: called `.as_ref().map(OsString::as_os_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:27:13 | LL | let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(OsString::new()).as_deref()` -error: called `.as_ref().map(PathBuf::as_path)` on an Option value. This can be done more directly by calling `Some(PathBuf::new()).as_deref()` instead +error: called `.as_ref().map(PathBuf::as_path)` on an `Option` value --> $DIR/option_as_ref_deref.rs:28:13 | LL | let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(PathBuf::new()).as_deref()` -error: called `.as_ref().map(Vec::as_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref()` instead +error: called `.as_ref().map(Vec::as_slice)` on an `Option` value --> $DIR/option_as_ref_deref.rs:29:13 | LL | let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(Vec::<()>::new()).as_deref()` -error: called `.as_mut().map(Vec::as_mut_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref_mut()` instead +error: called `.as_mut().map(Vec::as_mut_slice)` on an `Option` value --> $DIR/option_as_ref_deref.rs:30:13 | LL | let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `Some(Vec::<()>::new()).as_deref_mut()` -error: called `.as_ref().map(|x| x.deref())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(|x| x.deref())` on an `Option` value --> $DIR/option_as_ref_deref.rs:32:13 | LL | let _ = opt.as_ref().map(|x| x.deref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_mut().map(|x| x.deref_mut())` on an Option value. This can be done more directly by calling `opt.clone().as_deref_mut()` instead +error: called `.as_mut().map(|x| x.deref_mut())` on an `Option` value --> $DIR/option_as_ref_deref.rs:33:13 | LL | let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.clone().as_deref_mut()` -error: called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(|x| &**x)` on an `Option` value --> $DIR/option_as_ref_deref.rs:40:13 | LL | let _ = opt.as_ref().map(|x| &**x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_mut().map(|x| &mut **x)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead +error: called `.as_mut().map(|x| &mut **x)` on an `Option` value --> $DIR/option_as_ref_deref.rs:41:13 | LL | let _ = opt.as_mut().map(|x| &mut **x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()` -error: called `.as_ref().map(std::ops::Deref::deref)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(std::ops::Deref::deref)` on an `Option` value --> $DIR/option_as_ref_deref.rs:44:13 | LL | let _ = opt.as_ref().map(std::ops::Deref::deref); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()` -error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead +error: called `.as_ref().map(String::as_str)` on an `Option` value --> $DIR/option_as_ref_deref.rs:56:13 | LL | let _ = opt.as_ref().map(String::as_str); diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index f0113ca696e..363520112ef 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -92,11 +92,13 @@ fn pattern_to_vec(pattern: &str) -> Vec { } // #10335 -fn test_result_impure_else(variable: Result) { +fn test_result_impure_else(variable: Result) -> bool { variable.map_or_else(|_| { println!("Err"); + false }, |binding| { println!("Ok {binding}"); + true }) } @@ -213,15 +215,19 @@ mod issue10729 { pub fn reproduce(initial: &Option) { // 👇 needs `.as_ref()` because initial is an `&Option<_>` - initial.as_ref().map_or({}, |value| do_something(value)) + let _ = initial.as_ref().map_or(42, |value| do_something(value)); } pub fn reproduce2(initial: &mut Option) { - initial.as_mut().map_or({}, |value| do_something2(value)) + let _ = initial.as_mut().map_or(42, |value| do_something2(value)); } - fn do_something(_value: &str) {} - fn do_something2(_value: &mut str) {} + fn do_something(_value: &str) -> u32 { + todo!() + } + fn do_something2(_value: &mut str) -> u32 { + todo!() + } } fn issue11429() { @@ -237,3 +243,13 @@ fn issue11429() { let mut _hm = opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone()); } + +fn issue11893() { + use std::io::Write; + let mut output = std::io::stdout().lock(); + if let Some(name) = Some("stuff") { + writeln!(output, "{name:?}").unwrap(); + } else { + panic!("Haven't thought about this condition."); + } +} diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index 18b7af44392..aaa87a0db54 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -115,11 +115,13 @@ fn pattern_to_vec(pattern: &str) -> Vec { } // #10335 -fn test_result_impure_else(variable: Result) { +fn test_result_impure_else(variable: Result) -> bool { if let Ok(binding) = variable { println!("Ok {binding}"); + true } else { println!("Err"); + false } } @@ -254,21 +256,25 @@ mod issue10729 { pub fn reproduce(initial: &Option) { // 👇 needs `.as_ref()` because initial is an `&Option<_>` - match initial { + let _ = match initial { Some(value) => do_something(value), - None => {}, - } + None => 42, + }; } pub fn reproduce2(initial: &mut Option) { - match initial { + let _ = match initial { Some(value) => do_something2(value), - None => {}, - } + None => 42, + }; } - fn do_something(_value: &str) {} - fn do_something2(_value: &mut str) {} + fn do_something(_value: &str) -> u32 { + todo!() + } + fn do_something2(_value: &mut str) -> u32 { + todo!() + } } fn issue11429() { @@ -288,3 +294,13 @@ fn issue11429() { let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() }; } + +fn issue11893() { + use std::io::Write; + let mut output = std::io::stdout().lock(); + if let Some(name) = Some("stuff") { + writeln!(output, "{name:?}").unwrap(); + } else { + panic!("Haven't thought about this condition."); + } +} diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index e36357bcb38..55a8360ffd0 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -158,8 +158,10 @@ error: use Option::map_or_else instead of an if let/else | LL | / if let Ok(binding) = variable { LL | | println!("Ok {binding}"); +LL | | true LL | | } else { LL | | println!("Err"); +LL | | false LL | | } | |_____^ | @@ -167,19 +169,21 @@ help: try | LL ~ variable.map_or_else(|_| { LL + println!("Err"); +LL + false LL + }, |binding| { LL + println!("Ok {binding}"); +LL + true LL + }) | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:141: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:151:13 + --> $DIR/option_if_let_else.rs:153:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -201,13 +205,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:179: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:183:13 + --> $DIR/option_if_let_else.rs:185:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -227,7 +231,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:222:13 + --> $DIR/option_if_let_else.rs:224:13 | LL | let _ = match s { | _____________^ @@ -237,7 +241,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:226:13 + --> $DIR/option_if_let_else.rs:228:13 | LL | let _ = match Some(10) { | _____________^ @@ -247,7 +251,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:232:13 + --> $DIR/option_if_let_else.rs:234:13 | LL | let _ = match res { | _____________^ @@ -257,7 +261,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:236:13 + --> $DIR/option_if_let_else.rs:238:13 | LL | let _ = match res { | _____________^ @@ -267,31 +271,33 @@ 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:240: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:257:9 + --> $DIR/option_if_let_else.rs:259:17 | -LL | / match initial { +LL | let _ = match initial { + | _________________^ LL | | Some(value) => do_something(value), -LL | | None => {}, -LL | | } - | |_________^ help: try: `initial.as_ref().map_or({}, |value| do_something(value))` +LL | | None => 42, +LL | | }; + | |_________^ help: try: `initial.as_ref().map_or(42, |value| do_something(value))` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:264:9 + --> $DIR/option_if_let_else.rs:266:17 | -LL | / match initial { +LL | let _ = match initial { + | _________________^ LL | | Some(value) => do_something2(value), -LL | | None => {}, -LL | | } - | |_________^ help: try: `initial.as_mut().map_or({}, |value| do_something2(value))` +LL | | None => 42, +LL | | }; + | |_________^ help: try: `initial.as_mut().map_or(42, |value| do_something2(value))` error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:283:24 + --> $DIR/option_if_let_else.rs:289:24 | LL | let mut _hashmap = if let Some(hm) = &opt { | ________________________^ @@ -302,7 +308,7 @@ LL | | }; | |_____^ help: try: `opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone())` error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:289:19 + --> $DIR/option_if_let_else.rs:295:19 | LL | let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())` diff --git a/tests/ui/option_map_or_err_ok.fixed b/tests/ui/option_map_or_err_ok.fixed new file mode 100644 index 00000000000..131f4b2093e --- /dev/null +++ b/tests/ui/option_map_or_err_ok.fixed @@ -0,0 +1,7 @@ +#![warn(clippy::option_map_or_err_ok)] + +fn main() { + let x = Some("a"); + let _ = x.ok_or("a"); + //~^ ERROR: called `map_or(Err(_), Ok)` on an `Option` value +} diff --git a/tests/ui/option_map_or_err_ok.rs b/tests/ui/option_map_or_err_ok.rs new file mode 100644 index 00000000000..0f07a592ae5 --- /dev/null +++ b/tests/ui/option_map_or_err_ok.rs @@ -0,0 +1,7 @@ +#![warn(clippy::option_map_or_err_ok)] + +fn main() { + let x = Some("a"); + let _ = x.map_or(Err("a"), Ok); + //~^ ERROR: called `map_or(Err(_), Ok)` on an `Option` value +} diff --git a/tests/ui/option_map_or_err_ok.stderr b/tests/ui/option_map_or_err_ok.stderr new file mode 100644 index 00000000000..a193e3c4c49 --- /dev/null +++ b/tests/ui/option_map_or_err_ok.stderr @@ -0,0 +1,11 @@ +error: called `map_or(Err(_), Ok)` on an `Option` value + --> $DIR/option_map_or_err_ok.rs:5:13 + | +LL | let _ = x.map_or(Err("a"), Ok); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok_or` instead: `x.ok_or("a")` + | + = note: `-D clippy::option-map-or-err-ok` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::option_map_or_err_ok)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui/option_map_or_none.stderr b/tests/ui/option_map_or_none.stderr index fa150718f89..f2cfc3f9a28 100644 --- a/tests/ui/option_map_or_none.stderr +++ b/tests/ui/option_map_or_none.stderr @@ -1,4 +1,4 @@ -error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead +error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:10:26 | LL | let _: Option = opt.map_or(None, |x| Some(x + 1)); @@ -7,7 +7,7 @@ LL | let _: Option = opt.map_or(None, |x| Some(x + 1)); = note: `-D clippy::option-map-or-none` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::option_map_or_none)]` -error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `map(..)` instead +error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:13:26 | LL | let _: Option = opt.map_or(None, |x| { @@ -16,13 +16,13 @@ LL | | Some(x + 1) LL | | }); | |_________________________^ help: try using `map` instead: `opt.map(|x| x + 1)` -error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead +error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:17:26 | LL | let _: Option = opt.map_or(None, bar); | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `opt.and_then(bar)` -error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead +error: called `map_or(None, ..)` on an `Option` value --> $DIR/option_map_or_none.rs:18:26 | LL | let _: Option = opt.map_or(None, |x| { @@ -42,7 +42,7 @@ LL + Some(offset + height) LL ~ }); | -error: called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling `ok()` instead +error: called `map_or(None, Some)` on a `Result` value --> $DIR/option_map_or_none.rs:25:26 | LL | let _: Option = r.map_or(None, Some); diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index 91e2e7fd642..fcd716f4144 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -22,6 +22,12 @@ fn do_vec_mut(x: &mut Vec) { //Nothing here } +fn do_vec_mut2(x: &mut Vec) { + //~^ ERROR: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice w + x.len(); + x.is_empty(); +} + fn do_str(x: &String) { //~^ ERROR: writing `&String` instead of `&str` involves a new object where a slice will d //Nothing here either diff --git a/tests/ui/ptr_arg.stderr b/tests/ui/ptr_arg.stderr index cccf2d62d63..35bd8509205 100644 --- a/tests/ui/ptr_arg.stderr +++ b/tests/ui/ptr_arg.stderr @@ -13,38 +13,44 @@ error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a sl LL | fn do_vec_mut(x: &mut Vec) { | ^^^^^^^^^^^^^ help: change this to: `&mut [i64]` +error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do + --> $DIR/ptr_arg.rs:25:19 + | +LL | fn do_vec_mut2(x: &mut Vec) { + | ^^^^^^^^^^^^^ 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:25:14 + --> $DIR/ptr_arg.rs:31: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:30:18 + --> $DIR/ptr_arg.rs:36: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:35:15 + --> $DIR/ptr_arg.rs:41: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:40:19 + --> $DIR/ptr_arg.rs:46: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:49:18 + --> $DIR/ptr_arg.rs:55:18 | LL | fn do_vec(x: &Vec); | ^^^^^^^^^ help: change this to: `&[i64]` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:63:14 + --> $DIR/ptr_arg.rs:69:14 | LL | fn cloned(x: &Vec) -> Vec { | ^^^^^^^^ @@ -62,7 +68,7 @@ LL ~ x.to_owned() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:73:18 + --> $DIR/ptr_arg.rs:79:18 | LL | fn str_cloned(x: &String) -> String { | ^^^^^^^ @@ -79,7 +85,7 @@ LL ~ x.to_owned() | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:82:19 + --> $DIR/ptr_arg.rs:88:19 | LL | fn path_cloned(x: &PathBuf) -> PathBuf { | ^^^^^^^^ @@ -96,7 +102,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:91:44 + --> $DIR/ptr_arg.rs:97:44 | LL | fn false_positive_capacity(x: &Vec, y: &String) { | ^^^^^^^ @@ -111,19 +117,19 @@ LL ~ let c = y; | error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:106:25 + --> $DIR/ptr_arg.rs:112: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:136:66 + --> $DIR/ptr_arg.rs:142:66 | LL | fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec, _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:166:21 + --> $DIR/ptr_arg.rs:172:21 | LL | fn foo_vec(vec: &Vec) { | ^^^^^^^^ @@ -137,7 +143,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:172:23 + --> $DIR/ptr_arg.rs:178:23 | LL | fn foo_path(path: &PathBuf) { | ^^^^^^^^ @@ -151,7 +157,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:178:21 + --> $DIR/ptr_arg.rs:184:21 | LL | fn foo_str(str: &PathBuf) { | ^^^^^^^^ @@ -165,46 +171,46 @@ 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:185:29 + --> $DIR/ptr_arg.rs:191:29 | LL | fn mut_vec_slice_methods(v: &mut Vec) { | ^^^^^^^^^^^^^ 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:248:17 + --> $DIR/ptr_arg.rs:254:17 | LL | fn dyn_trait(a: &mut Vec, 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:248:35 + --> $DIR/ptr_arg.rs:254:35 | LL | fn dyn_trait(a: &mut Vec, 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:248:51 + --> $DIR/ptr_arg.rs:254:51 | LL | fn dyn_trait(a: &mut Vec, 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:274:39 + --> $DIR/ptr_arg.rs:280:39 | LL | fn cow_elided_lifetime<'a>(input: &'a Cow) -> &'a str { | ^^^^^^^^^^^^ help: change this to: `&str` error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:280:36 + --> $DIR/ptr_arg.rs:286: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:284:40 + --> $DIR/ptr_arg.rs:290:40 | LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str { | ^^^^^^^^^^^^^^^^ help: change this to: `&str` -error: aborting due to 23 previous errors +error: aborting due to 24 previous errors diff --git a/tests/ui/redundant_closure_call_fixable.fixed b/tests/ui/redundant_closure_call_fixable.fixed index bf268d0b583..f272d8359a3 100644 --- a/tests/ui/redundant_closure_call_fixable.fixed +++ b/tests/ui/redundant_closure_call_fixable.fixed @@ -84,3 +84,21 @@ fn issue9956() { bar()(42, 5); foo(42, 5); } + +async fn issue11357() { + async {}.await; +} + +mod issue11707 { + use core::future::Future; + + fn spawn_on(fut: impl Future) {} + + fn demo() { + spawn_on(async move {}); + } +} + +fn avoid_double_parens() { + std::convert::identity(13_i32 + 36_i32).leading_zeros(); +} diff --git a/tests/ui/redundant_closure_call_fixable.rs b/tests/ui/redundant_closure_call_fixable.rs index c8a91049d19..f45db8c9cff 100644 --- a/tests/ui/redundant_closure_call_fixable.rs +++ b/tests/ui/redundant_closure_call_fixable.rs @@ -84,3 +84,21 @@ fn issue9956() { bar()((|| || 42)()(), 5); foo((|| || 42)()(), 5); } + +async fn issue11357() { + (|| async {})().await; +} + +mod issue11707 { + use core::future::Future; + + fn spawn_on(fut: impl Future) {} + + fn demo() { + spawn_on((|| async move {})()); + } +} + +fn avoid_double_parens() { + std::convert::identity((|| 13_i32 + 36_i32)()).leading_zeros(); +} diff --git a/tests/ui/redundant_closure_call_fixable.stderr b/tests/ui/redundant_closure_call_fixable.stderr index a7cdb43693f..028d383ad35 100644 --- a/tests/ui/redundant_closure_call_fixable.stderr +++ b/tests/ui/redundant_closure_call_fixable.stderr @@ -123,5 +123,23 @@ error: try not to call a closure in the expression where it is declared LL | foo((|| || 42)()(), 5); | ^^^^^^^^^^^^^^ help: try doing something like: `42` -error: aborting due to 14 previous errors +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:89:5 + | +LL | (|| async {})().await; + | ^^^^^^^^^^^^^^^ help: try doing something like: `async {}` + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:98:18 + | +LL | spawn_on((|| async move {})()); + | ^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async move {}` + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:103:28 + | +LL | std::convert::identity((|| 13_i32 + 36_i32)()).leading_zeros(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `13_i32 + 36_i32` + +error: aborting due to 17 previous errors diff --git a/tests/ui/redundant_guards.fixed b/tests/ui/redundant_guards.fixed index f8af9092725..aef26ef225c 100644 --- a/tests/ui/redundant_guards.fixed +++ b/tests/ui/redundant_guards.fixed @@ -193,3 +193,60 @@ mod issue11465 { } } } + +fn issue11807() { + #![allow(clippy::single_match)] + + match Some(Some("")) { + Some(Some("")) => {}, + _ => {}, + } + + match Some(Some(String::new())) { + // Do not lint: String deref-coerces to &str + Some(Some(x)) if x.is_empty() => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some([])) => {}, + _ => {}, + } + + match Some(Some([] as [i32; 0])) { + Some(Some([])) => {}, + _ => {}, + } + + match Some(Some(Vec::<()>::new())) { + // Do not lint: Vec deref-coerces to &[T] + Some(Some(x)) if x.is_empty() => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some([..])) => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some([1, ..])) => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some([1, 2, ..])) => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some([.., 1, 2])) => {}, + _ => {}, + } + + match Some(Some(Vec::::new())) { + // Do not lint: deref coercion + Some(Some(x)) if x.starts_with(&[1, 2]) => {}, + _ => {}, + } +} diff --git a/tests/ui/redundant_guards.rs b/tests/ui/redundant_guards.rs index b46f8a6207e..5d476f5b040 100644 --- a/tests/ui/redundant_guards.rs +++ b/tests/ui/redundant_guards.rs @@ -193,3 +193,60 @@ mod issue11465 { } } } + +fn issue11807() { + #![allow(clippy::single_match)] + + match Some(Some("")) { + Some(Some(x)) if x.is_empty() => {}, + _ => {}, + } + + match Some(Some(String::new())) { + // Do not lint: String deref-coerces to &str + Some(Some(x)) if x.is_empty() => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some(x)) if x.is_empty() => {}, + _ => {}, + } + + match Some(Some([] as [i32; 0])) { + Some(Some(x)) if x.is_empty() => {}, + _ => {}, + } + + match Some(Some(Vec::<()>::new())) { + // Do not lint: Vec deref-coerces to &[T] + Some(Some(x)) if x.is_empty() => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some(x)) if x.starts_with(&[]) => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some(x)) if x.starts_with(&[1]) => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some(x)) if x.starts_with(&[1, 2]) => {}, + _ => {}, + } + + match Some(Some(&[] as &[i32])) { + Some(Some(x)) if x.ends_with(&[1, 2]) => {}, + _ => {}, + } + + match Some(Some(Vec::::new())) { + // Do not lint: deref coercion + Some(Some(x)) if x.starts_with(&[1, 2]) => {}, + _ => {}, + } +} diff --git a/tests/ui/redundant_guards.stderr b/tests/ui/redundant_guards.stderr index b8d7834e358..f78d2a814f9 100644 --- a/tests/ui/redundant_guards.stderr +++ b/tests/ui/redundant_guards.stderr @@ -203,5 +203,89 @@ LL - B { ref c, .. } if matches!(c, &1) => {}, LL + B { c: 1, .. } => {}, | -error: aborting due to 17 previous errors +error: redundant guard + --> $DIR/redundant_guards.rs:201:26 + | +LL | Some(Some(x)) if x.is_empty() => {}, + | ^^^^^^^^^^^^ + | +help: try + | +LL - Some(Some(x)) if x.is_empty() => {}, +LL + Some(Some("")) => {}, + | + +error: redundant guard + --> $DIR/redundant_guards.rs:212:26 + | +LL | Some(Some(x)) if x.is_empty() => {}, + | ^^^^^^^^^^^^ + | +help: try + | +LL - Some(Some(x)) if x.is_empty() => {}, +LL + Some(Some([])) => {}, + | + +error: redundant guard + --> $DIR/redundant_guards.rs:217:26 + | +LL | Some(Some(x)) if x.is_empty() => {}, + | ^^^^^^^^^^^^ + | +help: try + | +LL - Some(Some(x)) if x.is_empty() => {}, +LL + Some(Some([])) => {}, + | + +error: redundant guard + --> $DIR/redundant_guards.rs:228:26 + | +LL | Some(Some(x)) if x.starts_with(&[]) => {}, + | ^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - Some(Some(x)) if x.starts_with(&[]) => {}, +LL + Some(Some([..])) => {}, + | + +error: redundant guard + --> $DIR/redundant_guards.rs:233:26 + | +LL | Some(Some(x)) if x.starts_with(&[1]) => {}, + | ^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - Some(Some(x)) if x.starts_with(&[1]) => {}, +LL + Some(Some([1, ..])) => {}, + | + +error: redundant guard + --> $DIR/redundant_guards.rs:238:26 + | +LL | Some(Some(x)) if x.starts_with(&[1, 2]) => {}, + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - Some(Some(x)) if x.starts_with(&[1, 2]) => {}, +LL + Some(Some([1, 2, ..])) => {}, + | + +error: redundant guard + --> $DIR/redundant_guards.rs:243:26 + | +LL | Some(Some(x)) if x.ends_with(&[1, 2]) => {}, + | ^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL - Some(Some(x)) if x.ends_with(&[1, 2]) => {}, +LL + Some(Some([.., 1, 2])) => {}, + | + +error: aborting due to 24 previous errors diff --git a/tests/ui/result_map_or_into_option.fixed b/tests/ui/result_map_or_into_option.fixed index fb2db6cf5ec..cf42b24b2dd 100644 --- a/tests/ui/result_map_or_into_option.fixed +++ b/tests/ui/result_map_or_into_option.fixed @@ -3,6 +3,12 @@ fn main() { let opt: Result = Ok(1); let _ = opt.ok(); + //~^ ERROR: called `map_or(None, Some)` on a `Result` value + let _ = opt.ok(); + //~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value + #[rustfmt::skip] + let _ = opt.ok(); + //~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value let rewrap = |s: u32| -> Option { Some(s) }; @@ -14,4 +20,5 @@ fn main() { // return should not emit the lint let opt: Result = Ok(1); _ = opt.map_or(None, |_x| Some(1)); + let _ = opt.map_or_else(|a| a.parse::().ok(), Some); } diff --git a/tests/ui/result_map_or_into_option.rs b/tests/ui/result_map_or_into_option.rs index 06779a69925..cdb45d6b82a 100644 --- a/tests/ui/result_map_or_into_option.rs +++ b/tests/ui/result_map_or_into_option.rs @@ -3,6 +3,12 @@ fn main() { let opt: Result = Ok(1); let _ = opt.map_or(None, Some); + //~^ ERROR: called `map_or(None, Some)` on a `Result` value + let _ = opt.map_or_else(|_| None, Some); + //~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value + #[rustfmt::skip] + let _ = opt.map_or_else(|_| { None }, Some); + //~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value let rewrap = |s: u32| -> Option { Some(s) }; @@ -14,4 +20,5 @@ fn main() { // return should not emit the lint let opt: Result = Ok(1); _ = opt.map_or(None, |_x| Some(1)); + let _ = opt.map_or_else(|a| a.parse::().ok(), Some); } diff --git a/tests/ui/result_map_or_into_option.stderr b/tests/ui/result_map_or_into_option.stderr index 12de3b46088..3d6bfef48ec 100644 --- a/tests/ui/result_map_or_into_option.stderr +++ b/tests/ui/result_map_or_into_option.stderr @@ -1,4 +1,4 @@ -error: called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling `ok()` instead +error: called `map_or(None, Some)` on a `Result` value --> $DIR/result_map_or_into_option.rs:5:13 | LL | let _ = opt.map_or(None, Some); @@ -7,5 +7,17 @@ LL | let _ = opt.map_or(None, Some); = note: `-D clippy::result-map-or-into-option` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::result_map_or_into_option)]` -error: aborting due to 1 previous error +error: called `map_or_else(|_| None, Some)` on a `Result` value + --> $DIR/result_map_or_into_option.rs:7:13 + | +LL | let _ = opt.map_or_else(|_| None, Some); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()` + +error: called `map_or_else(|_| None, Some)` on a `Result` value + --> $DIR/result_map_or_into_option.rs:10:13 + | +LL | let _ = opt.map_or_else(|_| { None }, Some); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()` + +error: aborting due to 3 previous errors diff --git a/tests/ui/single_element_loop.fixed b/tests/ui/single_element_loop.fixed index a82eb6afcf5..4e59c763198 100644 --- a/tests/ui/single_element_loop.fixed +++ b/tests/ui/single_element_loop.fixed @@ -15,23 +15,19 @@ fn main() { dbg!(item); } - { - let item = &(0..5); + for item in 0..5 { dbg!(item); } - { - let item = &mut (0..5); + for item in 0..5 { dbg!(item); } - { - let item = 0..5; + for item in 0..5 { dbg!(item); } - { - let item = 0..5; + for item in 0..5 { dbg!(item); } diff --git a/tests/ui/single_element_loop.stderr b/tests/ui/single_element_loop.stderr index 603dd7406e4..952d704143a 100644 --- a/tests/ui/single_element_loop.stderr +++ b/tests/ui/single_element_loop.stderr @@ -32,69 +32,29 @@ LL + dbg!(item); LL + } | -error: for loop over a single element - --> $DIR/single_element_loop.rs:16:5 - | -LL | / for item in &[0..5] { -LL | | dbg!(item); -LL | | } - | |_____^ - | -help: try - | -LL ~ { -LL + let item = &(0..5); -LL + dbg!(item); -LL + } +error: this loops only once with `item` being `0..5` + --> $DIR/single_element_loop.rs:16:17 | +LL | for item in &[0..5] { + | ^^^^^^^ help: did you mean to iterate over the range instead?: `0..5` -error: for loop over a single element - --> $DIR/single_element_loop.rs:20:5 - | -LL | / for item in [0..5].iter_mut() { -LL | | dbg!(item); -LL | | } - | |_____^ - | -help: try - | -LL ~ { -LL + let item = &mut (0..5); -LL + dbg!(item); -LL + } +error: this loops only once with `item` being `0..5` + --> $DIR/single_element_loop.rs:20:17 | +LL | for item in [0..5].iter_mut() { + | ^^^^^^^^^^^^^^^^^ help: did you mean to iterate over the range instead?: `0..5` -error: for loop over a single element - --> $DIR/single_element_loop.rs:24:5 - | -LL | / for item in [0..5] { -LL | | dbg!(item); -LL | | } - | |_____^ - | -help: try - | -LL ~ { -LL + let item = 0..5; -LL + dbg!(item); -LL + } +error: this loops only once with `item` being `0..5` + --> $DIR/single_element_loop.rs:24:17 | +LL | for item in [0..5] { + | ^^^^^^ help: did you mean to iterate over the range instead?: `0..5` -error: for loop over a single element - --> $DIR/single_element_loop.rs:28:5 - | -LL | / for item in [0..5].into_iter() { -LL | | dbg!(item); -LL | | } - | |_____^ - | -help: try - | -LL ~ { -LL + let item = 0..5; -LL + dbg!(item); -LL + } +error: this loops only once with `item` being `0..5` + --> $DIR/single_element_loop.rs:28:17 | +LL | for item in [0..5].into_iter() { + | ^^^^^^^^^^^^^^^^^^ help: did you mean to iterate over the range instead?: `0..5` error: for loop over a single element --> $DIR/single_element_loop.rs:47:5 diff --git a/tests/ui/test_attr_in_doctest.rs b/tests/ui/test_attr_in_doctest.rs new file mode 100644 index 00000000000..4c904f7a09a --- /dev/null +++ b/tests/ui/test_attr_in_doctest.rs @@ -0,0 +1,51 @@ +/// This is a test for `#[test]` in doctests +/// +/// # Examples +/// +/// ``` +/// #[test] +/// fn should_be_linted() { +/// assert_eq!(1, 1); +/// } +/// ``` +/// +/// Make sure we catch multiple tests in one example, +/// and show that we really parse the attr: +/// +/// ``` +/// #[test] +/// fn should_also_be_linted() { +/// #[cfg(test)] +/// assert!(true); +/// } +/// +/// #[test] +/// fn should_be_linted_too() { +/// assert_eq!("#[test]", " +/// #[test] +/// "); +/// } +/// ``` +/// +/// We don't catch examples that aren't run: +/// +/// ```ignore +/// #[test] +/// fn ignored() { todo!() } +/// ``` +/// +/// ```no_run +/// #[test] +/// fn ignored() { todo!() } +/// ``` +/// +/// ```compile_fail +/// #[test] +/// fn ignored() { Err(()) } +/// ``` +/// +/// ```txt +/// #[test] +/// fn not_even_rust() { panic!("Ouch") } +/// ``` +fn test_attr_in_doctests() {} diff --git a/tests/ui/test_attr_in_doctest.stderr b/tests/ui/test_attr_in_doctest.stderr new file mode 100644 index 00000000000..605259f3bfb --- /dev/null +++ b/tests/ui/test_attr_in_doctest.stderr @@ -0,0 +1,29 @@ +error: unit tests in doctest are not executed + --> $DIR/test_attr_in_doctest.rs:6:5 + | +LL | /// #[test] + | _____^ +LL | | /// fn should_be_linted() { + | |_______________________^ + | + = note: `-D clippy::test-attr-in-doctest` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::test_attr_in_doctest)]` + +error: unit tests in doctest are not executed + --> $DIR/test_attr_in_doctest.rs:16:5 + | +LL | /// #[test] + | _____^ +LL | | /// fn should_also_be_linted() { + | |____________________________^ + +error: unit tests in doctest are not executed + --> $DIR/test_attr_in_doctest.rs:22:5 + | +LL | /// #[test] + | _____^ +LL | | /// fn should_be_linted_too() { + | |___________________________^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/transmute_ptr_to_ptr.fixed b/tests/ui/transmute_ptr_to_ptr.fixed index 19abced98bb..4e145693c55 100644 --- a/tests/ui/transmute_ptr_to_ptr.fixed +++ b/tests/ui/transmute_ptr_to_ptr.fixed @@ -43,6 +43,9 @@ fn transmute_ptr_to_ptr() { //~^ ERROR: transmute from a reference to a reference let _: &GenericParam = &*(&GenericParam { t: 1u32 } as *const GenericParam as *const GenericParam); //~^ ERROR: transmute from a reference to a reference + let u8_ref: &u8 = &0u8; + let u64_ref: &u64 = unsafe { &*(u8_ref as *const u8 as *const u64) }; + //~^ ERROR: transmute from a reference to a reference } // these are recommendations for solving the above; if these lint we need to update diff --git a/tests/ui/transmute_ptr_to_ptr.rs b/tests/ui/transmute_ptr_to_ptr.rs index abba2b8e524..086aadc3647 100644 --- a/tests/ui/transmute_ptr_to_ptr.rs +++ b/tests/ui/transmute_ptr_to_ptr.rs @@ -43,6 +43,9 @@ fn transmute_ptr_to_ptr() { //~^ ERROR: transmute from a reference to a reference let _: &GenericParam = std::mem::transmute(&GenericParam { t: 1u32 }); //~^ ERROR: transmute from a reference to a reference + let u8_ref: &u8 = &0u8; + let u64_ref: &u64 = unsafe { std::mem::transmute(u8_ref) }; + //~^ ERROR: transmute from a reference to a reference } // these are recommendations for solving the above; if these lint we need to update diff --git a/tests/ui/transmute_ptr_to_ptr.stderr b/tests/ui/transmute_ptr_to_ptr.stderr index 564339c067e..9f8599921ec 100644 --- a/tests/ui/transmute_ptr_to_ptr.stderr +++ b/tests/ui/transmute_ptr_to_ptr.stderr @@ -37,5 +37,11 @@ error: transmute from a reference to a reference LL | let _: &GenericParam = std::mem::transmute(&GenericParam { t: 1u32 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam as *const GenericParam)` -error: aborting due to 6 previous errors +error: transmute from a reference to a reference + --> $DIR/transmute_ptr_to_ptr.rs:47:38 + | +LL | let u64_ref: &u64 = unsafe { std::mem::transmute(u8_ref) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(u8_ref as *const u8 as *const u64)` + +error: aborting due to 7 previous errors diff --git a/tests/ui/transmute_ref_to_ref.rs b/tests/ui/transmute_ref_to_ref.rs new file mode 100644 index 00000000000..e7f35c57436 --- /dev/null +++ b/tests/ui/transmute_ref_to_ref.rs @@ -0,0 +1,18 @@ +//@no-rustfix + +#![deny(clippy::transmute_ptr_to_ptr)] +#![allow(dead_code)] + +fn main() { + unsafe { + let single_u64: &[u64] = &[0xDEAD_BEEF_DEAD_BEEF]; + let bools: &[bool] = unsafe { std::mem::transmute(single_u64) }; + //~^ ERROR: transmute from a reference to a reference + let a: &[u32] = &[0x12345678, 0x90ABCDEF, 0xFEDCBA09, 0x87654321]; + let b: &[u8] = unsafe { std::mem::transmute(a) }; + //~^ ERROR: transmute from a reference to a reference + let bytes = &[1u8, 2u8, 3u8, 4u8] as &[u8]; + let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; + //~^ ERROR: transmute from a reference to a reference + } +} diff --git a/tests/ui/transmute_ref_to_ref.stderr b/tests/ui/transmute_ref_to_ref.stderr new file mode 100644 index 00000000000..cc6b156b188 --- /dev/null +++ b/tests/ui/transmute_ref_to_ref.stderr @@ -0,0 +1,26 @@ +error: transmute from a reference to a reference + --> $DIR/transmute_ref_to_ref.rs:9:39 + | +LL | let bools: &[bool] = unsafe { std::mem::transmute(single_u64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(single_u64 as *const [u64] as *const [bool])` + | +note: the lint level is defined here + --> $DIR/transmute_ref_to_ref.rs:3:9 + | +LL | #![deny(clippy::transmute_ptr_to_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmute from a reference to a reference + --> $DIR/transmute_ref_to_ref.rs:12:33 + | +LL | let b: &[u8] = unsafe { std::mem::transmute(a) }; + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const [u32] as *const [u8])` + +error: transmute from a reference to a reference + --> $DIR/transmute_ref_to_ref.rs:15:42 + | +LL | let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index 4778eaefdbd..66598f89208 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -6,6 +6,8 @@ #![allow(clippy::needless_borrow)] #![allow(clippy::unnecessary_literal_unwrap)] #![allow(clippy::unit_arg)] +#![allow(arithmetic_overflow)] +#![allow(unconditional_panic)] use std::ops::Deref; @@ -190,3 +192,79 @@ fn issue9485() { // should not lint, is in proc macro with_span!(span Some(42).unwrap_or_else(|| 2);); } + +fn issue9422(x: usize) -> Option { + (x >= 5).then(|| x - 5) + // (x >= 5).then_some(x - 5) // clippy suggestion panics +} + +fn panicky_arithmetic_ops(x: usize, y: isize) { + #![allow(clippy::identity_op, clippy::eq_op)] + + // See comments in `eager_or_lazy.rs` for the rules that this is meant to follow + + let _x = false.then_some(i32::MAX + 1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(i32::MAX * 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(i32::MAX - 1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(i32::MIN - 1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some((1 + 2 * 3 - 2 / 3 + 9) << 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(255u8 << 7); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(255u8 << 8); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(255u8 >> 8); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 255u8 >> x); + let _x = false.then_some(i32::MAX + -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(-i32::MAX); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(-i32::MIN); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| -y); + let _x = false.then_some(255 >> -7); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(255 << -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(1 / 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(x << -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(x << 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| x + x); + let _x = false.then(|| x * x); + let _x = false.then(|| x - x); + let _x = false.then(|| x / x); + let _x = false.then(|| x % x); + let _x = false.then(|| x + 1); + let _x = false.then(|| 1 + x); + + let _x = false.then_some(x / 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(x % 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| y / -1); + let _x = false.then_some(1 / -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(i32::MIN / -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| i32::MIN / x as i32); + let _x = false.then_some(i32::MIN / 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then_some(4 / 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 1 / x); + + // const eval doesn't read variables, but floating point math never panics, so we can still emit a + // warning + let f1 = 1.0; + let f2 = 2.0; + let _x = false.then_some(f1 + f2); + //~^ ERROR: unnecessary closure used with `bool::then` +} diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index d4b7fd31b1b..5045fcd790e 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -6,6 +6,8 @@ #![allow(clippy::needless_borrow)] #![allow(clippy::unnecessary_literal_unwrap)] #![allow(clippy::unit_arg)] +#![allow(arithmetic_overflow)] +#![allow(unconditional_panic)] use std::ops::Deref; @@ -190,3 +192,79 @@ fn issue9485() { // should not lint, is in proc macro with_span!(span Some(42).unwrap_or_else(|| 2);); } + +fn issue9422(x: usize) -> Option { + (x >= 5).then(|| x - 5) + // (x >= 5).then_some(x - 5) // clippy suggestion panics +} + +fn panicky_arithmetic_ops(x: usize, y: isize) { + #![allow(clippy::identity_op, clippy::eq_op)] + + // See comments in `eager_or_lazy.rs` for the rules that this is meant to follow + + let _x = false.then(|| i32::MAX + 1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| i32::MAX * 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| i32::MAX - 1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| i32::MIN - 1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 255u8 << 7); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 255u8 << 8); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 255u8 >> 8); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 255u8 >> x); + let _x = false.then(|| i32::MAX + -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| -i32::MAX); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| -i32::MIN); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| -y); + let _x = false.then(|| 255 >> -7); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 255 << -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 1 / 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| x << -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| x << 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| x + x); + let _x = false.then(|| x * x); + let _x = false.then(|| x - x); + let _x = false.then(|| x / x); + let _x = false.then(|| x % x); + let _x = false.then(|| x + 1); + let _x = false.then(|| 1 + x); + + let _x = false.then(|| x / 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| x % 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| y / -1); + let _x = false.then(|| 1 / -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| i32::MIN / -1); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| i32::MIN / x as i32); + let _x = false.then(|| i32::MIN / 0); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 4 / 2); + //~^ ERROR: unnecessary closure used with `bool::then` + let _x = false.then(|| 1 / x); + + // const eval doesn't read variables, but floating point math never panics, so we can still emit a + // warning + let f1 = 1.0; + let f2 = 2.0; + let _x = false.then(|| f1 + f2); + //~^ ERROR: unnecessary closure used with `bool::then` +} diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index 1b0db4759bb..466664aee6c 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -1,5 +1,5 @@ error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:69:13 + --> $DIR/unnecessary_lazy_eval.rs:71:13 | LL | let _ = opt.unwrap_or_else(|| 2); | ^^^^-------------------- @@ -10,7 +10,7 @@ LL | let _ = opt.unwrap_or_else(|| 2); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_lazy_evaluations)]` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:70:13 + --> $DIR/unnecessary_lazy_eval.rs:72:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | ^^^^--------------------------------- @@ -18,7 +18,7 @@ LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:71:13 + --> $DIR/unnecessary_lazy_eval.rs:73:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | ^^^^------------------------------------- @@ -26,7 +26,7 @@ LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:73:13 + --> $DIR/unnecessary_lazy_eval.rs:75:13 | LL | let _ = opt.and_then(|_| ext_opt); | ^^^^--------------------- @@ -34,7 +34,7 @@ LL | let _ = opt.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:74:13 + --> $DIR/unnecessary_lazy_eval.rs:76:13 | LL | let _ = opt.or_else(|| ext_opt); | ^^^^------------------- @@ -42,7 +42,7 @@ LL | let _ = opt.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:75:13 + --> $DIR/unnecessary_lazy_eval.rs:77:13 | LL | let _ = opt.or_else(|| None); | ^^^^---------------- @@ -50,7 +50,7 @@ LL | let _ = opt.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:76:13 + --> $DIR/unnecessary_lazy_eval.rs:78:13 | LL | let _ = opt.get_or_insert_with(|| 2); | ^^^^------------------------ @@ -58,7 +58,7 @@ LL | let _ = opt.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:77:13 + --> $DIR/unnecessary_lazy_eval.rs:79:13 | LL | let _ = opt.ok_or_else(|| 2); | ^^^^---------------- @@ -66,7 +66,7 @@ LL | let _ = opt.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:78:13 + --> $DIR/unnecessary_lazy_eval.rs:80:13 | LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | ^^^^^^^^^^^^^^^^^------------------------------- @@ -74,7 +74,7 @@ LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))` error: unnecessary closure used with `bool::then` - --> $DIR/unnecessary_lazy_eval.rs:79:13 + --> $DIR/unnecessary_lazy_eval.rs:81:13 | LL | let _ = cond.then(|| astronomers_pi); | ^^^^^----------------------- @@ -82,7 +82,7 @@ LL | let _ = cond.then(|| astronomers_pi); | help: use `then_some(..)` instead: `then_some(astronomers_pi)` error: unnecessary closure used with `bool::then` - --> $DIR/unnecessary_lazy_eval.rs:80:13 + --> $DIR/unnecessary_lazy_eval.rs:82:13 | LL | let _ = true.then(|| -> _ {}); | ^^^^^---------------- @@ -90,7 +90,7 @@ LL | let _ = true.then(|| -> _ {}); | help: use `then_some(..)` instead: `then_some({})` error: unnecessary closure used with `bool::then` - --> $DIR/unnecessary_lazy_eval.rs:81:13 + --> $DIR/unnecessary_lazy_eval.rs:83:13 | LL | let _ = true.then(|| {}); | ^^^^^----------- @@ -98,7 +98,7 @@ LL | let _ = true.then(|| {}); | help: use `then_some(..)` instead: `then_some({})` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:85:13 + --> $DIR/unnecessary_lazy_eval.rs:87:13 | LL | let _ = Some(1).unwrap_or_else(|| *r); | ^^^^^^^^--------------------- @@ -106,7 +106,7 @@ LL | let _ = Some(1).unwrap_or_else(|| *r); | help: use `unwrap_or(..)` instead: `unwrap_or(*r)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:87:13 + --> $DIR/unnecessary_lazy_eval.rs:89:13 | LL | let _ = Some(1).unwrap_or_else(|| *b); | ^^^^^^^^--------------------- @@ -114,7 +114,7 @@ LL | let _ = Some(1).unwrap_or_else(|| *b); | help: use `unwrap_or(..)` instead: `unwrap_or(*b)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:89:13 + --> $DIR/unnecessary_lazy_eval.rs:91:13 | LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r); | ^^^^^^^^^^^^^^^^^--------------------- @@ -122,7 +122,7 @@ LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r); | help: use `unwrap_or(..)` instead: `unwrap_or(&r)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:90:13 + --> $DIR/unnecessary_lazy_eval.rs:92:13 | LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b); | ^^^^^^^^^^^^^^^^^--------------------- @@ -130,7 +130,7 @@ LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b); | help: use `unwrap_or(..)` instead: `unwrap_or(&b)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:93:13 + --> $DIR/unnecessary_lazy_eval.rs:95:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); | ^^^^^^^^^-------------------- @@ -138,7 +138,7 @@ LL | let _ = Some(10).unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:94:13 + --> $DIR/unnecessary_lazy_eval.rs:96:13 | LL | let _ = Some(10).and_then(|_| ext_opt); | ^^^^^^^^^--------------------- @@ -146,7 +146,7 @@ LL | let _ = Some(10).and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:95:28 + --> $DIR/unnecessary_lazy_eval.rs:97:28 | LL | let _: Option = None.or_else(|| ext_opt); | ^^^^^------------------- @@ -154,7 +154,7 @@ LL | let _: Option = None.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:96:13 + --> $DIR/unnecessary_lazy_eval.rs:98:13 | LL | let _ = None.get_or_insert_with(|| 2); | ^^^^^------------------------ @@ -162,7 +162,7 @@ LL | let _ = None.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:97:35 + --> $DIR/unnecessary_lazy_eval.rs:99:35 | LL | let _: Result = None.ok_or_else(|| 2); | ^^^^^---------------- @@ -170,7 +170,7 @@ LL | let _: Result = None.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:98:28 + --> $DIR/unnecessary_lazy_eval.rs:100:28 | LL | let _: Option = None.or_else(|| None); | ^^^^^---------------- @@ -178,7 +178,7 @@ LL | let _: Option = None.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:101:13 + --> $DIR/unnecessary_lazy_eval.rs:103:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); | ^^^^^^^-------------------- @@ -186,7 +186,7 @@ LL | let _ = deep.0.unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:102:13 + --> $DIR/unnecessary_lazy_eval.rs:104:13 | LL | let _ = deep.0.and_then(|_| ext_opt); | ^^^^^^^--------------------- @@ -194,7 +194,7 @@ LL | let _ = deep.0.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:103:13 + --> $DIR/unnecessary_lazy_eval.rs:105:13 | LL | let _ = deep.0.or_else(|| None); | ^^^^^^^---------------- @@ -202,7 +202,7 @@ LL | let _ = deep.0.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:104:13 + --> $DIR/unnecessary_lazy_eval.rs:106:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); | ^^^^^^^------------------------ @@ -210,7 +210,7 @@ LL | let _ = deep.0.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:105:13 + --> $DIR/unnecessary_lazy_eval.rs:107:13 | LL | let _ = deep.0.ok_or_else(|| 2); | ^^^^^^^---------------- @@ -218,7 +218,7 @@ LL | let _ = deep.0.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:135:28 + --> $DIR/unnecessary_lazy_eval.rs:137:28 | LL | let _: Option = None.or_else(|| Some(3)); | ^^^^^------------------- @@ -226,7 +226,7 @@ LL | let _: Option = None.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:136:13 + --> $DIR/unnecessary_lazy_eval.rs:138:13 | LL | let _ = deep.0.or_else(|| Some(3)); | ^^^^^^^------------------- @@ -234,7 +234,7 @@ LL | let _ = deep.0.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:137:13 + --> $DIR/unnecessary_lazy_eval.rs:139:13 | LL | let _ = opt.or_else(|| Some(3)); | ^^^^------------------- @@ -242,7 +242,7 @@ LL | let _ = opt.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:143:13 + --> $DIR/unnecessary_lazy_eval.rs:145:13 | LL | let _ = res2.unwrap_or_else(|_| 2); | ^^^^^--------------------- @@ -250,7 +250,7 @@ LL | let _ = res2.unwrap_or_else(|_| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:144:13 + --> $DIR/unnecessary_lazy_eval.rs:146:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | ^^^^^---------------------------------- @@ -258,7 +258,7 @@ LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:145:13 + --> $DIR/unnecessary_lazy_eval.rs:147:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^-------------------------------------- @@ -266,7 +266,7 @@ LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:167:35 + --> $DIR/unnecessary_lazy_eval.rs:169:35 | LL | let _: Result = res.and_then(|_| Err(2)); | ^^^^-------------------- @@ -274,7 +274,7 @@ LL | let _: Result = res.and_then(|_| Err(2)); | help: use `and(..)` instead: `and(Err(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:168:35 + --> $DIR/unnecessary_lazy_eval.rs:170:35 | LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | ^^^^--------------------------------- @@ -282,7 +282,7 @@ LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | help: use `and(..)` instead: `and(Err(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:169:35 + --> $DIR/unnecessary_lazy_eval.rs:171:35 | LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); | ^^^^------------------------------------- @@ -290,7 +290,7 @@ LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)) | help: use `and(..)` instead: `and(Err(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:171:35 + --> $DIR/unnecessary_lazy_eval.rs:173:35 | LL | let _: Result = res.or_else(|_| Ok(2)); | ^^^^------------------ @@ -298,7 +298,7 @@ LL | let _: Result = res.or_else(|_| Ok(2)); | help: use `or(..)` instead: `or(Ok(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:172:35 + --> $DIR/unnecessary_lazy_eval.rs:174:35 | LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | ^^^^------------------------------- @@ -306,7 +306,7 @@ LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | help: use `or(..)` instead: `or(Ok(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:173:35 + --> $DIR/unnecessary_lazy_eval.rs:175:35 | LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | ^^^^----------------------------------- @@ -314,7 +314,7 @@ LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:174:35 + --> $DIR/unnecessary_lazy_eval.rs:176:35 | LL | let _: Result = res. | ___________________________________^ @@ -328,5 +328,189 @@ LL | | or_else(|_| Ok(ext_str.some_field)); | | | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` -error: aborting due to 40 previous errors +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:206:14 + | +LL | let _x = false.then(|| i32::MAX + 1); + | ^^^^^^--------------------- + | | + | help: use `then_some(..)` instead: `then_some(i32::MAX + 1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:208:14 + | +LL | let _x = false.then(|| i32::MAX * 2); + | ^^^^^^--------------------- + | | + | help: use `then_some(..)` instead: `then_some(i32::MAX * 2)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:210:14 + | +LL | let _x = false.then(|| i32::MAX - 1); + | ^^^^^^--------------------- + | | + | help: use `then_some(..)` instead: `then_some(i32::MAX - 1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:212:14 + | +LL | let _x = false.then(|| i32::MIN - 1); + | ^^^^^^--------------------- + | | + | help: use `then_some(..)` instead: `then_some(i32::MIN - 1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:214:14 + | +LL | let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2); + | ^^^^^^------------------------------------- + | | + | help: use `then_some(..)` instead: `then_some((1 + 2 * 3 - 2 / 3 + 9) << 2)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:216:14 + | +LL | let _x = false.then(|| 255u8 << 7); + | ^^^^^^------------------- + | | + | help: use `then_some(..)` instead: `then_some(255u8 << 7)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:218:14 + | +LL | let _x = false.then(|| 255u8 << 8); + | ^^^^^^------------------- + | | + | help: use `then_some(..)` instead: `then_some(255u8 << 8)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:220:14 + | +LL | let _x = false.then(|| 255u8 >> 8); + | ^^^^^^------------------- + | | + | help: use `then_some(..)` instead: `then_some(255u8 >> 8)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:223:14 + | +LL | let _x = false.then(|| i32::MAX + -1); + | ^^^^^^---------------------- + | | + | help: use `then_some(..)` instead: `then_some(i32::MAX + -1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:225:14 + | +LL | let _x = false.then(|| -i32::MAX); + | ^^^^^^------------------ + | | + | help: use `then_some(..)` instead: `then_some(-i32::MAX)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:227:14 + | +LL | let _x = false.then(|| -i32::MIN); + | ^^^^^^------------------ + | | + | help: use `then_some(..)` instead: `then_some(-i32::MIN)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:230:14 + | +LL | let _x = false.then(|| 255 >> -7); + | ^^^^^^------------------ + | | + | help: use `then_some(..)` instead: `then_some(255 >> -7)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:232:14 + | +LL | let _x = false.then(|| 255 << -1); + | ^^^^^^------------------ + | | + | help: use `then_some(..)` instead: `then_some(255 << -1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:234:14 + | +LL | let _x = false.then(|| 1 / 0); + | ^^^^^^-------------- + | | + | help: use `then_some(..)` instead: `then_some(1 / 0)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:236:14 + | +LL | let _x = false.then(|| x << -1); + | ^^^^^^---------------- + | | + | help: use `then_some(..)` instead: `then_some(x << -1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:238:14 + | +LL | let _x = false.then(|| x << 2); + | ^^^^^^--------------- + | | + | help: use `then_some(..)` instead: `then_some(x << 2)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:248:14 + | +LL | let _x = false.then(|| x / 0); + | ^^^^^^-------------- + | | + | help: use `then_some(..)` instead: `then_some(x / 0)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:250:14 + | +LL | let _x = false.then(|| x % 0); + | ^^^^^^-------------- + | | + | help: use `then_some(..)` instead: `then_some(x % 0)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:253:14 + | +LL | let _x = false.then(|| 1 / -1); + | ^^^^^^--------------- + | | + | help: use `then_some(..)` instead: `then_some(1 / -1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:255:14 + | +LL | let _x = false.then(|| i32::MIN / -1); + | ^^^^^^---------------------- + | | + | help: use `then_some(..)` instead: `then_some(i32::MIN / -1)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:258:14 + | +LL | let _x = false.then(|| i32::MIN / 0); + | ^^^^^^--------------------- + | | + | help: use `then_some(..)` instead: `then_some(i32::MIN / 0)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:260:14 + | +LL | let _x = false.then(|| 4 / 2); + | ^^^^^^-------------- + | | + | help: use `then_some(..)` instead: `then_some(4 / 2)` + +error: unnecessary closure used with `bool::then` + --> $DIR/unnecessary_lazy_eval.rs:268:14 + | +LL | let _x = false.then(|| f1 + f2); + | ^^^^^^---------------- + | | + | help: use `then_some(..)` instead: `then_some(f1 + f2)` + +error: aborting due to 63 previous errors diff --git a/tests/ui/upper_case_acronyms.fixed b/tests/ui/upper_case_acronyms.fixed index 460567b097e..a8023ed00d2 100644 --- a/tests/ui/upper_case_acronyms.fixed +++ b/tests/ui/upper_case_acronyms.fixed @@ -59,4 +59,12 @@ enum Yaml { Str(String), } +// test for issue #7708 +enum AllowOnField { + Disallow, + //~^ ERROR: name `DISALLOW` contains a capitalized acronym + #[allow(clippy::upper_case_acronyms)] + ALLOW, +} + fn main() {} diff --git a/tests/ui/upper_case_acronyms.rs b/tests/ui/upper_case_acronyms.rs index 6a20aee62dc..c4711b87ec3 100644 --- a/tests/ui/upper_case_acronyms.rs +++ b/tests/ui/upper_case_acronyms.rs @@ -59,4 +59,12 @@ enum YAML { Str(String), } +// test for issue #7708 +enum AllowOnField { + DISALLOW, + //~^ ERROR: name `DISALLOW` contains a capitalized acronym + #[allow(clippy::upper_case_acronyms)] + ALLOW, +} + fn main() {} diff --git a/tests/ui/upper_case_acronyms.stderr b/tests/ui/upper_case_acronyms.stderr index c57b325e91a..009c53c725b 100644 --- a/tests/ui/upper_case_acronyms.stderr +++ b/tests/ui/upper_case_acronyms.stderr @@ -67,5 +67,11 @@ error: name `YAML` contains a capitalized acronym LL | enum YAML { | ^^^^ help: consider making the acronym lowercase, except the initial letter: `Yaml` -error: aborting due to 11 previous errors +error: name `DISALLOW` contains a capitalized acronym + --> $DIR/upper_case_acronyms.rs:64:5 + | +LL | DISALLOW, + | ^^^^^^^^ help: consider making the acronym lowercase, except the initial letter: `Disallow` + +error: aborting due to 12 previous errors