summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:43 +0000
commit3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245 (patch)
treedaf049b282ab10e8c3d03e409b3cd84ff3f7690c /src/tools/clippy
parentAdding debian version 1.68.2+dfsg1-1. (diff)
downloadrustc-3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245.tar.xz
rustc-3e3e70d529d8c7d7c4d7bc4fefc9f109393b9245.zip
Merging upstream version 1.69.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/clippy')
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml5
-rw-r--r--src/tools/clippy/CHANGELOG.md207
-rw-r--r--src/tools/clippy/Cargo.toml3
-rw-r--r--src/tools/clippy/README.md57
-rw-r--r--src/tools/clippy/book/src/README.md2
-rw-r--r--src/tools/clippy/book/src/SUMMARY.md1
-rw-r--r--src/tools/clippy/book/src/configuration.md16
-rw-r--r--src/tools/clippy/book/src/development/adding_lints.md7
-rw-r--r--src/tools/clippy/book/src/development/infrastructure/backport.md1
-rw-r--r--src/tools/clippy/book/src/development/infrastructure/book.md14
-rw-r--r--src/tools/clippy/book/src/development/infrastructure/changelog_update.md16
-rw-r--r--src/tools/clippy/book/src/development/infrastructure/sync.md3
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md553
-rw-r--r--src/tools/clippy/clippy_dev/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs127
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs9
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs6
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml4
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs90
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/copy_iterator.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs105
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_enum.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_variants.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_bools.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/exhaustive_items.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs229
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/result.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_return.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_impl.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/instant_subtraction.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_stack_arrays.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs268
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_assert.rs97
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs153
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_used.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_first.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_clone.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/open_options.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/search_is_some.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_trait_methods.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/module_style.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs186
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs65
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark_used.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs89
-rw-r--r--src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs142
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/self_named_constructors.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_block.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs423
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs107
-rw-r--r--src/tools/clippy/clippy_lints/src/trailing_empty_array.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/utils.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/vec_box.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap_in_result.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/dump_hir.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs79
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs2
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs8
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs13
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs30
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs76
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/numeric_literal.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs7
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs22
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs56
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs10
-rw-r--r--src/tools/clippy/declare_clippy_lint/Cargo.toml2
-rw-r--r--src/tools/clippy/lintcheck/Cargo.toml4
-rw-r--r--src/tools/clippy/lintcheck/src/config.rs2
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs12
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/driver.rs3
-rw-r--r--src/tools/clippy/src/main.rs2
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.rs3
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.stderr4
-rw-r--r--src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs12
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs59
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr52
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr1
-rw-r--r--src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs6
-rw-r--r--src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr10
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.rs27
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.stderr198
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/macro_rules.rs19
-rw-r--r--src/tools/clippy/tests/ui/bool_assert_comparison.fixed171
-rw-r--r--src/tools/clippy/tests/ui/bool_assert_comparison.rs53
-rw-r--r--src/tools/clippy/tests/ui/bool_assert_comparison.stderr353
-rw-r--r--src/tools/clippy/tests/ui/box_default.fixed18
-rw-r--r--src/tools/clippy/tests/ui/box_default.rs18
-rw-r--r--src/tools/clippy/tests/ui/box_default.stderr14
-rw-r--r--src/tools/clippy/tests/ui/bytes_nth.fixed6
-rw-r--r--src/tools/clippy/tests/ui/bytes_nth.rs2
-rw-r--r--src/tools/clippy/tests/ui/bytes_nth.stderr10
-rw-r--r--src/tools/clippy/tests/ui/cast.rs1
-rw-r--r--src/tools/clippy/tests/ui/cast.stderr163
-rw-r--r--src/tools/clippy/tests/ui/cast_size.stderr53
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2774.stderr5
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs17
-rw-r--r--src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr5
-rw-r--r--src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs9
-rw-r--r--src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr15
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.fixed2
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.rs4
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.stderr24
-rw-r--r--src/tools/clippy/tests/ui/entry.fixed14
-rw-r--r--src/tools/clippy/tests/ui/entry.rs14
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.fixed14
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.rs14
-rw-r--r--src/tools/clippy/tests/ui/extra_unused_type_parameters.rs110
-rw-r--r--src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr75
-rw-r--r--src/tools/clippy/tests/ui/format.fixed6
-rw-r--r--src/tools/clippy/tests/ui/format.rs6
-rw-r--r--src/tools/clippy/tests/ui/format.stderr30
-rw-r--r--src/tools/clippy/tests/ui/impl_trait_in_params.rs17
-rw-r--r--src/tools/clippy/tests/ui/impl_trait_in_params.stderr25
-rw-r--r--src/tools/clippy/tests/ui/large_digit_groups.fixed4
-rw-r--r--src/tools/clippy/tests/ui/large_digit_groups.stderr20
-rw-r--r--src/tools/clippy/tests/ui/len_without_is_empty.rs46
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_untyped.rs54
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_untyped.stderr51
-rw-r--r--src/tools/clippy/tests/ui/literals.stderr10
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2018.fixed35
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2018.stderr67
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else.rs11
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_match.rs29
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_match.stderr15
-rw-r--r--src/tools/clippy/tests/ui/map_flatten_fixable.fixed1
-rw-r--r--src/tools/clippy/tests/ui/map_flatten_fixable.rs1
-rw-r--r--src/tools/clippy/tests/ui/map_flatten_fixable.stderr18
-rw-r--r--src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed2
-rw-r--r--src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr8
-rw-r--r--src/tools/clippy/tests/ui/methods.rs1
-rw-r--r--src/tools/clippy/tests/ui/methods.stderr4
-rw-r--r--src/tools/clippy/tests/ui/missing_doc_impl.stderr4
-rw-r--r--src/tools/clippy/tests/ui/module_name_repetitions.stderr20
-rw-r--r--src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs119
-rw-r--r--src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr129
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.fixed2
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.rs2
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.fixed548
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.rs52
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.stderr391
-rw-r--r--src/tools/clippy/tests/ui/needless_range_loop.stderr8
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed20
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs20
-rw-r--r--src/tools/clippy/tests/ui/needless_return.stderr126
-rw-r--r--src/tools/clippy/tests/ui/never_loop.rs45
-rw-r--r--src/tools/clippy/tests/ui/never_loop.stderr15
-rw-r--r--src/tools/clippy/tests/ui/new_without_default.rs7
-rw-r--r--src/tools/clippy/tests/ui/new_without_default.stderr14
-rw-r--r--src/tools/clippy/tests/ui/no_mangle_with_rust_abi.fixed48
-rw-r--r--src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs48
-rw-r--r--src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr45
-rw-r--r--src/tools/clippy/tests/ui/question_mark_used.rs15
-rw-r--r--src/tools/clippy/tests/ui/question_mark_used.stderr11
-rw-r--r--src/tools/clippy/tests/ui/redundant_field_names.fixed2
-rw-r--r--src/tools/clippy/tests/ui/redundant_field_names.rs2
-rw-r--r--src/tools/clippy/tests/ui/regex.rs4
-rw-r--r--src/tools/clippy/tests/ui/regex.stderr66
-rw-r--r--src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed4
-rw-r--r--src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs4
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.fixed84
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.rs80
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.stderr94
-rw-r--r--src/tools/clippy/tests/ui/suspicious_command_arg_space.rs10
-rw-r--r--src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr25
-rw-r--r--src/tools/clippy/tests/ui/suspicious_to_owned.stderr43
-rw-r--r--src/tools/clippy/tests/ui/swap.fixed24
-rw-r--r--src/tools/clippy/tests/ui/swap.rs29
-rw-r--r--src/tools/clippy/tests/ui/swap.stderr65
-rw-r--r--src/tools/clippy/tests/ui/track-diagnostics.stderr2
-rw-r--r--src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs41
-rw-r--r--src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr64
-rw-r--r--src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed2
-rw-r--r--src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs2
-rw-r--r--src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr10
-rw-r--r--src/tools/clippy/tests/ui/type_repetition_in_bounds.rs1
-rw-r--r--src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr8
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args.fixed4
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args.rs4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_safety_comment.rs17
-rw-r--r--src/tools/clippy/tests/ui/unreadable_literal.fixed2
-rw-r--r--src/tools/clippy/tests/ui/unreadable_literal.stderr10
-rw-r--r--src/tools/clippy/tests/ui/unused_io_amount.rs8
-rw-r--r--src/tools/clippy/tests/ui/unused_io_amount.stderr44
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed2
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr4
314 files changed, 7732 insertions, 1640 deletions
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 1bc457a94..24e677ce8 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -157,6 +157,11 @@ jobs:
- name: Test metadata collection
run: cargo collect-metadata
+ - name: Test lint_configuration.md is up-to-date
+ run: |
+ echo "run \`cargo collect-metadata\` if this fails"
+ git update-index --refresh
+
integration_build:
needs: changelog
runs-on: ubuntu-latest
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 8e31e8f0d..765826ed8 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,204 @@ document.
## Unreleased / Beta / In Rust Nightly
-[4f142aa1...master](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...master)
+[d822110d...master](https://github.com/rust-lang/rust-clippy/compare/d822110d...master)
+
+## Rust 1.67
+
+Current stable, released 2023-01-26
+
+[4f142aa1...d822110d](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...d822110d)
+
+### New Lints
+
+* [`seek_from_current`]
+ [#9681](https://github.com/rust-lang/rust-clippy/pull/9681)
+* [`from_raw_with_void_ptr`]
+ [#9690](https://github.com/rust-lang/rust-clippy/pull/9690)
+* [`misnamed_getters`]
+ [#9770](https://github.com/rust-lang/rust-clippy/pull/9770)
+* [`seek_to_start_instead_of_rewind`]
+ [#9667](https://github.com/rust-lang/rust-clippy/pull/9667)
+* [`suspicious_xor_used_as_pow`]
+ [#9506](https://github.com/rust-lang/rust-clippy/pull/9506)
+* [`unnecessary_safety_doc`]
+ [#9822](https://github.com/rust-lang/rust-clippy/pull/9822)
+* [`unchecked_duration_subtraction`]
+ [#9570](https://github.com/rust-lang/rust-clippy/pull/9570)
+* [`manual_is_ascii_check`]
+ [#9765](https://github.com/rust-lang/rust-clippy/pull/9765)
+* [`unnecessary_safety_comment`]
+ [#9851](https://github.com/rust-lang/rust-clippy/pull/9851)
+* [`let_underscore_future`]
+ [#9760](https://github.com/rust-lang/rust-clippy/pull/9760)
+* [`manual_let_else`]
+ [#8437](https://github.com/rust-lang/rust-clippy/pull/8437)
+
+### Moves and Deprecations
+
+* Moved [`uninlined_format_args`] to `style` (Now warn-by-default)
+ [#9865](https://github.com/rust-lang/rust-clippy/pull/9865)
+* Moved [`needless_collect`] to `nursery` (Now allow-by-default)
+ [#9705](https://github.com/rust-lang/rust-clippy/pull/9705)
+* Moved [`or_fun_call`] to `nursery` (Now allow-by-default)
+ [#9829](https://github.com/rust-lang/rust-clippy/pull/9829)
+* Uplifted [`let_underscore_lock`] into rustc
+ [#9697](https://github.com/rust-lang/rust-clippy/pull/9697)
+* Uplifted [`let_underscore_drop`] into rustc
+ [#9697](https://github.com/rust-lang/rust-clippy/pull/9697)
+* Moved [`bool_to_int_with_if`] to `pedantic` (Now allow-by-default)
+ [#9830](https://github.com/rust-lang/rust-clippy/pull/9830)
+* Move `index_refutable_slice` to `pedantic` (Now warn-by-default)
+ [#9975](https://github.com/rust-lang/rust-clippy/pull/9975)
+* Moved [`manual_clamp`] to `nursery` (Now allow-by-default)
+ [#10101](https://github.com/rust-lang/rust-clippy/pull/10101)
+
+### Enhancements
+
+* The scope of `#![clippy::msrv]` is now tracked correctly
+ [#9924](https://github.com/rust-lang/rust-clippy/pull/9924)
+* `#[clippy::msrv]` can now be used as an outer attribute
+ [#9860](https://github.com/rust-lang/rust-clippy/pull/9860)
+* Clippy will now avoid Cargo's cache, if `Cargo.toml` or `clippy.toml` have changed
+ [#9707](https://github.com/rust-lang/rust-clippy/pull/9707)
+* [`uninlined_format_args`]: Added a new config `allow-mixed-uninlined-format-args` to allow the
+ lint, if only some arguments can be inlined
+ [#9865](https://github.com/rust-lang/rust-clippy/pull/9865)
+* [`needless_lifetimes`]: Now provides suggests for individual lifetimes
+ [#9743](https://github.com/rust-lang/rust-clippy/pull/9743)
+* [`needless_collect`]: Now detects needless `is_empty` and `contains` calls
+ [#8744](https://github.com/rust-lang/rust-clippy/pull/8744)
+* [`blanket_clippy_restriction_lints`]: Now lints, if `clippy::restriction` is enabled via the
+ command line arguments
+ [#9755](https://github.com/rust-lang/rust-clippy/pull/9755)
+* [`mutable_key_type`]: Now has the `ignore-interior-mutability` configuration, to add types which
+ should be ignored by the lint
+ [#9692](https://github.com/rust-lang/rust-clippy/pull/9692)
+* [`uninlined_format_args`]: Now works for multiline `format!` expressions
+ [#9945](https://github.com/rust-lang/rust-clippy/pull/9945)
+* [`cognitive_complexity`]: Now works for async functions
+ [#9828](https://github.com/rust-lang/rust-clippy/pull/9828)
+ [#9836](https://github.com/rust-lang/rust-clippy/pull/9836)
+* [`vec_box`]: Now avoids an off-by-one error when using the `vec-box-size-threshold` configuration
+ [#9848](https://github.com/rust-lang/rust-clippy/pull/9848)
+* [`never_loop`]: Now correctly handles breaks in nested labeled blocks
+ [#9858](https://github.com/rust-lang/rust-clippy/pull/9858)
+ [#9837](https://github.com/rust-lang/rust-clippy/pull/9837)
+* [`disallowed_methods`], [`disallowed_types`], [`disallowed_macros`]: Now correctly resolve
+ paths, if a crate is used multiple times with different versions
+ [#9800](https://github.com/rust-lang/rust-clippy/pull/9800)
+* [`disallowed_methods`]: Can now be used for local methods
+ [#9800](https://github.com/rust-lang/rust-clippy/pull/9800)
+* [`print_stdout`], [`print_stderr`]: Can now be enabled in test with the `allow-print-in-tests`
+ config value
+ [#9797](https://github.com/rust-lang/rust-clippy/pull/9797)
+* [`from_raw_with_void_ptr`]: Now works for `Rc`, `Arc`, `alloc::rc::Weak` and
+ `alloc::sync::Weak` types.
+ [#9700](https://github.com/rust-lang/rust-clippy/pull/9700)
+* [`needless_borrowed_reference`]: Now works for struct and tuple patterns with wildcards
+ [#9855](https://github.com/rust-lang/rust-clippy/pull/9855)
+* [`or_fun_call`]: Now supports `map_or` methods
+ [#9689](https://github.com/rust-lang/rust-clippy/pull/9689)
+* [`unwrap_used`], [`expect_used`]: No longer lints in test code
+ [#9686](https://github.com/rust-lang/rust-clippy/pull/9686)
+* [`fn_params_excessive_bools`]: Is now emitted with the lint level at the linted function
+ [#9698](https://github.com/rust-lang/rust-clippy/pull/9698)
+
+### False Positive Fixes
+
+* [`new_ret_no_self`]: No longer lints when `impl Trait<Self>` is returned
+ [#9733](https://github.com/rust-lang/rust-clippy/pull/9733)
+* [`unnecessary_lazy_evaluations`]: No longer lints, if the type has a significant drop
+ [#9750](https://github.com/rust-lang/rust-clippy/pull/9750)
+* [`option_if_let_else`]: No longer lints, if any arm has guard
+ [#9747](https://github.com/rust-lang/rust-clippy/pull/9747)
+* [`explicit_auto_deref`]: No longer lints, if the target type is a projection with generic
+ arguments
+ [#9813](https://github.com/rust-lang/rust-clippy/pull/9813)
+* [`unnecessary_to_owned`]: No longer lints, if the suggestion effects types
+ [#9796](https://github.com/rust-lang/rust-clippy/pull/9796)
+* [`needless_borrow`]: No longer lints, if the suggestion is affected by `Deref`
+ [#9674](https://github.com/rust-lang/rust-clippy/pull/9674)
+* [`unused_unit`]: No longer lints, if lifetimes are bound to the return type
+ [#9849](https://github.com/rust-lang/rust-clippy/pull/9849)
+* [`mut_mut`]: No longer lints cases with unsized mutable references
+ [#9835](https://github.com/rust-lang/rust-clippy/pull/9835)
+* [`bool_to_int_with_if`]: No longer lints in const context
+ [#9738](https://github.com/rust-lang/rust-clippy/pull/9738)
+* [`use_self`]: No longer lints in macros
+ [#9704](https://github.com/rust-lang/rust-clippy/pull/9704)
+* [`unnecessary_operation`]: No longer lints, if multiple macros are involved
+ [#9981](https://github.com/rust-lang/rust-clippy/pull/9981)
+* [`allow_attributes_without_reason`]: No longer lints inside external macros
+ [#9630](https://github.com/rust-lang/rust-clippy/pull/9630)
+* [`question_mark`]: No longer lints for `if let Err()` with an `else` branch
+ [#9722](https://github.com/rust-lang/rust-clippy/pull/9722)
+* [`unnecessary_cast`]: No longer lints if the identifier and cast originate from different macros
+ [#9980](https://github.com/rust-lang/rust-clippy/pull/9980)
+* [`arithmetic_side_effects`]: Now detects operations with associated constants
+ [#9592](https://github.com/rust-lang/rust-clippy/pull/9592)
+* [`explicit_auto_deref`]: No longer lints, if the initial value is not a reference or reference
+ receiver
+ [#9997](https://github.com/rust-lang/rust-clippy/pull/9997)
+* [`module_name_repetitions`], [`single_component_path_imports`]: Now handle `#[allow]`
+ attributes correctly
+ [#9879](https://github.com/rust-lang/rust-clippy/pull/9879)
+* [`bool_to_int_with_if`]: No longer lints `if let` statements
+ [#9714](https://github.com/rust-lang/rust-clippy/pull/9714)
+* [`needless_borrow`]: No longer lints, `if`-`else`-statements that require the borrow
+ [#9791](https://github.com/rust-lang/rust-clippy/pull/9791)
+* [`needless_borrow`]: No longer lints borrows, if moves were illegal
+ [#9711](https://github.com/rust-lang/rust-clippy/pull/9711)
+* [`manual_swap`]: No longer lints in const context
+ [#9871](https://github.com/rust-lang/rust-clippy/pull/9871)
+
+### Suggestion Fixes/Improvements
+
+* [`missing_safety_doc`], [`missing_errors_doc`], [`missing_panics_doc`]: No longer show the
+ entire item in the lint emission.
+ [#9772](https://github.com/rust-lang/rust-clippy/pull/9772)
+* [`needless_lifetimes`]: Only suggests `'_` when it's applicable
+ [#9743](https://github.com/rust-lang/rust-clippy/pull/9743)
+* [`use_self`]: Now suggests full paths correctly
+ [#9726](https://github.com/rust-lang/rust-clippy/pull/9726)
+* [`redundant_closure_call`]: Now correctly deals with macros during suggestion creation
+ [#9987](https://github.com/rust-lang/rust-clippy/pull/9987)
+* [`unnecessary_cast`]: Suggestions now correctly deal with references
+ [#9996](https://github.com/rust-lang/rust-clippy/pull/9996)
+* [`unnecessary_join`]: Suggestions now correctly use [turbofish] operators
+ [#9779](https://github.com/rust-lang/rust-clippy/pull/9779)
+* [`equatable_if_let`]: Can now suggest `matches!` replacements
+ [#9368](https://github.com/rust-lang/rust-clippy/pull/9368)
+* [`string_extend_chars`]: Suggestions now correctly work for `str` slices
+ [#9741](https://github.com/rust-lang/rust-clippy/pull/9741)
+* [`redundant_closure_for_method_calls`]: Suggestions now include angle brackets and generic
+ arguments if needed
+ [#9745](https://github.com/rust-lang/rust-clippy/pull/9745)
+* [`manual_let_else`]: Suggestions no longer expand macro calls
+ [#9943](https://github.com/rust-lang/rust-clippy/pull/9943)
+* [`infallible_destructuring_match`]: Suggestions now preserve references
+ [#9850](https://github.com/rust-lang/rust-clippy/pull/9850)
+* [`result_large_err`]: The error now shows the largest enum variant
+ [#9662](https://github.com/rust-lang/rust-clippy/pull/9662)
+* [`needless_return`]: Suggestions are now formatted better
+ [#9967](https://github.com/rust-lang/rust-clippy/pull/9967)
+* [`unused_rounding`]: The suggestion now preserves the original float literal notation
+ [#9870](https://github.com/rust-lang/rust-clippy/pull/9870)
+
+[turbofish]: https://turbo.fish/::%3CClippy%3E
+
+### ICE Fixes
+
+* [`result_large_err`]: Fixed ICE for empty enums
+ [#10007](https://github.com/rust-lang/rust-clippy/pull/10007)
+* [`redundant_allocation`]: Fixed ICE for types with bounded variables
+ [#9773](https://github.com/rust-lang/rust-clippy/pull/9773)
+* [`unused_rounding`]: Fixed ICE, if `_` was used as a separator
+ [#10001](https://github.com/rust-lang/rust-clippy/pull/10001)
## Rust 1.66
-Current stable, released 2022-12-15
+Released 2022-12-15
[b52fb523...4f142aa1](https://github.com/rust-lang/rust-clippy/compare/b52fb523...4f142aa1)
@@ -166,6 +359,7 @@ Current stable, released 2022-12-15
* [`unnecessary_to_owned`]: Avoid ICEs in favor of false negatives if information is missing
[#9505](https://github.com/rust-lang/rust-clippy/pull/9505)
+ [#10027](https://github.com/rust-lang/rust-clippy/pull/10027)
* [`manual_range_contains`]: No longer ICEs on values behind references
[#9627](https://github.com/rust-lang/rust-clippy/pull/9627)
* [`needless_pass_by_value`]: No longer ICEs on unsized `dyn Fn` arguments
@@ -4189,6 +4383,7 @@ Released 2018-09-13
[`extend_from_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_from_slice
[`extend_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_with_drain
[`extra_unused_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes
+[`extra_unused_type_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_type_parameters
[`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from
[`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
[`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file
@@ -4235,6 +4430,7 @@ Released 2018-09-13
[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
+[`impl_trait_in_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_in_params
[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
[`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
[`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
@@ -4299,6 +4495,7 @@ Released 2018-09-13
[`let_underscore_future`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_future
[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
+[`let_underscore_untyped`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_untyped
[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
[`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist
[`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
@@ -4383,6 +4580,7 @@ Released 2018-09-13
[`multi_assignments`]: https://rust-lang.github.io/rust-clippy/master/index.html#multi_assignments
[`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
[`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
+[`multiple_unsafe_ops_per_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_unsafe_ops_per_block
[`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate
[`must_use_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_unit
[`mut_from_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref
@@ -4424,6 +4622,7 @@ Released 2018-09-13
[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
[`no_effect_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_replace
[`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
+[`no_mangle_with_rust_abi`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_mangle_with_rust_abi
[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
[`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
[`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
@@ -4479,6 +4678,7 @@ Released 2018-09-13
[`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
[`pub_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_use
[`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark
+[`question_mark_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark_used
[`range_minus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_minus_one
[`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
[`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
@@ -4538,6 +4738,7 @@ Released 2018-09-13
[`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq
[`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
[`significant_drop_in_scrutinee`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_in_scrutinee
+[`significant_drop_tightening`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_tightening
[`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
[`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
[`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names
@@ -4568,6 +4769,7 @@ Released 2018-09-13
[`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops
[`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
[`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting
+[`suspicious_command_arg_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_command_arg_space
[`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting
[`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
[`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
@@ -4594,6 +4796,7 @@ Released 2018-09-13
[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
[`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
[`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
+[`transmute_int_to_non_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_non_zero
[`transmute_null_to_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_null_to_fn
[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
[`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index f8cb4b721..70d126809 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy"
-version = "0.1.68"
+version = "0.1.69"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@@ -42,6 +42,7 @@ filetime = "0.2"
rustc-workspace-hack = "1.0"
# UI test dependencies
+clap = { version = "4.1.4", features = ["derive"] }
clippy_utils = { path = "clippy_utils" }
derive-new = "0.5"
if_chain = "1.0"
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index 81254ba8b..3e7379ace 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -5,7 +5,7 @@
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
-[There are over 550 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.
@@ -19,21 +19,35 @@ You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the
| `clippy::complexity` | code that does something simple but in a complex way | **warn** |
| `clippy::perf` | code that can be written to run faster | **warn** |
| `clippy::pedantic` | lints which are rather strict or have occasional false positives | allow |
+| `clippy::restriction` | lints which prevent the use of language and library features[^restrict] | allow |
| `clippy::nursery` | new lints that are still under development | allow |
| `clippy::cargo` | lints for the cargo manifest | allow |
More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas!
-The [lint list](https://rust-lang.github.io/rust-clippy/master/index.html) also contains "restriction lints", which are
-for things which are usually not considered "bad", but may be useful to turn on in specific cases. These should be used
-very selectively, if at all.
+The `restriction` category should, *emphatically*, not be enabled as a whole. The contained
+lints may lint against perfectly reasonable code, may not have an alternative suggestion,
+and may contradict any other lints (including other categories). Lints should be considered
+on a case-by-case basis before enabling.
+
+[^restrict]: Some use cases for `restriction` lints include:
+ - Strict coding styles (e.g. [`clippy::else_if_without_else`]).
+ - Additional restrictions on CI (e.g. [`clippy::todo`]).
+ - Preventing panicking in certain functions (e.g. [`clippy::unwrap_used`]).
+ - Running a lint only on a subset of code (e.g. `#[forbid(clippy::float_arithmetic)]` on a module).
+
+[`clippy::else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
+[`clippy::todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
+[`clippy::unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
+
+---
Table of contents:
-* [Usage instructions](#usage)
-* [Configuration](#configuration)
-* [Contributing](#contributing)
-* [License](#license)
+* [Usage instructions](#usage)
+* [Configuration](#configuration)
+* [Contributing](#contributing)
+* [License](#license)
## Usage
@@ -64,6 +78,7 @@ Once you have rustup and the latest stable release (at least Rust 1.29) installe
```terminal
rustup component add clippy
```
+
If it says that it can't find the `clippy` component, please run `rustup self update`.
#### Step 3: Run Clippy
@@ -143,16 +158,16 @@ line. (You can swap `clippy::all` with the specific lint category you are target
You can add options to your code to `allow`/`warn`/`deny` Clippy lints:
-* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`).
+* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`).
Note that `rustc` has additional [lint groups](https://doc.rust-lang.org/rustc/lints/groups.html).
-* all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`,
+* all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`,
`#![deny(clippy::pedantic)]`). Note that `clippy::pedantic` contains some very aggressive
lints prone to false positives.
-* only some lints (`#![deny(clippy::single_match, clippy::box_vec)]`, etc.)
+* only some lints (`#![deny(clippy::single_match, clippy::box_vec)]`, etc.)
-* `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc.
+* `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc.
Note: `allow` means to suppress the lint for your code. With `warn` the lint
will only emit a warning, while with `deny` the lint will emit an error, when
@@ -176,12 +191,14 @@ cargo clippy -- -W clippy::lint_name
This also works with lint groups. For example, you
can run Clippy with warnings for all lints enabled:
+
```terminal
cargo clippy -- -W clippy::pedantic
```
If you care only about a single lint, you can allow all others and then explicitly warn on
the lint(s) you are interested in:
+
```terminal
cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::...
```
@@ -194,11 +211,21 @@ value` mapping e.g.
```toml
avoid-breaking-exported-api = false
disallowed-names = ["toto", "tata", "titi"]
-cognitive-complexity-threshold = 30
```
-See the [list of configurable lints](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration),
-the lint descriptions contain the names and meanings of these configuration variables.
+The [table of configurations](https://doc.rust-lang.org/nightly/clippy/lint_configuration.html)
+contains all config values, their default, and a list of lints they affect.
+Each [configurable lint](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration)
+, also contains information about these values.
+
+For configurations that are a list type with default values such as
+[disallowed-names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names),
+you can use the unique value `".."` to extend the default values instead of replacing them.
+
+```toml
+# default of disallowed-names is ["foo", "baz", "quux"]
+disallowed-names = ["bar", ".."] # -> ["bar", "foo", "baz", "quux"]
+```
> **Note**
>
diff --git a/src/tools/clippy/book/src/README.md b/src/tools/clippy/book/src/README.md
index 23867df8e..df4a1f270 100644
--- a/src/tools/clippy/book/src/README.md
+++ b/src/tools/clippy/book/src/README.md
@@ -6,7 +6,7 @@
A collection of lints to catch common mistakes and improve your
[Rust](https://github.com/rust-lang/rust) code.
-[There are over 550 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
Lints are divided into categories, each with a default [lint
level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how
diff --git a/src/tools/clippy/book/src/SUMMARY.md b/src/tools/clippy/book/src/SUMMARY.md
index 1f0b8db28..0649f7a63 100644
--- a/src/tools/clippy/book/src/SUMMARY.md
+++ b/src/tools/clippy/book/src/SUMMARY.md
@@ -5,6 +5,7 @@
- [Installation](installation.md)
- [Usage](usage.md)
- [Configuration](configuration.md)
+ - [Lint Configuration](lint_configuration.md)
- [Clippy's Lints](lints.md)
- [Continuous Integration](continuous_integration/README.md)
- [GitHub Actions](continuous_integration/github_actions.md)
diff --git a/src/tools/clippy/book/src/configuration.md b/src/tools/clippy/book/src/configuration.md
index 430ff8b73..87f4a697a 100644
--- a/src/tools/clippy/book/src/configuration.md
+++ b/src/tools/clippy/book/src/configuration.md
@@ -8,11 +8,21 @@ basic `variable = value` mapping eg.
```toml
avoid-breaking-exported-api = false
disallowed-names = ["toto", "tata", "titi"]
-cognitive-complexity-threshold = 30
```
-See the [list of configurable lints](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration),
-the lint descriptions contain the names and meanings of these configuration variables.
+The [table of configurations](./lint_configuration.md)
+contains all config values, their default, and a list of lints they affect.
+Each [configurable lint](https://rust-lang.github.io/rust-clippy/master/index.html#Configuration)
+, also contains information about these values.
+
+For configurations that are a list type with default values such as
+[disallowed-names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names),
+you can use the unique value `".."` to extend the default values instead of replacing them.
+
+```toml
+# default of disallowed-names is ["foo", "baz", "quux"]
+disallowed-names = ["bar", ".."] # -> ["bar", "foo", "baz", "quux"]
+```
To deactivate the "for further information visit *lint-link*" message you can define the `CLIPPY_DISABLE_DOCS_LINKS`
environment variable.
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index 8b4eee8c9..f57dc627d 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -146,7 +146,8 @@ For cargo lints, the process of testing differs in that we are interested in the
manifest.
If our new lint is named e.g. `foo_categories`, after running `cargo dev
-new_lint` we will find by default two new crates, each with its manifest file:
+new_lint --name=foo_categories --type=cargo --category=cargo` we will find by
+default two new crates, each with its manifest file:
* `tests/ui-cargo/foo_categories/fail/Cargo.toml`: this file should cause the
new lint to raise an error.
@@ -699,6 +700,10 @@ for some users. Adding a configuration is done in the following steps:
`clippy.toml` file with the configuration value and a rust file that
should be linted by Clippy. The test can otherwise be written as usual.
+5. Update [Lint Configuration](../lint_configuration.md)
+
+ Run `cargo collect-metadata` to generate documentation changes for the book.
+
[`clippy_lints::utils::conf`]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/conf.rs
[`clippy_lints` lib file]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs
[`tests/ui`]: https://github.com/rust-lang/rust-clippy/blob/master/tests/ui
diff --git a/src/tools/clippy/book/src/development/infrastructure/backport.md b/src/tools/clippy/book/src/development/infrastructure/backport.md
index 15f3d1f08..6920c4e46 100644
--- a/src/tools/clippy/book/src/development/infrastructure/backport.md
+++ b/src/tools/clippy/book/src/development/infrastructure/backport.md
@@ -28,6 +28,7 @@ repository. You can do this with:
```bash
# Assuming the current directory corresponds to the Rust repository
$ git checkout beta
+# Make sure to change `your-github-name` to your github name in the following command
$ git subtree pull -p src/tools/clippy https://github.com/<your-github-name>/rust-clippy backport
$ ./x.py test src/tools/clippy
```
diff --git a/src/tools/clippy/book/src/development/infrastructure/book.md b/src/tools/clippy/book/src/development/infrastructure/book.md
index a48742191..dbd624ecd 100644
--- a/src/tools/clippy/book/src/development/infrastructure/book.md
+++ b/src/tools/clippy/book/src/development/infrastructure/book.md
@@ -3,15 +3,15 @@
This document explains how to make additions and changes to the Clippy book, the
guide to Clippy that you're reading right now. The Clippy book is formatted with
[Markdown](https://www.markdownguide.org) and generated by
-[mdbook](https://github.com/rust-lang/mdBook).
+[mdBook](https://github.com/rust-lang/mdBook).
-- [Get mdbook](#get-mdbook)
+- [Get mdBook](#get-mdbook)
- [Make changes](#make-changes)
-## Get mdbook
+## Get mdBook
While not strictly necessary since the book source is simply Markdown text
-files, having mdbook locally will allow you to build, test and serve the book
+files, having mdBook locally will allow you to build, test and serve the book
locally to view changes before you commit them to the repository. You likely
already have `cargo` installed, so the easiest option is to simply:
@@ -19,7 +19,7 @@ already have `cargo` installed, so the easiest option is to simply:
cargo install mdbook
```
-See the mdbook [installation](https://github.com/rust-lang/mdBook#installation)
+See the mdBook [installation](https://github.com/rust-lang/mdBook#installation)
instructions for other options.
## Make changes
@@ -27,7 +27,7 @@ instructions for other options.
The book's
[src](https://github.com/rust-lang/rust-clippy/tree/master/book/src)
directory contains all of the markdown files used to generate the book. If you
-want to see your changes in real time, you can use the mdbook `serve` command to
+want to see your changes in real time, you can use the mdBook `serve` command to
run a web server locally that will automatically update changes as they are
made. From the top level of your `rust-clippy` directory:
@@ -38,5 +38,5 @@ mdbook serve book --open
Then navigate to `http://localhost:3000` to see the generated book. While the
server is running, changes you make will automatically be updated.
-For more information, see the mdbook
+For more information, see the mdBook
[guide](https://rust-lang.github.io/mdBook/).
diff --git a/src/tools/clippy/book/src/development/infrastructure/changelog_update.md b/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
index 80a47affe..d1ac7237b 100644
--- a/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
+++ b/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
@@ -95,11 +95,23 @@ As section headers, we use:
Please also be sure to update the Beta/Unreleased sections at the top with the
relevant commit ranges.
-If you have the time, it would be appreciated if you double-check, that the
-`#[clippy::version]` attributes for the added lints contains the correct version.
+#### 3.1 Include `beta-accepted` PRs
+
+Look for the [`beta-accepted`] label and make sure to also include the PRs with
+that label in the changelog. If you can, remove the `beta-accepted` labels
+**after** the changelog PR was merged.
+
+> _Note:_ Some of those PRs might even got backported to the previous `beta`.
+> Those have to be included in the changelog of the _previous_ release.
+
+### 4. Update `clippy::version` attributes
+
+Next, make sure to check that the `#[clippy::version]` attributes for the added
+lints contain the correct version.
[changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md
[forge]: https://forge.rust-lang.org/
[rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy
[rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools/clippy
[rust_stable_tools]: https://github.com/rust-lang/rust/releases
+[`beta-accepted`]: https://github.com/rust-lang/rust-clippy/issues?q=label%3Abeta-accepted+
diff --git a/src/tools/clippy/book/src/development/infrastructure/sync.md b/src/tools/clippy/book/src/development/infrastructure/sync.md
index 5a0f7409a..02cfc11b5 100644
--- a/src/tools/clippy/book/src/development/infrastructure/sync.md
+++ b/src/tools/clippy/book/src/development/infrastructure/sync.md
@@ -79,8 +79,7 @@ to be run inside the `rust` directory):
`rustup check`.
3. Sync the changes to the rust-copy of Clippy to your Clippy fork:
```bash
- # Make sure to change `your-github-name` to your github name in the following command. Also be
- # sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand
+ # Be sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand
# because changes cannot be fast forwarded and you have to run this command again.
git subtree push -P src/tools/clippy clippy-local sync-from-rust
```
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
new file mode 100644
index 000000000..995dd2f04
--- /dev/null
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -0,0 +1,553 @@
+<!--
+This file is generated by `cargo collect-metadata`.
+Please use that command to update the file and do not edit it by hand.
+-->
+
+## Lint Configuration Options
+| <div style="width:290px">Option</div> | Default Value |
+|--|--|
+| [arithmetic-side-effects-allowed](#arithmetic-side-effects-allowed) | `{}` |
+| [arithmetic-side-effects-allowed-binary](#arithmetic-side-effects-allowed-binary) | `[]` |
+| [arithmetic-side-effects-allowed-unary](#arithmetic-side-effects-allowed-unary) | `{}` |
+| [avoid-breaking-exported-api](#avoid-breaking-exported-api) | `true` |
+| [msrv](#msrv) | `None` |
+| [cognitive-complexity-threshold](#cognitive-complexity-threshold) | `25` |
+| [disallowed-names](#disallowed-names) | `["foo", "baz", "quux"]` |
+| [doc-valid-idents](#doc-valid-idents) | `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` |
+| [too-many-arguments-threshold](#too-many-arguments-threshold) | `7` |
+| [type-complexity-threshold](#type-complexity-threshold) | `250` |
+| [single-char-binding-names-threshold](#single-char-binding-names-threshold) | `4` |
+| [too-large-for-stack](#too-large-for-stack) | `200` |
+| [enum-variant-name-threshold](#enum-variant-name-threshold) | `3` |
+| [enum-variant-size-threshold](#enum-variant-size-threshold) | `200` |
+| [verbose-bit-mask-threshold](#verbose-bit-mask-threshold) | `1` |
+| [literal-representation-threshold](#literal-representation-threshold) | `16384` |
+| [trivial-copy-size-limit](#trivial-copy-size-limit) | `None` |
+| [pass-by-value-size-limit](#pass-by-value-size-limit) | `256` |
+| [too-many-lines-threshold](#too-many-lines-threshold) | `100` |
+| [array-size-threshold](#array-size-threshold) | `512000` |
+| [vec-box-size-threshold](#vec-box-size-threshold) | `4096` |
+| [max-trait-bounds](#max-trait-bounds) | `3` |
+| [max-struct-bools](#max-struct-bools) | `3` |
+| [max-fn-params-bools](#max-fn-params-bools) | `3` |
+| [warn-on-all-wildcard-imports](#warn-on-all-wildcard-imports) | `false` |
+| [disallowed-macros](#disallowed-macros) | `[]` |
+| [disallowed-methods](#disallowed-methods) | `[]` |
+| [disallowed-types](#disallowed-types) | `[]` |
+| [unreadable-literal-lint-fractions](#unreadable-literal-lint-fractions) | `true` |
+| [upper-case-acronyms-aggressive](#upper-case-acronyms-aggressive) | `false` |
+| [matches-for-let-else](#matches-for-let-else) | `WellKnownTypes` |
+| [cargo-ignore-publish](#cargo-ignore-publish) | `false` |
+| [standard-macro-braces](#standard-macro-braces) | `[]` |
+| [enforced-import-renames](#enforced-import-renames) | `[]` |
+| [allowed-scripts](#allowed-scripts) | `["Latin"]` |
+| [enable-raw-pointer-heuristic-for-send](#enable-raw-pointer-heuristic-for-send) | `true` |
+| [max-suggested-slice-pattern-length](#max-suggested-slice-pattern-length) | `3` |
+| [await-holding-invalid-types](#await-holding-invalid-types) | `[]` |
+| [max-include-file-size](#max-include-file-size) | `1000000` |
+| [allow-expect-in-tests](#allow-expect-in-tests) | `false` |
+| [allow-unwrap-in-tests](#allow-unwrap-in-tests) | `false` |
+| [allow-dbg-in-tests](#allow-dbg-in-tests) | `false` |
+| [allow-print-in-tests](#allow-print-in-tests) | `false` |
+| [large-error-threshold](#large-error-threshold) | `128` |
+| [ignore-interior-mutability](#ignore-interior-mutability) | `["bytes::Bytes"]` |
+| [allow-mixed-uninlined-format-args](#allow-mixed-uninlined-format-args) | `true` |
+| [suppress-restriction-lint-in-const](#suppress-restriction-lint-in-const) | `false` |
+| [missing-docs-in-crate-items](#missing-docs-in-crate-items) | `false` |
+
+### arithmetic-side-effects-allowed
+Suppress checking of the passed type names in all types of operations.
+
+If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead.
+
+#### Example
+
+```toml
+arithmetic-side-effects-allowed = ["SomeType", "AnotherType"]
+```
+
+#### Noteworthy
+
+A type, say `SomeType`, listed in this configuration has the same behavior of
+`["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
+
+**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
+
+* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects)
+
+
+### arithmetic-side-effects-allowed-binary
+Suppress checking of the passed type pair names in binary operations like addition or
+multiplication.
+
+Supports the "*" wildcard to indicate that a certain type won't trigger the lint regardless
+of the involved counterpart. For example, `["SomeType", "*"]` or `["*", "AnotherType"]`.
+
+Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the same as
+`["AnotherType", "SomeType"]`.
+
+#### Example
+
+```toml
+arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]]
+```
+
+**Default Value:** `[]` (`Vec<[String; 2]>`)
+
+* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects)
+
+
+### arithmetic-side-effects-allowed-unary
+Suppress checking of the passed type names in unary operations like "negation" (`-`).
+
+#### Example
+
+```toml
+arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
+```
+
+**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
+
+* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects)
+
+
+### avoid-breaking-exported-api
+Suppress lints whenever the suggested change would cause breakage for other crates.
+
+**Default Value:** `true` (`bool`)
+
+* [enum_variant_names](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names)
+* [large_types_passed_by_value](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value)
+* [trivially_copy_pass_by_ref](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref)
+* [unnecessary_wraps](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps)
+* [unused_self](https://rust-lang.github.io/rust-clippy/master/index.html#unused_self)
+* [upper_case_acronyms](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms)
+* [wrong_self_convention](https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention)
+* [box_collection](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection)
+* [redundant_allocation](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation)
+* [rc_buffer](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer)
+* [vec_box](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box)
+* [option_option](https://rust-lang.github.io/rust-clippy/master/index.html#option_option)
+* [linkedlist](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist)
+* [rc_mutex](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex)
+
+
+### msrv
+The minimum rust version that the project supports
+
+**Default Value:** `None` (`Option<String>`)
+
+* [manual_split_once](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once)
+* [manual_str_repeat](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat)
+* [cloned_instead_of_copied](https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied)
+* [redundant_field_names](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names)
+* [redundant_static_lifetimes](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes)
+* [filter_map_next](https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next)
+* [checked_conversions](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions)
+* [manual_range_contains](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains)
+* [use_self](https://rust-lang.github.io/rust-clippy/master/index.html#use_self)
+* [mem_replace_with_default](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default)
+* [manual_non_exhaustive](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive)
+* [option_as_ref_deref](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref)
+* [map_unwrap_or](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or)
+* [match_like_matches_macro](https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro)
+* [manual_strip](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip)
+* [missing_const_for_fn](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn)
+* [unnested_or_patterns](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns)
+* [from_over_into](https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into)
+* [ptr_as_ptr](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr)
+* [if_then_some_else_none](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none)
+* [approx_constant](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant)
+* [deprecated_cfg_attr](https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr)
+* [index_refutable_slice](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice)
+* [map_clone](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone)
+* [borrow_as_ptr](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr)
+* [manual_bits](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits)
+* [err_expect](https://rust-lang.github.io/rust-clippy/master/index.html#err_expect)
+* [cast_abs_to_unsigned](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned)
+* [uninlined_format_args](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args)
+* [manual_clamp](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp)
+* [manual_let_else](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else)
+* [unchecked_duration_subtraction](https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction)
+* [collapsible_str_replace](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace)
+* [seek_from_current](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current)
+* [seek_rewind](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind)
+* [unnecessary_lazy_evaluations](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations)
+* [transmute_ptr_to_ref](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref)
+* [almost_complete_range](https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range)
+* [needless_borrow](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow)
+* [derivable_impls](https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls)
+* [manual_is_ascii_check](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check)
+* [manual_rem_euclid](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid)
+* [manual_retain](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain)
+
+
+### cognitive-complexity-threshold
+The maximum cognitive complexity a function can have
+
+**Default Value:** `25` (`u64`)
+
+* [cognitive_complexity](https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity)
+
+
+### disallowed-names
+The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
+`".."` can be used as part of the list to indicate, that the configured values should be appended to the
+default configuration of Clippy. By default any configuration will replace the default value.
+
+**Default Value:** `["foo", "baz", "quux"]` (`Vec<String>`)
+
+* [disallowed_names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names)
+
+
+### doc-valid-idents
+The list of words this lint should not consider as identifiers needing ticks. The value
+`".."` can be used as part of the list to indicate, that the configured values should be appended to the
+default configuration of Clippy. By default any configuraction will replace the default value. For example:
+* `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
+* `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
+
+Default list:
+
+**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` (`Vec<String>`)
+
+* [doc_markdown](https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown)
+
+
+### too-many-arguments-threshold
+The maximum number of argument a function or method can have
+
+**Default Value:** `7` (`u64`)
+
+* [too_many_arguments](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments)
+
+
+### type-complexity-threshold
+The maximum complexity a type can have
+
+**Default Value:** `250` (`u64`)
+
+* [type_complexity](https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity)
+
+
+### single-char-binding-names-threshold
+The maximum number of single char bindings a scope may have
+
+**Default Value:** `4` (`u64`)
+
+* [many_single_char_names](https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names)
+
+
+### too-large-for-stack
+The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
+
+**Default Value:** `200` (`u64`)
+
+* [boxed_local](https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local)
+* [useless_vec](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec)
+
+
+### enum-variant-name-threshold
+The minimum number of enum variants for the lints about variant names to trigger
+
+**Default Value:** `3` (`u64`)
+
+* [enum_variant_names](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names)
+
+
+### enum-variant-size-threshold
+The maximum size of an enum's variant to avoid box suggestion
+
+**Default Value:** `200` (`u64`)
+
+* [large_enum_variant](https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant)
+
+
+### verbose-bit-mask-threshold
+The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
+
+**Default Value:** `1` (`u64`)
+
+* [verbose_bit_mask](https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask)
+
+
+### literal-representation-threshold
+The lower bound for linting decimal literals
+
+**Default Value:** `16384` (`u64`)
+
+* [decimal_literal_representation](https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation)
+
+
+### trivial-copy-size-limit
+The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
+
+**Default Value:** `None` (`Option<u64>`)
+
+* [trivially_copy_pass_by_ref](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref)
+
+
+### pass-by-value-size-limit
+The minimum size (in bytes) to consider a type for passing by reference instead of by value.
+
+**Default Value:** `256` (`u64`)
+
+* [large_types_passed_by_value](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value)
+
+
+### too-many-lines-threshold
+The maximum number of lines a function or method can have
+
+**Default Value:** `100` (`u64`)
+
+* [too_many_lines](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines)
+
+
+### array-size-threshold
+The maximum allowed size for arrays on the stack
+
+**Default Value:** `512000` (`u64`)
+
+* [large_stack_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays)
+* [large_const_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays)
+
+
+### vec-box-size-threshold
+The size of the boxed type in bytes, where boxing in a `Vec` is allowed
+
+**Default Value:** `4096` (`u64`)
+
+* [vec_box](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box)
+
+
+### max-trait-bounds
+The maximum number of bounds a trait can have to be linted
+
+**Default Value:** `3` (`u64`)
+
+* [type_repetition_in_bounds](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds)
+
+
+### max-struct-bools
+The maximum number of bool fields a struct can have
+
+**Default Value:** `3` (`u64`)
+
+* [struct_excessive_bools](https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools)
+
+
+### max-fn-params-bools
+The maximum number of bool parameters a function can have
+
+**Default Value:** `3` (`u64`)
+
+* [fn_params_excessive_bools](https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools)
+
+
+### warn-on-all-wildcard-imports
+Whether to allow certain wildcard imports (prelude, super in tests).
+
+**Default Value:** `false` (`bool`)
+
+* [wildcard_imports](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports)
+
+
+### disallowed-macros
+The list of disallowed macros, written as fully qualified paths.
+
+**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
+
+* [disallowed_macros](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros)
+
+
+### disallowed-methods
+The list of disallowed methods, written as fully qualified paths.
+
+**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
+
+* [disallowed_methods](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods)
+
+
+### disallowed-types
+The list of disallowed types, written as fully qualified paths.
+
+**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
+
+* [disallowed_types](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types)
+
+
+### unreadable-literal-lint-fractions
+Should the fraction of a decimal be linted to include separators.
+
+**Default Value:** `true` (`bool`)
+
+* [unreadable_literal](https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal)
+
+
+### upper-case-acronyms-aggressive
+Enables verbose mode. Triggers if there is more than one uppercase char next to each other
+
+**Default Value:** `false` (`bool`)
+
+* [upper_case_acronyms](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms)
+
+
+### matches-for-let-else
+Whether the matches should be considered by the lint, and whether there should
+be filtering for common types.
+
+**Default Value:** `WellKnownTypes` (`crate::manual_let_else::MatchLintBehaviour`)
+
+* [manual_let_else](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else)
+
+
+### cargo-ignore-publish
+For internal testing only, ignores the current `publish` settings in the Cargo manifest.
+
+**Default Value:** `false` (`bool`)
+
+* [_cargo_common_metadata](https://rust-lang.github.io/rust-clippy/master/index.html#_cargo_common_metadata)
+
+
+### standard-macro-braces
+Enforce the named macros always use the braces specified.
+
+A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
+is could be used with a full path two `MacroMatcher`s have to be added one with the full path
+`crate_name::macro_name` and one with just the macro name.
+
+**Default Value:** `[]` (`Vec<crate::nonstandard_macro_braces::MacroMatcher>`)
+
+* [nonstandard_macro_braces](https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces)
+
+
+### enforced-import-renames
+The list of imports to always rename, a fully qualified path followed by the rename.
+
+**Default Value:** `[]` (`Vec<crate::utils::conf::Rename>`)
+
+* [missing_enforced_import_renames](https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames)
+
+
+### allowed-scripts
+The list of unicode scripts allowed to be used in the scope.
+
+**Default Value:** `["Latin"]` (`Vec<String>`)
+
+* [disallowed_script_idents](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents)
+
+
+### enable-raw-pointer-heuristic-for-send
+Whether to apply the raw pointer heuristic to determine if a type is `Send`.
+
+**Default Value:** `true` (`bool`)
+
+* [non_send_fields_in_send_ty](https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty)
+
+
+### max-suggested-slice-pattern-length
+When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in
+the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed.
+For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
+
+**Default Value:** `3` (`u64`)
+
+* [index_refutable_slice](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice)
+
+
+### await-holding-invalid-types
+
+
+**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
+
+* [await_holding_invalid_type](https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_invalid_type)
+
+
+### max-include-file-size
+The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
+
+**Default Value:** `1000000` (`u64`)
+
+* [large_include_file](https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file)
+
+
+### allow-expect-in-tests
+Whether `expect` should be allowed in test functions or `#[cfg(test)]`
+
+**Default Value:** `false` (`bool`)
+
+* [expect_used](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used)
+
+
+### allow-unwrap-in-tests
+Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
+
+**Default Value:** `false` (`bool`)
+
+* [unwrap_used](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used)
+
+
+### allow-dbg-in-tests
+Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
+
+**Default Value:** `false` (`bool`)
+
+* [dbg_macro](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro)
+
+
+### allow-print-in-tests
+Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
+
+**Default Value:** `false` (`bool`)
+
+* [print_stdout](https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout)
+* [print_stderr](https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr)
+
+
+### large-error-threshold
+The maximum size of the `Err`-variant in a `Result` returned from a function
+
+**Default Value:** `128` (`u64`)
+
+* [result_large_err](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err)
+
+
+### ignore-interior-mutability
+A list of paths to types that should be treated like `Arc`, i.e. ignored but
+for the generic parameters for determining interior mutability
+
+**Default Value:** `["bytes::Bytes"]` (`Vec<String>`)
+
+* [mutable_key_type](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type)
+
+
+### allow-mixed-uninlined-format-args
+Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
+
+**Default Value:** `true` (`bool`)
+
+* [uninlined_format_args](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args)
+
+
+### suppress-restriction-lint-in-const
+Whether to suppress a restriction lint in constant code. In same
+cases the restructured operation might not be unavoidable, as the
+suggested counterparts are unavailable in constant code. This
+configuration will cause restriction lints to trigger even
+if no suggestion can be made.
+
+**Default Value:** `false` (`bool`)
+
+* [indexing_slicing](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing)
+
+
+### missing-docs-in-crate-items
+Whether to **only** check for missing documentation in items visible within the current
+crate. For example, `pub(crate)` items.
+
+**Default Value:** `false` (`bool`)
+
+* [missing_docs_in_private_items](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items)
+
+
+
diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml
index 510c7e852..c3f8a782d 100644
--- a/src/tools/clippy/clippy_dev/Cargo.toml
+++ b/src/tools/clippy/clippy_dev/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
[dependencies]
aho-corasick = "0.7"
-clap = "3.2"
+clap = "4.1.4"
indoc = "1.0"
itertools = "0.10.1"
opener = "0.5"
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index d3e036692..e2457e5a8 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -2,7 +2,7 @@
// warn on lints, that are included in `rust-lang/rust`s bootstrap
#![warn(rust_2018_idioms, unused_lifetimes)]
-use clap::{Arg, ArgAction, ArgMatches, Command, PossibleValue};
+use clap::{Arg, ArgAction, ArgMatches, Command};
use clippy_dev::{bless, dogfood, fmt, lint, new_lint, serve, setup, update_lints};
use indoc::indoc;
@@ -11,22 +11,22 @@ fn main() {
match matches.subcommand() {
Some(("bless", matches)) => {
- bless::bless(matches.contains_id("ignore-timestamp"));
+ bless::bless(matches.get_flag("ignore-timestamp"));
},
Some(("dogfood", matches)) => {
dogfood::dogfood(
- matches.contains_id("fix"),
- matches.contains_id("allow-dirty"),
- matches.contains_id("allow-staged"),
+ matches.get_flag("fix"),
+ matches.get_flag("allow-dirty"),
+ matches.get_flag("allow-staged"),
);
},
Some(("fmt", matches)) => {
- fmt::run(matches.contains_id("check"), matches.contains_id("verbose"));
+ fmt::run(matches.get_flag("check"), matches.get_flag("verbose"));
},
Some(("update_lints", matches)) => {
- if matches.contains_id("print-only") {
+ if matches.get_flag("print-only") {
update_lints::print_lints();
- } else if matches.contains_id("check") {
+ } else if matches.get_flag("check") {
update_lints::update(update_lints::UpdateMode::Check);
} else {
update_lints::update(update_lints::UpdateMode::Change);
@@ -38,7 +38,7 @@ fn main() {
matches.get_one::<String>("name"),
matches.get_one::<String>("category").map(String::as_str),
matches.get_one::<String>("type").map(String::as_str),
- matches.contains_id("msrv"),
+ matches.get_flag("msrv"),
) {
Ok(_) => update_lints::update(update_lints::UpdateMode::Change),
Err(e) => eprintln!("Unable to create lint: {e}"),
@@ -46,7 +46,7 @@ fn main() {
},
Some(("setup", sub_command)) => match sub_command.subcommand() {
Some(("intellij", matches)) => {
- if matches.contains_id("remove") {
+ if matches.get_flag("remove") {
setup::intellij::remove_rustc_src();
} else {
setup::intellij::setup_rustc_src(
@@ -57,17 +57,17 @@ fn main() {
}
},
Some(("git-hook", matches)) => {
- if matches.contains_id("remove") {
+ if matches.get_flag("remove") {
setup::git_hook::remove_hook();
} else {
- setup::git_hook::install_hook(matches.contains_id("force-override"));
+ setup::git_hook::install_hook(matches.get_flag("force-override"));
}
},
Some(("vscode-tasks", matches)) => {
- if matches.contains_id("remove") {
+ if matches.get_flag("remove") {
setup::vscode::remove_tasks();
} else {
- setup::vscode::install_tasks(matches.contains_id("force-override"));
+ setup::vscode::install_tasks(matches.get_flag("force-override"));
}
},
_ => {},
@@ -91,7 +91,7 @@ fn main() {
Some(("rename_lint", matches)) => {
let old_name = matches.get_one::<String>("old_name").unwrap();
let new_name = matches.get_one::<String>("new_name").unwrap_or(old_name);
- let uplift = matches.contains_id("uplift");
+ let uplift = matches.get_flag("uplift");
update_lints::rename(old_name, new_name, uplift);
},
Some(("deprecate", matches)) => {
@@ -110,24 +110,37 @@ fn get_clap_config() -> ArgMatches {
Command::new("bless").about("bless the test output changes").arg(
Arg::new("ignore-timestamp")
.long("ignore-timestamp")
+ .action(ArgAction::SetTrue)
.help("Include files updated before clippy was built"),
),
Command::new("dogfood").about("Runs the dogfood test").args([
- Arg::new("fix").long("fix").help("Apply the suggestions when possible"),
+ Arg::new("fix")
+ .long("fix")
+ .action(ArgAction::SetTrue)
+ .help("Apply the suggestions when possible"),
Arg::new("allow-dirty")
.long("allow-dirty")
+ .action(ArgAction::SetTrue)
.help("Fix code even if the working directory has changes")
.requires("fix"),
Arg::new("allow-staged")
.long("allow-staged")
+ .action(ArgAction::SetTrue)
.help("Fix code even if the working directory has staged changes")
.requires("fix"),
]),
Command::new("fmt")
.about("Run rustfmt on all projects and tests")
.args([
- Arg::new("check").long("check").help("Use the rustfmt --check option"),
- Arg::new("verbose").short('v').long("verbose").help("Echo commands run"),
+ Arg::new("check")
+ .long("check")
+ .action(ArgAction::SetTrue)
+ .help("Use the rustfmt --check option"),
+ Arg::new("verbose")
+ .short('v')
+ .long("verbose")
+ .action(ArgAction::SetTrue)
+ .help("Echo commands run"),
]),
Command::new("update_lints")
.about("Updates lint registration and information from the source code")
@@ -140,13 +153,17 @@ fn get_clap_config() -> ArgMatches {
* all lints are registered in the lint store",
)
.args([
- Arg::new("print-only").long("print-only").help(
- "Print a table of lints to STDOUT. \
- This does not include deprecated and internal lints. \
- (Does not modify any files)",
- ),
+ Arg::new("print-only")
+ .long("print-only")
+ .action(ArgAction::SetTrue)
+ .help(
+ "Print a table of lints to STDOUT. \
+ This does not include deprecated and internal lints. \
+ (Does not modify any files)",
+ ),
Arg::new("check")
.long("check")
+ .action(ArgAction::SetTrue)
.help("Checks that `cargo dev update_lints` has been run. Used on CI."),
]),
Command::new("new_lint")
@@ -156,15 +173,13 @@ fn get_clap_config() -> ArgMatches {
.short('p')
.long("pass")
.help("Specify whether the lint runs during the early or late pass")
- .takes_value(true)
- .value_parser([PossibleValue::new("early"), PossibleValue::new("late")])
+ .value_parser(["early", "late"])
.conflicts_with("type")
.required_unless_present("type"),
Arg::new("name")
.short('n')
.long("name")
.help("Name of the new lint in snake case, ex: fn_too_long")
- .takes_value(true)
.required(true),
Arg::new("category")
.short('c')
@@ -172,25 +187,23 @@ fn get_clap_config() -> ArgMatches {
.help("What category the lint belongs to")
.default_value("nursery")
.value_parser([
- PossibleValue::new("style"),
- PossibleValue::new("correctness"),
- PossibleValue::new("suspicious"),
- PossibleValue::new("complexity"),
- PossibleValue::new("perf"),
- PossibleValue::new("pedantic"),
- PossibleValue::new("restriction"),
- PossibleValue::new("cargo"),
- PossibleValue::new("nursery"),
- PossibleValue::new("internal"),
- PossibleValue::new("internal_warn"),
- ])
- .takes_value(true),
- Arg::new("type")
- .long("type")
- .help("What directory the lint belongs in")
- .takes_value(true)
- .required(false),
- Arg::new("msrv").long("msrv").help("Add MSRV config code to the lint"),
+ "style",
+ "correctness",
+ "suspicious",
+ "complexity",
+ "perf",
+ "pedantic",
+ "restriction",
+ "cargo",
+ "nursery",
+ "internal",
+ "internal_warn",
+ ]),
+ Arg::new("type").long("type").help("What directory the lint belongs in"),
+ Arg::new("msrv")
+ .long("msrv")
+ .action(ArgAction::SetTrue)
+ .help("Add MSRV config code to the lint"),
]),
Command::new("setup")
.about("Support for setting up your personal development environment")
@@ -201,13 +214,12 @@ fn get_clap_config() -> ArgMatches {
.args([
Arg::new("remove")
.long("remove")
- .help("Remove the dependencies added with 'cargo dev setup intellij'")
- .required(false),
+ .action(ArgAction::SetTrue)
+ .help("Remove the dependencies added with 'cargo dev setup intellij'"),
Arg::new("rustc-repo-path")
.long("repo-path")
.short('r')
.help("The path to a rustc repo that will be used for setting the dependencies")
- .takes_value(true)
.value_name("path")
.conflicts_with("remove")
.required(true),
@@ -217,26 +229,26 @@ fn get_clap_config() -> ArgMatches {
.args([
Arg::new("remove")
.long("remove")
- .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'")
- .required(false),
+ .action(ArgAction::SetTrue)
+ .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"),
Arg::new("force-override")
.long("force-override")
.short('f')
- .help("Forces the override of an existing git pre-commit hook")
- .required(false),
+ .action(ArgAction::SetTrue)
+ .help("Forces the override of an existing git pre-commit hook"),
]),
Command::new("vscode-tasks")
.about("Add several tasks to vscode for formatting, validation and testing")
.args([
Arg::new("remove")
.long("remove")
- .help("Remove the tasks added with 'cargo dev setup vscode-tasks'")
- .required(false),
+ .action(ArgAction::SetTrue)
+ .help("Remove the tasks added with 'cargo dev setup vscode-tasks'"),
Arg::new("force-override")
.long("force-override")
.short('f')
- .help("Forces the override of existing vscode tasks")
- .required(false),
+ .action(ArgAction::SetTrue)
+ .help("Forces the override of existing vscode tasks"),
]),
]),
Command::new("remove")
@@ -295,6 +307,7 @@ fn get_clap_config() -> ArgMatches {
.help("The new name of the lint"),
Arg::new("uplift")
.long("uplift")
+ .action(ArgAction::SetTrue)
.help("This lint will be uplifted into rustc"),
]),
Command::new("deprecate").about("Deprecates the given lint").args([
@@ -305,8 +318,6 @@ fn get_clap_config() -> ArgMatches {
Arg::new("reason")
.long("reason")
.short('r')
- .required(false)
- .takes_value(true)
.help("The reason for deprecation"),
]),
])
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index ec7f1dd0d..420214d92 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -1,5 +1,6 @@
use crate::clippy_project_root;
use indoc::{formatdoc, writedoc};
+use std::fmt;
use std::fmt::Write as _;
use std::fs::{self, OpenOptions};
use std::io::prelude::*;
@@ -256,7 +257,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
)
});
- let _ = write!(result, "{}", get_lint_declaration(&name_upper, category));
+ let _: fmt::Result = write!(result, "{}", get_lint_declaration(&name_upper, category));
result.push_str(&if enable_msrv {
formatdoc!(
@@ -353,7 +354,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
let mut lint_file_contents = String::new();
if enable_msrv {
- let _ = writedoc!(
+ let _: fmt::Result = writedoc!(
lint_file_contents,
r#"
use clippy_utils::msrvs::{{self, Msrv}};
@@ -373,7 +374,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
name_upper = name_upper,
);
} else {
- let _ = writedoc!(
+ let _: fmt::Result = writedoc!(
lint_file_contents,
r#"
use rustc_lint::{{{context_import}, LintContext}};
@@ -521,7 +522,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
.chain(std::iter::once(&*lint_name_upper))
.filter(|s| !s.is_empty())
{
- let _ = write!(new_arr_content, "\n {ident},");
+ let _: fmt::Result = write!(new_arr_content, "\n {ident},");
}
new_arr_content.push('\n');
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 837618c92..779e4d0e1 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -5,7 +5,7 @@ use itertools::Itertools;
use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
use std::collections::{HashMap, HashSet};
use std::ffi::OsStr;
-use std::fmt::Write;
+use std::fmt::{self, Write};
use std::fs::{self, OpenOptions};
use std::io::{self, Read, Seek, SeekFrom, Write as _};
use std::ops::Range;
@@ -691,7 +691,7 @@ fn gen_deprecated(lints: &[DeprecatedLint]) -> String {
let mut output = GENERATED_FILE_COMMENT.to_string();
output.push_str("{\n");
for lint in lints {
- let _ = write!(
+ let _: fmt::Result = write!(
output,
concat!(
" store.register_removed(\n",
@@ -726,7 +726,7 @@ fn gen_declared_lints<'a>(
if !is_public {
output.push_str(" #[cfg(feature = \"internal\")]\n");
}
- let _ = writeln!(output, " crate::{module_name}::{lint_name}_INFO,");
+ let _: fmt::Result = writeln!(output, " crate::{module_name}::{lint_name}_INFO,");
}
output.push_str("];\n");
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index a9f69b1ba..796f1ff16 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy_lints"
-version = "0.1.68"
+version = "0.1.69"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@@ -9,7 +9,7 @@ keywords = ["clippy", "lint", "plugin"]
edition = "2021"
[dependencies]
-cargo_metadata = "0.14"
+cargo_metadata = "0.15.3"
clippy_utils = { path = "../clippy_utils" }
declare_clippy_lint = { path = "../declare_clippy_lint" }
if_chain = "1.0"
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index 82d368bb8..1d9096ea6 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -1,10 +1,12 @@
+use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
-use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::{implements_trait, is_copy};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Lit};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::Ident;
@@ -33,19 +35,19 @@ declare_clippy_lint! {
declare_lint_pass!(BoolAssertComparison => [BOOL_ASSERT_COMPARISON]);
-fn is_bool_lit(e: &Expr<'_>) -> bool {
- matches!(
- e.kind,
- ExprKind::Lit(Lit {
- node: LitKind::Bool(_),
- ..
- })
- ) && !e.span.from_expansion()
+fn extract_bool_lit(e: &Expr<'_>) -> Option<bool> {
+ if let ExprKind::Lit(Lit {
+ node: LitKind::Bool(b), ..
+ }) = e.kind
+ && !e.span.from_expansion()
+ {
+ Some(b)
+ } else {
+ None
+ }
}
-fn is_impl_not_trait_with_bool_out(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
- let ty = cx.typeck_results().expr_ty(e);
-
+fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
cx.tcx
.lang_items()
.not_trait()
@@ -70,38 +72,70 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
let macro_name = cx.tcx.item_name(macro_call.def_id);
- if !matches!(
- macro_name.as_str(),
- "assert_eq" | "debug_assert_eq" | "assert_ne" | "debug_assert_ne"
- ) {
- return;
- }
+ let eq_macro = match macro_name.as_str() {
+ "assert_eq" | "debug_assert_eq" => true,
+ "assert_ne" | "debug_assert_ne" => false,
+ _ => return,
+ };
let Some ((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
- if !(is_bool_lit(a) ^ is_bool_lit(b)) {
+
+ let a_span = a.span.source_callsite();
+ let b_span = b.span.source_callsite();
+
+ let (lit_span, bool_value, non_lit_expr) = match (extract_bool_lit(a), extract_bool_lit(b)) {
+ // assert_eq!(true/false, b)
+ // ^^^^^^^^^^^^
+ (Some(bool_value), None) => (a_span.until(b_span), bool_value, b),
+ // assert_eq!(a, true/false)
+ // ^^^^^^^^^^^^
+ (None, Some(bool_value)) => (b_span.with_lo(a_span.hi()), bool_value, a),
// If there are two boolean arguments, we definitely don't understand
// what's going on, so better leave things as is...
//
// Or there is simply no boolean and then we can leave things as is!
- return;
- }
+ _ => return,
+ };
+
+ let non_lit_ty = cx.typeck_results().expr_ty(non_lit_expr);
- if !is_impl_not_trait_with_bool_out(cx, a) || !is_impl_not_trait_with_bool_out(cx, b) {
+ if !is_impl_not_trait_with_bool_out(cx, non_lit_ty) {
// At this point the expression which is not a boolean
// literal does not implement Not trait with a bool output,
// so we cannot suggest to rewrite our code
return;
}
+ if !is_copy(cx, non_lit_ty) {
+ // Only lint with types that are `Copy` because `assert!(x)` takes
+ // ownership of `x` whereas `assert_eq(x, true)` does not
+ return;
+ }
+
let macro_name = macro_name.as_str();
let non_eq_mac = &macro_name[..macro_name.len() - 3];
- span_lint_and_sugg(
+ span_lint_and_then(
cx,
BOOL_ASSERT_COMPARISON,
macro_call.span,
&format!("used `{macro_name}!` with a literal bool"),
- "replace it with",
- format!("{non_eq_mac}!(..)"),
- Applicability::MaybeIncorrect,
+ |diag| {
+ // assert_eq!(...)
+ // ^^^^^^^^^
+ let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!');
+
+ let mut suggestions = vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())];
+
+ if bool_value ^ eq_macro {
+ let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) else { return };
+ suggestions.push((non_lit_expr.span, (!sugg).to_string()));
+ }
+
+ diag.multipart_suggestion(
+ format!("replace it with `{non_eq_mac}!(..)`"),
+ suggestions,
+ Applicability::MachineApplicable,
+ );
+ },
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 939bdbcdc..e8106beec 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -6,9 +6,10 @@ use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
-use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, UnOp};
+use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::Span;
use rustc_span::sym;
@@ -82,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
_: &'tcx FnDecl<'_>,
body: &'tcx Body<'_>,
_: Span,
- _: HirId,
+ _: LocalDefId,
) {
NonminimalBoolVisitor { cx }.visit_body(body);
}
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 9d98a6bab..dfa949d1a 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -117,7 +117,8 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
) => {
if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) &&
let Some(sig) = expr_sig(cx, path) &&
- let Some(input) = sig.input(index)
+ let Some(input) = sig.input(index) &&
+ !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait()
{
input.no_bound_vars().is_some()
} else {
diff --git a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
index 9409f4844..1633ffd58 100644
--- a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
@@ -17,7 +17,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
&& let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind
&& method_name.ident.name == rustc_span::sym::as_ptr
&& let Some(as_ptr_did) = cx.typeck_results().type_dependent_def_id(cast_expr.peel_blocks().hir_id)
- && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did)
+ && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).subst_identity()
&& let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next()
&& let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind()
&& let Some(recv) = snippet_opt(cx, receiver.span)
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index a63764849..823970e35 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -1,11 +1,14 @@
use clippy_utils::consts::{constant, Constant};
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::expr_or_init;
+use clippy_utils::source::snippet;
use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
+use rustc_errors::{Applicability, SuggestionStyle};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, FloatTy, Ty};
+use rustc_span::Span;
use rustc_target::abi::IntegerType;
use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION};
@@ -74,7 +77,14 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
}
}
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ cast_expr: &Expr<'_>,
+ cast_from: Ty<'_>,
+ cast_to: Ty<'_>,
+ cast_to_span: Span,
+) {
let msg = match (cast_from.kind(), cast_to.is_integral()) {
(ty::Int(_) | ty::Uint(_), true) => {
let from_nbits = apply_reductions(
@@ -139,7 +149,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
);
return;
}
- format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",)
+ format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}")
},
(ty::Float(_), true) => {
@@ -153,5 +163,19 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
_ => return,
};
- span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg);
+ let name_of_cast_from = snippet(cx, cast_expr.span, "..");
+ let cast_to_snip = snippet(cx, cast_to_span, "..");
+ let suggestion = format!("{cast_to_snip}::try_from({name_of_cast_from})");
+
+ span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| {
+ diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...");
+ diag.span_suggestion_with_style(
+ expr.span,
+ "... or use `try_from` and handle the error accordingly",
+ suggestion,
+ Applicability::Unspecified,
+ // always show the suggestion in a separate line
+ SuggestionStyle::ShowAlways,
+ );
+ });
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index 97054a0d1..6c8ee296c 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -66,7 +66,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned")
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
&& let Some(def_id) = cx.tcx.impl_of_method(def_id)
- && cx.tcx.type_of(def_id).is_unsafe_ptr()
+ && cx.tcx.type_of(def_id).subst_identity().is_unsafe_ptr()
{
true
} else {
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index 161e3a698..362f70d12 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -80,7 +80,8 @@ declare_clippy_lint! {
/// ### What it does
/// Checks for casts between numerical types that may
/// truncate large values. This is expected behavior, so the cast is `Allow` by
- /// default.
+ /// default. It suggests user either explicitly ignore the lint,
+ /// or use `try_from()` and handle the truncation, default, or panic explicitly.
///
/// ### Why is this bad?
/// In some problem domains, it is good practice to avoid
@@ -93,6 +94,21 @@ declare_clippy_lint! {
/// x as u8
/// }
/// ```
+ /// Use instead:
+ /// ```
+ /// fn as_u8(x: u64) -> u8 {
+ /// if let Ok(x) = u8::try_from(x) {
+ /// x
+ /// } else {
+ /// todo!();
+ /// }
+ /// }
+ /// // Or
+ /// #[allow(clippy::cast_possible_truncation)]
+ /// fn as_u16(x: u64) -> u16 {
+ /// x as u16
+ /// }
+ /// ```
#[clippy::version = "pre 1.29.0"]
pub CAST_POSSIBLE_TRUNCATION,
pedantic,
@@ -712,7 +728,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
- cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
+ cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span);
if cast_from.is_numeric() {
cast_possible_wrap::check(cx, expr, cast_from, cast_to);
cast_precision_loss::check(cx, expr, cast_from, cast_to);
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 1c3a89a97..e8531157e 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -8,9 +8,10 @@ use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack};
use core::ops::ControlFlow;
use rustc_ast::ast::Attribute;
use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::Span;
use rustc_span::{sym, BytePos};
@@ -140,9 +141,8 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity {
decl: &'tcx FnDecl<'_>,
body: &'tcx Body<'_>,
span: Span,
- hir_id: HirId,
+ def_id: LocalDefId,
) {
- let def_id = cx.tcx.hir().local_def_id(hir_id);
if !cx.tcx.has_attr(def_id.to_def_id(), sym::test) {
let expr = if is_async_fn(kind) {
match get_async_fn_body(cx.tcx, body) {
diff --git a/src/tools/clippy/clippy_lints/src/copy_iterator.rs b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
index e38f77268..0fc115232 100644
--- a/src/tools/clippy/clippy_lints/src/copy_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
@@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for CopyIterator {
of_trait: Some(ref trait_ref),
..
}) = item.kind;
- let ty = cx.tcx.type_of(item.owner_id);
+ let ty = cx.tcx.type_of(item.owner_id).subst_identity();
if is_copy(cx, ty);
if let Some(trait_id) = trait_ref.trait_def_id();
if cx.tcx.is_diagnostic_item(sym::Iterator, trait_id);
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 91ca73633..cd5dd7a57 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -156,6 +156,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO,
crate::exit::EXIT_INFO,
crate::explicit_write::EXPLICIT_WRITE_INFO,
+ crate::extra_unused_type_parameters::EXTRA_UNUSED_TYPE_PARAMETERS_INFO,
crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO,
crate::float_literal::EXCESSIVE_PRECISION_INFO,
crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
@@ -178,6 +179,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
crate::functions::DOUBLE_MUST_USE_INFO,
+ crate::functions::IMPL_TRAIT_IN_PARAMS_INFO,
crate::functions::MISNAMED_GETTERS_INFO,
crate::functions::MUST_USE_CANDIDATE_INFO,
crate::functions::MUST_USE_UNIT_INFO,
@@ -223,6 +225,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::let_underscore::LET_UNDERSCORE_FUTURE_INFO,
crate::let_underscore::LET_UNDERSCORE_LOCK_INFO,
crate::let_underscore::LET_UNDERSCORE_MUST_USE_INFO,
+ crate::let_underscore::LET_UNDERSCORE_UNTYPED_INFO,
crate::lifetimes::EXTRA_UNUSED_LIFETIMES_INFO,
crate::lifetimes::NEEDLESS_LIFETIMES_INFO,
crate::literal_representation::DECIMAL_LITERAL_REPRESENTATION_INFO,
@@ -377,6 +380,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::methods::SKIP_WHILE_NEXT_INFO,
crate::methods::STABLE_SORT_PRIMITIVE_INFO,
crate::methods::STRING_EXTEND_CHARS_INFO,
+ crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO,
crate::methods::SUSPICIOUS_MAP_INFO,
crate::methods::SUSPICIOUS_SPLITN_INFO,
crate::methods::SUSPICIOUS_TO_OWNED_INFO,
@@ -422,6 +426,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::module_style::MOD_MODULE_FILES_INFO,
crate::module_style::SELF_NAMED_MODULE_FILES_INFO,
crate::multi_assignments::MULTI_ASSIGNMENTS_INFO,
+ crate::multiple_unsafe_ops_per_block::MULTIPLE_UNSAFE_OPS_PER_BLOCK_INFO,
crate::mut_key::MUTABLE_KEY_TYPE_INFO,
crate::mut_mut::MUT_MUT_INFO,
crate::mut_reference::UNNECESSARY_MUT_PASSED_INFO,
@@ -445,6 +450,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::no_effect::NO_EFFECT_INFO,
crate::no_effect::NO_EFFECT_UNDERSCORE_BINDING_INFO,
crate::no_effect::UNNECESSARY_OPERATION_INFO,
+ crate::no_mangle_with_rust_abi::NO_MANGLE_WITH_RUST_ABI_INFO,
crate::non_copy_const::BORROW_INTERIOR_MUTABLE_CONST_INFO,
crate::non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST_INFO,
crate::non_expressive_names::JUST_UNDERSCORES_AND_DIGITS_INFO,
@@ -504,6 +510,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO,
crate::pub_use::PUB_USE_INFO,
crate::question_mark::QUESTION_MARK_INFO,
+ crate::question_mark_used::QUESTION_MARK_USED_INFO,
crate::ranges::MANUAL_RANGE_CONTAINS_INFO,
crate::ranges::RANGE_MINUS_ONE_INFO,
crate::ranges::RANGE_PLUS_ONE_INFO,
@@ -534,6 +541,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::shadow::SHADOW_REUSE_INFO,
crate::shadow::SHADOW_SAME_INFO,
crate::shadow::SHADOW_UNRELATED_INFO,
+ crate::significant_drop_tightening::SIGNIFICANT_DROP_TIGHTENING_INFO,
crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO,
crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO,
crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO,
@@ -571,6 +579,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
+ crate::transmute::TRANSMUTE_INT_TO_NON_ZERO_INFO,
crate::transmute::TRANSMUTE_NULL_TO_FN_INFO,
crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index a04693f46..080d44e63 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -150,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
.fields
.iter()
.all(|field| {
- is_copy(cx, cx.tcx.type_of(field.did))
+ is_copy(cx, cx.tcx.type_of(field.did).subst_identity())
});
if !has_drop(cx, binding_type) || all_fields_are_copy;
then {
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index 03460689e..4e1a6cd4d 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -141,7 +141,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
ExprKind::MethodCall(_, receiver, args, _) => {
if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
- let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
+ let fn_sig = self.cx.tcx.fn_sig(def_id).subst_identity().skip_binder();
for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) {
self.ty_bounds.push((*bound).into());
self.visit_expr(expr);
@@ -167,7 +167,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
.iter()
.find_map(|f_def| {
if f_def.ident(self.cx.tcx) == field.ident
- { Some(self.cx.tcx.type_of(f_def.did)) }
+ { Some(self.cx.tcx.type_of(f_def.did).subst_identity()) }
else { None }
});
self.ty_bounds.push(bound.into());
@@ -215,7 +215,7 @@ fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<'
let node_ty = cx.typeck_results().node_type_opt(hir_id)?;
// We can't use `Ty::fn_sig` because it automatically performs substs, this may result in FNs.
match node_ty.kind() {
- ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id)),
+ ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id).subst_identity()),
ty::FnPtr(fn_sig) => Some(*fn_sig),
_ => None,
}
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 05f2b92c0..7f3f26bed 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -3,7 +3,7 @@ use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exact
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res};
+use clippy_utils::ty::{adt_and_variant_of_res, expr_sig, is_copy, peel_mid_ty_refs, ty_sig};
use clippy_utils::{
fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage,
};
@@ -26,8 +26,8 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::{Rvalue, StatementKind};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::{
- self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind,
- ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults,
+ self, Binder, BoundVariableKind, Clause, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy,
+ PredicateKind, ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults,
};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{symbol::sym, Span, Symbol};
@@ -735,8 +735,8 @@ fn walk_parents<'tcx>(
span,
..
}) if span.ctxt() == ctxt => {
- let ty = cx.tcx.type_of(owner_id.def_id);
- Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx))
+ let ty = cx.tcx.type_of(owner_id.def_id).subst_identity();
+ Some(ty_auto_deref_stability(cx.tcx, cx.param_env, ty, precedence).position_for_result(cx))
},
Node::Item(&Item {
@@ -759,8 +759,8 @@ fn walk_parents<'tcx>(
}) if span.ctxt() == ctxt => {
let output = cx
.tcx
- .erase_late_bound_regions(cx.tcx.fn_sig(owner_id.to_def_id()).output());
- Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx))
+ .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
+ Some(ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx))
},
Node::ExprField(field) if field.span.ctxt() == ctxt => match get_parent_expr_for_hir(cx, field.hir_id) {
@@ -768,31 +768,44 @@ fn walk_parents<'tcx>(
hir_id,
kind: ExprKind::Struct(path, ..),
..
- }) => variant_of_res(cx, cx.qpath_res(path, *hir_id))
- .and_then(|variant| variant.fields.iter().find(|f| f.name == field.ident.name))
- .map(|field_def| {
- ty_auto_deref_stability(cx, cx.tcx.type_of(field_def.did), precedence).position_for_arg()
+ }) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
+ .and_then(|(adt, variant)| {
+ variant
+ .fields
+ .iter()
+ .find(|f| f.name == field.ident.name)
+ .map(|f| (adt, f))
+ })
+ .map(|(adt, field_def)| {
+ ty_auto_deref_stability(
+ cx.tcx,
+ // Use the param_env of the target type.
+ cx.tcx.param_env(adt.did()),
+ cx.tcx.type_of(field_def.did).subst_identity(),
+ precedence,
+ )
+ .position_for_arg()
}),
_ => None,
},
Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
ExprKind::Ret(_) => {
- let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap());
+ let owner_id = cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap());
Some(
if let Node::Expr(
closure_expr @ Expr {
kind: ExprKind::Closure(closure),
..
},
- ) = cx.tcx.hir().get(owner_id)
+ ) = cx.tcx.hir().get_by_def_id(owner_id)
{
closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence)
} else {
let output = cx
.tcx
- .erase_late_bound_regions(cx.tcx.fn_sig(cx.tcx.hir().local_def_id(owner_id)).output());
- ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)
+ .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).subst_identity().output());
+ ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx)
},
)
},
@@ -835,15 +848,20 @@ fn walk_parents<'tcx>(
msrv,
)
} else {
- ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
- .position_for_arg()
+ ty_auto_deref_stability(
+ cx.tcx,
+ // Use the param_env of the target function.
+ sig.predicates_id().map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id)),
+ cx.tcx.erase_late_bound_regions(ty),
+ precedence
+ ).position_for_arg()
}
},
}
})
}),
ExprKind::MethodCall(method, receiver, args, _) => {
- let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
+ let fn_id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
if receiver.hir_id == child_id {
// Check for calls to trait methods where the trait is implemented on a reference.
// Two cases need to be handled:
@@ -852,13 +870,17 @@ fn walk_parents<'tcx>(
// priority.
if e.hir_id != child_id {
return Some(Position::ReborrowStable(precedence))
- } else if let Some(trait_id) = cx.tcx.trait_of_item(id)
+ } else if let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
&& let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
&& let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
&& let subs = cx
.typeck_results()
.node_substs_opt(parent.hir_id).map(|subs| &subs[1..]).unwrap_or_default()
- && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
+ && let impl_ty = if cx.tcx.fn_sig(fn_id)
+ .subst_identity()
+ .skip_binder()
+ .inputs()[0].is_ref()
+ {
// Trait methods taking `&self`
sub_ty
} else {
@@ -879,10 +901,13 @@ fn walk_parents<'tcx>(
return Some(Position::MethodReceiver);
}
args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
- let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
+ let ty = cx.tcx.fn_sig(fn_id).subst_identity().input(i + 1);
// `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
// `method.args.is_none()` for https://github.com/rust-lang/rust-clippy/issues/9782
- if e.hir_id == child_id && method.args.is_none() && let ty::Param(param_ty) = ty.kind() {
+ if e.hir_id == child_id
+ && method.args.is_none()
+ && let ty::Param(param_ty) = ty.skip_binder().kind()
+ {
needless_borrow_impl_arg_position(
cx,
possible_borrowers,
@@ -895,8 +920,10 @@ fn walk_parents<'tcx>(
)
} else {
ty_auto_deref_stability(
- cx,
- cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
+ cx.tcx,
+ // Use the param_env of the target function.
+ cx.tcx.param_env(fn_id),
+ cx.tcx.erase_late_bound_regions(ty),
precedence,
)
.position_for_arg()
@@ -1022,7 +1049,7 @@ fn binding_ty_auto_deref_stability<'tcx>(
))
.is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
),
- TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
+ TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err(_) => {
Position::ReborrowStable(precedence)
},
};
@@ -1038,7 +1065,7 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
if self.0
|| matches!(
ty.kind,
- TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(_) | TyKind::Err
+ TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(_) | TyKind::Err(_)
)
{
self.0 = true;
@@ -1093,7 +1120,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
let Some(callee_def_id) = fn_def_id(cx, parent) else { return Position::Other(precedence) };
- let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+ let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
let substs_with_expr_ty = cx
.typeck_results()
.node_substs(if let ExprKind::Call(callee, _) = parent.kind {
@@ -1221,7 +1248,7 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
.in_definition_order()
.any(|assoc_item| {
if assoc_item.fn_has_self_parameter {
- let self_ty = cx.tcx.fn_sig(assoc_item.def_id).skip_binder().inputs()[0];
+ let self_ty = cx.tcx.fn_sig(assoc_item.def_id).subst_identity().skip_binder().inputs()[0];
matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Mut))
} else {
false
@@ -1330,10 +1357,10 @@ fn replace_types<'tcx>(
&& let Some(term_ty) = projection_predicate.term.ty()
&& let ty::Param(term_param_ty) = term_ty.kind()
{
- let item_def_id = projection_predicate.projection_ty.def_id;
- let assoc_item = cx.tcx.associated_item(item_def_id);
- let projection = cx.tcx
- .mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, []));
+ let projection = cx.tcx.mk_ty_from_kind(ty::Alias(
+ ty::Projection,
+ projection_predicate.projection_ty.with_self_ty(cx.tcx, new_ty),
+ ));
if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection)
&& substs[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty)
@@ -1378,11 +1405,18 @@ impl<'tcx> TyPosition<'tcx> {
}
// Checks whether a type is stable when switching to auto dereferencing,
-fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> TyPosition<'tcx> {
+fn ty_auto_deref_stability<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ precedence: i8,
+) -> TyPosition<'tcx> {
let ty::Ref(_, mut ty, _) = *ty.kind() else {
return Position::Other(precedence).into();
};
+ ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
+
loop {
break match *ty.kind() {
ty::Ref(_, ref_ty, _) => {
@@ -1419,12 +1453,11 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
| ty::FnDef(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
+ | ty::GeneratorWitnessMIR(..)
| ty::Closure(..)
| ty::Never
| ty::Tuple(_)
- | ty::Alias(ty::Projection, _) => {
- Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds())).into()
- },
+ | ty::Alias(ty::Projection, _) => Position::DerefStable(precedence, ty.is_sized(tcx, param_env)).into(),
};
}
}
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index bc18e2e5e..f95b8ccf0 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -184,7 +184,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
if let ImplItemKind::Fn(_, b) = &impl_item.kind;
if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
- if let Some(adt_def) = cx.tcx.type_of(item.owner_id).ty_adt_def();
+ if let Some(adt_def) = cx.tcx.type_of(item.owner_id).subst_identity().ty_adt_def();
if let attrs = cx.tcx.hir().attrs(item.hir_id());
if !attrs.iter().any(|attr| attr.doc_str().is_some());
if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 248d73884..b8428d66a 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -7,7 +7,7 @@ use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
use rustc_hir::{
- self as hir, BlockCheckMode, BodyId, Constness, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, UnsafeSource,
+ self as hir, BlockCheckMode, BodyId, Constness, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource,
Unsafety,
};
use rustc_lint::{LateContext, LateLintPass};
@@ -18,6 +18,7 @@ use rustc_middle::ty::{
TraitPredicate, Ty, TyCtxt,
};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::Span;
use rustc_span::sym;
@@ -210,7 +211,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
..
}) = item.kind
{
- let ty = cx.tcx.type_of(item.owner_id);
+ let ty = cx.tcx.type_of(item.owner_id).subst_identity();
let is_automatically_derived = cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived);
check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
@@ -346,7 +347,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h
let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(&copy_id).map_or(false, |impls| {
impls
.iter()
- .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did()))
+ .any(|&id| matches!(cx.tcx.type_of(id).subst_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did()))
});
if !has_copy_impl {
return;
@@ -425,7 +426,7 @@ struct UnsafeVisitor<'a, 'tcx> {
impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
type NestedFilter = nested_filter::All;
- fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: HirId) {
+ fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: LocalDefId) {
if self.has_unsafe {
return;
}
@@ -513,7 +514,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
}
ParamEnv::new(
- tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain(
+ tcx.mk_predicates_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate {
trait_ref: tcx.mk_trait_ref(eq_trait_id, [tcx.mk_param_from_def(param)]),
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index cdc23a4d2..384aca7fe 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -6,12 +6,17 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty};
use if_chain::if_chain;
use itertools::Itertools;
+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, AttrKind, Attribute, Fn, FnRetTy, ItemKind};
use rustc_ast::token::CommentKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::{Applicability, Handler, SuggestionStyle};
+use rustc_errors::{Applicability, Handler, SuggestionStyle, TerminalUrl};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{AnonConst, Expr};
@@ -23,7 +28,6 @@ use rustc_parse::maybe_new_parser_from_source_str;
use rustc_parse::parser::ForceCollect;
use rustc_session::parse::ParseSess;
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::def_id::LocalDefId;
use rustc_span::edition::Edition;
use rustc_span::source_map::{BytePos, FilePathMapping, SourceMap, Span};
use rustc_span::{sym, FileName, Pos};
@@ -251,7 +255,7 @@ declare_clippy_lint! {
/// unimplemented!();
/// }
/// ```
- #[clippy::version = "1.66.0"]
+ #[clippy::version = "1.67.0"]
pub UNNECESSARY_SAFETY_DOC,
restriction,
"`pub fn` or `pub trait` with `# Safety` docs"
@@ -302,7 +306,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
panic_span: None,
};
fpu.visit_expr(body.value);
- lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, Some(body_id), fpu.panic_span);
+ lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span);
}
},
hir::ItemKind::Impl(impl_) => {
@@ -338,7 +342,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return };
if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
if !in_external_macro(cx.tcx.sess, item.span) {
- lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, None, None);
+ lint_for_missing_headers(cx, item.owner_id, sig, headers, None, None);
}
}
}
@@ -357,20 +361,20 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
panic_span: None,
};
fpu.visit_expr(body.value);
- lint_for_missing_headers(cx, item.owner_id.def_id, sig, headers, Some(body_id), fpu.panic_span);
+ lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span);
}
}
}
fn lint_for_missing_headers(
cx: &LateContext<'_>,
- def_id: LocalDefId,
+ owner_id: hir::OwnerId,
sig: &hir::FnSig<'_>,
headers: DocHeaders,
body_id: Option<hir::BodyId>,
panic_span: Option<Span>,
) {
- if !cx.effective_visibilities.is_exported(def_id) {
+ if !cx.effective_visibilities.is_exported(owner_id.def_id) {
return; // Private functions do not require doc comments
}
@@ -378,13 +382,13 @@ fn lint_for_missing_headers(
if cx
.tcx
.hir()
- .parent_iter(cx.tcx.hir().local_def_id_to_hir_id(def_id))
+ .parent_iter(owner_id.into())
.any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id)))
{
return;
}
- let span = cx.tcx.def_span(def_id);
+ let span = cx.tcx.def_span(owner_id);
match (headers.safety, sig.header.unsafety) {
(false, hir::Unsafety::Unsafe) => span_lint(
cx,
@@ -411,8 +415,7 @@ fn lint_for_missing_headers(
);
}
if !headers.errors {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
- if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::Result) {
+ if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) {
span_lint(
cx,
MISSING_ERRORS_DOC,
@@ -499,7 +502,6 @@ struct DocHeaders {
}
fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[Attribute]) -> Option<DocHeaders> {
- use pulldown_cmark::{BrokenLink, CowStr, Options};
/// We don't want the parser to choke on intra doc links. Since we don't
/// actually care about rendering them, just pretend that all broken links are
/// point to a fake address.
@@ -540,8 +542,6 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
pulldown_cmark::Parser::new_with_broken_link_callback(&doc, Options::empty(), Some(&mut cb)).into_offset_iter();
// Iterate over all `Events` and combine consecutive events into one
let events = parser.coalesce(|previous, current| {
- use pulldown_cmark::Event::Text;
-
let previous_range = previous.1;
let current_range = current.1;
@@ -566,12 +566,6 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
spans: &[(usize, Span)],
) -> DocHeaders {
// true if a safety header was found
- 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::{CodeBlockKind, CowStr};
-
let mut headers = DocHeaders::default();
let mut in_code = false;
let mut in_link = None;
@@ -662,6 +656,12 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
check_link_quotes(cx, in_link.is_some(), trimmed_text, span, &range, begin, text.len());
// Adjust for the beginning of the current `Event`
let span = span.with_lo(span.lo() + BytePos::from_usize(range.start - begin));
+ if let Some(link) = in_link.as_ref()
+ && let Ok(url) = Url::parse(link)
+ && (url.scheme() == "https" || url.scheme() == "http") {
+ // Don't check the text associated with external URLs
+ continue;
+ }
text_to_check.push((text, span));
}
},
@@ -707,7 +707,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
let fallback_bundle =
- rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+ rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
let emitter = EmitterWriter::new(
Box::new(io::sink()),
None,
@@ -719,6 +719,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
None,
false,
false,
+ TerminalUrl::No,
);
let handler = Handler::with_emitter(false, None, Box::new(emitter));
let sess = ParseSess::with_span_handler(handler, sm);
diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs
index 0570c2a10..d94664daa 100644
--- a/src/tools/clippy/clippy_lints/src/empty_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs
@@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for EmptyEnum {
}
if let ItemKind::Enum(..) = item.kind {
- let ty = cx.tcx.type_of(item.owner_id);
+ let ty = cx.tcx.type_of(item.owner_id).subst_identity();
let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
if adt.variants().is_empty() {
span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index b44e62435..48a54f602 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -6,7 +6,7 @@ use clippy_utils::{
source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context},
SpanlessEq,
};
-use core::fmt::Write;
+use core::fmt::{self, Write};
use rustc_errors::Applicability;
use rustc_hir::{
hir_id::HirIdSet,
@@ -65,6 +65,10 @@ declare_lint_pass!(HashMapPass => [MAP_ENTRY]);
impl<'tcx> LateLintPass<'tcx> for HashMapPass {
#[expect(clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ if expr.span.from_expansion() {
+ return;
+ }
+
let Some(higher::If { cond: cond_expr, then: then_expr, r#else: else_expr }) = higher::If::hir(expr) else {
return
};
@@ -532,7 +536,7 @@ impl<'tcx> InsertSearchResults<'tcx> {
if is_expr_used_or_unified(cx.tcx, insertion.call) {
write_wrapped(&mut res, insertion, ctxt, app);
} else {
- let _ = write!(
+ let _: fmt::Result = write!(
res,
"e.insert({})",
snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0
@@ -548,7 +552,7 @@ impl<'tcx> InsertSearchResults<'tcx> {
(
self.snippet(cx, span, app, |res, insertion, ctxt, app| {
// Insertion into a map would return `Some(&mut value)`, but the entry returns `&mut value`
- let _ = write!(
+ let _: fmt::Result = write!(
res,
"Some(e.insert({}))",
snippet_with_context(cx, insertion.value.span, ctxt, "..", app).0
@@ -562,7 +566,7 @@ impl<'tcx> InsertSearchResults<'tcx> {
(
self.snippet(cx, span, app, |res, insertion, ctxt, app| {
// Insertion into a map would return `None`, but the entry returns a mutable reference.
- let _ = if is_expr_final_block_expr(cx.tcx, insertion.call) {
+ let _: fmt::Result = if is_expr_final_block_expr(cx.tcx, insertion.call) {
write!(
res,
"e.insert({});\n{}None",
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index da6788882..e275efaba 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
for var in def.variants {
if let Some(anon_const) = &var.disr_expr {
let def_id = cx.tcx.hir().body_owner_def_id(anon_const.body);
- let mut ty = cx.tcx.type_of(def_id.to_def_id());
+ let mut ty = cx.tcx.type_of(def_id.to_def_id()).subst_identity();
let constant = cx
.tcx
.const_eval_poly(def_id.to_def_id())
diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs
index b77b5621b..4c69dacf3 100644
--- a/src/tools/clippy/clippy_lints/src/enum_variants.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs
@@ -277,7 +277,7 @@ impl LateLintPass<'_> for EnumVariantNames {
Some(c) if is_word_beginning(c) => span_lint(
cx,
MODULE_NAME_REPETITIONS,
- item.span,
+ item.ident.span,
"item name starts with its containing module's name",
),
_ => (),
@@ -287,7 +287,7 @@ impl LateLintPass<'_> for EnumVariantNames {
span_lint(
cx,
MODULE_NAME_REPETITIONS,
- item.span,
+ item.ident.span,
"item name ends with its containing module's name",
);
}
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index dfb438933..d6ab4c25e 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -8,6 +8,7 @@ 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_span::def_id::LocalDefId;
use rustc_span::source_map::Span;
use rustc_span::symbol::kw;
use rustc_target::spec::abi::Abi;
@@ -63,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
_: &'tcx FnDecl<'_>,
body: &'tcx Body<'_>,
_: Span,
- hir_id: HirId,
+ fn_def_id: LocalDefId,
) {
if let Some(header) = fn_kind.header() {
if header.abi != Abi::Rust {
@@ -71,7 +72,11 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
}
}
- let parent_id = cx.tcx.hir().get_parent_item(hir_id).def_id;
+ let parent_id = cx
+ .tcx
+ .hir()
+ .get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(fn_def_id))
+ .def_id;
let parent_node = cx.tcx.hir().find_by_def_id(parent_id);
let mut trait_self_ty = None;
@@ -84,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
// find `self` ty for this trait if relevant
if let ItemKind::Trait(_, _, _, _, items) = item.kind {
for trait_item in items {
- if trait_item.id.hir_id() == hir_id {
+ if trait_item.id.owner_id.def_id == fn_def_id {
// be sure we have `self` parameter in this function
if trait_item.kind == (AssocItemKind::Fn { has_self: true }) {
trait_self_ty = Some(
@@ -105,7 +110,6 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
too_large_for_stack: self.too_large_for_stack,
};
- let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
let infcx = cx.tcx.infer_ctxt().build();
ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 3543910c3..b2071f4dc 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -11,7 +11,7 @@ use rustc_hir::{Closure, Expr, ExprKind, Param, PatKind, Unsafety};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::{self, EarlyBinder, SubstsRef, Ty, TypeVisitable};
+use rustc_middle::ty::{self, EarlyBinder, SubstsRef, Ty, TypeVisitableExt};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::sym;
@@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
if check_inputs(cx, body.params, None, args);
let callee_ty = cx.typeck_results().expr_ty_adjusted(callee);
let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id)
- .map_or(callee_ty, |id| cx.tcx.type_of(id));
+ .map_or(callee_ty, |id| cx.tcx.type_of(id).subst_identity());
if check_sig(cx, closure_ty, call_ty);
let substs = cx.typeck_results().node_substs(callee.hir_id);
// This fixes some false positives that I don't entirely understand
@@ -153,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
if check_inputs(cx, body.params, Some(receiver), args);
let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
let substs = cx.typeck_results().node_substs(body.value.hir_id);
- let call_ty = cx.tcx.bound_type_of(method_def_id).subst(cx.tcx, substs);
+ let call_ty = cx.tcx.type_of(method_def_id).subst(cx.tcx, substs);
if check_sig(cx, closure_ty, call_ty);
then {
span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| {
@@ -233,7 +233,7 @@ fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs
match assoc_item.container {
ty::TraitContainer => cx.tcx.def_path_str(def_id),
ty::ImplContainer => {
- let ty = cx.tcx.type_of(def_id);
+ let ty = cx.tcx.type_of(def_id).skip_binder();
match ty.kind() {
ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()),
ty::Array(..)
diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
index fc2912f69..aef2db385 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
@@ -1,9 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{get_parent_as_impl, has_repr_attr, is_bool};
use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, FnDecl, HirId, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty};
+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_span::def_id::LocalDefId;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
@@ -168,8 +169,9 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
fn_decl: &'tcx FnDecl<'tcx>,
_: &'tcx Body<'tcx>,
span: Span,
- hir_id: HirId,
+ def_id: LocalDefId,
) {
+ let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
if let Some(fn_header) = fn_kind.header()
&& fn_header.abi == Abi::Rust
&& get_parent_as_impl(cx.tcx, hir_id)
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index 1fece5d1c..9fd13084d 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -79,8 +79,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
then {
let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
if v.fields().iter().any(|f| {
- let def_id = cx.tcx.hir().local_def_id(f.hir_id);
- !cx.tcx.visibility(def_id).is_public()
+ !cx.tcx.visibility(f.def_id).is_public()
}) {
// skip structs with private fields
return;
diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
new file mode 100644
index 000000000..20565e1d2
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
@@ -0,0 +1,229 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::trait_ref_of_method;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::MultiSpan;
+use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor};
+use rustc_hir::{
+ BodyId, ExprKind, GenericBound, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind,
+ PredicateOrigin, Ty, TyKind, WherePredicate,
+};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::hir::nested_filter;
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{
+ def_id::{DefId, LocalDefId},
+ Span,
+};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for type parameters in generics that are never used anywhere else.
+ ///
+ /// ### Why is this bad?
+ /// Functions cannot infer the value of unused type parameters; therefore, calling them
+ /// requires using a turbofish, which serves no purpose but to satisfy the compiler.
+ ///
+ /// ### Example
+ /// ```rust
+ /// fn unused_ty<T>(x: u8) {
+ /// // ..
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// fn no_unused_ty(x: u8) {
+ /// // ..
+ /// }
+ /// ```
+ #[clippy::version = "1.69.0"]
+ pub EXTRA_UNUSED_TYPE_PARAMETERS,
+ complexity,
+ "unused type parameters in function definitions"
+}
+
+pub struct ExtraUnusedTypeParameters {
+ avoid_breaking_exported_api: bool,
+}
+
+impl ExtraUnusedTypeParameters {
+ pub fn new(avoid_breaking_exported_api: bool) -> Self {
+ Self {
+ avoid_breaking_exported_api,
+ }
+ }
+
+ /// Don't lint external macros or functions with empty bodies. Also, don't lint public items if
+ /// the `avoid_breaking_exported_api` config option is set.
+ fn check_false_positive(&self, cx: &LateContext<'_>, span: Span, def_id: LocalDefId, body_id: BodyId) -> bool {
+ let body = cx.tcx.hir().body(body_id).value;
+ let fn_empty = matches!(&body.kind, ExprKind::Block(blk, None) if blk.stmts.is_empty() && blk.expr.is_none());
+ let is_exported = cx.effective_visibilities.is_exported(def_id);
+ in_external_macro(cx.sess(), span) || (self.avoid_breaking_exported_api && is_exported) || fn_empty
+ }
+}
+
+impl_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]);
+
+/// A visitor struct that walks a given function and gathers generic type parameters, plus any
+/// trait bounds those parameters have.
+struct TypeWalker<'cx, 'tcx> {
+ cx: &'cx LateContext<'tcx>,
+ /// Collection of all the function's type parameters.
+ ty_params: FxHashMap<DefId, Span>,
+ /// Collection of any (inline) trait bounds corresponding to each type parameter.
+ bounds: FxHashMap<DefId, Span>,
+ /// The entire `Generics` object of the function, useful for querying purposes.
+ generics: &'tcx Generics<'tcx>,
+ /// The value of this will remain `true` if *every* parameter:
+ /// 1. Is a type parameter, and
+ /// 2. Goes unused in the function.
+ /// Otherwise, if any type parameters end up being used, or if any lifetime or const-generic
+ /// parameters are present, this will be set to `false`.
+ all_params_unused: bool,
+}
+
+impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
+ fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'tcx>) -> Self {
+ let mut all_params_unused = true;
+ let ty_params = generics
+ .params
+ .iter()
+ .filter_map(|param| {
+ if let GenericParamKind::Type { synthetic, .. } = param.kind {
+ (!synthetic).then_some((param.def_id.into(), param.span))
+ } else {
+ if !param.is_elided_lifetime() {
+ all_params_unused = false;
+ }
+ None
+ }
+ })
+ .collect();
+
+ Self {
+ cx,
+ ty_params,
+ bounds: FxHashMap::default(),
+ generics,
+ all_params_unused,
+ }
+ }
+
+ fn mark_param_used(&mut self, def_id: DefId) {
+ if self.ty_params.remove(&def_id).is_some() {
+ self.all_params_unused = false;
+ }
+ }
+
+ fn emit_lint(&self) {
+ let (msg, help) = match self.ty_params.len() {
+ 0 => return,
+ 1 => (
+ "type parameter goes unused in function definition",
+ "consider removing the parameter",
+ ),
+ _ => (
+ "type parameters go unused in function definition",
+ "consider removing the parameters",
+ ),
+ };
+
+ let source_map = self.cx.sess().source_map();
+ let span = if self.all_params_unused {
+ self.generics.span.into() // Remove the entire list of generics
+ } else {
+ MultiSpan::from_spans(
+ self.ty_params
+ .iter()
+ .map(|(def_id, &span)| {
+ // Extend the span past any trait bounds, and include the comma at the end.
+ let span_to_extend = self.bounds.get(def_id).copied().map_or(span, Span::shrink_to_hi);
+ let comma_range = source_map.span_extend_to_next_char(span_to_extend, '>', false);
+ let comma_span = source_map.span_through_char(comma_range, ',');
+ span.with_hi(comma_span.hi())
+ })
+ .collect(),
+ )
+ };
+
+ span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, span, msg, None, help);
+ }
+}
+
+/// Given a generic bound, if the bound is for a trait that's not a `LangItem`, return the
+/// `LocalDefId` for that trait.
+fn bound_to_trait_def_id(bound: &GenericBound<'_>) -> Option<LocalDefId> {
+ bound.trait_ref()?.trait_def_id()?.as_local()
+}
+
+impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
+ type NestedFilter = nested_filter::OnlyBodies;
+
+ fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
+ if let Some((def_id, _)) = t.peel_refs().as_generic_param() {
+ self.mark_param_used(def_id);
+ } else if let TyKind::OpaqueDef(id, _, _) = t.kind {
+ // Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls
+ // `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're
+ // using `OnlyBodies`, so the check ends up failing and the type isn't fully walked.
+ let item = self.nested_visit_map().item(id);
+ walk_item(self, item);
+ } else {
+ walk_ty(self, t);
+ }
+ }
+
+ fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) {
+ if let WherePredicate::BoundPredicate(predicate) = predicate {
+ // Collect spans for any bounds on type parameters. We only keep bounds that appear in
+ // the list of generics (not in a where-clause).
+ if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param() {
+ // If the bound contains non-public traits, err on the safe side and don't lint the
+ // corresponding parameter.
+ if !predicate
+ .bounds
+ .iter()
+ .filter_map(bound_to_trait_def_id)
+ .all(|id| self.cx.effective_visibilities.is_exported(id))
+ {
+ self.mark_param_used(def_id);
+ } else if let PredicateOrigin::GenericParam = predicate.origin {
+ self.bounds.insert(def_id, predicate.span);
+ }
+ }
+ // Only walk the right-hand side of where-bounds
+ for bound in predicate.bounds {
+ walk_param_bound(self, bound);
+ }
+ }
+ }
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.cx.tcx.hir()
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+ if let ItemKind::Fn(_, generics, body_id) = item.kind
+ && !self.check_false_positive(cx, item.span, item.owner_id.def_id, body_id)
+ {
+ let mut walker = TypeWalker::new(cx, generics);
+ walk_item(&mut walker, item);
+ walker.emit_lint();
+ }
+ }
+
+ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
+ // Only lint on inherent methods, not trait methods.
+ if let ImplItemKind::Fn(.., body_id) = item.kind
+ && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+ && !self.check_false_positive(cx, item.span, item.owner_id.def_id, body_id)
+ {
+ let mut walker = TypeWalker::new(cx, item.generics);
+ walk_impl_item(&mut walker, item);
+ walker.emit_lint();
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 04e6949e1..c511d85e9 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -7,14 +7,14 @@ use clippy_utils::macros::{
};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::ty::{implements_trait, is_type_lang_item};
use if_chain::if_chain;
use itertools::Itertools;
use rustc_errors::{
Applicability,
SuggestionStyle::{CompletelyHidden, ShowCode},
};
-use rustc_hir::{Expr, ExprKind, HirId, QPath};
+use rustc_hir::{Expr, ExprKind, HirId, LangItem, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_middle::ty::Ty;
@@ -237,7 +237,7 @@ fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) {
);
}
- if is_type_diagnostic_item(cx, param_ty, sym::Arguments) && !arg.format.is_default_for_trait() {
+ if is_type_lang_item(cx, param_ty, LangItem::FormatArguments) && !arg.format.is_default_for_trait() {
span_lint_and_then(
cx,
UNUSED_FORMAT_SPECS,
@@ -311,6 +311,10 @@ fn check_uninlined_args(
// in those cases, make the code suggestion hidden
let multiline_fix = fixes.iter().any(|(span, _)| cx.sess().source_map().is_multiline(*span));
+ // Suggest removing each argument only once, for example in `format!("{0} {0}", arg)`.
+ fixes.sort_unstable_by_key(|(span, _)| *span);
+ fixes.dedup_by_key(|(span, _)| *span);
+
span_lint_and_then(
cx,
UNINLINED_FORMAT_ARGS,
@@ -336,6 +340,7 @@ fn check_one_arg(
if matches!(param.kind, Implicit | Starred | Named(_) | Numbered)
&& let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind
&& let [segment] = path.segments
+ && segment.args.is_none()
&& let Some(arg_span) = args.value_with_prev_comma_span(param.value.hir_id)
{
let replacement = match param.usage {
diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
index 00f5ba564..096508dc4 100644
--- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
@@ -31,7 +31,7 @@ declare_clippy_lint! {
/// let _ = unsafe { Box::from_raw(ptr as *mut usize) };
/// ```
///
- #[clippy::version = "1.66.0"]
+ #[clippy::version = "1.67.0"]
pub FROM_RAW_WITH_VOID_PTR,
suspicious,
"creating a `Box` from a void raw pointer"
diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
new file mode 100644
index 000000000..2811a73f6
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
@@ -0,0 +1,50 @@
+use clippy_utils::{diagnostics::span_lint_and_then, is_in_test_function};
+
+use rustc_hir::{intravisit::FnKind, Body, HirId};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+
+use super::IMPL_TRAIT_IN_PARAMS;
+
+pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) {
+ if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() && !is_in_test_function(cx.tcx, hir_id)
+ {
+ if let FnKind::ItemFn(ident, generics, _) = kind {
+ for param in generics.params {
+ if param.is_impl_trait() {
+ // No generics with nested generics, and no generics like FnMut(x)
+ span_lint_and_then(
+ cx,
+ IMPL_TRAIT_IN_PARAMS,
+ param.span,
+ "'`impl Trait` used as a function parameter'",
+ |diag| {
+ if let Some(gen_span) = generics.span_for_param_suggestion() {
+ diag.span_suggestion_with_style(
+ gen_span,
+ "add a type paremeter",
+ format!(", {{ /* Generic name */ }}: {}", &param.name.ident().as_str()[5..]),
+ rustc_errors::Applicability::HasPlaceholders,
+ rustc_errors::SuggestionStyle::ShowAlways,
+ );
+ } else {
+ diag.span_suggestion_with_style(
+ Span::new(
+ body.params[0].span.lo() - rustc_span::BytePos(1),
+ ident.span.hi(),
+ ident.span.ctxt(),
+ ident.span.parent(),
+ ),
+ "add a type paremeter",
+ format!("<{{ /* Generic name */ }}: {}>", &param.name.ident().as_str()[5..]),
+ rustc_errors::Applicability::HasPlaceholders,
+ rustc_errors::SuggestionStyle::ShowAlways,
+ );
+ }
+ },
+ );
+ }
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
index 27acad45c..8b53ee68e 100644
--- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
-use rustc_hir::{intravisit::FnKind, Body, ExprKind, FnDecl, HirId, ImplicitSelfKind, Unsafety};
+use rustc_hir::{intravisit::FnKind, Body, ExprKind, FnDecl, ImplicitSelfKind, Unsafety};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::Span;
@@ -10,14 +10,7 @@ use std::iter;
use super::MISNAMED_GETTERS;
-pub fn check_fn(
- cx: &LateContext<'_>,
- kind: FnKind<'_>,
- decl: &FnDecl<'_>,
- body: &Body<'_>,
- span: Span,
- _hir_id: HirId,
-) {
+pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: &Body<'_>, span: Span) {
let FnKind::Method(ref ident, sig) = kind else {
return;
};
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index 9dbce3f88..d2852b4ac 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -1,3 +1,4 @@
+mod impl_trait_in_params;
mod misnamed_getters;
mod must_use;
mod not_unsafe_ptr_arg_deref;
@@ -9,6 +10,7 @@ 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_span::def_id::LocalDefId;
use rustc_span::Span;
declare_clippy_lint! {
@@ -326,6 +328,32 @@ declare_clippy_lint! {
"getter method returning the wrong field"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Lints when `impl Trait` is being used in a function's paremeters.
+ /// ### Why is this bad?
+ /// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor.
+ ///
+ /// ### Example
+ /// ```rust
+ /// trait MyTrait {}
+ /// fn foo(a: impl MyTrait) {
+ /// // [...]
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// trait MyTrait {}
+ /// fn foo<T: MyTrait>(a: T) {
+ /// // [...]
+ /// }
+ /// ```
+ #[clippy::version = "1.68.0"]
+ pub IMPL_TRAIT_IN_PARAMS,
+ restriction,
+ "`impl Trait` is used in the function's parameters"
+}
+
#[derive(Copy, Clone)]
pub struct Functions {
too_many_arguments_threshold: u64,
@@ -353,6 +381,7 @@ impl_lint_pass!(Functions => [
RESULT_UNIT_ERR,
RESULT_LARGE_ERR,
MISNAMED_GETTERS,
+ IMPL_TRAIT_IN_PARAMS,
]);
impl<'tcx> LateLintPass<'tcx> for Functions {
@@ -363,12 +392,14 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
decl: &'tcx hir::FnDecl<'_>,
body: &'tcx hir::Body<'_>,
span: Span,
- hir_id: hir::HirId,
+ def_id: LocalDefId,
) {
+ let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold);
too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold);
- not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, hir_id);
- misnamed_getters::check_fn(cx, kind, decl, body, span, hir_id);
+ not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id);
+ misnamed_getters::check_fn(cx, kind, decl, body, span);
+ impl_trait_in_params::check_fn(cx, &kind, body, hir_id);
}
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index d22bede36..29bdc46b6 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -1,6 +1,6 @@
use rustc_ast::ast::Attribute;
use rustc_errors::Applicability;
-use rustc_hir::def_id::{DefIdSet, LocalDefId};
+use rustc_hir::def_id::DefIdSet;
use rustc_hir::{self as hir, def::Res, QPath};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::{
@@ -27,14 +27,14 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
if let Some(attr) = attr {
- check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
+ check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
} else if is_public && !is_proc_macro(cx.sess(), attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
check_must_use_candidate(
cx,
sig.decl,
cx.tcx.hir().body(*body_id),
item.span,
- item.owner_id.def_id,
+ item.owner_id,
item.span.with_hi(sig.decl.output.span().hi()),
"this function could have a `#[must_use]` attribute",
);
@@ -49,7 +49,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
let attrs = cx.tcx.hir().attrs(item.hir_id());
let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
if let Some(attr) = attr {
- check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
+ check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
} else if is_public
&& !is_proc_macro(cx.sess(), attrs)
&& trait_ref_of_method(cx, item.owner_id.def_id).is_none()
@@ -59,7 +59,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
sig.decl,
cx.tcx.hir().body(*body_id),
item.span,
- item.owner_id.def_id,
+ item.owner_id,
item.span.with_hi(sig.decl.output.span().hi()),
"this method could have a `#[must_use]` attribute",
);
@@ -75,7 +75,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
let attrs = cx.tcx.hir().attrs(item.hir_id());
let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
if let Some(attr) = attr {
- check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
+ check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
} else if let hir::TraitFn::Provided(eid) = *eid {
let body = cx.tcx.hir().body(eid);
if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) {
@@ -84,7 +84,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
sig.decl,
body,
item.span,
- item.owner_id.def_id,
+ item.owner_id,
item.span.with_hi(sig.decl.output.span().hi()),
"this method could have a `#[must_use]` attribute",
);
@@ -96,7 +96,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
fn check_needless_must_use(
cx: &LateContext<'_>,
decl: &hir::FnDecl<'_>,
- item_id: hir::HirId,
+ item_id: hir::OwnerId,
item_span: Span,
fn_header_span: Span,
attr: &Attribute,
@@ -131,7 +131,7 @@ fn check_must_use_candidate<'tcx>(
decl: &'tcx hir::FnDecl<'_>,
body: &'tcx hir::Body<'_>,
item_span: Span,
- item_id: LocalDefId,
+ item_id: hir::OwnerId,
fn_span: Span,
msg: &str,
) {
@@ -139,8 +139,8 @@ fn check_must_use_candidate<'tcx>(
|| mutates_static(cx, body)
|| in_external_macro(cx.sess(), item_span)
|| returns_unit(decl)
- || !cx.effective_visibilities.is_exported(item_id)
- || is_must_use_ty(cx, return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(item_id)))
+ || !cx.effective_visibilities.is_exported(item_id.def_id)
+ || is_must_use_ty(cx, return_ty(cx, item_id))
{
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index 2c0bf551f..f2aa7b597 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -17,7 +17,7 @@ pub(super) fn check_fn<'tcx>(
kind: intravisit::FnKind<'tcx>,
decl: &'tcx hir::FnDecl<'tcx>,
body: &'tcx hir::Body<'tcx>,
- hir_id: hir::HirId,
+ def_id: LocalDefId,
) {
let unsafety = match kind {
intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }) => unsafety,
@@ -25,7 +25,7 @@ pub(super) fn check_fn<'tcx>(
intravisit::FnKind::Closure => return,
};
- check_raw_ptr(cx, unsafety, decl, body, cx.tcx.hir().local_def_id(hir_id));
+ check_raw_ptr(cx, unsafety, decl, body, def_id);
}
pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
@@ -58,7 +58,7 @@ fn check_raw_ptr<'tcx>(
},
hir::ExprKind::MethodCall(_, recv, args, _) => {
let def_id = typeck.type_dependent_def_id(e.hir_id).unwrap();
- if cx.tcx.fn_sig(def_id).skip_binder().unsafety == hir::Unsafety::Unsafe {
+ if cx.tcx.fn_sig(def_id).skip_binder().skip_binder().unsafety == hir::Unsafety::Unsafe {
check_arg(cx, &raw_ptrs, recv);
for arg in args {
check_arg(cx, &raw_ptrs, arg);
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
index 23da145d0..fa2a9b30c 100644
--- a/src/tools/clippy/clippy_lints/src/functions/result.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -21,7 +21,7 @@ fn result_err_ty<'tcx>(
) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> {
if !in_external_macro(cx.sess(), item_span)
&& let hir::FnRetTy::Return(hir_ty) = decl.output
- && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).output())
+ && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).subst_identity().output())
&& is_type_diagnostic_item(cx, ty, sym::Result)
&& let ty::Adt(_, substs) = ty.kind()
{
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 989f83cf8..9fb73a371 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -1,11 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::return_ty;
use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, FnDecl, HirId};
+use rustc_hir::{Body, FnDecl};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, AliasTy, Clause, EarlyBinder, PredicateKind};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span};
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
use rustc_trait_selection::traits::{self, FulfillmentError};
@@ -56,12 +57,12 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
decl: &'tcx FnDecl<'tcx>,
_: &'tcx Body<'tcx>,
_: Span,
- hir_id: HirId,
+ fn_def_id: LocalDefId,
) {
if let FnKind::Closure = kind {
return;
}
- let ret_ty = return_ty(cx, hir_id);
+ let ret_ty = return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(fn_def_id).expect_owner());
if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() {
let preds = cx.tcx.explicit_item_bounds(def_id);
let mut is_future = false;
@@ -78,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
let span = decl.output.span();
let infcx = cx.tcx.infer_ctxt().build();
- let cause = traits::ObligationCause::misc(span, hir_id);
+ let cause = traits::ObligationCause::misc(span, fn_def_id);
let send_errors = traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait);
if !send_errors.is_empty() {
span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index 946d04eff..372b6ead3 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -11,6 +11,7 @@ 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_span::def_id::LocalDefId;
use rustc_span::{Span, SyntaxContext};
declare_clippy_lint! {
@@ -223,7 +224,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
decl: &'tcx FnDecl<'_>,
body: &'tcx Body<'_>,
span: Span,
- _: HirId,
+ _: LocalDefId,
) {
if (!matches!(kind, FnKind::Closure) && matches!(decl.output, FnRetTy::DefaultReturn(_)))
|| span.ctxt() != body.value.span.ctxt()
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index 29d59c26d..0c7aea6da 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
if let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(const_id);
if let None = cx.tcx.impl_trait_ref(impl_id); // An inherent impl
- if cx.tcx.type_of(impl_id).is_integral();
+ if cx.tcx.type_of(impl_id).subst_identity().is_integral();
then {
print_lint_and_sugg(cx, var_name, expr)
}
@@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
if let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(func_id);
if let None = cx.tcx.impl_trait_ref(impl_id); // An inherent impl
- if cx.tcx.type_of(impl_id).is_integral();
+ if cx.tcx.type_of(impl_id).subst_identity().is_integral();
then {
print_lint_and_sugg(cx, var_name, expr)
}
diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
index e2f2d3d42..1ad886f2c 100644
--- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -7,7 +7,7 @@ use rustc_hir::{self as hir, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::Symbol;
-use std::fmt::Write as _;
+use std::fmt::{self, Write as _};
declare_clippy_lint! {
/// ### What it does
@@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
let mut fields_snippet = String::new();
let (last_ident, idents) = ordered_fields.split_last().unwrap();
for ident in idents {
- let _ = write!(fields_snippet, "{ident}, ");
+ let _: fmt::Result = write!(fields_snippet, "{ident}, ");
}
fields_snippet.push_str(&last_ident.to_string());
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index eebfb753a..c384172fb 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -109,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
if let Some(range) = higher::Range::hir(index) {
// Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
if let ty::Array(_, s) = ty.kind() {
- let size: u128 = if let Some(size) = s.try_eval_usize(cx.tcx, cx.param_env) {
+ let size: u128 = if let Some(size) = s.try_eval_target_usize(cx.tcx, cx.param_env) {
size.into()
} else {
return;
diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
index e9b2e31a7..7c41699f3 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
@@ -66,7 +66,8 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
)
}) {
for impl_id in impl_ids.iter().map(|id| id.expect_local()) {
- match type_map.entry(cx.tcx.type_of(impl_id)) {
+ let impl_ty = cx.tcx.type_of(impl_id).subst_identity();
+ match type_map.entry(impl_ty) {
Entry::Vacant(e) => {
// Store the id for the first impl block of this type. The span is retrieved lazily.
e.insert(IdOrSpan::Id(impl_id));
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index aaecc4fa8..d43e5cc9b 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
if impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }));
// Check if return type is String
- if is_type_lang_item(cx, return_ty(cx, impl_item.hir_id()), LangItem::String);
+ if is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String);
// Filters instances of to_string which are required by a trait
if trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none();
@@ -124,7 +124,7 @@ fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) {
.expect("Failed to get trait ID of `Display`!");
// Get the real type of 'self'
- let self_type = cx.tcx.fn_sig(item.owner_id).input(0);
+ let self_type = cx.tcx.fn_sig(item.owner_id).skip_binder().input(0);
let self_type = self_type.skip_binder().peel_refs();
// Emit either a warning or an error
diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
index 9f6e89405..668110c7c 100644
--- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
+++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
@@ -59,7 +59,7 @@ declare_clippy_lint! {
///
/// [`Duration`]: std::time::Duration
/// [`Instant::now()`]: std::time::Instant::now;
- #[clippy::version = "1.65.0"]
+ #[clippy::version = "1.67.0"]
pub UNCHECKED_DURATION_SUBTRACTION,
pedantic,
"finds unchecked subtraction of a 'Duration' from an 'Instant'"
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index e76de77f1..c924d7361 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -66,7 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
if sig.decl.implicit_self.has_implicit_self() {
- let ret_ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(fn_id).output());
+ let ret_ty = cx
+ .tcx
+ .erase_late_bound_regions(cx.tcx.fn_sig(fn_id).subst_identity().output());
let ret_ty = cx
.tcx
.try_normalize_erasing_regions(cx.param_env, ret_ty)
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index db637dfc0..4dc750c03 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
if let ty::Array(element_type, cst) = ty.kind();
if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind();
- if let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx);
+ if let Ok(element_count) = element_count.try_to_target_usize(cx.tcx);
if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes());
if self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size);
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index b8d4abdbb..1c99bd2f3 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
return;
}
if let ItemKind::Enum(ref def, _) = item.kind {
- let ty = cx.tcx.type_of(item.owner_id);
+ let ty = cx.tcx.type_of(item.owner_id).subst_identity();
let Adt(adt, subst) = ty.kind() else {
panic!("already checked whether this is an enum")
};
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
index 89ae83d48..32c6312e0 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
@@ -41,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
if let ExprKind::Repeat(_, _) = expr.kind
&& let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind()
&& let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind()
- && let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx)
+ && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx)
&& let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
&& !cx.tcx.hir().parent_iter(expr.hir_id)
.any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. })))
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 3c70c9cf1..e13bc4797 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -135,6 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
if item.ident.name == sym::len;
if let ImplItemKind::Fn(sig, _) = &item.kind;
if sig.decl.implicit_self.has_implicit_self();
+ if sig.decl.inputs.len() == 1;
if cx.effective_visibilities.is_exported(item.owner_id.def_id);
if matches!(sig.decl.output, FnRetTy::Return(_));
if let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id());
@@ -144,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
if let Some(local_id) = ty_id.as_local();
let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
if !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id);
- if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).skip_binder());
+ if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).subst_identity().skip_binder());
then {
let (name, kind) = match cx.tcx.hir().find(ty_hir_id) {
Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"),
@@ -196,7 +197,15 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool {
item.ident.name == name
&& if let AssocItemKind::Fn { has_self } = item.kind {
- has_self && { cx.tcx.fn_sig(item.id.owner_id).inputs().skip_binder().len() == 1 }
+ has_self && {
+ cx.tcx
+ .fn_sig(item.id.owner_id)
+ .skip_binder()
+ .inputs()
+ .skip_binder()
+ .len()
+ == 1
+ }
} else {
false
}
@@ -224,7 +233,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
.any(|i| {
i.kind == ty::AssocKind::Fn
&& i.fn_has_self_parameter
- && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
+ && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1
});
if !is_empty_method_found {
@@ -342,7 +351,11 @@ fn check_for_is_empty<'tcx>(
),
Some(is_empty)
if !(is_empty.fn_has_self_parameter
- && check_is_empty_sig(cx.tcx.fn_sig(is_empty.def_id).skip_binder(), self_kind, output)) =>
+ && check_is_empty_sig(
+ cx.tcx.fn_sig(is_empty.def_id).subst_identity().skip_binder(),
+ self_kind,
+ output,
+ )) =>
{
(
format!(
@@ -473,7 +486,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
/// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
if item.kind == ty::AssocKind::Fn {
- let sig = cx.tcx.fn_sig(item.def_id);
+ let sig = cx.tcx.fn_sig(item.def_id).skip_binder();
let ty = sig.skip_binder();
ty.inputs().len() == 1
} else {
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 61f87b914..7600777fa 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -84,13 +84,51 @@ declare_clippy_lint! {
/// let _ = foo().await;
/// # }
/// ```
- #[clippy::version = "1.66"]
+ #[clippy::version = "1.67.0"]
pub LET_UNDERSCORE_FUTURE,
suspicious,
"non-binding `let` on a future"
}
-declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE]);
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for `let _ = <expr>` without a type annotation, and suggests to either provide one,
+ /// or remove the `let` keyword altogether.
+ ///
+ /// ### Why is this bad?
+ /// The `let _ = <expr>` expression ignores the value of `<expr>` but will remain doing so even
+ /// if the type were to change, thus potentially introducing subtle bugs. By supplying a type
+ /// annotation, one will be forced to re-visit the decision to ignore the value in such cases.
+ ///
+ /// ### Known problems
+ /// The `_ = <expr>` is not properly supported by some tools (e.g. IntelliJ) and may seem odd
+ /// to many developers. This lint also partially overlaps with the other `let_underscore_*`
+ /// lints.
+ ///
+ /// ### Example
+ /// ```rust
+ /// fn foo() -> Result<u32, ()> {
+ /// Ok(123)
+ /// }
+ /// let _ = foo();
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// fn foo() -> Result<u32, ()> {
+ /// Ok(123)
+ /// }
+ /// // Either provide a type annotation:
+ /// let _: Result<u32, ()> = foo();
+ /// // …or drop the let keyword:
+ /// _ = foo();
+ /// ```
+ #[clippy::version = "1.69.0"]
+ pub LET_UNDERSCORE_UNTYPED,
+ pedantic,
+ "non-binding `let` without a type annotation"
+}
+
+declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE, LET_UNDERSCORE_UNTYPED]);
const SYNC_GUARD_PATHS: [&[&str]; 3] = [
&paths::PARKING_LOT_MUTEX_GUARD,
@@ -148,6 +186,18 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
"consider explicitly using function result",
);
}
+
+ if local.pat.default_binding_modes && local.ty.is_none() {
+ // When `default_binding_modes` is true, the `let` keyword is present.
+ span_lint_and_help(
+ cx,
+ LET_UNDERSCORE_UNTYPED,
+ local.span,
+ "non-binding `let` without a type annotation",
+ None,
+ "consider adding a type annotation or removing the `let` keyword",
+ );
+ }
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index e93f27bee..c626e0bd9 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -1,8 +1,8 @@
#![feature(array_windows)]
#![feature(binary_heap_into_iter_sorted)]
#![feature(box_patterns)]
-#![feature(control_flow_enum)]
#![feature(drain_filter)]
+#![feature(if_let_guard)]
#![feature(iter_intersperse)]
#![feature(let_chains)]
#![feature(lint_reasons)]
@@ -43,6 +43,7 @@ extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;
extern crate rustc_trait_selection;
+extern crate thin_vec;
#[macro_use]
extern crate clippy_utils;
@@ -122,6 +123,7 @@ mod excessive_bools;
mod exhaustive_items;
mod exit;
mod explicit_write;
+mod extra_unused_type_parameters;
mod fallible_impl_from;
mod float_literal;
mod floating_point_arithmetic;
@@ -198,6 +200,7 @@ mod missing_trait_methods;
mod mixed_read_write_in_expression;
mod module_style;
mod multi_assignments;
+mod multiple_unsafe_ops_per_block;
mod mut_key;
mod mut_mut;
mod mut_reference;
@@ -217,6 +220,7 @@ mod neg_cmp_op_on_partial_ord;
mod neg_multiply;
mod new_without_default;
mod no_effect;
+mod no_mangle_with_rust_abi;
mod non_copy_const;
mod non_expressive_names;
mod non_octal_unix_permissions;
@@ -241,6 +245,7 @@ mod ptr;
mod ptr_offset_with_cast;
mod pub_use;
mod question_mark;
+mod question_mark_used;
mod ranges;
mod rc_clone_in_vec_init;
mod read_zero_byte_vec;
@@ -262,6 +267,7 @@ mod semicolon_block;
mod semicolon_if_nothing_returned;
mod serde_api;
mod shadow;
+mod significant_drop_tightening;
mod single_char_lifetime_names;
mod single_component_path_imports;
mod size_of_in_element_count;
@@ -557,6 +563,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction));
store.register_late_pass(|_| Box::new(mut_mut::MutMut));
store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed));
+ store.register_late_pass(|_| Box::<significant_drop_tightening::SignificantDropTightening<'_>>::default());
store.register_late_pass(|_| Box::new(len_zero::LenZero));
store.register_late_pass(|_| Box::new(attrs::Attributes));
store.register_late_pass(|_| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
@@ -663,12 +670,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
))
});
let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
+ let missing_docs_in_crate_items = conf.missing_docs_in_crate_items;
store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply));
store.register_late_pass(|_| Box::new(mem_forget::MemForget));
store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq));
store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
- store.register_late_pass(|_| Box::new(missing_doc::MissingDoc::new()));
+ store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(missing_docs_in_crate_items)));
store.register_late_pass(|_| Box::new(missing_inline::MissingInline));
store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems));
store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk));
@@ -692,6 +700,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher));
store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom));
store.register_late_pass(|_| Box::new(question_mark::QuestionMark));
+ store.register_late_pass(|_| Box::new(question_mark_used::QuestionMarkUsed));
store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
store.register_late_pass(|_| Box::new(map_unit_fn::MapUnit));
@@ -908,6 +917,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
+ store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock));
+ store.register_late_pass(move |_| {
+ Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters::new(
+ avoid_breaking_exported_api,
+ ))
+ });
+ store.register_late_pass(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi));
// add lints here, do not remove this comment, it's used in `new_lint`
}
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 7cf1a6b80..986ffcad8 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -1,21 +1,21 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::trait_ref_of_method;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::Applicability;
use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
use rustc_hir::intravisit::{
- walk_fn_decl, walk_generic_arg, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
+ walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
walk_poly_trait_ref, walk_trait_ref, walk_ty, Visitor,
};
-use rustc_hir::lang_items;
use rustc_hir::FnRetTy::Return;
use rustc_hir::{
- BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
- ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, PolyTraitRef, PredicateOrigin, TraitFn,
- TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
+ lang_items, BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics,
+ Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef,
+ PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::nested_filter as middle_nested_filter;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::Span;
@@ -34,8 +34,6 @@ declare_clippy_lint! {
/// ### Known problems
/// - We bail out if the function has a `where` clause where lifetimes
/// are mentioned due to potential false positives.
- /// - Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the
- /// placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`.
///
/// ### Example
/// ```rust
@@ -93,7 +91,7 @@ declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]);
impl<'tcx> LateLintPass<'tcx> for Lifetimes {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Fn(ref sig, generics, id) = item.kind {
- check_fn_inner(cx, sig.decl, Some(id), None, generics, item.span, true);
+ check_fn_inner(cx, sig, Some(id), None, generics, item.span, true);
} else if let ItemKind::Impl(impl_) = item.kind {
if !item.span.from_expansion() {
report_extra_impl_lifetimes(cx, impl_);
@@ -106,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id.def_id).is_none();
check_fn_inner(
cx,
- sig.decl,
+ sig,
Some(id),
None,
item.generics,
@@ -122,29 +120,21 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
TraitFn::Required(sig) => (None, Some(sig)),
TraitFn::Provided(id) => (Some(id), None),
};
- check_fn_inner(cx, sig.decl, body, trait_sig, item.generics, item.span, true);
+ check_fn_inner(cx, sig, body, trait_sig, item.generics, item.span, true);
}
}
}
-/// The lifetime of a &-reference.
-#[derive(PartialEq, Eq, Hash, Debug, Clone)]
-enum RefLt {
- Unnamed,
- Static,
- Named(LocalDefId),
-}
-
fn check_fn_inner<'tcx>(
cx: &LateContext<'tcx>,
- decl: &'tcx FnDecl<'_>,
+ sig: &'tcx FnSig<'_>,
body: Option<BodyId>,
trait_sig: Option<&[Ident]>,
generics: &'tcx Generics<'_>,
span: Span,
report_extra_lifetimes: bool,
) {
- if span.from_expansion() || has_where_lifetimes(cx, generics) {
+ if in_external_macro(cx.sess(), span) || has_where_lifetimes(cx, generics) {
return;
}
@@ -154,7 +144,11 @@ fn check_fn_inner<'tcx>(
.filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
for typ in types {
- for pred in generics.bounds_for_param(cx.tcx.hir().local_def_id(typ.hir_id)) {
+ if !typ.span.eq_ctxt(span) {
+ return;
+ }
+
+ for pred in generics.bounds_for_param(typ.def_id) {
if pred.origin == PredicateOrigin::WhereClause {
// has_where_lifetimes checked that this predicate contains no lifetime.
continue;
@@ -163,7 +157,7 @@ fn check_fn_inner<'tcx>(
for bound in pred.bounds {
let mut visitor = RefVisitor::new(cx);
walk_param_bound(&mut visitor, bound);
- if visitor.lts.iter().any(|lt| matches!(lt, RefLt::Named(_))) {
+ if visitor.lts.iter().any(|lt| matches!(lt.res, LifetimeName::Param(_))) {
return;
}
if let GenericBound::Trait(ref trait_ref, _) = *bound {
@@ -190,12 +184,16 @@ fn check_fn_inner<'tcx>(
}
}
- if let Some(elidable_lts) = could_use_elision(cx, decl, body, trait_sig, generics.params) {
+ if let Some((elidable_lts, usages)) = could_use_elision(cx, sig.decl, body, trait_sig, generics.params) {
+ if usages.iter().any(|usage| !usage.ident.span.eq_ctxt(span)) {
+ return;
+ }
+
let lts = elidable_lts
.iter()
// In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
// `Node::GenericParam`.
- .filter_map(|&(def_id, _)| cx.tcx.hir().get_by_def_id(def_id).ident())
+ .filter_map(|&def_id| cx.tcx.hir().get_by_def_id(def_id).ident())
.map(|ident| ident.to_string())
.collect::<Vec<_>>()
.join(", ");
@@ -203,21 +201,99 @@ fn check_fn_inner<'tcx>(
span_lint_and_then(
cx,
NEEDLESS_LIFETIMES,
- span.with_hi(decl.output.span().hi()),
+ span.with_hi(sig.decl.output.span().hi()),
&format!("the following explicit lifetimes could be elided: {lts}"),
|diag| {
- if let Some(span) = elidable_lts.iter().find_map(|&(_, span)| span) {
- diag.span_help(span, "replace with `'_` in generic arguments such as here");
+ if sig.header.is_async() {
+ // async functions have usages whose spans point at the lifetime declaration which messes up
+ // suggestions
+ return;
+ };
+
+ if let Some(suggestions) = elision_suggestions(cx, generics, &elidable_lts, &usages) {
+ diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable);
}
},
);
}
if report_extra_lifetimes {
- self::report_extra_lifetimes(cx, decl, generics);
+ self::report_extra_lifetimes(cx, sig.decl, generics);
}
}
+fn elision_suggestions(
+ cx: &LateContext<'_>,
+ generics: &Generics<'_>,
+ elidable_lts: &[LocalDefId],
+ usages: &[Lifetime],
+) -> Option<Vec<(Span, String)>> {
+ let explicit_params = generics
+ .params
+ .iter()
+ .filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait())
+ .collect::<Vec<_>>();
+
+ let mut suggestions = if elidable_lts.len() == explicit_params.len() {
+ // if all the params are elided remove the whole generic block
+ //
+ // fn x<'a>() {}
+ // ^^^^
+ vec![(generics.span, String::new())]
+ } else {
+ elidable_lts
+ .iter()
+ .map(|&id| {
+ let pos = explicit_params.iter().position(|param| param.def_id == id)?;
+ let param = explicit_params.get(pos)?;
+
+ let span = if let Some(next) = explicit_params.get(pos + 1) {
+ // fn x<'prev, 'a, 'next>() {}
+ // ^^^^
+ param.span.until(next.span)
+ } else {
+ // `pos` should be at least 1 here, because the param in position 0 would either have a `next`
+ // param or would have taken the `elidable_lts.len() == explicit_params.len()` branch.
+ let prev = explicit_params.get(pos - 1)?;
+
+ // fn x<'prev, 'a>() {}
+ // ^^^^
+ param.span.with_lo(prev.span.hi())
+ };
+
+ Some((span, String::new()))
+ })
+ .collect::<Option<Vec<_>>>()?
+ };
+
+ suggestions.extend(
+ usages
+ .iter()
+ .filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id)))
+ .map(|usage| {
+ match cx.tcx.hir().get_parent(usage.hir_id) {
+ Node::Ty(Ty {
+ kind: TyKind::Ref(..), ..
+ }) => {
+ // expand `&'a T` to `&'a T`
+ // ^^ ^^^
+ let span = cx
+ .sess()
+ .source_map()
+ .span_extend_while(usage.ident.span, |ch| ch.is_ascii_whitespace())
+ .unwrap_or(usage.ident.span);
+
+ (span, String::new())
+ },
+ // `T<'a>` and `impl Foo + 'a` should be replaced by `'_`
+ _ => (usage.ident.span, String::from("'_")),
+ }
+ }),
+ );
+
+ Some(suggestions)
+}
+
// elision doesn't work for explicit self types, see rust-lang/rust#69064
fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>) -> bool {
if_chain! {
@@ -237,13 +313,20 @@ fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident:
}
}
+fn named_lifetime(lt: &Lifetime) -> Option<LocalDefId> {
+ match lt.res {
+ LifetimeName::Param(id) if !lt.is_anonymous() => Some(id),
+ _ => None,
+ }
+}
+
fn could_use_elision<'tcx>(
cx: &LateContext<'tcx>,
func: &'tcx FnDecl<'_>,
body: Option<BodyId>,
trait_sig: Option<&[Ident]>,
named_generics: &'tcx [GenericParam<'_>],
-) -> Option<Vec<(LocalDefId, Option<Span>)>> {
+) -> Option<(Vec<LocalDefId>, Vec<Lifetime>)> {
// There are two scenarios where elision works:
// * no output references, all input references have different LT
// * output references, exactly one input reference with same LT
@@ -251,7 +334,7 @@ fn could_use_elision<'tcx>(
// level of the current item.
// check named LTs
- let allowed_lts = allowed_lts_from(cx.tcx, named_generics);
+ let allowed_lts = allowed_lts_from(named_generics);
// these will collect all the lifetimes for references in arg/return types
let mut input_visitor = RefVisitor::new(cx);
@@ -301,32 +384,24 @@ fn could_use_elision<'tcx>(
// check for lifetimes from higher scopes
for lt in input_lts.iter().chain(output_lts.iter()) {
- if !allowed_lts.contains(lt) {
+ if let Some(id) = named_lifetime(lt)
+ && !allowed_lts.contains(&id)
+ {
return None;
}
}
// check for higher-ranked trait bounds
if !input_visitor.nested_elision_site_lts.is_empty() || !output_visitor.nested_elision_site_lts.is_empty() {
- let allowed_lts: FxHashSet<_> = allowed_lts
- .iter()
- .filter_map(|lt| match lt {
- RefLt::Named(def_id) => Some(cx.tcx.item_name(def_id.to_def_id())),
- _ => None,
- })
- .collect();
+ let allowed_lts: FxHashSet<_> = allowed_lts.iter().map(|id| cx.tcx.item_name(id.to_def_id())).collect();
for lt in input_visitor.nested_elision_site_lts {
- if let RefLt::Named(def_id) = lt {
- if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
- return None;
- }
+ if allowed_lts.contains(&lt.ident.name) {
+ return None;
}
}
for lt in output_visitor.nested_elision_site_lts {
- if let RefLt::Named(def_id) = lt {
- if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
- return None;
- }
+ if allowed_lts.contains(&lt.ident.name) {
+ return None;
}
}
}
@@ -338,15 +413,10 @@ fn could_use_elision<'tcx>(
let elidable_lts = named_lifetime_occurrences(&input_lts)
.into_iter()
.filter_map(|(def_id, occurrences)| {
- if occurrences == 1 && (input_lts.len() == 1 || !output_lts.contains(&RefLt::Named(def_id))) {
- Some((
- def_id,
- input_visitor
- .lifetime_generic_arg_spans
- .get(&def_id)
- .or_else(|| output_visitor.lifetime_generic_arg_spans.get(&def_id))
- .copied(),
- ))
+ if occurrences == 1
+ && (input_lts.len() == 1 || !output_lts.iter().any(|lt| named_lifetime(lt) == Some(def_id)))
+ {
+ Some(def_id)
} else {
None
}
@@ -354,31 +424,34 @@ fn could_use_elision<'tcx>(
.collect::<Vec<_>>();
if elidable_lts.is_empty() {
- None
- } else {
- Some(elidable_lts)
+ return None;
}
+
+ let usages = itertools::chain(input_lts, output_lts).collect();
+
+ Some((elidable_lts, usages))
}
-fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
- let mut allowed_lts = FxHashSet::default();
- for par in named_generics.iter() {
- if let GenericParamKind::Lifetime { .. } = par.kind {
- allowed_lts.insert(RefLt::Named(tcx.hir().local_def_id(par.hir_id)));
- }
- }
- allowed_lts.insert(RefLt::Unnamed);
- allowed_lts.insert(RefLt::Static);
- allowed_lts
+fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<LocalDefId> {
+ named_generics
+ .iter()
+ .filter_map(|par| {
+ if let GenericParamKind::Lifetime { .. } = par.kind {
+ Some(par.def_id)
+ } else {
+ None
+ }
+ })
+ .collect()
}
/// Number of times each named lifetime occurs in the given slice. Returns a vector to preserve
/// relative order.
#[must_use]
-fn named_lifetime_occurrences(lts: &[RefLt]) -> Vec<(LocalDefId, usize)> {
+fn named_lifetime_occurrences(lts: &[Lifetime]) -> Vec<(LocalDefId, usize)> {
let mut occurrences = Vec::new();
for lt in lts {
- if let &RefLt::Named(curr_def_id) = lt {
+ if let Some(curr_def_id) = named_lifetime(lt) {
if let Some(pair) = occurrences
.iter_mut()
.find(|(prev_def_id, _)| *prev_def_id == curr_def_id)
@@ -392,12 +465,10 @@ fn named_lifetime_occurrences(lts: &[RefLt]) -> Vec<(LocalDefId, usize)> {
occurrences
}
-/// A visitor usable for `rustc_front::visit::walk_ty()`.
struct RefVisitor<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
- lts: Vec<RefLt>,
- lifetime_generic_arg_spans: FxHashMap<LocalDefId, Span>,
- nested_elision_site_lts: Vec<RefLt>,
+ lts: Vec<Lifetime>,
+ nested_elision_site_lts: Vec<Lifetime>,
unelided_trait_object_lifetime: bool,
}
@@ -406,32 +477,16 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
Self {
cx,
lts: Vec::new(),
- lifetime_generic_arg_spans: FxHashMap::default(),
nested_elision_site_lts: Vec::new(),
unelided_trait_object_lifetime: false,
}
}
- fn record(&mut self, lifetime: &Option<Lifetime>) {
- if let Some(ref lt) = *lifetime {
- if lt.is_static() {
- self.lts.push(RefLt::Static);
- } else if lt.is_anonymous() {
- // Fresh lifetimes generated should be ignored.
- self.lts.push(RefLt::Unnamed);
- } else if let LifetimeName::Param(def_id) = lt.res {
- self.lts.push(RefLt::Named(def_id));
- }
- } else {
- self.lts.push(RefLt::Unnamed);
- }
- }
-
- fn all_lts(&self) -> Vec<RefLt> {
+ fn all_lts(&self) -> Vec<Lifetime> {
self.lts
.iter()
.chain(self.nested_elision_site_lts.iter())
- .cloned()
+ .copied()
.collect::<Vec<_>>()
}
@@ -443,7 +498,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
// for lifetimes as parameters of generics
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
- self.record(&Some(*lifetime));
+ self.lts.push(*lifetime);
}
fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>) {
@@ -468,11 +523,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
walk_item(self, item);
self.lts.truncate(len);
self.lts.extend(bounds.iter().filter_map(|bound| match bound {
- GenericArg::Lifetime(l) => Some(if let LifetimeName::Param(def_id) = l.res {
- RefLt::Named(def_id)
- } else {
- RefLt::Unnamed
- }),
+ GenericArg::Lifetime(&l) => Some(l),
_ => None,
}));
},
@@ -492,13 +543,6 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
_ => walk_ty(self, ty),
}
}
-
- fn visit_generic_arg(&mut self, generic_arg: &'tcx GenericArg<'tcx>) {
- if let GenericArg::Lifetime(l) = generic_arg && let LifetimeName::Param(def_id) = l.res {
- self.lifetime_generic_arg_spans.entry(def_id).or_insert(l.ident.span);
- }
- walk_generic_arg(self, generic_arg);
- }
}
/// Are any lifetimes mentioned in the `where` clause? If so, we don't try to
@@ -516,14 +560,18 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
return true;
}
// if the bounds define new lifetimes, they are fine to occur
- let allowed_lts = allowed_lts_from(cx.tcx, pred.bound_generic_params);
+ let allowed_lts = allowed_lts_from(pred.bound_generic_params);
// now walk the bounds
for bound in pred.bounds.iter() {
walk_param_bound(&mut visitor, bound);
}
// and check that all lifetimes are allowed
- if visitor.all_lts().iter().any(|it| !allowed_lts.contains(it)) {
- return true;
+ for lt in visitor.all_lts() {
+ if let Some(id) = named_lifetime(&lt)
+ && !allowed_lts.contains(&id)
+ {
+ return true;
+ }
}
},
WherePredicate::EqPredicate(ref pred) => {
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index 3a7b7835c..dadcd9c51 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -210,7 +210,7 @@ impl WarningType {
cx,
UNUSUAL_BYTE_GROUPINGS,
span,
- "digits of hex or binary literal not grouped by four",
+ "digits of hex, binary or octal literal not in groups of equal size",
"consider",
suggested_format,
Applicability::MachineApplicable,
@@ -427,8 +427,12 @@ impl LiteralDigitGrouping {
let first = groups.next().expect("At least one group");
- if (radix == Radix::Binary || radix == Radix::Hexadecimal) && groups.any(|i| i != 4 && i != 2) {
- return Err(WarningType::UnusualByteGroupings);
+ if radix == Radix::Binary || radix == Radix::Octal || radix == Radix::Hexadecimal {
+ if let Some(second_size) = groups.next() {
+ if !groups.all(|i| i == second_size) || first > second_size {
+ return Err(WarningType::UnusualByteGroupings);
+ }
+ }
}
if let Some(second) = groups.next() {
@@ -484,7 +488,7 @@ impl DecimalLiteralRepresentation {
then {
let hex = format!("{val:#X}");
let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
- let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| {
+ let _: Result<(), ()> = Self::do_lint(num_lit.integer).map_err(|warning_type| {
warning_type.display(num_lit.format(), cx, span);
});
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index b1f294162..151c7f1d5 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -68,7 +68,7 @@ fn is_iterable_array<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
// IntoIterator is currently only implemented for array sizes <= 32 in rustc
match ty.kind() {
ty::Array(_, n) => n
- .try_eval_usize(cx.tcx, cx.param_env)
+ .try_eval_target_usize(cx.tcx, cx.param_env)
.map_or(false, |val| (0..=32).contains(&val)),
_ => false,
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 8e52cac43..610a0233e 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -61,7 +61,8 @@ declare_clippy_lint! {
///
/// ### Why is this bad?
/// Just iterating the collection itself makes the intent
- /// more clear and is probably faster.
+ /// more clear and is probably faster because it eliminates
+ /// the bounds check that is done when indexing.
///
/// ### Example
/// ```rust
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 3bca93d80..5c317c2a5 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -149,7 +149,7 @@ pub(super) fn check<'tcx>(
|diag| {
multispan_sugg(
diag,
- "consider using an iterator",
+ "consider using an iterator and enumerate()",
vec![
(pat.span, format!("({}, <item>)", ident.name)),
(
@@ -211,7 +211,7 @@ fn is_end_eq_array_len<'tcx>(
if let ExprKind::Lit(ref lit) = end.kind;
if let ast::LitKind::Int(end_int, _) = lit.node;
if let ty::Array(_, arr_len_const) = indexed_ty.kind();
- if let Some(arr_len) = arr_len_const.try_eval_usize(cx.tcx, cx.param_env);
+ if let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env);
then {
return match limits {
ast::RangeLimits::Closed => end_int + 1 >= arr_len.into(),
@@ -370,7 +370,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
ExprKind::MethodCall(_, receiver, args, _) => {
let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
for (ty, expr) in iter::zip(
- self.cx.tcx.fn_sig(def_id).inputs().skip_binder(),
+ self.cx.tcx.fn_sig(def_id).subst_identity().inputs().skip_binder(),
std::iter::once(receiver).chain(args.iter()),
) {
self.prefer_mutable = false;
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 14f161f51..b1bc10802 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -39,6 +39,7 @@ pub(super) fn check(
});
},
NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
+ NeverLoopResult::IgnoreUntilEnd(_) => unreachable!(),
}
}
@@ -48,6 +49,8 @@ enum NeverLoopResult {
AlwaysBreak,
// A continue may occur for the main loop.
MayContinueMainLoop,
+ // Ignore everything until the end of the block with this id
+ IgnoreUntilEnd(HirId),
Otherwise,
}
@@ -56,6 +59,7 @@ fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
match arg {
NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
+ NeverLoopResult::IgnoreUntilEnd(id) => NeverLoopResult::IgnoreUntilEnd(id),
}
}
@@ -63,27 +67,26 @@ fn absorb_break(arg: NeverLoopResult) -> NeverLoopResult {
#[must_use]
fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResult {
match first {
- NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop => first,
- NeverLoopResult::Otherwise => second,
- }
-}
-
-// Combine two results where both parts are called but not necessarily in order.
-#[must_use]
-fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResult {
- match (left, right) {
- (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
- NeverLoopResult::MayContinueMainLoop
+ NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop | NeverLoopResult::IgnoreUntilEnd(_) => {
+ first
},
- (NeverLoopResult::AlwaysBreak, _) | (_, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
- (NeverLoopResult::Otherwise, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise,
+ NeverLoopResult::Otherwise => second,
}
}
// Combine two results where only one of the part may have been executed.
#[must_use]
-fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult {
+fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult, ignore_ids: &[HirId]) -> NeverLoopResult {
match (b1, b2) {
+ (NeverLoopResult::IgnoreUntilEnd(a), NeverLoopResult::IgnoreUntilEnd(b)) => {
+ if ignore_ids.iter().find(|&e| e == &a || e == &b).unwrap() == &a {
+ NeverLoopResult::IgnoreUntilEnd(b)
+ } else {
+ NeverLoopResult::IgnoreUntilEnd(a)
+ }
+ },
+ (i @ NeverLoopResult::IgnoreUntilEnd(_), NeverLoopResult::AlwaysBreak)
+ | (NeverLoopResult::AlwaysBreak, i @ NeverLoopResult::IgnoreUntilEnd(_)) => i,
(NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
NeverLoopResult::MayContinueMainLoop
@@ -103,7 +106,7 @@ fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id
let e = never_loop_expr(e, ignore_ids, main_loop_id);
// els is an else block in a let...else binding
els.map_or(e, |els| {
- combine_branches(e, never_loop_block(els, ignore_ids, main_loop_id))
+ combine_branches(e, never_loop_block(els, ignore_ids, main_loop_id), ignore_ids)
})
})
.fold(NeverLoopResult::Otherwise, combine_seq)
@@ -139,7 +142,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
ExprKind::Struct(_, fields, base) => {
let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id);
if let Some(base) = base {
- combine_both(fields, never_loop_expr(base, ignore_ids, main_loop_id))
+ combine_seq(fields, never_loop_expr(base, ignore_ids, main_loop_id))
} else {
fields
}
@@ -159,7 +162,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| {
never_loop_expr(e, ignore_ids, main_loop_id)
});
- combine_seq(e1, combine_branches(e2, e3))
+ combine_seq(e1, combine_branches(e2, e3, ignore_ids))
},
ExprKind::Match(e, arms, _) => {
let e = never_loop_expr(e, ignore_ids, main_loop_id);
@@ -175,8 +178,13 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
ignore_ids.push(b.hir_id);
}
let ret = never_loop_block(b, ignore_ids, main_loop_id);
- ignore_ids.pop();
- ret
+ if l.is_some() {
+ ignore_ids.pop();
+ }
+ match ret {
+ NeverLoopResult::IgnoreUntilEnd(a) if a == b.hir_id => NeverLoopResult::Otherwise,
+ _ => ret,
+ }
},
ExprKind::Continue(d) => {
let id = d
@@ -190,8 +198,8 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
},
// checks if break targets a block instead of a loop
ExprKind::Break(Destination { target_id: Ok(t), .. }, e) if ignore_ids.contains(&t) => e
- .map_or(NeverLoopResult::Otherwise, |e| {
- combine_seq(never_loop_expr(e, ignore_ids, main_loop_id), NeverLoopResult::Otherwise)
+ .map_or(NeverLoopResult::IgnoreUntilEnd(t), |e| {
+ never_loop_expr(e, ignore_ids, main_loop_id)
}),
ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
combine_seq(
@@ -218,13 +226,13 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
| InlineAsmOperand::SymFn { .. }
| InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise,
})
- .fold(NeverLoopResult::Otherwise, combine_both),
+ .fold(NeverLoopResult::Otherwise, combine_seq),
ExprKind::Yield(_, _)
| ExprKind::Closure { .. }
| ExprKind::Path(_)
| ExprKind::ConstBlock(_)
| ExprKind::Lit(_)
- | ExprKind::Err => NeverLoopResult::Otherwise,
+ | ExprKind::Err(_) => NeverLoopResult::Otherwise,
}
}
@@ -234,7 +242,7 @@ fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr<'a>>>(
main_loop_id: HirId,
) -> NeverLoopResult {
es.map(|e| never_loop_expr(e, ignore_ids, main_loop_id))
- .fold(NeverLoopResult::Otherwise, combine_both)
+ .fold(NeverLoopResult::Otherwise, combine_seq)
}
fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
@@ -242,8 +250,9 @@ fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
ignore_ids: &mut Vec<HirId>,
main_loop_id: HirId,
) -> NeverLoopResult {
- e.map(|e| never_loop_expr(e, ignore_ids, main_loop_id))
- .fold(NeverLoopResult::AlwaysBreak, combine_branches)
+ e.fold(NeverLoopResult::AlwaysBreak, |a, b| {
+ combine_branches(a, never_loop_expr(b, ignore_ids, main_loop_id), ignore_ids)
+ })
}
fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) -> String {
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index 4277455a3..ce5d657bc 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -1,7 +1,6 @@
use crate::rustc_lint::LintContext;
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::macros::{root_macro_call, FormatArgsExpn};
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::macros::root_macro_call;
use clippy_utils::{is_else_clause, peel_blocks_with_stmt, span_extract_comment, sugg};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, UnOp};
@@ -38,57 +37,57 @@ declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]);
impl<'tcx> LateLintPass<'tcx> for ManualAssert {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
- if_chain! {
- if let ExprKind::If(cond, then, None) = expr.kind;
- if !matches!(cond.kind, ExprKind::Let(_));
- if !expr.span.from_expansion();
- let then = peel_blocks_with_stmt(then);
- if let Some(macro_call) = root_macro_call(then.span);
- if cx.tcx.item_name(macro_call.def_id) == sym::panic;
- if !cx.tcx.sess.source_map().is_multiline(cond.span);
- if let Some(format_args) = FormatArgsExpn::find_nested(cx, then, macro_call.expn);
+ if let ExprKind::If(cond, then, None) = expr.kind
+ && !matches!(cond.kind, ExprKind::Let(_))
+ && !expr.span.from_expansion()
+ && let then = peel_blocks_with_stmt(then)
+ && let Some(macro_call) = root_macro_call(then.span)
+ && cx.tcx.item_name(macro_call.def_id) == sym::panic
+ && !cx.tcx.sess.source_map().is_multiline(cond.span)
+ && let Ok(panic_snippet) = cx.sess().source_map().span_to_snippet(macro_call.span)
+ && let Some(panic_snippet) = panic_snippet.strip_suffix(')')
+ && let Some((_, format_args_snip)) = panic_snippet.split_once('(')
// Don't change `else if foo { panic!(..) }` to `else { assert!(foo, ..) }` as it just
// shuffles the condition around.
// Should this have a config value?
- if !is_else_clause(cx.tcx, expr);
- then {
- let mut applicability = Applicability::MachineApplicable;
- let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability);
- let cond = cond.peel_drop_temps();
- let mut comments = span_extract_comment(cx.sess().source_map(), expr.span);
- if !comments.is_empty() {
- comments += "\n";
- }
- let (cond, not) = match cond.kind {
- ExprKind::Unary(UnOp::Not, e) => (e, ""),
- _ => (cond, "!"),
- };
- let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
- let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
- // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block
- span_lint_and_then(
- cx,
- MANUAL_ASSERT,
- expr.span,
- "only a `panic!` in `if`-then statement",
- |diag| {
- // comments can be noisy, do not show them to the user
- if !comments.is_empty() {
- diag.tool_only_span_suggestion(
- expr.span.shrink_to_lo(),
- "add comments back",
- comments,
- applicability);
- }
- diag.span_suggestion(
- expr.span,
- "try instead",
- sugg,
- applicability);
- }
-
- );
+ && !is_else_clause(cx.tcx, expr)
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let cond = cond.peel_drop_temps();
+ let mut comments = span_extract_comment(cx.sess().source_map(), expr.span);
+ if !comments.is_empty() {
+ comments += "\n";
}
+ let (cond, not) = match cond.kind {
+ ExprKind::Unary(UnOp::Not, e) => (e, ""),
+ _ => (cond, "!"),
+ };
+ let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
+ let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
+ // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block
+ span_lint_and_then(
+ cx,
+ MANUAL_ASSERT,
+ expr.span,
+ "only a `panic!` in `if`-then statement",
+ |diag| {
+ // comments can be noisy, do not show them to the user
+ if !comments.is_empty() {
+ diag.tool_only_span_suggestion(
+ expr.span.shrink_to_lo(),
+ "add comments back",
+ comments,
+ applicability
+ );
+ }
+ diag.span_suggestion(
+ expr.span,
+ "try instead",
+ sugg,
+ applicability
+ );
+ }
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 63212beaa..3778eb4c7 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -6,10 +6,11 @@ use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound,
- HirId, ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
+ ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span};
declare_clippy_lint! {
@@ -45,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
decl: &'tcx FnDecl<'_>,
body: &'tcx Body<'_>,
span: Span,
- _: HirId,
+ _: LocalDefId,
) {
if_chain! {
if let Some(header) = kind.header();
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index d9ef7dffa..2fd32c009 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -43,7 +43,7 @@ declare_clippy_lint! {
/// 'A'.is_ascii_uppercase();
/// }
/// ```
- #[clippy::version = "1.66.0"]
+ #[clippy::version = "1.67.0"]
pub MANUAL_IS_ASCII_CHECK,
style,
"use dedicated method to check ascii range"
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 9c6f8b43c..98e698c6c 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -4,11 +4,12 @@ use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::peel_blocks;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::visitors::{for_each_expr, Descend};
+use clippy_utils::visitors::{Descend, Visitable};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::intravisit::{walk_expr, Visitor};
+use rustc_hir::{Expr, ExprKind, HirId, ItemId, Local, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind, Ty};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -115,6 +116,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
.enumerate()
.find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types));
let Some((idx, diverging_arm)) = diverging_arm_opt else { return; };
+ // If the non-diverging arm is the first one, its pattern can be reused in a let/else statement.
+ // However, if it arrives in second position, its pattern may cover some cases already covered
+ // by the diverging one.
+ // TODO: accept the non-diverging arm as a second position if patterns are disjointed.
+ if idx == 0 {
+ return;
+ }
let pat_arm = &arms[1 - idx];
if !expr_is_simple_identity(pat_arm.pat, pat_arm.body) {
return;
@@ -162,61 +170,102 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat:
);
}
-fn expr_diverges(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
- fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
- if let Some(ty) = cx.typeck_results().expr_ty_opt(expr) {
- return ty.is_never();
- }
- false
+/// Check whether an expression is divergent. May give false negatives.
+fn expr_diverges(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ struct V<'cx, 'tcx> {
+ cx: &'cx LateContext<'tcx>,
+ res: ControlFlow<(), Descend>,
}
- // We can't just call is_never on expr and be done, because the type system
- // sometimes coerces the ! type to something different before we can get
- // our hands on it. So instead, we do a manual search. We do fall back to
- // is_never in some places when there is no better alternative.
- for_each_expr(expr, |ex| {
- match ex.kind {
- ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => ControlFlow::Break(()),
- ExprKind::Call(call, _) => {
- if is_never(cx, ex) || is_never(cx, call) {
- return ControlFlow::Break(());
- }
- ControlFlow::Continue(Descend::Yes)
- },
- ExprKind::MethodCall(..) => {
- if is_never(cx, ex) {
- return ControlFlow::Break(());
- }
- ControlFlow::Continue(Descend::Yes)
- },
- ExprKind::If(if_expr, if_then, if_else) => {
- let else_diverges = if_else.map_or(false, |ex| expr_diverges(cx, ex));
- let diverges = expr_diverges(cx, if_expr) || (else_diverges && expr_diverges(cx, if_then));
- if diverges {
- return ControlFlow::Break(());
+ impl<'tcx> Visitor<'tcx> for V<'_, '_> {
+ fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
+ fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
+ if let Some(ty) = cx.typeck_results().expr_ty_opt(expr) {
+ return ty.is_never();
}
- ControlFlow::Continue(Descend::No)
- },
- ExprKind::Match(match_expr, match_arms, _) => {
- let diverges = expr_diverges(cx, match_expr)
- || match_arms.iter().all(|arm| {
- let guard_diverges = arm.guard.as_ref().map_or(false, |g| expr_diverges(cx, g.body()));
- guard_diverges || expr_diverges(cx, arm.body)
- });
- if diverges {
- return ControlFlow::Break(());
- }
- ControlFlow::Continue(Descend::No)
- },
+ false
+ }
- // Don't continue into loops or labeled blocks, as they are breakable,
- // and we'd have to start checking labels.
- ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => ControlFlow::Continue(Descend::No),
+ if self.res.is_break() {
+ return;
+ }
- // Default: descend
- _ => ControlFlow::Continue(Descend::Yes),
+ // We can't just call is_never on expr and be done, because the type system
+ // sometimes coerces the ! type to something different before we can get
+ // our hands on it. So instead, we do a manual search. We do fall back to
+ // is_never in some places when there is no better alternative.
+ self.res = match e.kind {
+ ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => ControlFlow::Break(()),
+ ExprKind::Call(call, _) => {
+ if is_never(self.cx, e) || is_never(self.cx, call) {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(Descend::Yes)
+ }
+ },
+ ExprKind::MethodCall(..) => {
+ if is_never(self.cx, e) {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(Descend::Yes)
+ }
+ },
+ ExprKind::If(if_expr, if_then, if_else) => {
+ let else_diverges = if_else.map_or(false, |ex| expr_diverges(self.cx, ex));
+ let diverges =
+ expr_diverges(self.cx, if_expr) || (else_diverges && expr_diverges(self.cx, if_then));
+ if diverges {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(Descend::No)
+ }
+ },
+ ExprKind::Match(match_expr, match_arms, _) => {
+ let diverges = expr_diverges(self.cx, match_expr)
+ || match_arms.iter().all(|arm| {
+ let guard_diverges = arm.guard.as_ref().map_or(false, |g| expr_diverges(self.cx, g.body()));
+ guard_diverges || expr_diverges(self.cx, arm.body)
+ });
+ if diverges {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(Descend::No)
+ }
+ },
+
+ // Don't continue into loops or labeled blocks, as they are breakable,
+ // and we'd have to start checking labels.
+ ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => ControlFlow::Continue(Descend::No),
+
+ // Default: descend
+ _ => ControlFlow::Continue(Descend::Yes),
+ };
+ if let ControlFlow::Continue(Descend::Yes) = self.res {
+ walk_expr(self, e);
+ }
+ }
+
+ fn visit_local(&mut self, local: &'tcx Local<'_>) {
+ // Don't visit the else block of a let/else statement as it will not make
+ // the statement divergent even though the else block is divergent.
+ if let Some(init) = local.init {
+ self.visit_expr(init);
+ }
}
- })
- .is_some()
+
+ // Avoid unnecessary `walk_*` calls.
+ fn visit_ty(&mut self, _: &'tcx Ty<'tcx>) {}
+ fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {}
+ fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {}
+ // Avoid monomorphising all `visit_*` functions.
+ fn visit_nested_item(&mut self, _: ItemId) {}
+ }
+
+ let mut v = V {
+ cx,
+ res: ControlFlow::Continue(Descend::Yes),
+ };
+ expr.visit(&mut v);
+ v.res.is_break()
}
fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: bool) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index bca193be9..9a84068d4 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -157,11 +157,10 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
&& def.variants.len() > 1
{
let mut iter = def.variants.iter().filter_map(|v| {
- let id = cx.tcx.hir().local_def_id(v.hir_id);
- (matches!(v.data, hir::VariantData::Unit(..))
+ (matches!(v.data, hir::VariantData::Unit(_, _))
&& v.ident.as_str().starts_with('_')
&& is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)))
- .then_some((id, v.span))
+ .then_some((v.def_id, v.span))
});
if let Some((id, span)) = iter.next()
&& iter.next().is_none()
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index 59195d1ae..edcab6968 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -104,7 +104,7 @@ fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
let ty = cx.typeck_results().expr_ty(expr);
if let ty::FnDef(id, _) = *ty.kind() {
- if let Some(fn_type) = cx.tcx.fn_sig(id).no_bound_vars() {
+ if let Some(fn_type) = cx.tcx.fn_sig(id).subst_identity().no_bound_vars() {
return is_unit_type(fn_type.output());
}
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index 59de8c038..3126b5901 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -45,8 +45,13 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
// Accumulate the variants which should be put in place of the wildcard because they're not
// already covered.
- let has_hidden = adt_def.variants().iter().any(|x| is_hidden(cx, x));
- let mut missing_variants: Vec<_> = adt_def.variants().iter().filter(|x| !is_hidden(cx, x)).collect();
+ let is_external = adt_def.did().as_local().is_none();
+ let has_external_hidden = is_external && adt_def.variants().iter().any(|x| is_hidden(cx, x));
+ let mut missing_variants: Vec<_> = adt_def
+ .variants()
+ .iter()
+ .filter(|x| !(is_external && is_hidden(cx, x)))
+ .collect();
let mut path_prefix = CommonPrefixSearcher::None;
for arm in arms {
@@ -133,7 +138,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
match missing_variants.as_slice() {
[] => (),
- [x] if !adt_def.is_variant_list_non_exhaustive() && !has_hidden => span_lint_and_sugg(
+ [x] if !adt_def.is_variant_list_non_exhaustive() && !has_external_hidden => span_lint_and_sugg(
cx,
MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
wildcard_span,
@@ -144,7 +149,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
),
variants => {
let mut suggestions: Vec<_> = variants.iter().copied().map(format_suggestion).collect();
- let message = if adt_def.is_variant_list_non_exhaustive() || has_hidden {
+ let message = if adt_def.is_variant_list_non_exhaustive() || has_external_hidden {
suggestions.push("_".into());
"wildcard matches known variants and will also match future added variants"
} else {
diff --git a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
index 0aadb482a..d06bcdaa2 100644
--- a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
@@ -10,7 +10,7 @@ pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) {
if !pat.span.from_expansion();
if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind;
if let Some(def_id) = path.res.opt_def_id();
- let ty = cx.tcx.type_of(def_id);
+ let ty = cx.tcx.type_of(def_id).subst_identity();
if let ty::Adt(def, _) = ty.kind();
if def.is_struct() || def.is_union();
if fields.len() == def.non_enum_variant().fields.len();
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index f587c69f7..b33a24781 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -341,7 +341,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
ExprKind::ConstBlock(_) |
ExprKind::Continue(_) |
ExprKind::DropTemps(_) |
- ExprKind::Err |
+ ExprKind::Err(_) |
ExprKind::InlineAsm(_) |
ExprKind::Let(_) |
ExprKind::Lit(_) |
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
index 89aaad359..46a20ad41 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
@@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(
if_chain! {
if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id);
- if cx.tcx.type_of(impl_id).is_str();
+ if cx.tcx.type_of(impl_id).subst_identity().is_str();
let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs();
if ty.is_str() || is_type_lang_item(cx, ty, hir::LangItem::String);
then {
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
index d512cc4ee..c5fc145b2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
@@ -5,6 +5,8 @@ use rustc_errors::Applicability;
use rustc_hir::{Expr, LangItem};
use rustc_lint::LateContext;
+use crate::methods::method_call;
+
use super::BYTES_NTH;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, n_arg: &'tcx Expr<'tcx>) {
@@ -16,18 +18,32 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
} else {
return;
};
+
let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- BYTES_NTH,
- expr.span,
- &format!("called `.bytes().nth()` on a `{caller_type}`"),
- "try",
- format!(
- "{}.as_bytes().get({})",
- snippet_with_applicability(cx, recv.span, "..", &mut applicability),
- snippet_with_applicability(cx, n_arg.span, "..", &mut applicability)
- ),
- applicability,
- );
+ let receiver = snippet_with_applicability(cx, recv.span, "..", &mut applicability);
+ let n = snippet_with_applicability(cx, n_arg.span, "..", &mut applicability);
+
+ if let Some(parent) = clippy_utils::get_parent_expr(cx, expr)
+ && let Some((name, _, _, _, _)) = method_call(parent)
+ && name == "unwrap" {
+ span_lint_and_sugg(
+ cx,
+ BYTES_NTH,
+ parent.span,
+ &format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"),
+ "try",
+ format!("{receiver}.as_bytes()[{n}]",),
+ applicability
+ );
+ } else {
+ span_lint_and_sugg(
+ cx,
+ BYTES_NTH,
+ expr.span,
+ &format!("called `.bytes().nth()` on a `{caller_type}`"),
+ "try",
+ format!("{receiver}.as_bytes().get({n}).copied()"),
+ applicability
+ );
+ };
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
index 0b3bf2274..7711aa78b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
if_chain! {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- if cx.tcx.type_of(impl_id).is_str();
+ if cx.tcx.type_of(impl_id).subst_identity().is_str();
if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind;
if (2..=6).contains(&ext_literal.as_str().len());
let ext_str = ext_literal.as_str();
diff --git a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
index ac61b4377..5e01ed90f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
@@ -54,7 +54,7 @@ fn collect_replace_calls<'tcx>(
from_args.push_front(from);
ControlFlow::Continue(())
} else {
- ControlFlow::BREAK
+ ControlFlow::Break(())
}
} else {
ControlFlow::Continue(())
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index a9189b31c..a22285058 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -33,7 +33,7 @@ pub(super) fn check<'tcx>(
if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && {
let arg_type = cx.typeck_results().expr_ty(receiver);
let base_type = arg_type.peel_refs();
- *base_type.kind() == ty::Str || is_type_lang_item(cx, base_type, hir::LangItem::String)
+ base_type.is_str() || is_type_lang_item(cx, base_type, hir::LangItem::String)
} {
receiver
} else {
@@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(
return false;
}
if let ty::Ref(_, ty, ..) = arg_ty.kind() {
- if *ty.kind() == ty::Str && can_be_static_str(cx, arg) {
+ if ty.is_str() && can_be_static_str(cx, arg) {
return false;
}
};
@@ -70,7 +70,7 @@ pub(super) fn check<'tcx>(
if let hir::ExprKind::Path(ref p) = fun.kind {
match cx.qpath_res(p, fun.hir_id) {
hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!(
- cx.tcx.fn_sig(def_id).output().skip_binder().kind(),
+ cx.tcx.fn_sig(def_id).subst_identity().output().skip_binder().kind(),
ty::Ref(re, ..) if re.is_static(),
),
_ => false,
@@ -84,7 +84,7 @@ pub(super) fn check<'tcx>(
.type_dependent_def_id(arg.hir_id)
.map_or(false, |method_id| {
matches!(
- cx.tcx.fn_sig(method_id).output().skip_binder().kind(),
+ cx.tcx.fn_sig(method_id).subst_identity().output().skip_binder().kind(),
ty::Ref(re, ..) if re.is_static()
)
})
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
index cce8f797e..614610335 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_in_cfg_test;
use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_in_cfg_test, is_in_test_function};
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::sym;
@@ -27,7 +27,7 @@ pub(super) fn check(
let method = if is_err { "expect_err" } else { "expect" };
- if allow_expect_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) {
+ if allow_expect_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
index cb17af608..945bbf53b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_first.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
@@ -19,7 +19,7 @@ pub(super) fn check<'tcx>(
if_chain! {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- if cx.tcx.type_of(impl_id).is_slice();
+ if cx.tcx.type_of(impl_id).subst_identity().is_slice();
if let Some(_) = is_slice_of_primitives(cx, recv);
if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind;
then {
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index 06ecbce4e..5a78a4168 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -53,7 +53,9 @@ pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir
"to_vec" => cx
.tcx
.impl_of_method(method_def_id)
- .filter(|&impl_did| cx.tcx.type_of(impl_did).is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none())
+ .filter(|&impl_did| {
+ cx.tcx.type_of(impl_did).subst_identity().is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none()
+ })
.is_some(),
_ => false,
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
index 5b758f1e6..b9a0ec779 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
@@ -21,7 +21,7 @@ pub(super) fn check<'tcx>(
if_chain! {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Option);
+ if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Option);
if let ExprKind::Call(err_path, [err_arg]) = or_expr.kind;
if is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr);
if is_ok_wrapping(cx, map_expr);
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
index 52cc1e046..2b26ef014 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_
if_chain! {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id);
if cx.tcx.impl_of_method(method_id)
- .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id), sym::Option))
+ .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id).subst_identity(), sym::Option))
|| is_diag_trait_item(cx, method_id, sym::Iterator);
if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind;
then {
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
index b773b3e42..a5beb291f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
@@ -9,7 +9,7 @@ use super::MAP_ERR_IGNORE;
pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
- && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Result)
+ && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Result)
&& let ExprKind::Closure(&Closure {
capture_clause: CaptureBy::Ref,
body,
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 77be61b47..702df4b28 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -80,6 +80,7 @@ mod skip_while_next;
mod stable_sort_primitive;
mod str_splitn;
mod string_extend_chars;
+mod suspicious_command_arg_space;
mod suspicious_map;
mod suspicious_splitn;
mod suspicious_to_owned;
@@ -1818,6 +1819,7 @@ declare_clippy_lint! {
/// - `or_else` to `or`
/// - `get_or_insert_with` to `get_or_insert`
/// - `ok_or_else` to `ok_or`
+ /// - `then` to `then_some` (for msrv >= 1.62.0)
///
/// ### Why is this bad?
/// Using eager evaluation is shorter and simpler in some cases.
@@ -3102,7 +3104,7 @@ declare_clippy_lint! {
/// Ok(())
/// }
/// ```
- #[clippy::version = "1.66.0"]
+ #[clippy::version = "1.67.0"]
pub SEEK_FROM_CURRENT,
complexity,
"use dedicated method for seek from current position"
@@ -3133,7 +3135,7 @@ declare_clippy_lint! {
/// t.rewind();
/// }
/// ```
- #[clippy::version = "1.66.0"]
+ #[clippy::version = "1.67.0"]
pub SEEK_TO_START_INSTEAD_OF_REWIND,
complexity,
"jumping to the start of stream using `seek` method"
@@ -3161,6 +3163,32 @@ declare_clippy_lint! {
"collecting an iterator when collect is not needed"
}
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// Checks for `Command::arg()` invocations that look like they
+ /// should be multiple arguments instead, such as `arg("-t ext2")`.
+ ///
+ /// ### Why is this bad?
+ ///
+ /// `Command::arg()` does not split arguments by space. An argument like `arg("-t ext2")`
+ /// will be passed as a single argument to the command,
+ /// which is likely not what was intended.
+ ///
+ /// ### Example
+ /// ```rust
+ /// std::process::Command::new("echo").arg("-n hello").spawn().unwrap();
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap();
+ /// ```
+ #[clippy::version = "1.67.0"]
+ pub SUSPICIOUS_COMMAND_ARG_SPACE,
+ suspicious,
+ "single command line argument that looks like it should be multiple arguments"
+}
+
pub struct Methods {
avoid_breaking_exported_api: bool,
msrv: Msrv,
@@ -3288,6 +3316,7 @@ impl_lint_pass!(Methods => [
SEEK_FROM_CURRENT,
SEEK_TO_START_INSTEAD_OF_REWIND,
NEEDLESS_COLLECT,
+ SUSPICIOUS_COMMAND_ARG_SPACE,
]);
/// Extracts a method call name, args, and `Span` of the method name.
@@ -3348,11 +3377,11 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
let name = impl_item.ident.name.as_str();
let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
let item = cx.tcx.hir().expect_item(parent);
- let self_ty = cx.tcx.type_of(item.owner_id);
+ let self_ty = cx.tcx.type_of(item.owner_id).subst_identity();
let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind {
- let method_sig = cx.tcx.fn_sig(impl_item.owner_id);
+ let method_sig = cx.tcx.fn_sig(impl_item.owner_id).subst_identity();
let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
let first_arg_ty_opt = method_sig.inputs().iter().next().copied();
// if this impl block implements a trait, lint in trait definition instead
@@ -3412,7 +3441,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
}
if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
- let ret_ty = return_ty(cx, impl_item.hir_id());
+ let ret_ty = return_ty(cx, impl_item.owner_id);
if contains_ty_adt_constructor_opaque(cx, ret_ty, self_ty) {
return;
@@ -3460,7 +3489,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
if_chain! {
if item.ident.name == sym::new;
if let TraitItemKind::Fn(_, _) = item.kind;
- let ret_ty = return_ty(cx, item.hir_id());
+ let ret_ty = return_ty(cx, item.owner_id);
let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
.self_ty()
.skip_binder();
@@ -3495,6 +3524,9 @@ impl Methods {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
}
},
+ ("arg", [arg]) => {
+ suspicious_command_arg_space::check(cx, recv, arg, span);
+ }
("as_deref" | "as_deref_mut", []) => {
needless_option_as_deref::check(cx, expr, recv, name);
},
diff --git a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
index b9593b368..d0aa39d06 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
@@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'
if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind();
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Mutex);
+ if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Mutex);
then {
span_lint_and_sugg(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index f4d3ef3b7..0b0c6adc5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -137,7 +137,7 @@ pub(super) fn check<'tcx>(
/// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool`
fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool {
cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| {
- let sig = cx.tcx.fn_sig(id).skip_binder();
+ let sig = cx.tcx.fn_sig(id).subst_identity().skip_binder();
sig.inputs().len() == 1 && sig.output().is_bool()
})
}
@@ -165,7 +165,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty:
fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -> bool {
let typeck = cx.typeck_results();
if let Some(id) = typeck.type_dependent_def_id(call_id)
- && let sig = cx.tcx.fn_sig(id)
+ && let sig = cx.tcx.fn_sig(id).subst_identity()
&& sig.skip_binder().output().is_bool()
&& let [_, search_ty] = *sig.skip_binder().inputs()
&& let ty::Ref(_, search_ty, Mutability::Not) = *cx.tcx.erase_late_bound_regions(sig.rebind(search_ty)).kind()
@@ -173,7 +173,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -
&& let Some(iter_item) = cx.tcx
.associated_items(iter_trait)
.find_by_name_and_kind(cx.tcx, Ident::with_dummy_span(Symbol::intern("Item")), AssocKind::Type, iter_trait)
- && let substs = cx.tcx.mk_substs([GenericArg::from(typeck.expr_ty_adjusted(iter_expr))].into_iter())
+ && let substs = cx.tcx.mk_substs(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))])
&& let proj_ty = cx.tcx.mk_projection(iter_item.def_id, substs)
&& let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty)
{
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index 597af853d..c6a27cdd6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -11,7 +11,7 @@ use super::NONSENSICAL_OPEN_OPTIONS;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
- && match_type(cx, cx.tcx.type_of(impl_id), &paths::OPEN_OPTIONS)
+ && match_type(cx, cx.tcx.type_of(impl_id).subst_identity(), &paths::OPEN_OPTIONS)
{
let mut options = Vec::new();
get_open_options(cx, recv, &mut options);
diff --git a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
index 0cc28c0dc..e3f2de3cd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
if_chain! {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::PathBuf);
+ if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::PathBuf);
if let ExprKind::Lit(ref lit) = arg.kind;
if let LitKind::Str(ref path_lit, _) = lit.node;
if let pushed_path = Path::new(path_lit.as_str());
diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
index 1c031ad6a..afdb8ce94 100644
--- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
@@ -8,7 +8,6 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::PatKind;
use rustc_lint::LateContext;
-use rustc_middle::ty;
use rustc_span::source_map::Span;
use rustc_span::symbol::sym;
@@ -108,7 +107,7 @@ pub(super) fn check<'tcx>(
if is_type_lang_item(cx, self_ty, hir::LangItem::String) {
true
} else {
- *self_ty.kind() == ty::Str
+ self_ty.is_str()
}
};
if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
index 4221c52d5..4d704ec39 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
@@ -47,7 +47,7 @@ pub(super) fn check(
for &(method, pos) in &PATTERN_METHODS {
if_chain! {
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind();
- if *ty.kind() == ty::Str;
+ if ty.is_str();
if method_name.as_str() == method && args.len() > pos;
let arg = &args[pos];
let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
index 09c8ca4cb..b5fd0ad8c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/stable_sort_primitive.rs
@@ -10,7 +10,7 @@ use super::STABLE_SORT_PRIMITIVE;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
- && cx.tcx.type_of(impl_id).is_slice()
+ && cx.tcx.type_of(impl_id).subst_identity().is_slice()
&& let Some(slice_type) = is_slice_of_primitives(cx, recv)
{
span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
index f35d81cee..2c20c6d75 100644
--- a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
@@ -5,7 +5,6 @@ use clippy_utils::ty::is_type_lang_item;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_middle::ty;
use super::STRING_EXTEND_CHARS;
@@ -17,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
if let Some(arglists) = method_chain_args(arg, &["chars"]) {
let target = &arglists[0].0;
let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
- let ref_str = if *self_ty.kind() == ty::Str {
+ let ref_str = if self_ty.is_str() {
if matches!(target.kind, hir::ExprKind::Index(..)) {
"&"
} else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs
new file mode 100644
index 000000000..73632c5a3
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs
@@ -0,0 +1,39 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::paths;
+use clippy_utils::ty::match_type;
+use rustc_ast as ast;
+use rustc_errors::{Applicability, Diagnostic};
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_span::Span;
+
+use super::SUSPICIOUS_COMMAND_ARG_SPACE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) {
+ let ty = cx.typeck_results().expr_ty(recv).peel_refs();
+
+ if match_type(cx, ty, &paths::STD_PROCESS_COMMAND)
+ && let hir::ExprKind::Lit(lit) = &arg.kind
+ && let ast::LitKind::Str(s, _) = &lit.node
+ && let Some((arg1, arg2)) = s.as_str().split_once(' ')
+ && arg1.starts_with('-')
+ && arg1.chars().all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
+ {
+ span_lint_and_then(
+ cx,
+ SUSPICIOUS_COMMAND_ARG_SPACE,
+ arg.span,
+ "single argument that looks like it should be multiple arguments",
+ |diag: &mut Diagnostic| {
+ diag.multipart_suggestion_verbose(
+ "consider splitting the argument",
+ vec![
+ (span, "args".to_string()),
+ (arg.span, format!("[{arg1:?}, {arg2:?}]")),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
index 2ac0786b3..0dc7fe2a2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
@@ -11,10 +11,8 @@ use super::SUSPICIOUS_MAP;
pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) {
if_chain! {
if is_trait_method(cx, count_recv, sym::Iterator);
- let closure = expr_or_init(cx, map_arg);
- if let Some(def_id) = cx.tcx.hir().opt_local_def_id(closure.hir_id);
- if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(def_id);
- let closure_body = cx.tcx.hir().body(body_id);
+ if let hir::ExprKind::Closure(closure) = expr_or_init(cx, map_arg).kind;
+ let closure_body = cx.tcx.hir().body(closure.body);
if !cx.typeck_results().expr_ty(closure_body.value).is_unit();
then {
if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
index 219a9edd6..90ca66bd7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
@@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(call_id);
if cx.tcx.impl_trait_ref(impl_id).is_none();
- let self_ty = cx.tcx.type_of(impl_id);
+ let self_ty = cx.tcx.type_of(impl_id).subst_identity();
if self_ty.is_slice() || self_ty.is_str();
then {
// Ignore empty slice and string literals when used with a literal count.
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
index fe88fa41f..e818f1892 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_diag_trait_item;
use clippy_utils::source::snippet_with_context;
use if_chain::if_chain;
@@ -17,19 +17,31 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -
let input_type = cx.typeck_results().expr_ty(expr);
if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind();
if cx.tcx.is_diagnostic_item(sym::Cow, adt.did());
+
then {
let mut app = Applicability::MaybeIncorrect;
let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
- span_lint_and_sugg(
+ span_lint_and_then(
cx,
SUSPICIOUS_TO_OWNED,
expr.span,
&with_forced_trimmed_paths!(format!(
"this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"
)),
- "consider using, depending on intent",
- format!("{recv_snip}.clone()` or `{recv_snip}.into_owned()"),
- app,
+ |diag| {
+ diag.span_suggestion(
+ expr.span,
+ "depending on intent, either make the Cow an Owned variant",
+ format!("{recv_snip}.into_owned()"),
+ app
+ );
+ diag.span_suggestion(
+ expr.span,
+ "or clone the Cow itself",
+ format!("{recv_snip}.clone()"),
+ app
+ );
+ }
);
return true;
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
index ed5a75b0f..5201da52b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -122,7 +122,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp
if_chain! {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- if cx.tcx.type_of(impl_id).is_slice();
+ if cx.tcx.type_of(impl_id).subst_identity().is_slice();
if let ExprKind::Closure(&Closure { body, .. }) = arg.kind;
if let closure_body = cx.tcx.hir().body(body);
if let &[
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 9263f0519..df26b36b7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -246,7 +246,7 @@ fn check_other_call_arg<'tcx>(
if_chain! {
if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
if let Some((callee_def_id, _, recv, call_args)) = get_callee_substs_and_args(cx, maybe_call);
- let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+ let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
if let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id);
if let Some(input) = fn_sig.inputs().get(i);
let (input, n_refs) = peel_mid_ty_refs(*input);
@@ -368,10 +368,9 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
Node::Block(..) => continue,
Node::Item(item) => {
if let ItemKind::Fn(_, _, body_id) = &item.kind
- && let output_ty = return_ty(cx, item.hir_id())
- && let local_def_id = cx.tcx.hir().local_def_id(item.hir_id())
- && Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
- let fn_ctxt = FnCtxt::new(inherited, cx.param_env, item.hir_id());
+ && let output_ty = return_ty(cx, item.owner_id)
+ && Inherited::build(cx.tcx, item.owner_id.def_id).enter(|inherited| {
+ let fn_ctxt = FnCtxt::new(inherited, cx.param_env, item.owner_id.def_id);
fn_ctxt.can_coerce(ty, output_ty)
}) {
if has_lifetime(output_ty) && has_lifetime(ty) {
@@ -386,7 +385,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
Node::Expr(parent_expr) => {
if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr)
{
- let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+ let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
&& let Some(param_ty) = fn_sig.inputs().get(arg_index)
&& let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind()
@@ -415,7 +414,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
}
});
- let new_subst = cx.tcx.mk_substs(
+ let new_subst = cx.tcx.mk_substs_from_iter(
call_substs.iter()
.enumerate()
.map(|(i, t)|
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
index 90983f249..5e4c3daee 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_in_cfg_test, is_lint_allowed};
+use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::sym;
@@ -27,7 +27,7 @@ pub(super) fn check(
let method_suffix = if is_err { "_err" } else { "" };
- if allow_unwrap_in_tests && is_in_cfg_test(cx.tcx, expr.hir_id) {
+ if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index ae6b165fd..c96d69226 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -22,7 +22,7 @@ pub(super) fn derefs_to_slice<'tcx>(
ty::Slice(_) => true,
ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::Vec),
- ty::Array(_, size) => size.try_eval_usize(cx.tcx, cx.param_env).is_some(),
+ ty::Array(_, size) => size.try_eval_target_usize(cx.tcx, cx.param_env).is_some(),
ty::Ref(_, inner, _) => may_slice(cx, *inner),
_ => false,
}
@@ -143,7 +143,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
if_chain! {
if args.iter().all(|arg| !self.is_binding(arg));
if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id);
- let method_ty = self.cx.tcx.type_of(method_def_id);
+ let method_ty = self.cx.tcx.type_of(method_def_id).subst_identity();
let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder();
if matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Not));
then {
diff --git a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
index 02d8364cb..b0cfc163f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
@@ -20,7 +20,7 @@ pub(super) fn check<'tcx>(
if_chain! {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Vec);
+ if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::Vec);
if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = count_arg.kind;
if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = default_arg.kind;
then {
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 9f4beb92b..0705029a6 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -4,12 +4,13 @@ use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
- self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind,
- Stmt, StmtKind, TyKind,
+ self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, Stmt,
+ StmtKind, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::source_map::{ExpnKind, Span};
@@ -151,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
decl: &'tcx FnDecl<'_>,
body: &'tcx Body<'_>,
span: Span,
- _: HirId,
+ _: LocalDefId,
) {
if let FnKind::Closure = k {
// Does not apply to closures
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index 5bc04bc17..87bd007a2 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -6,11 +6,12 @@ use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_ma
use rustc_hir as hir;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
+use rustc_hir::{Body, Constness, FnDecl, GenericParamKind};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
declare_clippy_lint! {
@@ -91,14 +92,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
_: &FnDecl<'_>,
body: &Body<'tcx>,
span: Span,
- hir_id: HirId,
+ def_id: LocalDefId,
) {
if !self.msrv.meets(msrvs::CONST_IF_MATCH) {
return;
}
- let def_id = cx.tcx.hir().local_def_id(hir_id);
-
if in_external_macro(cx.tcx.sess, span) || is_entrypoint_fn(cx, def_id.to_def_id()) {
return;
}
@@ -132,6 +131,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
FnKind::Closure => return,
}
+ let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
+
// Const fns are not allowed as methods in a trait.
{
let parent = cx.tcx.hir().get_parent_item(hir_id).def_id;
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 6fd100762..9659ca8ce 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -8,10 +8,12 @@
use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_from_proc_macro;
+use hir::def_id::LocalDefId;
+use if_chain::if_chain;
use rustc_ast::ast::{self, MetaItem, MetaItemKind};
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::DefIdTree;
+use rustc_middle::ty::{DefIdTree, Visibility};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::source_map::Span;
@@ -34,6 +36,9 @@ declare_clippy_lint! {
}
pub struct MissingDoc {
+ /// Whether to **only** check for missing documentation in items visible within the current
+ /// crate. For example, `pub(crate)` items.
+ crate_items_only: bool,
/// Stack of whether #[doc(hidden)] is set
/// at each level which has lint attributes.
doc_hidden_stack: Vec<bool>,
@@ -42,14 +47,15 @@ pub struct MissingDoc {
impl Default for MissingDoc {
#[must_use]
fn default() -> Self {
- Self::new()
+ Self::new(false)
}
}
impl MissingDoc {
#[must_use]
- pub fn new() -> Self {
+ pub fn new(crate_items_only: bool) -> Self {
Self {
+ crate_items_only,
doc_hidden_stack: vec![false],
}
}
@@ -75,6 +81,7 @@ impl MissingDoc {
fn check_missing_docs_attrs(
&self,
cx: &LateContext<'_>,
+ def_id: LocalDefId,
attrs: &[ast::Attribute],
sp: Span,
article: &'static str,
@@ -95,6 +102,13 @@ impl MissingDoc {
return;
}
+ if self.crate_items_only && def_id != CRATE_DEF_ID {
+ let vis = cx.tcx.visibility(def_id);
+ if vis == Visibility::Public || vis != Visibility::Restricted(CRATE_DEF_ID.into()) {
+ return;
+ }
+ }
+
let has_doc = attrs
.iter()
.any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
@@ -123,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
- self.check_missing_docs_attrs(cx, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate");
+ self.check_missing_docs_attrs(cx, CRATE_DEF_ID, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate");
}
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
@@ -159,7 +173,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
let attrs = cx.tcx.hir().attrs(it.hir_id());
if !is_from_proc_macro(cx, it) {
- self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
+ self.check_missing_docs_attrs(cx, it.owner_id.def_id, attrs, it.span, article, desc);
}
}
@@ -168,7 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
if !is_from_proc_macro(cx, trait_item) {
- self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
+ self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, attrs, trait_item.span, article, desc);
}
}
@@ -185,7 +199,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
if !is_from_proc_macro(cx, impl_item) {
- self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
+ self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, attrs, impl_item.span, article, desc);
}
}
@@ -193,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
if !sf.is_positional() {
let attrs = cx.tcx.hir().attrs(sf.hir_id);
if !is_from_proc_macro(cx, sf) {
- self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
+ self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field");
}
}
}
@@ -201,7 +215,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
let attrs = cx.tcx.hir().attrs(v.hir_id);
if !is_from_proc_macro(cx, v) {
- self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
+ self.check_missing_docs_attrs(cx, v.def_id, attrs, v.span, "a", "variant");
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
index 3371b4cce..e99081ad0 100644
--- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods {
"implement the method",
);
}
- })
+ });
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs
index 0742943df..349fcd227 100644
--- a/src/tools/clippy/clippy_lints/src/module_style.rs
+++ b/src/tools/clippy/clippy_lints/src/module_style.rs
@@ -134,7 +134,7 @@ fn process_paths_for_mod_files<'a>(
mod_folders: &mut FxHashSet<&'a OsStr>,
) {
let mut comp = path.components().rev().peekable();
- let _ = comp.next();
+ let _: Option<_> = comp.next();
if path.ends_with("mod.rs") {
mod_folders.insert(comp.peek().map(|c| c.as_os_str()).unwrap_or_default());
}
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
new file mode 100644
index 000000000..63c575fca
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -0,0 +1,186 @@
+use clippy_utils::{
+ diagnostics::span_lint_and_then,
+ visitors::{for_each_expr_with_closures, Descend, Visitable},
+};
+use core::ops::ControlFlow::Continue;
+use hir::{
+ def::{DefKind, Res},
+ BlockCheckMode, ExprKind, QPath, UnOp, Unsafety,
+};
+use rustc_ast::Mutability;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for `unsafe` blocks that contain more than one unsafe operation.
+ ///
+ /// ### Why is this bad?
+ /// Combined with `undocumented_unsafe_blocks`,
+ /// this lint ensures that each unsafe operation must be independently justified.
+ /// Combined with `unused_unsafe`, this lint also ensures
+ /// elimination of unnecessary unsafe blocks through refactoring.
+ ///
+ /// ### Example
+ /// ```rust
+ /// /// Reads a `char` from the given pointer.
+ /// ///
+ /// /// # Safety
+ /// ///
+ /// /// `ptr` must point to four consecutive, initialized bytes which
+ /// /// form a valid `char` when interpreted in the native byte order.
+ /// fn read_char(ptr: *const u8) -> char {
+ /// // SAFETY: The caller has guaranteed that the value pointed
+ /// // to by `bytes` is a valid `char`.
+ /// unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// /// Reads a `char` from the given pointer.
+ /// ///
+ /// /// # Safety
+ /// ///
+ /// /// - `ptr` must be 4-byte aligned, point to four consecutive
+ /// /// initialized bytes, and be valid for reads of 4 bytes.
+ /// /// - The bytes pointed to by `ptr` must represent a valid
+ /// /// `char` when interpreted in the native byte order.
+ /// fn read_char(ptr: *const u8) -> char {
+ /// // SAFETY: `ptr` is 4-byte aligned, points to four consecutive
+ /// // initialized bytes, and is valid for reads of 4 bytes.
+ /// let int_value = unsafe { *ptr.cast::<u32>() };
+ ///
+ /// // SAFETY: The caller has guaranteed that the four bytes
+ /// // pointed to by `bytes` represent a valid `char`.
+ /// unsafe { char::from_u32_unchecked(int_value) }
+ /// }
+ /// ```
+ #[clippy::version = "1.68.0"]
+ pub MULTIPLE_UNSAFE_OPS_PER_BLOCK,
+ restriction,
+ "more than one unsafe operation per `unsafe` block"
+}
+declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK]);
+
+impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock {
+ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
+ if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) || in_external_macro(cx.tcx.sess, block.span) {
+ return;
+ }
+ let mut unsafe_ops = vec![];
+ collect_unsafe_exprs(cx, block, &mut unsafe_ops);
+ if unsafe_ops.len() > 1 {
+ span_lint_and_then(
+ cx,
+ MULTIPLE_UNSAFE_OPS_PER_BLOCK,
+ block.span,
+ &format!(
+ "this `unsafe` block contains {} unsafe operations, expected only one",
+ unsafe_ops.len()
+ ),
+ |diag| {
+ for (msg, span) in unsafe_ops {
+ diag.span_note(span, msg);
+ }
+ },
+ );
+ }
+ }
+}
+
+fn collect_unsafe_exprs<'tcx>(
+ cx: &LateContext<'tcx>,
+ node: impl Visitable<'tcx>,
+ unsafe_ops: &mut Vec<(&'static str, Span)>,
+) {
+ for_each_expr_with_closures(cx, node, |expr| {
+ match expr.kind {
+ ExprKind::InlineAsm(_) => unsafe_ops.push(("inline assembly used here", expr.span)),
+
+ ExprKind::Field(e, _) => {
+ if cx.typeck_results().expr_ty(e).is_union() {
+ unsafe_ops.push(("union field access occurs here", expr.span));
+ }
+ },
+
+ ExprKind::Path(QPath::Resolved(
+ _,
+ hir::Path {
+ res: Res::Def(DefKind::Static(Mutability::Mut), _),
+ ..
+ },
+ )) => {
+ unsafe_ops.push(("access of a mutable static occurs here", expr.span));
+ },
+
+ ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty_adjusted(e).is_unsafe_ptr() => {
+ unsafe_ops.push(("raw pointer dereference occurs here", expr.span));
+ },
+
+ ExprKind::Call(path_expr, _) => match path_expr.kind {
+ ExprKind::Path(QPath::Resolved(
+ _,
+ hir::Path {
+ res: Res::Def(kind, def_id),
+ ..
+ },
+ )) if kind.is_fn_like() => {
+ let sig = cx.tcx.fn_sig(*def_id);
+ if sig.0.unsafety() == Unsafety::Unsafe {
+ unsafe_ops.push(("unsafe function call occurs here", expr.span));
+ }
+ },
+
+ ExprKind::Path(QPath::TypeRelative(..)) => {
+ if let Some(sig) = cx
+ .typeck_results()
+ .type_dependent_def_id(path_expr.hir_id)
+ .map(|def_id| cx.tcx.fn_sig(def_id))
+ {
+ if sig.0.unsafety() == Unsafety::Unsafe {
+ unsafe_ops.push(("unsafe function call occurs here", expr.span));
+ }
+ }
+ },
+
+ _ => {},
+ },
+
+ ExprKind::MethodCall(..) => {
+ if let Some(sig) = cx
+ .typeck_results()
+ .type_dependent_def_id(expr.hir_id)
+ .map(|def_id| cx.tcx.fn_sig(def_id))
+ {
+ if sig.0.unsafety() == Unsafety::Unsafe {
+ unsafe_ops.push(("unsafe method call occurs here", expr.span));
+ }
+ }
+ },
+
+ ExprKind::AssignOp(_, lhs, rhs) | ExprKind::Assign(lhs, rhs, _) => {
+ if matches!(
+ lhs.kind,
+ ExprKind::Path(QPath::Resolved(
+ _,
+ hir::Path {
+ res: Res::Def(DefKind::Static(Mutability::Mut), _),
+ ..
+ }
+ ))
+ ) {
+ unsafe_ops.push(("modification of a mutable static occurs here", expr.span));
+ collect_unsafe_exprs(cx, rhs, unsafe_ops);
+ return Continue(Descend::No);
+ }
+ },
+
+ _ => {},
+ };
+
+ Continue::<(), _>(Descend::Yes)
+ });
+}
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index a651020ca..8aa814b74 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -3,9 +3,10 @@ use clippy_utils::{def_path_def_ids, trait_ref_of_method};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::TypeVisitable;
+use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::Span;
use rustc_span::symbol::sym;
use std::iter;
@@ -102,21 +103,21 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
if let hir::ItemKind::Fn(ref sig, ..) = item.kind {
- self.check_sig(cx, item.hir_id(), sig.decl);
+ self.check_sig(cx, item.owner_id.def_id, sig.decl);
}
}
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) {
if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind {
if trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
- self.check_sig(cx, item.hir_id(), sig.decl);
+ self.check_sig(cx, item.owner_id.def_id, sig.decl);
}
}
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'tcx>) {
if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
- self.check_sig(cx, item.hir_id(), sig.decl);
+ self.check_sig(cx, item.owner_id.def_id, sig.decl);
}
}
@@ -136,9 +137,8 @@ impl MutableKeyType {
}
}
- fn check_sig(&self, cx: &LateContext<'_>, item_hir_id: hir::HirId, decl: &hir::FnDecl<'_>) {
- let fn_def_id = cx.tcx.hir().local_def_id(item_hir_id);
- let fn_sig = cx.tcx.fn_sig(fn_def_id);
+ fn check_sig(&self, cx: &LateContext<'_>, fn_def_id: LocalDefId, decl: &hir::FnDecl<'_>) {
+ let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity();
for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) {
self.check_ty_(cx, hir_ty.span, *ty);
}
@@ -166,7 +166,8 @@ impl MutableKeyType {
Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || self.is_interior_mutable_type(cx, inner_ty),
Slice(inner_ty) => self.is_interior_mutable_type(cx, inner_ty),
Array(inner_ty, size) => {
- size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
+ size.try_eval_target_usize(cx.tcx, cx.param_env)
+ .map_or(true, |u| u != 0)
&& self.is_interior_mutable_type(cx, inner_ty)
},
Tuple(fields) => fields.iter().any(|ty| self.is_interior_mutable_type(cx, ty)),
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index 4547ed7ea..e91aac41b 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
ExprKind::MethodCall(path, receiver, arguments, _) => {
let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
let substs = cx.typeck_results().node_substs(e.hir_id);
- let method_type = cx.tcx.bound_type_of(def_id).subst(cx.tcx, substs);
+ let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
check_arguments(
cx,
std::iter::once(receiver).chain(arguments.iter()).collect(),
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 8c9d4c5cf..1ab81aee7 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -18,8 +18,9 @@ use rustc_hir_typeck::expr_use_visitor as euv;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::FakeReadCause;
-use rustc_middle::ty::{self, TypeVisitable};
+use rustc_middle::ty::{self, TypeVisitableExt};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::kw;
use rustc_span::{sym, Span};
use rustc_target::spec::abi::Abi;
@@ -82,12 +83,14 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
decl: &'tcx FnDecl<'_>,
body: &'tcx Body<'_>,
span: Span,
- hir_id: HirId,
+ fn_def_id: LocalDefId,
) {
if span.from_expansion() {
return;
}
+ let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
+
match kind {
FnKind::ItemFn(.., header) => {
let attrs = cx.tcx.hir().attrs(hir_id);
@@ -119,8 +122,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
let sized_trait = need!(cx.tcx.lang_items().sized_trait());
- let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
-
let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds().iter())
.filter(|p| !p.is_global())
.filter_map(|obligation| {
@@ -147,8 +148,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
ctx
};
- let fn_sig = cx.tcx.fn_sig(fn_def_id);
- let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig);
+ let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity();
+ let fn_sig = cx.tcx.liberate_late_bound_regions(fn_def_id.to_def_id(), fn_sig);
for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params).enumerate() {
// All spans generated from a proc-macro invocation are the same...
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 54a3c82b7..653b1a8a0 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
}
if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
let name = impl_item.ident.name;
- let id = impl_item.hir_id();
+ let id = impl_item.owner_id;
if sig.header.constness == hir::Constness::Const {
// can't be implemented by default
return;
@@ -97,15 +97,16 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
if sig.decl.inputs.is_empty();
if name == sym::new;
if cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id);
- let self_def_id = cx.tcx.hir().get_parent_item(id);
- let self_ty = cx.tcx.type_of(self_def_id);
+ let self_def_id = cx.tcx.hir().get_parent_item(id.into());
+ let self_ty = cx.tcx.type_of(self_def_id).subst_identity();
if self_ty == return_ty(cx, id);
if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
then {
if self.impling_types.is_none() {
let mut impls = HirIdSet::default();
cx.tcx.for_each_impl(default_trait_id, |d| {
- if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
+ let ty = cx.tcx.type_of(d).subst_identity();
+ if let Some(ty_def) = ty.ty_adt_def() {
if let Some(local_def_id) = ty_def.did().as_local() {
impls.insert(cx.tcx.hir().local_def_id_to_hir_id(local_def_id));
}
@@ -118,7 +119,8 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
// generics
if_chain! {
if let Some(ref impling_types) = self.impling_types;
- if let Some(self_def) = cx.tcx.type_of(self_def_id).ty_adt_def();
+ let self_def = cx.tcx.type_of(self_def_id).subst_identity();
+ if let Some(self_def) = self_def.ty_adt_def();
if let Some(self_local_did) = self_def.did().as_local();
let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
if impling_types.contains(&self_id);
@@ -133,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
span_lint_hir_and_then(
cx,
NEW_WITHOUT_DEFAULT,
- id,
+ id.into(),
impl_item.span,
&format!(
"you should consider adding a `Default` implementation for `{self_type_snip}`"
diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
new file mode 100644
index 000000000..bc64ccb29
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
@@ -0,0 +1,65 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+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_target::spec::abi::Abi;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for Rust ABI functions with the `#[no_mangle]` attribute.
+ ///
+ /// ### Why is this bad?
+ /// The Rust ABI is not stable, but in many simple cases matches
+ /// enough with the C ABI that it is possible to forget to add
+ /// `extern "C"` to a function called from C. Changes to the
+ /// Rust ABI can break this at any point.
+ ///
+ /// ### Example
+ /// ```rust
+ /// #[no_mangle]
+ /// fn example(arg_one: u32, arg_two: usize) {}
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust
+ /// #[no_mangle]
+ /// extern "C" fn example(arg_one: u32, arg_two: usize) {}
+ /// ```
+ #[clippy::version = "1.69.0"]
+ pub NO_MANGLE_WITH_RUST_ABI,
+ pedantic,
+ "convert Rust ABI functions to C ABI"
+}
+declare_lint_pass!(NoMangleWithRustAbi => [NO_MANGLE_WITH_RUST_ABI]);
+
+impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+ if let ItemKind::Fn(fn_sig, _, _) = &item.kind {
+ let attrs = cx.tcx.hir().attrs(item.hir_id());
+ let mut applicability = Applicability::MachineApplicable;
+ let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut applicability);
+ for attr in attrs {
+ if let Some(ident) = attr.ident()
+ && ident.name == rustc_span::sym::no_mangle
+ && fn_sig.header.abi == Abi::Rust
+ && !snippet.contains("extern") {
+
+ let suggestion = snippet.split_once("fn")
+ .map_or(String::new(), |(first, second)| format!(r#"{first}extern "C" fn{second}"#));
+
+ span_lint_and_sugg(
+ cx,
+ NO_MANGLE_WITH_RUST_ABI,
+ fn_sig.span,
+ "attribute #[no_mangle] set on a Rust ABI function",
+ "try",
+ suggestion,
+ applicability
+ );
+ }
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 07fd321d6..0bedab05e 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -313,7 +313,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
// and, in that case, the definition is *not* generic.
cx.tcx.normalize_erasing_regions(
cx.tcx.param_env(of_trait_def_id),
- cx.tcx.type_of(of_assoc_item),
+ cx.tcx.type_of(of_assoc_item).subst_identity(),
),
))
.is_err();
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index 7b1d974f2..8b77a5c99 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdMap;
use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
+use rustc_middle::ty::subst::{EarlyBinder, GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, ConstKind};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::{kw, Ident};
@@ -244,7 +244,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
})) => {
#[allow(trivial_casts)]
if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into())
- && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(|t| t.subst_identity())
+ && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::subst_identity)
&& let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id
{
(
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index cff82b875..87a8a2ed1 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -1,8 +1,8 @@
use super::ARITHMETIC_SIDE_EFFECTS;
use clippy_utils::{
- consts::{constant, constant_simple},
+ consts::{constant, constant_simple, Constant},
diagnostics::span_lint,
- peel_hir_expr_refs, peel_hir_expr_unary,
+ is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary,
};
use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -97,17 +97,19 @@ impl ArithmeticSideEffects {
self.expr_span = Some(expr.span);
}
- /// If `expr` is not a literal integer like `1`, returns `None`.
+ /// Returns the numeric value of a literal integer originated from `expr`, if any.
///
- /// Returns the absolute value of the expression, if this is an integer literal.
- fn literal_integer(expr: &hir::Expr<'_>) -> Option<u128> {
+ /// Literal integers can be originated from adhoc declarations like `1`, associated constants
+ /// like `i32::MAX` or constant references like `N` from `const N: i32 = 1;`,
+ fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<u128> {
let actual = peel_hir_expr_unary(expr).0;
if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
- Some(n)
+ return Some(n)
}
- else {
- None
+ if let Some((Constant::Int(n), _)) = constant(cx, cx.typeck_results(), expr) {
+ return Some(n);
}
+ None
}
/// Manages when the lint should be triggered. Operations in constant environments, hard coded
@@ -143,7 +145,10 @@ impl ArithmeticSideEffects {
let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
- match (Self::literal_integer(actual_lhs), Self::literal_integer(actual_rhs)) {
+ match (
+ Self::literal_integer(cx, actual_lhs),
+ Self::literal_integer(cx, actual_rhs),
+ ) {
(None, None) => false,
(None, Some(n)) | (Some(n), None) => match (&op.node, n) {
(hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
@@ -180,20 +185,22 @@ impl ArithmeticSideEffects {
return;
}
let actual_un_expr = peel_hir_expr_refs(un_expr).0;
- if Self::literal_integer(actual_un_expr).is_some() {
+ if Self::literal_integer(cx, actual_un_expr).is_some() {
return;
}
self.issue_lint(cx, expr);
}
- fn should_skip_expr(&mut self, expr: &hir::Expr<'_>) -> bool {
- self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span))
+ fn should_skip_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
+ is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id)
+ || self.expr_span.is_some()
+ || self.const_span.map_or(false, |sp| sp.contains(expr.span))
}
}
impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) {
- if self.should_skip_expr(expr) {
+ if self.should_skip_expr(cx, expr) {
return;
}
match &expr.kind {
@@ -209,7 +216,8 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
let body_owner = cx.tcx.hir().body_owner(body.id());
- let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner);
+ let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id());
+
let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id);
if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind {
let body_span = cx.tcx.hir().span_with_body(body_owner);
diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
index 24aeb82a3..d3de9699f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -49,10 +49,10 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
(arg, arg.span)
},
ExprKind::Call(path, [arg])
- if path_def_id(cx, path).map_or(false, |id| {
- if match_def_path(cx, id, &paths::FROM_STR_METHOD) {
+ if path_def_id(cx, path).map_or(false, |did| {
+ if match_def_path(cx, did, &paths::FROM_STR_METHOD) {
true
- } else if cx.tcx.lang_items().from_fn() == Some(id) {
+ } else if cx.tcx.is_diagnostic_item(sym::from_fn, did) {
!is_copy(cx, typeck.expr_ty(expr))
} else {
false
diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
index 0830a106f..777395f45 100644
--- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
@@ -96,7 +96,7 @@ impl Context {
pub fn enter_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
let body_owner = cx.tcx.hir().body_owner(body.id());
- let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner);
+ let body_owner_def_id = cx.tcx.hir().body_owner_def_id(body.id());
match cx.tcx.hir().body_owner_kind(body_owner_def_id) {
hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => {
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index 472f52380..c5ea09590 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -25,11 +25,11 @@ declare_clippy_lint! {
/// Using the dedicated functions of the `Option` type is clearer and
/// more concise than an `if let` expression.
///
- /// ### Known problems
- /// This lint uses a deliberately conservative metric for checking
- /// if the inside of either body contains breaks or continues which will
- /// cause it to not suggest a fix if either block contains a loop with
- /// continues or breaks contained within the loop.
+ /// ### Notes
+ /// This lint uses a deliberately conservative metric for checking if the
+ /// inside of either body contains loop control expressions `break` or
+ /// `continue` (which cannot be used within closures). If these are found,
+ /// this lint will not be raised.
///
/// ### Example
/// ```rust
diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
index efec12489..849cd03dd 100644
--- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
@@ -8,6 +8,7 @@ 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_span::def_id::LocalDefId;
use rustc_span::{sym, Span};
declare_clippy_lint! {
@@ -49,9 +50,13 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn {
_: &'tcx hir::FnDecl<'tcx>,
body: &'tcx hir::Body<'tcx>,
span: Span,
- hir_id: hir::HirId,
+ def_id: LocalDefId,
) {
- if !matches!(fn_kind, FnKind::Closure) && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::Result) {
+ if matches!(fn_kind, FnKind::Closure) {
+ return;
+ }
+ let owner = cx.tcx.hir().local_def_id_to_hir_id(def_id).expect_owner();
+ if is_type_diagnostic_item(cx, return_ty(cx, owner), sym::Result) {
lint_impl_body(cx, span, body);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 2d21aaa4f..0d78c3048 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
-use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, Impl, ItemKind, MutTy, Mutability, Node, PatKind};
+use rustc_hir::{BindingAnnotation, Body, FnDecl, Impl, ItemKind, MutTy, Mutability, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::adjustment::{Adjust, PointerCast};
use rustc_middle::ty::layout::LayoutOf;
@@ -143,7 +143,7 @@ impl<'tcx> PassByRefOrValue {
return;
}
- let fn_sig = cx.tcx.fn_sig(def_id);
+ let fn_sig = cx.tcx.fn_sig(def_id).subst_identity();
let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id));
// Gather all the lifetimes found in the output type which may affect whether
@@ -272,12 +272,13 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
decl: &'tcx FnDecl<'_>,
_body: &'tcx Body<'_>,
span: Span,
- hir_id: HirId,
+ def_id: LocalDefId,
) {
if span.from_expansion() {
return;
}
+ let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
match kind {
FnKind::ItemFn(.., header) => {
if header.abi != Abi::Rust {
@@ -308,6 +309,6 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
}
}
- self.check_poly_fn(cx, cx.tcx.hir().local_def_id(hir_id), decl, Some(span));
+ self.check_poly_fn(cx, def_id, decl, Some(span));
}
}
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
index 97b5a4ce3..9f98195d3 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_hir::{
- intravisit, Body, Expr, ExprKind, FnDecl, HirId, Let, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind,
-};
+use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, Let, LocalSource, Mutability, Pat, PatKind, 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_span::def_id::LocalDefId;
use rustc_span::source_map::Span;
declare_clippy_lint! {
@@ -116,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
_: &'tcx FnDecl<'_>,
body: &'tcx Body<'_>,
_: Span,
- _: HirId,
+ _: LocalDefId,
) {
for param in body.params {
apply_lint(cx, param.pat, DerefPossible::Impossible);
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 262953042..fc5509361 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -164,7 +164,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
check_mut_from_ref(cx, sig, None);
for arg in check_fn_args(
cx,
- cx.tcx.fn_sig(item.owner_id).skip_binder().inputs(),
+ cx.tcx.fn_sig(item.owner_id).subst_identity().skip_binder().inputs(),
sig.decl.inputs,
&[],
)
@@ -217,7 +217,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
check_mut_from_ref(cx, sig, Some(body));
let decl = sig.decl;
- let sig = cx.tcx.fn_sig(item_id).skip_binder();
+ let sig = cx.tcx.fn_sig(item_id).subst_identity().skip_binder();
let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, body.params)
.filter(|arg| !is_trait_item || arg.mutability() == Mutability::Not)
.collect();
@@ -505,13 +505,13 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
if let FnRetTy::Return(ty) = sig.decl.output
&& let Some((out, Mutability::Mut, _)) = get_ref_lm(ty)
{
- let out_region = cx.tcx.named_region(out.hir_id);
+ let out_region = cx.tcx.named_bound_var(out.hir_id);
let args: Option<Vec<_>> = sig
.decl
.inputs
.iter()
.filter_map(get_ref_lm)
- .filter(|&(lt, _, _)| cx.tcx.named_region(lt.hir_id) == out_region)
+ .filter(|&(lt, _, _)| cx.tcx.named_bound_var(lt.hir_id) == out_region)
.map(|(_, mutability, span)| (mutability == Mutability::Not).then_some(span))
.collect();
if let Some(args) = args
@@ -624,7 +624,10 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
return;
};
- match *self.cx.tcx.fn_sig(id).skip_binder().inputs()[i].peel_refs().kind() {
+ match *self.cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i]
+ .peel_refs()
+ .kind()
+ {
ty::Dynamic(preds, _, _) if !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds) => {
set_skip_flag();
},
diff --git a/src/tools/clippy/clippy_lints/src/question_mark_used.rs b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
new file mode 100644
index 000000000..9b678e8d7
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs
@@ -0,0 +1,52 @@
+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};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for expressions that use the question mark operator and rejects them.
+ ///
+ /// ### Why is this bad?
+ /// Sometimes code wants to avoid the question mark operator because for instance a local
+ /// block requires a macro to re-throw errors to attach additional information to the
+ /// error.
+ ///
+ /// ### Example
+ /// ```ignore
+ /// let result = expr?;
+ /// ```
+ ///
+ /// Could be written:
+ ///
+ /// ```ignore
+ /// utility_macro!(expr);
+ /// ```
+ #[clippy::version = "pre 1.29.0"]
+ pub QUESTION_MARK_USED,
+ restriction,
+ "complains if the question mark operator is used"
+}
+
+declare_lint_pass!(QuestionMarkUsed => [QUESTION_MARK_USED]);
+
+impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ if let ExprKind::Match(_, _, MatchSource::TryDesugar) = expr.kind {
+ if !span_is_local(expr.span) {
+ return;
+ }
+
+ span_lint_and_help(
+ cx,
+ QUESTION_MARK_USED,
+ expr.span,
+ "question mark operator was used",
+ None,
+ "consider using a custom macro or match expression",
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index c1677fb3d..944a33cc3 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -6,11 +6,12 @@ use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
-use rustc_hir::{def_id, Body, FnDecl, HirId, LangItem};
+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_span::def_id::LocalDefId;
use rustc_span::source_map::{BytePos, Span};
use rustc_span::sym;
@@ -69,12 +70,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
cx: &LateContext<'tcx>,
_: FnKind<'tcx>,
_: &'tcx FnDecl<'_>,
- body: &'tcx Body<'_>,
+ _: &'tcx Body<'_>,
_: Span,
- _: HirId,
+ def_id: LocalDefId,
) {
- let def_id = cx.tcx.hir().body_owner_def_id(body.id());
-
// Building MIR for `fn`s with unsatisfiable preds results in ICE.
if fn_has_unsatisfiable_preds(cx, def_id.to_def_id()) {
return;
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 245a02ea2..2fdd775ad 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -11,8 +11,6 @@ use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::subst::GenericArg;
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use std::iter;
-
declare_clippy_lint! {
/// ### What it does
/// Checks for redundant slicing expressions which use the full range, and
@@ -136,7 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
} else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
cx.param_env,
- cx.tcx.mk_projection(target_id, cx.tcx.mk_substs(iter::once(GenericArg::from(indexed_ty)))),
+ cx.tcx.mk_projection(target_id, cx.tcx.mk_substs(&[GenericArg::from(indexed_ty)])),
) {
if deref_ty == expr_ty {
let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 1fda58fa5..9e6c6c73d 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -1,5 +1,8 @@
+use std::fmt::Display;
+
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::source::snippet_opt;
use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_ast::ast::{LitKind, StrStyle};
@@ -77,13 +80,45 @@ impl<'tcx> LateLintPass<'tcx> for Regex {
}
}
-#[must_use]
-fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u8) -> Span {
- let offset = u32::from(offset);
- let end = base.lo() + BytePos(u32::try_from(c.end.offset).expect("offset too large") + offset);
- let start = base.lo() + BytePos(u32::try_from(c.start.offset).expect("offset too large") + offset);
- assert!(start <= end);
- Span::new(start, end, base.ctxt(), base.parent())
+fn lint_syntax_error(cx: &LateContext<'_>, error: &regex_syntax::Error, unescaped: &str, base: Span, offset: u8) {
+ let parts: Option<(_, _, &dyn Display)> = match &error {
+ regex_syntax::Error::Parse(e) => Some((e.span(), e.auxiliary_span(), e.kind())),
+ regex_syntax::Error::Translate(e) => Some((e.span(), None, e.kind())),
+ _ => None,
+ };
+
+ let convert_span = |regex_span: &regex_syntax::ast::Span| {
+ let offset = u32::from(offset);
+ let start = base.lo() + BytePos(u32::try_from(regex_span.start.offset).expect("offset too large") + offset);
+ let end = base.lo() + BytePos(u32::try_from(regex_span.end.offset).expect("offset too large") + offset);
+
+ Span::new(start, end, base.ctxt(), base.parent())
+ };
+
+ if let Some((primary, auxiliary, kind)) = parts
+ && let Some(literal_snippet) = snippet_opt(cx, base)
+ && let Some(inner) = literal_snippet.get(offset as usize..)
+ // Only convert to native rustc spans if the parsed regex matches the
+ // source snippet exactly, to ensure the span offsets are correct
+ && inner.get(..unescaped.len()) == Some(unescaped)
+ {
+ let spans = if let Some(auxiliary) = auxiliary {
+ vec![convert_span(primary), convert_span(auxiliary)]
+ } else {
+ vec![convert_span(primary)]
+ };
+
+ span_lint(cx, INVALID_REGEX, spans, &format!("regex syntax error: {kind}"));
+ } else {
+ span_lint_and_help(
+ cx,
+ INVALID_REGEX,
+ base,
+ &error.to_string(),
+ None,
+ "consider using a raw string literal: `r\"..\"`",
+ );
+ }
}
fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<String> {
@@ -155,25 +190,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl);
}
},
- Err(regex_syntax::Error::Parse(e)) => {
- span_lint(
- cx,
- INVALID_REGEX,
- str_span(expr.span, *e.span(), offset),
- &format!("regex syntax error: {}", e.kind()),
- );
- },
- Err(regex_syntax::Error::Translate(e)) => {
- span_lint(
- cx,
- INVALID_REGEX,
- str_span(expr.span, *e.span(), offset),
- &format!("regex syntax error: {}", e.kind()),
- );
- },
- Err(e) => {
- span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {e}"));
- },
+ Err(e) => lint_syntax_error(cx, &e, r, expr.span, offset),
}
}
} else if let Some(r) = const_str(cx, expr) {
@@ -183,25 +200,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl);
}
},
- Err(regex_syntax::Error::Parse(e)) => {
- span_lint(
- cx,
- INVALID_REGEX,
- expr.span,
- &format!("regex syntax error on position {}: {}", e.span().start.offset, e.kind()),
- );
- },
- Err(regex_syntax::Error::Translate(e)) => {
- span_lint(
- cx,
- INVALID_REGEX,
- expr.span,
- &format!("regex syntax error on position {}: {}", e.span().start.offset, e.kind()),
- );
- },
- Err(e) => {
- span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {e}"));
- },
+ Err(e) => span_lint(cx, INVALID_REGEX, expr.span, &e.to_string()),
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
index b77faf732..bccf421e8 100644
--- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::is_must_use_ty;
use clippy_utils::{nth_arg, return_ty};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, FnDecl, HirId, TraitItem, TraitItemKind};
+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};
@@ -68,7 +68,7 @@ declare_clippy_lint! {
declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]);
-fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, hir_id: HirId) {
+fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, owner_id: OwnerId) {
if_chain! {
// If it comes from an external macro, better ignore it.
if !in_external_macro(cx.sess(), span);
@@ -76,10 +76,10 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa
// We only show this warning for public exported methods.
if cx.effective_visibilities.is_exported(fn_def);
// We don't want to emit this lint if the `#[must_use]` attribute is already there.
- if !cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::must_use));
+ if !cx.tcx.hir().attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use));
if cx.tcx.visibility(fn_def.to_def_id()).is_public();
- let ret_ty = return_ty(cx, hir_id);
- let self_arg = nth_arg(cx, hir_id, 0);
+ let ret_ty = return_ty(cx, owner_id);
+ let self_arg = nth_arg(cx, owner_id, 0);
// If `Self` has the same type as the returned type, then we want to warn.
//
// For this check, we don't want to remove the reference on the returned type because if
@@ -109,26 +109,26 @@ impl<'tcx> LateLintPass<'tcx> for ReturnSelfNotMustUse {
decl: &'tcx FnDecl<'tcx>,
_: &'tcx Body<'tcx>,
span: Span,
- hir_id: HirId,
+ fn_def: LocalDefId,
) {
if_chain! {
// We are only interested in methods, not in functions or associated functions.
if matches!(kind, FnKind::Method(_, _));
- if let Some(fn_def) = cx.tcx.hir().opt_local_def_id(hir_id);
if let Some(impl_def) = cx.tcx.impl_of_method(fn_def.to_def_id());
// We don't want this method to be te implementation of a trait because the
// `#[must_use]` should be put on the trait definition directly.
if cx.tcx.trait_id_of_impl(impl_def).is_none();
then {
- check_method(cx, decl, fn_def, span, hir_id);
+ let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def);
+ check_method(cx, decl, fn_def, span, hir_id.expect_owner());
}
}
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
if let TraitItemKind::Fn(ref sig, _) = item.kind {
- check_method(cx, sig.decl, item.owner_id.def_id, item.span, item.hir_id());
+ check_method(cx, sig.decl, item.owner_id.def_id, item.span, item.owner_id);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index bbbd9e498..f0d7dd23a 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -1,18 +1,20 @@
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::source::{snippet_opt, snippet_with_context};
use clippy_utils::visitors::{for_each_expr, Descend};
-use clippy_utils::{fn_def_id, path_to_local_id};
+use clippy_utils::{fn_def_id, path_to_local_id, span_find_starting_semi};
use core::ops::ControlFlow;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, LangItem, MatchSource, PatKind, QPath, StmtKind};
+use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, MatchSource, PatKind, QPath, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::Span;
use rustc_span::{BytePos, Pos};
+use std::borrow::Cow;
declare_clippy_lint! {
/// ### What it does
@@ -68,31 +70,41 @@ declare_clippy_lint! {
"using a return statement like `return expr;` where an expression would suffice"
}
-#[derive(PartialEq, Eq, Copy, Clone)]
-enum RetReplacement {
+#[derive(PartialEq, Eq, Clone)]
+enum RetReplacement<'tcx> {
Empty,
Block,
Unit,
+ IfSequence(Cow<'tcx, str>, Applicability),
+ Expr(Cow<'tcx, str>, Applicability),
}
-impl RetReplacement {
+impl<'tcx> RetReplacement<'tcx> {
fn sugg_help(self) -> &'static str {
match self {
- Self::Empty => "remove `return`",
+ Self::Empty | Self::Expr(..) => "remove `return`",
Self::Block => "replace `return` with an empty block",
Self::Unit => "replace `return` with a unit value",
+ Self::IfSequence(..) => "remove `return` and wrap the sequence with parentheses",
+ }
+ }
+ fn applicability(&self) -> Option<Applicability> {
+ match self {
+ Self::Expr(_, ap) | Self::IfSequence(_, ap) => Some(*ap),
+ _ => None,
}
}
}
-impl ToString for RetReplacement {
+impl<'tcx> ToString for RetReplacement<'tcx> {
fn to_string(&self) -> String {
- match *self {
- Self::Empty => "",
- Self::Block => "{}",
- Self::Unit => "()",
+ match self {
+ Self::Empty => String::new(),
+ Self::Block => "{}".to_string(),
+ Self::Unit => "()".to_string(),
+ Self::IfSequence(inner, _) => format!("({inner})"),
+ Self::Expr(inner, _) => inner.to_string(),
}
- .to_string()
}
}
@@ -151,8 +163,8 @@ impl<'tcx> LateLintPass<'tcx> for Return {
kind: FnKind<'tcx>,
_: &'tcx FnDecl<'tcx>,
body: &'tcx Body<'tcx>,
- _: Span,
- _: HirId,
+ sp: Span,
+ _: LocalDefId,
) {
match kind {
FnKind::Closure => {
@@ -166,14 +178,14 @@ impl<'tcx> LateLintPass<'tcx> for Return {
check_final_expr(cx, body.value, vec![], replacement);
},
FnKind::ItemFn(..) | FnKind::Method(..) => {
- check_block_return(cx, &body.value.kind, vec![]);
+ check_block_return(cx, &body.value.kind, sp, vec![]);
},
}
}
}
// if `expr` is a block, check if there are needless returns in it
-fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, semi_spans: Vec<Span>) {
+fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>, sp: Span, mut semi_spans: Vec<Span>) {
if let ExprKind::Block(block, _) = expr_kind {
if let Some(block_expr) = block.expr {
check_final_expr(cx, block_expr, semi_spans, RetReplacement::Empty);
@@ -183,12 +195,14 @@ fn check_block_return<'tcx>(cx: &LateContext<'tcx>, expr_kind: &ExprKind<'tcx>,
check_final_expr(cx, expr, semi_spans, RetReplacement::Empty);
},
StmtKind::Semi(semi_expr) => {
- let mut semi_spans_and_this_one = semi_spans;
- // we only want the span containing the semicolon so we can remove it later. From `entry.rs:382`
- if let Some(semicolon_span) = stmt.span.trim_start(semi_expr.span) {
- semi_spans_and_this_one.push(semicolon_span);
- check_final_expr(cx, semi_expr, semi_spans_and_this_one, RetReplacement::Empty);
+ // Remove ending semicolons and any whitespace ' ' in between.
+ // Without `return`, the suggestion might not compile if the semicolon is retained
+ if let Some(semi_span) = stmt.span.trim_start(semi_expr.span) {
+ let semi_span_to_remove =
+ span_find_starting_semi(cx.sess().source_map(), semi_span.with_hi(sp.hi()));
+ semi_spans.push(semi_span_to_remove);
}
+ check_final_expr(cx, semi_expr, semi_spans, RetReplacement::Empty);
},
_ => (),
}
@@ -201,19 +215,38 @@ fn check_final_expr<'tcx>(
expr: &'tcx Expr<'tcx>,
semi_spans: Vec<Span>, /* containing all the places where we would need to remove semicolons if finding an
* needless return */
- replacement: RetReplacement,
+ replacement: RetReplacement<'tcx>,
) {
let peeled_drop_expr = expr.peel_drop_temps();
match &peeled_drop_expr.kind {
// simple return is always "bad"
ExprKind::Ret(ref inner) => {
- // if desugar of `do yeet`, don't lint
- if let Some(inner_expr) = inner
- && let ExprKind::Call(path_expr, _) = inner_expr.kind
- && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind
- {
- return;
- }
+ // check if expr return nothing
+ let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
+ extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
+ } else {
+ peeled_drop_expr.span
+ };
+
+ let replacement = if let Some(inner_expr) = inner {
+ // if desugar of `do yeet`, don't lint
+ if let ExprKind::Call(path_expr, _) = inner_expr.kind
+ && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind
+ {
+ return;
+ }
+
+ let mut applicability = Applicability::MachineApplicable;
+ let (snippet, _) = snippet_with_context(cx, inner_expr.span, ret_span.ctxt(), "..", &mut applicability);
+ if expr_contains_conjunctive_ifs(inner_expr) {
+ RetReplacement::IfSequence(snippet, applicability)
+ } else {
+ RetReplacement::Expr(snippet, applicability)
+ }
+ } else {
+ replacement
+ };
+
if !cx.tcx.hir().attrs(expr.hir_id).is_empty() {
return;
}
@@ -221,19 +254,13 @@ fn check_final_expr<'tcx>(
if borrows {
return;
}
- // check if expr return nothing
- let ret_span = if inner.is_none() && replacement == RetReplacement::Empty {
- extend_span_to_previous_non_ws(cx, peeled_drop_expr.span)
- } else {
- peeled_drop_expr.span
- };
- emit_return_lint(cx, ret_span, semi_spans, inner.as_ref().map(|i| i.span), replacement);
+ emit_return_lint(cx, ret_span, semi_spans, replacement);
},
ExprKind::If(_, then, else_clause_opt) => {
- check_block_return(cx, &then.kind, semi_spans.clone());
+ check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
if let Some(else_clause) = else_clause_opt {
- check_block_return(cx, &else_clause.kind, semi_spans);
+ check_block_return(cx, &else_clause.kind, peeled_drop_expr.span, semi_spans);
}
},
// a match expr, check all arms
@@ -246,33 +273,29 @@ fn check_final_expr<'tcx>(
}
},
// if it's a whole block, check it
- other_expr_kind => check_block_return(cx, other_expr_kind, semi_spans),
+ other_expr_kind => check_block_return(cx, other_expr_kind, peeled_drop_expr.span, semi_spans),
}
}
-fn emit_return_lint(
- cx: &LateContext<'_>,
- ret_span: Span,
- semi_spans: Vec<Span>,
- inner_span: Option<Span>,
- replacement: RetReplacement,
-) {
+fn expr_contains_conjunctive_ifs<'tcx>(expr: &'tcx Expr<'tcx>) -> bool {
+ fn contains_if(expr: &Expr<'_>, on_if: bool) -> bool {
+ match expr.kind {
+ ExprKind::If(..) => on_if,
+ ExprKind::Binary(_, left, right) => contains_if(left, true) || contains_if(right, true),
+ _ => false,
+ }
+ }
+
+ contains_if(expr, false)
+}
+
+fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec<Span>, replacement: RetReplacement<'_>) {
if ret_span.from_expansion() {
return;
}
- let mut applicability = Applicability::MachineApplicable;
- let return_replacement = inner_span.map_or_else(
- || replacement.to_string(),
- |inner_span| {
- let (snippet, _) = snippet_with_context(cx, inner_span, ret_span.ctxt(), "..", &mut applicability);
- snippet.to_string()
- },
- );
- let sugg_help = if inner_span.is_some() {
- "remove `return`"
- } else {
- replacement.sugg_help()
- };
+ let applicability = replacement.applicability().unwrap_or(Applicability::MachineApplicable);
+ let return_replacement = replacement.to_string();
+ let sugg_help = replacement.sugg_help();
span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
diag.span_suggestion_hidden(ret_span, sugg_help, return_replacement, applicability);
// for each parent statement, we need to remove the semicolon
@@ -288,6 +311,7 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
&& cx
.tcx
.fn_sig(def_id)
+ .subst_identity()
.skip_binder()
.output()
.walk()
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index 17763128c..a37e2772d 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
let mut map = FxHashMap::<Res, ExistingName>::default();
for id in cx.tcx.hir().items() {
- if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl)
+ if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl { .. })
&& let item = cx.tcx.hir().item(id)
&& let ItemKind::Impl(Impl {
items,
diff --git a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
index 71b387c66..beca203c8 100644
--- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
+++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs
@@ -53,8 +53,8 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
let item = cx.tcx.hir().expect_item(parent);
- let self_ty = cx.tcx.type_of(item.owner_id);
- let ret_ty = return_ty(cx, impl_item.hir_id());
+ let self_ty = cx.tcx.type_of(item.owner_id).subst_identity();
+ let ret_ty = return_ty(cx, impl_item.owner_id);
// Do not check trait impls
if matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. })) {
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index 8f1d1490e..34a3e5ddf 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -30,7 +30,7 @@ declare_clippy_lint! {
/// # let x = 0;
/// unsafe { f(x); }
/// ```
- #[clippy::version = "1.66.0"]
+ #[clippy::version = "1.68.0"]
pub SEMICOLON_INSIDE_BLOCK,
restriction,
"add a semicolon inside the block"
@@ -59,7 +59,7 @@ declare_clippy_lint! {
/// # let x = 0;
/// unsafe { f(x) };
/// ```
- #[clippy::version = "1.66.0"]
+ #[clippy::version = "1.68.0"]
pub SEMICOLON_OUTSIDE_BLOCK,
restriction,
"add a semicolon outside the block"
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
new file mode 100644
index 000000000..c3e99aa00
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -0,0 +1,423 @@
+use clippy_utils::{
+ diagnostics::span_lint_and_then,
+ get_attr,
+ source::{indent_of, snippet},
+};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::{Applicability, Diagnostic};
+use rustc_hir::{
+ self as hir,
+ intravisit::{walk_expr, Visitor},
+};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::ty::{subst::GenericArgKind, Ty, TypeAndMut};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{symbol::Ident, Span, DUMMY_SP};
+
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// Searches for elements marked with `#[clippy::significant_drop]` that could be early
+ /// dropped but are in fact dropped at the end of their scopes. In other words, enforces the
+ /// "tightening" of their possible lifetimes.
+ ///
+ /// ### Why is this bad?
+ ///
+ /// Elements marked with `#[clippy::has_significant_drop]` are generally synchronizing
+ /// primitives that manage shared resources, as such, it is desired to release them as soon as
+ /// possible to avoid unnecessary resource contention.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,ignore
+ /// fn main() {
+ /// let lock = some_sync_resource.lock();
+ /// let owned_rslt = lock.do_stuff_with_resource();
+ /// // Only `owned_rslt` is needed but `lock` is still held.
+ /// do_heavy_computation_that_takes_time(owned_rslt);
+ /// }
+ /// ```
+ ///
+ /// Use instead:
+ ///
+ /// ```rust,ignore
+ /// fn main() {
+ /// let owned_rslt = some_sync_resource.lock().do_stuff_with_resource();
+ /// do_heavy_computation_that_takes_time(owned_rslt);
+ /// }
+ /// ```
+ #[clippy::version = "1.67.0"]
+ pub SIGNIFICANT_DROP_TIGHTENING,
+ nursery,
+ "Searches for elements marked with `#[clippy::has_significant_drop]` that could be early dropped but are in fact dropped at the end of their scopes"
+}
+
+impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]);
+
+#[derive(Default)]
+pub struct SignificantDropTightening<'tcx> {
+ /// Auxiliary structure used to avoid having to verify the same type multiple times.
+ seen_types: FxHashSet<Ty<'tcx>>,
+ type_cache: FxHashMap<Ty<'tcx>, bool>,
+}
+
+impl<'tcx> SignificantDropTightening<'tcx> {
+ /// Unifies the statements of a block with its return expression.
+ fn all_block_stmts<'ret, 'rslt, 'stmts>(
+ block_stmts: &'stmts [hir::Stmt<'tcx>],
+ dummy_ret_stmt: Option<&'ret hir::Stmt<'tcx>>,
+ ) -> impl Iterator<Item = &'rslt hir::Stmt<'tcx>>
+ where
+ 'ret: 'rslt,
+ 'stmts: 'rslt,
+ {
+ block_stmts.iter().chain(dummy_ret_stmt)
+ }
+
+ /// Searches for at least one statement that could slow down the release of a significant drop.
+ fn at_least_one_stmt_is_expensive<'stmt>(stmts: impl Iterator<Item = &'stmt hir::Stmt<'tcx>>) -> bool
+ where
+ 'tcx: 'stmt,
+ {
+ for stmt in stmts {
+ match stmt.kind {
+ hir::StmtKind::Expr(expr) if let hir::ExprKind::Path(_) = expr.kind => {}
+ hir::StmtKind::Local(local) if let Some(expr) = local.init
+ && let hir::ExprKind::Path(_) = expr.kind => {},
+ _ => return true
+ };
+ }
+ false
+ }
+
+ /// Verifies if the expression is of type `drop(some_lock_path)` to assert that the temporary
+ /// is already being dropped before the end of its scope.
+ fn has_drop(expr: &'tcx hir::Expr<'_>, init_bind_ident: Ident) -> bool {
+ if let hir::ExprKind::Call(fun, args) = expr.kind
+ && let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind
+ && let [fun_ident, ..] = fun_path.segments
+ && fun_ident.ident.name == rustc_span::sym::drop
+ && let [first_arg, ..] = args
+ && let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &first_arg.kind
+ && let [first_arg_ps, .. ] = arg_path.segments
+ {
+ first_arg_ps.ident == init_bind_ident
+ }
+ else {
+ false
+ }
+ }
+
+ /// Tries to find types marked with `#[has_significant_drop]` of an expression `expr` that is
+ /// originated from `stmt` and then performs common logic on `sdap`.
+ fn modify_sdap_if_sig_drop_exists(
+ &mut self,
+ cx: &LateContext<'tcx>,
+ expr: &'tcx hir::Expr<'_>,
+ idx: usize,
+ sdap: &mut SigDropAuxParams,
+ stmt: &hir::Stmt<'_>,
+ cb: impl Fn(&mut SigDropAuxParams),
+ ) {
+ let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types, &mut self.type_cache);
+ sig_drop_finder.visit_expr(expr);
+ if sig_drop_finder.has_sig_drop {
+ cb(sdap);
+ if sdap.number_of_stmts > 0 {
+ sdap.last_use_stmt_idx = idx;
+ sdap.last_use_stmt_span = stmt.span;
+ if let hir::ExprKind::MethodCall(_, _, _, span) = expr.kind {
+ sdap.last_use_method_span = span;
+ }
+ }
+ sdap.number_of_stmts = sdap.number_of_stmts.wrapping_add(1);
+ }
+ }
+
+ /// Shows generic overall messages as well as specialized messages depending on the usage.
+ fn set_suggestions(cx: &LateContext<'tcx>, block_span: Span, diag: &mut Diagnostic, sdap: &SigDropAuxParams) {
+ match sdap.number_of_stmts {
+ 0 | 1 => {},
+ 2 => {
+ let indent = " ".repeat(indent_of(cx, sdap.last_use_stmt_span).unwrap_or(0));
+ let init_method = snippet(cx, sdap.init_method_span, "..");
+ let usage_method = snippet(cx, sdap.last_use_method_span, "..");
+ let stmt = if let Some(last_use_bind_span) = sdap.last_use_bind_span {
+ format!(
+ "\n{indent}let {} = {init_method}.{usage_method};",
+ snippet(cx, last_use_bind_span, ".."),
+ )
+ } else {
+ format!("\n{indent}{init_method}.{usage_method};")
+ };
+ diag.span_suggestion_verbose(
+ sdap.init_stmt_span,
+ "merge the temporary construction with its single usage",
+ stmt,
+ Applicability::MaybeIncorrect,
+ );
+ diag.span_suggestion(
+ sdap.last_use_stmt_span,
+ "remove separated single usage",
+ "",
+ Applicability::MaybeIncorrect,
+ );
+ },
+ _ => {
+ diag.span_suggestion(
+ sdap.last_use_stmt_span.shrink_to_hi(),
+ "drop the temporary after the end of its last usage",
+ format!(
+ "\n{}drop({});",
+ " ".repeat(indent_of(cx, sdap.last_use_stmt_span).unwrap_or(0)),
+ sdap.init_bind_ident
+ ),
+ Applicability::MaybeIncorrect,
+ );
+ },
+ }
+ diag.note("this might lead to unnecessary resource contention");
+ diag.span_label(
+ block_span,
+ format!(
+ "temporary `{}` is currently being dropped at the end of its contained scope",
+ sdap.init_bind_ident
+ ),
+ );
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> {
+ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
+ let dummy_ret_stmt = block.expr.map(|expr| hir::Stmt {
+ hir_id: hir::HirId::INVALID,
+ kind: hir::StmtKind::Expr(expr),
+ span: DUMMY_SP,
+ });
+ let mut sdap = SigDropAuxParams::default();
+ for (idx, stmt) in Self::all_block_stmts(block.stmts, dummy_ret_stmt.as_ref()).enumerate() {
+ match stmt.kind {
+ hir::StmtKind::Expr(expr) => self.modify_sdap_if_sig_drop_exists(
+ cx,
+ expr,
+ idx,
+ &mut sdap,
+ stmt,
+ |_| {}
+ ),
+ hir::StmtKind::Local(local) if let Some(expr) = local.init => self.modify_sdap_if_sig_drop_exists(
+ cx,
+ expr,
+ idx,
+ &mut sdap,
+ stmt,
+ |local_sdap| {
+ if local_sdap.number_of_stmts == 0 {
+ if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind {
+ local_sdap.init_bind_ident = ident;
+ }
+ if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr.kind {
+ local_sdap.init_method_span = local_expr.span.to(span);
+ }
+ local_sdap.init_stmt_span = stmt.span;
+ }
+ else if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind {
+ local_sdap.last_use_bind_span = Some(ident.span);
+ }
+ }
+ ),
+ hir::StmtKind::Semi(expr) => {
+ if Self::has_drop(expr, sdap.init_bind_ident) {
+ return;
+ }
+ self.modify_sdap_if_sig_drop_exists(cx, expr, idx, &mut sdap, stmt, |_| {});
+ },
+ _ => {}
+ };
+ }
+
+ let idx = sdap.last_use_stmt_idx.wrapping_add(1);
+ let stmts_after_last_use = Self::all_block_stmts(block.stmts, dummy_ret_stmt.as_ref()).skip(idx);
+ if sdap.number_of_stmts > 1 && Self::at_least_one_stmt_is_expensive(stmts_after_last_use) {
+ span_lint_and_then(
+ cx,
+ SIGNIFICANT_DROP_TIGHTENING,
+ sdap.init_bind_ident.span,
+ "temporary with significant `Drop` can be early dropped",
+ |diag| {
+ Self::set_suggestions(cx, block.span, diag, &sdap);
+ },
+ );
+ }
+ }
+}
+
+/// Auxiliary parameters used on each block check.
+struct SigDropAuxParams {
+ /// The binding or variable that references the initial construction of the type marked with
+ /// `#[has_significant_drop]`.
+ init_bind_ident: Ident,
+ /// Similar to `init_bind_ident` but encompasses the right-hand method call.
+ init_method_span: Span,
+ /// Similar to `init_bind_ident` but encompasses the whole contained statement.
+ init_stmt_span: Span,
+
+ /// The last visited binding or variable span within a block that had any referenced inner type
+ /// marked with `#[has_significant_drop]`.
+ last_use_bind_span: Option<Span>,
+ /// Index of the last visited statement within a block that had any referenced inner type
+ /// marked with `#[has_significant_drop]`.
+ last_use_stmt_idx: usize,
+ /// Similar to `last_use_bind_span` but encompasses the whole contained statement.
+ last_use_stmt_span: Span,
+ /// Similar to `last_use_bind_span` but encompasses the right-hand method call.
+ last_use_method_span: Span,
+
+ /// Total number of statements within a block that have any referenced inner type marked with
+ /// `#[has_significant_drop]`.
+ number_of_stmts: usize,
+}
+
+impl Default for SigDropAuxParams {
+ fn default() -> Self {
+ Self {
+ init_bind_ident: Ident::empty(),
+ init_method_span: DUMMY_SP,
+ init_stmt_span: DUMMY_SP,
+ last_use_bind_span: None,
+ last_use_method_span: DUMMY_SP,
+ last_use_stmt_idx: 0,
+ last_use_stmt_span: DUMMY_SP,
+ number_of_stmts: 0,
+ }
+ }
+}
+
+/// Checks the existence of the `#[has_significant_drop]` attribute
+struct SigDropChecker<'cx, 'sdt, 'tcx> {
+ cx: &'cx LateContext<'tcx>,
+ seen_types: &'sdt mut FxHashSet<Ty<'tcx>>,
+ type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>,
+}
+
+impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> {
+ pub(crate) fn new(
+ cx: &'cx LateContext<'tcx>,
+ seen_types: &'sdt mut FxHashSet<Ty<'tcx>>,
+ type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>,
+ ) -> Self {
+ seen_types.clear();
+ Self {
+ cx,
+ seen_types,
+ type_cache,
+ }
+ }
+
+ pub(crate) fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>) -> bool {
+ if let Some(adt) = ty.ty_adt_def() {
+ let mut iter = get_attr(
+ self.cx.sess(),
+ self.cx.tcx.get_attrs_unchecked(adt.did()),
+ "has_significant_drop",
+ );
+ if iter.next().is_some() {
+ return true;
+ }
+ }
+ match ty.kind() {
+ rustc_middle::ty::Adt(a, b) => {
+ for f in a.all_fields() {
+ let ty = f.ty(self.cx.tcx, b);
+ if !self.has_seen_ty(ty) && self.has_sig_drop_attr(ty) {
+ return true;
+ }
+ }
+ for generic_arg in b.iter() {
+ if let GenericArgKind::Type(ty) = generic_arg.unpack() {
+ if self.has_sig_drop_attr(ty) {
+ return true;
+ }
+ }
+ }
+ false
+ },
+ rustc_middle::ty::Array(ty, _)
+ | rustc_middle::ty::RawPtr(TypeAndMut { ty, .. })
+ | rustc_middle::ty::Ref(_, ty, _)
+ | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(*ty),
+ _ => false,
+ }
+ }
+
+ pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool {
+ // The borrow checker prevents us from using something fancier like or_insert_with.
+ if let Some(ty) = self.type_cache.get(&ty) {
+ return *ty;
+ }
+ let value = self.has_sig_drop_attr_uncached(ty);
+ self.type_cache.insert(ty, value);
+ value
+ }
+
+ fn has_seen_ty(&mut self, ty: Ty<'tcx>) -> bool {
+ !self.seen_types.insert(ty)
+ }
+}
+
+/// Performs recursive calls to find any inner type marked with `#[has_significant_drop]`.
+struct SigDropFinder<'cx, 'sdt, 'tcx> {
+ cx: &'cx LateContext<'tcx>,
+ has_sig_drop: bool,
+ sig_drop_checker: SigDropChecker<'cx, 'sdt, 'tcx>,
+}
+
+impl<'cx, 'sdt, 'tcx> SigDropFinder<'cx, 'sdt, 'tcx> {
+ fn new(
+ cx: &'cx LateContext<'tcx>,
+ seen_types: &'sdt mut FxHashSet<Ty<'tcx>>,
+ type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>,
+ ) -> Self {
+ Self {
+ cx,
+ has_sig_drop: false,
+ sig_drop_checker: SigDropChecker::new(cx, seen_types, type_cache),
+ }
+ }
+}
+
+impl<'cx, 'sdt, 'tcx> Visitor<'tcx> for SigDropFinder<'cx, 'sdt, 'tcx> {
+ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'_>) {
+ if self
+ .sig_drop_checker
+ .has_sig_drop_attr(self.cx.typeck_results().expr_ty(ex))
+ {
+ self.has_sig_drop = true;
+ return;
+ }
+
+ match ex.kind {
+ hir::ExprKind::MethodCall(_, expr, ..) => {
+ self.visit_expr(expr);
+ },
+ hir::ExprKind::Array(..)
+ | hir::ExprKind::Assign(..)
+ | hir::ExprKind::AssignOp(..)
+ | hir::ExprKind::Binary(..)
+ | hir::ExprKind::Box(..)
+ | hir::ExprKind::Call(..)
+ | hir::ExprKind::Field(..)
+ | hir::ExprKind::If(..)
+ | hir::ExprKind::Index(..)
+ | hir::ExprKind::Match(..)
+ | hir::ExprKind::Repeat(..)
+ | hir::ExprKind::Ret(..)
+ | hir::ExprKind::Tup(..)
+ | hir::ExprKind::Unary(..)
+ | hir::ExprKind::Yield(..) => {
+ walk_expr(self, ex);
+ },
+ _ => {},
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index bc18cad6d..b2f4b3109 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -190,7 +190,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd {
},
ExprKind::Index(target, _idx) => {
let e_ty = cx.typeck_results().expr_ty(target).peel_refs();
- if matches!(e_ty.kind(), ty::Str) || is_type_lang_item(cx, e_ty, LangItem::String) {
+ if e_ty.is_str() || is_type_lang_item(cx, e_ty, LangItem::String) {
span_lint(
cx,
STRING_SLICE,
@@ -407,7 +407,7 @@ impl<'tcx> LateLintPass<'tcx> for StrToString {
if path.ident.name == sym::to_string;
let ty = cx.typeck_results().expr_ty(self_arg);
if let ty::Ref(_, ty, ..) = ty.kind();
- if *ty.kind() == ty::Str;
+ if ty.is_str();
then {
span_lint_and_help(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
index 301aa5798..9c0dc8096 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
@@ -9,7 +9,7 @@ declare_clippy_lint! {
/// ### What it does
/// Warns for a Bitwise XOR (`^`) operator being probably confused as a powering. It will not trigger if any of the numbers are not in decimal.
/// ### Why is this bad?
- /// It's most probably a typo and may lead to unexpected behaviours.
+ /// It's most probably a typo and may lead to unexpected behaviours.
/// ### Example
/// ```rust
/// let x = 3_i32 ^ 4_i32;
@@ -18,7 +18,7 @@ declare_clippy_lint! {
/// ```rust
/// let x = 3_i32.pow(4);
/// ```
- #[clippy::version = "1.66.0"]
+ #[clippy::version = "1.67.0"]
pub SUSPICIOUS_XOR_USED_AS_POW,
restriction,
"XOR (`^`) operator possibly used as exponentiation operator"
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 17e9cc5f6..0f062cecf 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;
-use rustc_span::{sym, Span};
+use rustc_span::{sym, symbol::Ident, Span};
declare_clippy_lint! {
/// ### What it does
@@ -174,53 +174,74 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
/// Implementation of the `ALMOST_SWAPPED` lint.
fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
- for w in block.stmts.windows(2) {
- if_chain! {
- if let StmtKind::Semi(first) = w[0].kind;
- if let StmtKind::Semi(second) = w[1].kind;
- if first.span.ctxt() == second.span.ctxt();
- if let ExprKind::Assign(lhs0, rhs0, _) = first.kind;
- if let ExprKind::Assign(lhs1, rhs1, _) = second.kind;
- if eq_expr_value(cx, lhs0, rhs1);
- if eq_expr_value(cx, lhs1, rhs0);
- then {
- let lhs0 = Sugg::hir_opt(cx, lhs0);
- let rhs0 = Sugg::hir_opt(cx, rhs0);
- let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) {
- (
- format!(" `{first}` and `{second}`"),
- first.mut_addr().to_string(),
- second.mut_addr().to_string(),
- )
- } else {
- (String::new(), String::new(), String::new())
- };
+ for [first, second] in block.stmts.array_windows() {
+ if let Some((lhs0, rhs0)) = parse(first)
+ && let Some((lhs1, rhs1)) = parse(second)
+ && first.span.eq_ctxt(second.span)
+ && is_same(cx, lhs0, rhs1)
+ && is_same(cx, lhs1, rhs0)
+ && let Some(lhs_sugg) = match &lhs0 {
+ ExprOrIdent::Expr(expr) => Sugg::hir_opt(cx, expr),
+ ExprOrIdent::Ident(ident) => Some(Sugg::NonParen(ident.as_str().into())),
+ }
+ && let Some(rhs_sugg) = Sugg::hir_opt(cx, rhs0)
+ {
+ let span = first.span.to(rhs1.span);
+ let Some(sugg) = std_or_core(cx) else { return };
+ span_lint_and_then(
+ cx,
+ ALMOST_SWAPPED,
+ span,
+ &format!("this looks like you are trying to swap `{lhs_sugg}` and `{rhs_sugg}`"),
+ |diag| {
+ diag.span_suggestion(
+ span,
+ "try",
+ format!("{sugg}::mem::swap({}, {})", lhs_sugg.mut_addr(), rhs_sugg.mut_addr()),
+ Applicability::MaybeIncorrect,
+ );
+ diag.note(format!("or maybe you should use `{sugg}::mem::replace`?"));
+ },
+ );
+ }
+ }
+}
+
+fn is_same(cx: &LateContext<'_>, lhs: ExprOrIdent<'_>, rhs: &Expr<'_>) -> bool {
+ match lhs {
+ ExprOrIdent::Expr(expr) => eq_expr_value(cx, expr, rhs),
+ ExprOrIdent::Ident(ident) => {
+ if let ExprKind::Path(QPath::Resolved(None, path)) = rhs.kind
+ && let [segment] = &path.segments
+ && segment.ident == ident
+ {
+ true
+ } else {
+ false
+ }
+ }
+ }
+}
- let span = first.span.to(second.span);
- let Some(sugg) = std_or_core(cx) else { return };
+#[derive(Debug, Clone, Copy)]
+enum ExprOrIdent<'a> {
+ Expr(&'a Expr<'a>),
+ Ident(Ident),
+}
- span_lint_and_then(cx,
- ALMOST_SWAPPED,
- span,
- &format!("this looks like you are trying to swap{what}"),
- |diag| {
- if !what.is_empty() {
- diag.span_suggestion(
- span,
- "try",
- format!(
- "{sugg}::mem::swap({lhs}, {rhs})",
- ),
- Applicability::MaybeIncorrect,
- );
- diag.note(
- format!("or maybe you should use `{sugg}::mem::replace`?")
- );
- }
- });
+fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr<'hir>)> {
+ if let StmtKind::Semi(expr) = stmt.kind {
+ if let ExprKind::Assign(lhs, rhs, _) = expr.kind {
+ return Some((ExprOrIdent::Expr(lhs), rhs));
+ }
+ } else if let StmtKind::Local(expr) = stmt.kind {
+ if let Some(rhs) = expr.init {
+ if let PatKind::Binding(_, _, ident_l, _) = expr.pat.kind {
+ return Some((ExprOrIdent::Ident(ident_l), rhs));
}
}
}
+ None
}
/// Implementation of the xor case for `MANUAL_SWAP` lint.
diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
index 63b326048..1382c1a40 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -61,9 +61,8 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_
if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind;
// Then check if that that array zero-sized
- let length_ldid = cx.tcx.hir().local_def_id(length.hir_id);
- let length = Const::from_anon_const(cx.tcx, length_ldid);
- let length = length.try_eval_usize(cx.tcx, cx.param_env);
+ let length = Const::from_anon_const(cx.tcx, length.def_id);
+ let length = length.try_eval_target_usize(cx.tcx, cx.param_env);
if let Some(length) = length;
then {
length == 0
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index 691d759d7..c01cbe509 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -3,6 +3,7 @@ mod transmute_float_to_int;
mod transmute_int_to_bool;
mod transmute_int_to_char;
mod transmute_int_to_float;
+mod transmute_int_to_non_zero;
mod transmute_null_to_fn;
mod transmute_num_to_bytes;
mod transmute_ptr_to_ptr;
@@ -255,6 +256,31 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
+ /// Checks for transmutes from integers to `NonZero*` types, and suggests their `new_unchecked`
+ /// method instead.
+ ///
+ /// ### Why is this bad?
+ /// Transmutes work on any types and thus might cause unsoundness when those types change
+ /// elsewhere. `new_unchecked` only works for the appropriate types instead.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use core::num::NonZeroU32;
+ /// let _non_zero: NonZeroU32 = unsafe { std::mem::transmute(123) };
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # use core::num::NonZeroU32;
+ /// let _non_zero = unsafe { NonZeroU32::new_unchecked(123) };
+ /// ```
+ #[clippy::version = "1.69.0"]
+ pub TRANSMUTE_INT_TO_NON_ZERO,
+ complexity,
+ "transmutes from an integer to a non-zero wrapper"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
/// Checks for transmutes from a float to an integer.
///
/// ### Why is this bad?
@@ -451,6 +477,7 @@ impl_lint_pass!(Transmute => [
TRANSMUTE_BYTES_TO_STR,
TRANSMUTE_INT_TO_BOOL,
TRANSMUTE_INT_TO_FLOAT,
+ TRANSMUTE_INT_TO_NON_ZERO,
TRANSMUTE_FLOAT_TO_INT,
TRANSMUTE_NUM_TO_BYTES,
UNSOUND_COLLECTION_TRANSMUTE,
@@ -479,7 +506,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
// - char conversions (https://github.com/rust-lang/rust/issues/89259)
let const_context = in_constant(cx, e.hir_id);
- let from_ty = cx.typeck_results().expr_ty_adjusted(arg);
+ let (from_ty, from_ty_adjusted) = match cx.typeck_results().expr_adjustments(arg) {
+ [] => (cx.typeck_results().expr_ty(arg), false),
+ [.., a] => (a.target, true),
+ };
// Adjustments for `to_ty` happen after the call to `transmute`, so don't use them.
let to_ty = cx.typeck_results().expr_ty(e);
@@ -498,6 +528,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
| transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
| transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
| transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context)
+ | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg)
| transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context)
| transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context)
| (
@@ -506,7 +537,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
);
if !linted {
- transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, arg);
+ transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
new file mode 100644
index 000000000..550365325
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
@@ -0,0 +1,61 @@
+use super::TRANSMUTE_INT_TO_NON_ZERO;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::sugg;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::{
+ query::Key,
+ ty::{self, Ty},
+};
+use rustc_span::symbol::sym;
+
+/// Checks for `transmute_int_to_non_zero` lint.
+/// Returns `true` if it's triggered, otherwise returns `false`.
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ e: &'tcx Expr<'_>,
+ from_ty: Ty<'tcx>,
+ to_ty: Ty<'tcx>,
+ arg: &'tcx Expr<'_>,
+) -> bool {
+ let (ty::Int(_) | ty::Uint(_), Some(to_ty_id)) = (&from_ty.kind(), to_ty.ty_adt_id()) else {
+ return false;
+ };
+ let Some(to_type_sym) = cx.tcx.get_diagnostic_name(to_ty_id) else {
+ return false;
+ };
+
+ if !matches!(
+ to_type_sym,
+ sym::NonZeroU8
+ | sym::NonZeroU16
+ | sym::NonZeroU32
+ | sym::NonZeroU64
+ | sym::NonZeroU128
+ | sym::NonZeroI8
+ | sym::NonZeroI16
+ | sym::NonZeroI32
+ | sym::NonZeroI64
+ | sym::NonZeroI128
+ ) {
+ return false;
+ }
+
+ span_lint_and_then(
+ cx,
+ TRANSMUTE_INT_TO_NON_ZERO,
+ e.span,
+ &format!("transmute from a `{from_ty}` to a `{to_type_sym}`"),
+ |diag| {
+ let arg = sugg::Sugg::hir(cx, arg, "..");
+ diag.span_suggestion(
+ e.span,
+ "consider using",
+ format!("{to_type_sym}::{}({arg})", sym::new_unchecked),
+ Applicability::Unspecified,
+ );
+ },
+ );
+ true
+}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
index 54ac04df1..6bdb9aa5a 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
@@ -6,7 +6,7 @@ use clippy_utils::sugg;
use rustc_errors::Applicability;
use rustc_hir::{self as hir, Expr, GenericArg, Mutability, Path, TyKind};
use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty, TypeVisitable};
+use rustc_middle::ty::{self, Ty, TypeVisitableExt};
/// Checks for `transmute_ptr_to_ref` lint.
/// Returns `true` if it's triggered, otherwise returns `false`.
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
index afb7f2e13..426c72538 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
@@ -22,7 +22,8 @@ pub(super) fn check<'tcx>(
if let (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) = (&from_ty.kind(), &to_ty.kind()) {
if_chain! {
- if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind(), &ty_to.kind());
+ if let ty::Slice(slice_ty) = *ty_from.kind();
+ if ty_to.is_str();
if let ty::Uint(ty::UintTy::U8) = slice_ty.kind();
if from_mutbl == to_mutbl;
then {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
index af0242348..5e24213d0 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -273,7 +273,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
.non_enum_variant()
.fields
.iter()
- .map(|f| cx.tcx.bound_type_of(f.did).subst(cx.tcx, substs));
+ .map(|f| cx.tcx.type_of(f.did).subst(cx.tcx, substs));
let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
return ReducedTy::TypeErasure { raw_ptr_only: false };
};
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
index b79d4e915..8530b4324 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
@@ -1,11 +1,11 @@
-use super::utils::can_be_expressed_as_pointer_cast;
+use super::utils::check_cast;
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::sugg;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{cast::CastKind, Ty};
/// Checks for `transmutes_expressible_as_ptr_casts` lint.
/// Returns `true` if it's triggered, otherwise returns `false`.
@@ -13,24 +13,40 @@ pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
e: &'tcx Expr<'_>,
from_ty: Ty<'tcx>,
+ from_ty_adjusted: bool,
to_ty: Ty<'tcx>,
arg: &'tcx Expr<'_>,
) -> bool {
- if can_be_expressed_as_pointer_cast(cx, e, from_ty, to_ty) {
- span_lint_and_then(
- cx,
- TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
- e.span,
- &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
- |diag| {
- if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
- let sugg = arg.as_ty(to_ty.to_string()).to_string();
- diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
- }
- },
- );
- true
- } else {
- false
- }
+ use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
+ let mut app = Applicability::MachineApplicable;
+ let sugg = match check_cast(cx, e, from_ty, to_ty) {
+ Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => {
+ Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
+ .as_ty(to_ty.to_string())
+ .to_string()
+ },
+ Some(PtrAddrCast) if !from_ty_adjusted => Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
+ .as_ty(to_ty.to_string())
+ .to_string(),
+
+ // The only adjustments here would be ref-to-ptr and unsize coercions. The result of an unsize coercions can't
+ // be transmuted to a usize. For ref-to-ptr coercions, borrows need to be cast to a pointer before being cast to
+ // a usize.
+ Some(PtrAddrCast) => format!(
+ "{} as {to_ty}",
+ Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app).as_ty(from_ty)
+ ),
+ _ => return false,
+ };
+
+ span_lint_and_sugg(
+ cx,
+ TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
+ e.span,
+ &format!("transmute from `{from_ty}` to `{to_ty}` which could be expressed as a pointer cast instead"),
+ "try",
+ sugg,
+ app,
+ );
+ true
}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
index 871c3fadb..56207fe76 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
@@ -4,7 +4,7 @@ use clippy_utils::sugg;
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty, TypeVisitable};
+use rustc_middle::ty::{self, Ty, TypeVisitableExt};
/// Checks for `useless_transmute` lint.
/// Returns `true` if it's triggered, otherwise returns `false`.
diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
index 49d863ec0..cddaf9450 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
@@ -20,33 +20,21 @@ pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx
}
}
-/// Check if the type conversion can be expressed as a pointer cast, instead of
-/// a transmute. In certain cases, including some invalid casts from array
-/// references to pointers, this may cause additional errors to be emitted and/or
-/// ICE error messages. This function will panic if that occurs.
-pub(super) fn can_be_expressed_as_pointer_cast<'tcx>(
- cx: &LateContext<'tcx>,
- e: &'tcx Expr<'_>,
- from_ty: Ty<'tcx>,
- to_ty: Ty<'tcx>,
-) -> bool {
- use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
- matches!(
- check_cast(cx, e, from_ty, to_ty),
- Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast)
- )
-}
-
/// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of
/// the cast. In certain cases, including some invalid casts from array references
/// to pointers, this may cause additional errors to be emitted and/or ICE error
/// messages. This function will panic if that occurs.
-fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option<CastKind> {
+pub(super) fn check_cast<'tcx>(
+ cx: &LateContext<'tcx>,
+ e: &'tcx Expr<'_>,
+ from_ty: Ty<'tcx>,
+ to_ty: Ty<'tcx>,
+) -> Option<CastKind> {
let hir_id = e.hir_id;
let local_def_id = hir_id.owner.def_id;
Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
- let fn_ctxt = FnCtxt::new(inherited, cx.param_env, hir_id);
+ let fn_ctxt = FnCtxt::new(inherited, cx.param_env, local_def_id);
// If we already have errors, we can't be sure we can pointer cast.
assert!(
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 229478b7c..c1f228d5f 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -12,11 +12,12 @@ mod vec_box;
use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
- Body, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem,
+ Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem,
TraitItemKind, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::Span;
declare_clippy_lint! {
@@ -311,15 +312,27 @@ pub struct Types {
impl_lint_pass!(Types => [BOX_COLLECTION, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER, RC_MUTEX, TYPE_COMPLEXITY]);
impl<'tcx> LateLintPass<'tcx> for Types {
- fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
- let is_in_trait_impl =
- if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(id).def_id) {
- matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
- } else {
- false
- };
+ fn check_fn(
+ &mut self,
+ cx: &LateContext<'_>,
+ _: FnKind<'_>,
+ decl: &FnDecl<'_>,
+ _: &Body<'_>,
+ _: Span,
+ def_id: LocalDefId,
+ ) {
+ let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(
+ cx.tcx
+ .hir()
+ .get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(def_id))
+ .def_id,
+ ) {
+ matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
+ } else {
+ false
+ };
- let is_exported = cx.effective_visibilities.is_exported(cx.tcx.hir().local_def_id(id));
+ let is_exported = cx.effective_visibilities.is_exported(def_id);
self.check_fn_decl(
cx,
@@ -379,9 +392,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
}
fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
- let is_exported = cx
- .effective_visibilities
- .is_exported(cx.tcx.hir().local_def_id(field.hir_id));
+ let is_exported = cx.effective_visibilities.is_exported(field.def_id);
self.check_ty(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
index f9b9a66b5..f7adc9d35 100644
--- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
+++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
@@ -5,7 +5,7 @@ use rustc_errors::Applicability;
use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::LateContext;
-use rustc_middle::ty::TypeVisitable;
+use rustc_middle::ty::TypeVisitableExt;
use rustc_span::symbol::sym;
use super::{utils, REDUNDANT_ALLOCATION};
diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
index 7a3c7cd8a..d3062f3d2 100644
--- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
@@ -7,7 +7,7 @@ use rustc_hir::{self as hir, def_id::DefId, GenericArg, QPath, TyKind};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::LateContext;
use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::TypeVisitable;
+use rustc_middle::ty::TypeVisitableExt;
use rustc_span::symbol::sym;
use super::VEC_BOX;
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 2e1b6d8d4..2920684ad 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -263,6 +263,18 @@ fn expr_has_unnecessary_safety_comment<'tcx>(
expr: &'tcx hir::Expr<'tcx>,
comment_pos: BytePos,
) -> Option<Span> {
+ if cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, ref node)| {
+ matches!(
+ node,
+ Node::Block(&Block {
+ rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
+ ..
+ }),
+ )
+ }) {
+ return None;
+ }
+
// this should roughly be the reverse of `block_parents_have_safety_comment`
if for_each_expr_with_closures(cx, expr, |expr| match expr.kind {
hir::ExprKind::Block(
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index a138a4baa..289ca4e9b 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -76,7 +76,7 @@ fn get_projection_pred<'tcx>(
fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Vec<(usize, String)> {
let mut args_to_check = Vec::new();
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
- let fn_sig = cx.tcx.fn_sig(def_id);
+ let fn_sig = cx.tcx.fn_sig(def_id).subst_identity();
let generics = cx.tcx.predicates_of(def_id);
let fn_mut_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().fn_mut_trait());
let ord_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.get_diagnostic_item(sym::Ord));
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index ce9ebad8c..d6167a621 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -156,7 +156,7 @@ fn needs_inferred_result_ty(
},
_ => return false,
};
- let sig = cx.tcx.fn_sig(id).skip_binder();
+ let sig = cx.tcx.fn_sig(id).subst_identity().skip_binder();
if let ty::Param(output_ty) = *sig.output().kind() {
let args: Vec<&Expr<'_>> = if let Some(receiver) = receiver {
std::iter::once(receiver).chain(args.iter()).collect()
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
index 9f207d32f..6e802794f 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
@@ -7,6 +7,7 @@ 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_span::symbol::sym;
declare_clippy_lint! {
/// ### What it does
@@ -54,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings {
);
} else {
if_chain! {
- if Some(fun_def_id) == cx.tcx.lang_items().from_fn();
+ if cx.tcx.is_diagnostic_item(sym::from_fn, fun_def_id);
if let [.., last_arg] = args;
if let ExprKind::Lit(spanned) = &last_arg.kind;
if let LitKind::Str(symbol, _) = spanned.node;
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index 84ec0d0fb..8b0e0ce5a 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -5,10 +5,11 @@ use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::LangItem::{OptionSome, ResultOk};
-use rustc_hir::{Body, ExprKind, FnDecl, HirId, Impl, ItemKind, Node};
+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_span::def_id::LocalDefId;
use rustc_span::symbol::sym;
use rustc_span::Span;
@@ -77,12 +78,11 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
fn_decl: &FnDecl<'tcx>,
body: &Body<'tcx>,
span: Span,
- hir_id: HirId,
+ def_id: LocalDefId,
) {
// Abort if public function/method or closure.
match fn_kind {
FnKind::ItemFn(..) | FnKind::Method(..) => {
- let def_id = cx.tcx.hir().local_def_id(hir_id);
if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
return;
}
@@ -91,6 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
}
// Abort if the method is implementing a trait or of it a trait method.
+ let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
if matches!(
item.kind,
@@ -101,17 +102,18 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
}
// Get the wrapper and inner types, if can't, abort.
- let (return_type_label, lang_item, inner_type) = if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id).kind() {
- if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) {
- ("Option", OptionSome, subst.type_at(0))
- } else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did()) {
- ("Result", ResultOk, subst.type_at(0))
+ let (return_type_label, lang_item, inner_type) =
+ if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id.expect_owner()).kind() {
+ if cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) {
+ ("Option", OptionSome, subst.type_at(0))
+ } else if cx.tcx.is_diagnostic_item(sym::Result, adt_def.did()) {
+ ("Result", ResultOk, subst.type_at(0))
+ } else {
+ return;
+ }
} else {
return;
- }
- } else {
- return;
- };
+ };
// Check if all return expression respect the following condition and collect them.
let mut suggs = Vec::new();
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 7355260ae..a57bf7ee8 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -12,9 +12,9 @@ use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::DUMMY_SP;
-
use std::cell::Cell;
use std::mem;
+use thin_vec::{thin_vec, ThinVec};
declare_clippy_lint! {
/// ### What it does
@@ -214,7 +214,7 @@ macro_rules! always_pat {
/// Focus on `focus_idx` in `alternatives`,
/// attempting to extend it with elements of the same constructor `C`
/// in `alternatives[focus_idx + 1..]`.
-fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize) -> bool {
+fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: usize) -> bool {
// Extract the kind; we'll need to make some changes in it.
let mut focus_kind = mem::replace(&mut alternatives[focus_idx].kind, PatKind::Wild);
// We'll focus on `alternatives[focus_idx]`,
@@ -296,7 +296,7 @@ fn extend_with_struct_pat(
fps1: &mut [ast::PatField],
rest1: bool,
start: usize,
- alternatives: &mut Vec<P<Pat>>,
+ alternatives: &mut ThinVec<P<Pat>>,
) -> bool {
(0..fps1.len()).any(|idx| {
let pos_in_2 = Cell::new(None); // The element `k`.
@@ -336,9 +336,9 @@ fn extend_with_struct_pat(
fn extend_with_matching_product(
targets: &mut [P<Pat>],
start: usize,
- alternatives: &mut Vec<P<Pat>>,
+ alternatives: &mut ThinVec<P<Pat>>,
predicate: impl Fn(&PatKind, &[P<Pat>], usize) -> bool,
- extract: impl Fn(PatKind) -> Vec<P<Pat>>,
+ extract: impl Fn(PatKind) -> ThinVec<P<Pat>>,
) -> bool {
(0..targets.len()).any(|idx| {
let tail_or = drain_matching(
@@ -365,14 +365,14 @@ fn take_pat(from: &mut Pat) -> Pat {
/// Extend `target` as an or-pattern with the alternatives
/// in `tail_or` if there are any and return if there were.
-fn extend_with_tail_or(target: &mut Pat, tail_or: Vec<P<Pat>>) -> bool {
- fn extend(target: &mut Pat, mut tail_or: Vec<P<Pat>>) {
+fn extend_with_tail_or(target: &mut Pat, tail_or: ThinVec<P<Pat>>) -> bool {
+ fn extend(target: &mut Pat, mut tail_or: ThinVec<P<Pat>>) {
match target {
// On an existing or-pattern in the target, append to it.
Pat { kind: Or(ps), .. } => ps.append(&mut tail_or),
// Otherwise convert the target to an or-pattern.
target => {
- let mut init_or = vec![P(take_pat(target))];
+ let mut init_or = thin_vec![P(take_pat(target))];
init_or.append(&mut tail_or);
target.kind = Or(init_or);
},
@@ -391,26 +391,42 @@ fn extend_with_tail_or(target: &mut Pat, tail_or: Vec<P<Pat>>) -> bool {
// Only elements beginning with `start` are considered for extraction.
fn drain_matching(
start: usize,
- alternatives: &mut Vec<P<Pat>>,
+ alternatives: &mut ThinVec<P<Pat>>,
predicate: impl Fn(&PatKind) -> bool,
extract: impl Fn(PatKind) -> P<Pat>,
-) -> Vec<P<Pat>> {
- let mut tail_or = vec![];
+) -> ThinVec<P<Pat>> {
+ let mut tail_or = ThinVec::new();
let mut idx = 0;
- for pat in alternatives.drain_filter(|p| {
- // Check if we should extract, but only if `idx >= start`.
+
+ // If `ThinVec` had the `drain_filter` method, this loop could be rewritten
+ // like so:
+ //
+ // for pat in alternatives.drain_filter(|p| {
+ // // Check if we should extract, but only if `idx >= start`.
+ // idx += 1;
+ // idx > start && predicate(&p.kind)
+ // }) {
+ // tail_or.push(extract(pat.into_inner().kind));
+ // }
+ let mut i = 0;
+ while i < alternatives.len() {
idx += 1;
- idx > start && predicate(&p.kind)
- }) {
- tail_or.push(extract(pat.into_inner().kind));
+ // Check if we should extract, but only if `idx >= start`.
+ if idx > start && predicate(&alternatives[i].kind) {
+ let pat = alternatives.remove(i);
+ tail_or.push(extract(pat.into_inner().kind));
+ } else {
+ i += 1;
+ }
}
+
tail_or
}
fn extend_with_matching(
target: &mut Pat,
start: usize,
- alternatives: &mut Vec<P<Pat>>,
+ alternatives: &mut ThinVec<P<Pat>>,
predicate: impl Fn(&PatKind) -> bool,
extract: impl Fn(PatKind) -> P<Pat>,
) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index 3538bef6e..55651a28b 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -1,9 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, YieldSource};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, YieldSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
declare_clippy_lint! {
@@ -66,11 +67,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
fn_decl: &'tcx FnDecl<'tcx>,
body: &Body<'tcx>,
span: Span,
- hir_id: HirId,
+ def_id: LocalDefId,
) {
if !span.from_expansion() && fn_kind.asyncness().is_async() {
let mut visitor = AsyncFnVisitor { cx, found_await: false };
- walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), hir_id);
+ walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id);
if !visitor.found_await {
span_lint_and_help(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index 92053cec5..0e526c216 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
}
},
hir::ExprKind::MethodCall(path, arg_0, ..) => match path.ident.as_str() {
- "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => {
+ "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" | "is_ok" | "is_err" => {
check_map_error(cx, arg_0, expr);
},
_ => (),
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index ea878043c..377d3fb6f 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -11,6 +11,7 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::Ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
use rustc_span::source_map::Span;
use rustc_span::sym;
@@ -312,7 +313,7 @@ impl<'tcx> LateLintPass<'tcx> for Unwrap {
decl: &'tcx FnDecl<'_>,
body: &'tcx Body<'_>,
span: Span,
- fn_id: HirId,
+ fn_id: LocalDefId,
) {
if span.from_expansion() {
return;
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index f3611d174..3a1845425 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -64,8 +64,8 @@ impl<'tcx> LateLintPass<'tcx> for UnwrapInResult {
// first check if it's a method or function
if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind;
// checking if its return type is `result` or `option`
- if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::Result)
- || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::Option);
+ if is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Result)
+ || is_type_diagnostic_item(cx, return_ty(cx, impl_item.owner_id), sym::Option);
then {
lint_impl_body(cx, impl_item.span, impl_item);
}
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 6ae9d9d63..e7c540006 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
.associated_item(impl_item.owner_id)
.trait_item_def_id
.expect("impl method matches a trait method");
- let trait_method_sig = cx.tcx.fn_sig(trait_method);
+ let trait_method_sig = cx.tcx.fn_sig(trait_method).subst_identity();
let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig);
// `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the
@@ -218,7 +218,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
} else {
hir_ty_to_ty(cx.tcx, hir_ty)
};
- if same_type_and_consts(ty, cx.tcx.type_of(impl_id));
+ if same_type_and_consts(ty, cx.tcx.type_of(impl_id).subst_identity());
then {
span_lint(cx, hir_ty.span);
}
@@ -230,7 +230,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
if !expr.span.from_expansion();
if self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS);
if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
- if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id);
+ if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id).subst_identity();
then {} else { return; }
}
match expr.kind {
@@ -254,7 +254,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
if let PatKind::Path(QPath::Resolved(_, path))
| PatKind::TupleStruct(QPath::Resolved(_, path), _, _)
| PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind;
- if cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id);
+ if cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id).subst_identity();
then {
check_path(cx, path);
}
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index a95e7b613..fede625f7 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -161,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
}
if_chain! {
- if Some(def_id) == cx.tcx.lang_items().from_fn();
+ if cx.tcx.is_diagnostic_item(sym::from_fn, def_id);
if same_type_and_consts(a, b);
then {
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index bd7daf077..c37e5bb67 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -588,7 +588,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
},
}
},
- ExprKind::Err => kind!("Err"),
+ ExprKind::Err(_) => kind!("Err"),
ExprKind::DropTemps(expr) => {
bind!(self, expr);
kind!("DropTemps({expr})");
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 3e7d0028c..1c7f3e96d 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -219,7 +219,8 @@ define_Conf! {
///
/// #### Noteworthy
///
- /// A type, say `SomeType`, listed in this configuration has the same behavior of `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
+ /// A type, say `SomeType`, listed in this configuration has the same behavior of
+ /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
(arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
/// Lint: ARITHMETIC_SIDE_EFFECTS.
///
@@ -252,7 +253,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, 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.
+ /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, 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.
///
/// The minimum rust version that the project supports
(msrv: Option<String> = None),
@@ -322,7 +323,7 @@ define_Conf! {
///
/// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
(trivial_copy_size_limit: Option<u64> = None),
- /// Lint: LARGE_TYPE_PASS_BY_MOVE.
+ /// Lint: LARGE_TYPES_PASSED_BY_VALUE.
///
/// The minimum size (in bytes) to consider a type for passing by reference instead of by value.
(pass_by_value_size_limit: u64 = 256),
@@ -410,7 +411,7 @@ define_Conf! {
/// the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed.
/// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
(max_suggested_slice_pattern_length: u64 = 3),
- /// Lint: AWAIT_HOLDING_INVALID_TYPE
+ /// Lint: AWAIT_HOLDING_INVALID_TYPE.
(await_holding_invalid_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
/// Lint: LARGE_INCLUDE_FILE.
///
@@ -418,25 +419,25 @@ define_Conf! {
(max_include_file_size: u64 = 1_000_000),
/// Lint: EXPECT_USED.
///
- /// Whether `expect` should be allowed within `#[cfg(test)]`
+ /// Whether `expect` should be allowed in test functions or `#[cfg(test)]`
(allow_expect_in_tests: bool = false),
/// Lint: UNWRAP_USED.
///
- /// Whether `unwrap` should be allowed in test cfg
+ /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
(allow_unwrap_in_tests: bool = false),
/// Lint: DBG_MACRO.
///
- /// Whether `dbg!` should be allowed in test functions
+ /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
(allow_dbg_in_tests: bool = false),
/// Lint: PRINT_STDOUT, PRINT_STDERR.
///
- /// Whether print macros (ex. `println!`) should be allowed in test functions
+ /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
(allow_print_in_tests: bool = false),
/// Lint: RESULT_LARGE_ERR.
///
/// The maximum size of the `Err`-variant in a `Result` returned from a function
(large_error_threshold: u64 = 128),
- /// Lint: MUTABLE_KEY.
+ /// Lint: MUTABLE_KEY_TYPE.
///
/// A list of paths to types that should be treated like `Arc`, i.e. ignored but
/// for the generic parameters for determining interior mutability
@@ -445,7 +446,7 @@ define_Conf! {
///
/// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
(allow_mixed_uninlined_format_args: bool = true),
- /// Lint: INDEXING_SLICING
+ /// Lint: INDEXING_SLICING.
///
/// Whether to suppress a restriction lint in constant code. In same
/// cases the restructured operation might not be unavoidable, as the
@@ -453,6 +454,11 @@ define_Conf! {
/// configuration will cause restriction lints to trigger even
/// if no suggestion can be made.
(suppress_restriction_lint_in_const: bool = false),
+ /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS.
+ ///
+ /// Whether to **only** check for missing documentation in items visible within the current
+ /// crate. For example, `pub(crate)` items.
+ (missing_docs_in_crate_items: bool = false),
}
/// Search for the configuration file.
diff --git a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
index 01efc527a..092041aec 100644
--- a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
@@ -1,4 +1,5 @@
use clippy_utils::get_attr;
+use hir::TraitItem;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -47,6 +48,18 @@ impl<'tcx> LateLintPass<'tcx> for DumpHir {
println!("{stmt:#?}");
}
}
+
+ fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
+ if has_attr(cx, item.hir_id()) {
+ println!("{item:#?}");
+ }
+ }
+
+ fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &hir::ImplItem<'_>) {
+ if has_attr(cx, item.hir_id()) {
+ println!("{item:#?}");
+ }
+ }
}
fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
index 4b33d492a..688a8b865 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
for item in cx.tcx.module_children(def_id).iter() {
if_chain! {
if let Res::Def(DefKind::Const, item_def_id) = item.res;
- let ty = cx.tcx.type_of(item_def_id);
+ let ty = cx.tcx.type_of(item_def_id).subst_identity();
if match_type(cx, ty, &paths::SYMBOL);
if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id);
if let Ok(value) = value.to_u32();
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
index 4c3b1b131..f71820765 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
@@ -215,14 +215,13 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
cx,
};
let body_id = cx.tcx.hir().body_owned_by(
- cx.tcx.hir().local_def_id(
- impl_item_refs
- .iter()
- .find(|iiref| iiref.ident.as_str() == "get_lints")
- .expect("LintPass needs to implement get_lints")
- .id
- .hir_id(),
- ),
+ impl_item_refs
+ .iter()
+ .find(|iiref| iiref.ident.as_str() == "get_lints")
+ .expect("LintPass needs to implement get_lints")
+ .id
+ .owner_id
+ .def_id,
);
collector.visit_expr(cx.tcx.hir().body(body_id).value);
}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index c4d8c28f0..b1b5164ff 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -14,6 +14,7 @@ use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
use clippy_utils::{last_path_segment, match_def_path, match_function_call, match_path, paths};
use if_chain::if_chain;
+use itertools::Itertools;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{
@@ -34,8 +35,10 @@ use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
-/// This is the output file of the lint collector.
-const OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
+/// This is the json output file of the lint collector.
+const JSON_OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
+/// This is the markdown output file of the lint collector.
+const MARKDOWN_OUTPUT_FILE: &str = "../book/src/lint_configuration.md";
/// These lints are excluded from the export.
const BLACK_LISTED_LINTS: &[&str] = &["lint_author", "dump_hir", "internal_metadata_collector"];
/// These groups will be ignored by the lint group matcher. This is useful for collections like
@@ -176,6 +179,23 @@ This lint has the following configuration variables:
)
})
}
+
+ fn configs_to_markdown(&self, map_fn: fn(&ClippyConfiguration) -> String) -> String {
+ self.config
+ .iter()
+ .filter(|config| config.deprecation_reason.is_none())
+ .filter(|config| !config.lints.is_empty())
+ .map(map_fn)
+ .join("\n")
+ }
+
+ fn get_markdown_docs(&self) -> String {
+ format!(
+ "## Lint Configuration Options\n| <div style=\"width:290px\">Option</div> | Default Value |\n|--|--|\n{}\n\n{}\n",
+ self.configs_to_markdown(ClippyConfiguration::to_markdown_table_entry),
+ self.configs_to_markdown(ClippyConfiguration::to_markdown_paragraph),
+ )
+ }
}
impl Drop for MetadataCollector {
@@ -199,12 +219,37 @@ impl Drop for MetadataCollector {
collect_renames(&mut lints);
- // Outputting
- if Path::new(OUTPUT_FILE).exists() {
- fs::remove_file(OUTPUT_FILE).unwrap();
+ // Outputting json
+ if Path::new(JSON_OUTPUT_FILE).exists() {
+ fs::remove_file(JSON_OUTPUT_FILE).unwrap();
}
- let mut file = OpenOptions::new().write(true).create(true).open(OUTPUT_FILE).unwrap();
+ let mut file = OpenOptions::new()
+ .write(true)
+ .create(true)
+ .open(JSON_OUTPUT_FILE)
+ .unwrap();
writeln!(file, "{}", serde_json::to_string_pretty(&lints).unwrap()).unwrap();
+
+ // Outputting markdown
+ if Path::new(MARKDOWN_OUTPUT_FILE).exists() {
+ fs::remove_file(MARKDOWN_OUTPUT_FILE).unwrap();
+ }
+ let mut file = OpenOptions::new()
+ .write(true)
+ .create(true)
+ .open(MARKDOWN_OUTPUT_FILE)
+ .unwrap();
+ writeln!(
+ file,
+ "<!--
+This file is generated by `cargo collect-metadata`.
+Please use that command to update the file and do not edit it by hand.
+-->
+
+{}",
+ self.get_markdown_docs(),
+ )
+ .unwrap();
}
}
@@ -505,6 +550,28 @@ impl ClippyConfiguration {
deprecation_reason,
}
}
+
+ fn to_markdown_paragraph(&self) -> String {
+ format!(
+ "### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n",
+ self.name,
+ self.doc
+ .lines()
+ .map(|line| line.strip_prefix(" ").unwrap_or(line))
+ .join("\n"),
+ self.default,
+ self.config_type,
+ self.lints
+ .iter()
+ .map(|name| name.to_string().split_whitespace().next().unwrap().to_string())
+ .map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
+ .join("\n"),
+ )
+ }
+
+ fn to_markdown_table_entry(&self) -> String {
+ format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default)
+ }
}
fn collect_configs() -> Vec<ClippyConfiguration> {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
index 9876a8a76..09f0f0d0a 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
@@ -39,6 +39,7 @@ impl LateLintPass<'_> for MsrvAttrImpl {
if self_ty_def.all_fields().any(|f| {
cx.tcx
.type_of(f.did)
+ .subst_identity()
.walk()
.filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
.any(|t| match_type(cx, t.expect_ty(), &paths::MSRV))
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
index 714436363..b59ef4086 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
@@ -44,7 +44,7 @@ impl_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]);
#[derive(Default)]
pub struct UnnecessaryDefPath {
- array_def_ids: FxHashSet<(DefId, Span)>,
+ array_def_ids: FxIndexSet<(DefId, Span)>,
linted_def_ids: FxHashSet<DefId>,
}
@@ -229,11 +229,11 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
Res::Def(DefKind::Static(_), def_id) => read_mir_alloc_def_path(
cx,
cx.tcx.eval_static_initializer(def_id).ok()?.inner(),
- cx.tcx.type_of(def_id),
+ cx.tcx.type_of(def_id).subst_identity(),
),
Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? {
ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => {
- read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id))
+ read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id).subst_identity())
},
_ => None,
},
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index 6cf2a955f..93e4b023c 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -5,7 +5,7 @@ use rustc_hir::{self as hir, HirId, ItemKind, Node};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf as _;
-use rustc_middle::ty::{Adt, Ty, TypeVisitable};
+use rustc_middle::ty::{Adt, Ty, TypeVisitableExt};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index ac6a566b9..173469f6c 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy_utils"
-version = "0.1.68"
+version = "0.1.69"
edition = "2021"
publish = false
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 9d0263e93..d82098523 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -144,7 +144,8 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
(_, Paren(r)) => eq_expr(l, r),
(Err, Err) => true,
(Box(l), Box(r)) | (Try(l), Try(r)) | (Await(l), Await(r)) => eq_expr(l, r),
- (Array(l), Array(r)) | (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)),
+ (Array(l), Array(r)) => over(l, r, |l, r| eq_expr(l, r)),
+ (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)),
(Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value),
(Call(lc, la), Call(rc, ra)) => eq_expr(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
(
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index a67bd8d46..bb8890dca 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -237,7 +237,7 @@ pub fn constant<'tcx>(
typeck_results,
param_env: lcx.param_env,
needed_resolution: false,
- substs: lcx.tcx.intern_substs(&[]),
+ substs: ty::List::empty(),
};
cx.expr(e).map(|cst| (cst, cx.needed_resolution))
}
@@ -306,7 +306,7 @@ pub fn constant_context<'a, 'tcx>(
typeck_results,
param_env: lcx.param_env,
needed_resolution: false,
- substs: lcx.tcx.intern_substs(&[]),
+ substs: ty::List::empty(),
}
}
@@ -335,7 +335,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
ExprKind::Repeat(value, _) => {
let n = match self.typeck_results.expr_ty(e).kind() {
- ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?,
+ ty::Array(_, n) => n.try_eval_target_usize(self.lcx.tcx, self.lcx.param_env)?,
_ => span_bug!(e.span, "typeck error"),
};
self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
@@ -640,7 +640,7 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -
},
mir::ConstantKind::Val(ConstValue::ByRef { alloc, offset: _ }, _) => match result.ty().kind() {
ty::Array(sub_type, len) => match sub_type.kind() {
- ty::Float(FloatTy::F32) => match len.kind().try_to_machine_usize(tcx) {
+ ty::Float(FloatTy::F32) => match len.kind().try_to_target_usize(tcx) {
Some(len) => alloc
.inner()
.inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap()))
@@ -651,7 +651,7 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -
.map(Constant::Vec),
_ => None,
},
- ty::Float(FloatTy::F64) => match len.kind().try_to_machine_usize(tcx) {
+ ty::Float(FloatTy::F64) => match len.kind().try_to_target_usize(tcx) {
Some(len) => alloc
.inner()
.inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap()))
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 967119369..ee2f816f1 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -50,7 +50,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
let name = name.as_str();
let ty = match cx.tcx.impl_of_method(fn_id) {
- Some(id) => cx.tcx.type_of(id),
+ Some(id) => cx.tcx.type_of(id).subst_identity(),
None => return Lazy,
};
@@ -71,7 +71,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
.variants()
.iter()
.flat_map(|v| v.fields.iter())
- .any(|x| matches!(cx.tcx.type_of(x.did).peel_refs().kind(), ty::Param(_)))
+ .any(|x| matches!(cx.tcx.type_of(x.did).subst_identity().peel_refs().kind(), ty::Param(_)))
&& all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() {
PredicateKind::Clause(ty::Clause::Trait(pred)) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker,
_ => true,
@@ -79,7 +79,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
&& subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_)))
{
// Limit the function to either `(self) -> bool` or `(&self) -> bool`
- match &**cx.tcx.fn_sig(fn_id).skip_binder().inputs_and_output {
+ match &**cx.tcx.fn_sig(fn_id).subst_identity().skip_binder().inputs_and_output {
[arg, res] if !arg.is_mutable_ptr() && arg.peel_refs() == ty && res.is_bool() => NoChange,
_ => Lazy,
}
@@ -193,7 +193,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
| ExprKind::Ret(_)
| ExprKind::InlineAsm(_)
| ExprKind::Yield(..)
- | ExprKind::Err => {
+ | ExprKind::Err(_) => {
self.eagerness = ForceNoChange;
return;
},
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 4604ae5c2..50bef3709 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -287,15 +287,12 @@ impl<'a> VecArgs<'a> {
Some(VecArgs::Repeat(&args[0], &args[1]))
} else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
// `vec![a, b, c]` case
- if_chain! {
- if let hir::ExprKind::Box(boxed) = args[0].kind;
- if let hir::ExprKind::Array(args) = boxed.kind;
- then {
- return Some(VecArgs::Vec(args));
- }
+ if let hir::ExprKind::Call(_, [arg]) = &args[0].kind
+ && let hir::ExprKind::Array(args) = arg.kind {
+ Some(VecArgs::Vec(args))
+ } else {
+ None
}
-
- None
} else if match_def_path(cx, fun_def_id, &paths::VEC_NEW) && args.is_empty() {
Some(VecArgs::Vec(&[]))
} else {
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 2bbe1a19b..0603755f8 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -714,7 +714,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
}
self.hash_pat(pat);
},
- ExprKind::Err => {},
+ ExprKind::Err(_) => {},
ExprKind::Lit(ref l) => {
l.node.hash(&mut self.s);
},
@@ -986,7 +986,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
TyKind::Typeof(anon_const) => {
self.hash_body(anon_const.body);
},
- TyKind::Err | TyKind::Infer | TyKind::Never => {},
+ TyKind::Err(_) | TyKind::Infer | TyKind::Never => {},
}
}
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 7a4a9036d..f02f8ecb4 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1,6 +1,5 @@
#![feature(array_chunks)]
#![feature(box_patterns)]
-#![feature(control_flow_enum)]
#![feature(let_chains)]
#![feature(lint_reasons)]
#![feature(never_type)]
@@ -105,7 +104,7 @@ use rustc_middle::ty::fast_reject::SimplifiedType::{
PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType,
};
use rustc_middle::ty::{
- layout::IntegerExt, BorrowKind, ClosureKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeVisitable, UpvarCapture,
+ layout::IntegerExt, BorrowKind, ClosureKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UpvarCapture,
};
use rustc_middle::ty::{FloatTy, IntTy, UintTy};
use rustc_span::hygiene::{ExpnKind, MacroKind};
@@ -318,7 +317,7 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str])
/// Checks if a method is defined in an impl of a diagnostic item
pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
- if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() {
+ if let Some(adt) = cx.tcx.type_of(impl_did).subst_identity().ty_adt_def() {
return cx.tcx.is_diagnostic_item(diag_item, adt.did());
}
}
@@ -553,7 +552,7 @@ fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol)
.filter(|item| item.ident.name == name)
.map(|child| child.res.expect_non_local())
.collect(),
- DefKind::Impl => tcx
+ DefKind::Impl { .. } => tcx
.associated_item_def_ids(def_id)
.iter()
.copied()
@@ -813,7 +812,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<
if let QPath::TypeRelative(_, method) = path {
if method.ident.name == sym::new {
if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
- if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() {
+ if let Some(adt) = cx.tcx.type_of(impl_did).subst_identity().ty_adt_def() {
return std_types_symbols.iter().any(|&symbol| {
cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string()
});
@@ -1119,9 +1118,8 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'
self.captures.entry(l).and_modify(|e| *e |= cap).or_insert(cap);
}
},
- ExprKind::Closure { .. } => {
- let closure_id = self.cx.tcx.hir().local_def_id(e.hir_id);
- for capture in self.cx.typeck_results().closure_min_captures_flattened(closure_id) {
+ ExprKind::Closure(closure) => {
+ for capture in self.cx.typeck_results().closure_min_captures_flattened(closure.def_id) {
let local_id = match capture.place.base {
PlaceBase::Local(id) => id,
PlaceBase::Upvar(var) => var.var_path.hir_id,
@@ -1379,7 +1377,7 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
.chain(args.iter())
.position(|arg| arg.hir_id == id)?;
let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
- let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
+ let ty = cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i];
ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
},
_ => None,
@@ -1578,16 +1576,14 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
}
/// Convenience function to get the return type of a function.
-pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> {
- let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
- let ret_ty = cx.tcx.fn_sig(fn_def_id).output();
+pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId) -> Ty<'tcx> {
+ let ret_ty = cx.tcx.fn_sig(fn_def_id).subst_identity().output();
cx.tcx.erase_late_bound_regions(ret_ty)
}
/// Convenience function to get the nth argument type of a function.
-pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId, nth: usize) -> Ty<'tcx> {
- let fn_def_id = cx.tcx.hir().local_def_id(fn_item);
- let arg = cx.tcx.fn_sig(fn_def_id).input(nth);
+pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: hir::OwnerId, nth: usize) -> Ty<'tcx> {
+ let arg = cx.tcx.fn_sig(fn_def_id).subst_identity().input(nth);
cx.tcx.erase_late_bound_regions(arg)
}
@@ -2491,6 +2487,10 @@ pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String {
comments_buf.join("\n")
}
+pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
+ sm.span_take_while(span, |&ch| ch == ' ' || ch == ';')
+}
+
macro_rules! op_utils {
($($name:ident $assign:ident)*) => {
/// Binary operation traits like `LangItem::Add`
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index 77c5f1155..be6133d32 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -1,6 +1,5 @@
#![allow(clippy::similar_names)] // `expr` and `expn`
-use crate::is_path_diagnostic_item;
use crate::source::snippet_opt;
use crate::visitors::{for_each_expr, Descend};
@@ -8,7 +7,7 @@ use arrayvec::ArrayVec;
use itertools::{izip, Either, Itertools};
use rustc_ast::ast::LitKind;
use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, Node, QPath};
+use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, LangItem, Node, QPath, TyKind};
use rustc_lexer::unescape::unescape_literal;
use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
use rustc_lint::LateContext;
@@ -328,7 +327,7 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) ->
} else {
match cx.tcx.item_name(macro_call.def_id) {
// `cfg!(debug_assertions)` in `debug_assert!`
- sym::cfg => ControlFlow::CONTINUE,
+ sym::cfg => ControlFlow::Continue(()),
// assert!(other_macro!(..))
_ => ControlFlow::Break(true),
}
@@ -392,11 +391,18 @@ impl FormatString {
};
let mut unescaped = String::with_capacity(inner.len());
+ // Sometimes the original string comes from a macro which accepts a malformed string, such as in a
+ // #[display(""somestring)] attribute (accepted by the `displaythis` crate). Reconstructing the
+ // string from the span will not be possible, so we will just return None here.
+ let mut unparsable = false;
unescape_literal(inner, mode, &mut |_, ch| match ch {
Ok(ch) => unescaped.push(ch),
Err(e) if !e.is_fatal() => (),
- Err(e) => panic!("{e:?}"),
+ Err(_) => unparsable = true,
});
+ if unparsable {
+ return None;
+ }
let mut parts = Vec::new();
let _: Option<!> = for_each_expr(pieces, |expr| {
@@ -439,8 +445,7 @@ impl<'tcx> FormatArgsValues<'tcx> {
// ArgumentV1::from_usize(<val>)
if let ExprKind::Call(callee, [val]) = expr.kind
&& let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind
- && let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind
- && path.segments.last().unwrap().ident.name == sym::ArgumentV1
+ && let TyKind::Path(QPath::LangItem(LangItem::FormatArgument, _, _)) = ty.kind
{
let val_idx = if val.span.ctxt() == expr.span.ctxt()
&& let ExprKind::Field(_, field) = val.kind
@@ -486,20 +491,6 @@ struct ParamPosition {
impl<'tcx> Visitor<'tcx> for ParamPosition {
fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) {
- fn parse_count(expr: &Expr<'_>) -> Option<usize> {
- // ::core::fmt::rt::v1::Count::Param(1usize),
- if let ExprKind::Call(ctor, [val]) = expr.kind
- && let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind
- && path.segments.last()?.ident.name == sym::Param
- && let ExprKind::Lit(lit) = &val.kind
- && let LitKind::Int(pos, _) = lit.node
- {
- Some(pos as usize)
- } else {
- None
- }
- }
-
match field.ident.name {
sym::position => {
if let ExprKind::Lit(lit) = &field.expr.kind
@@ -519,15 +510,41 @@ impl<'tcx> Visitor<'tcx> for ParamPosition {
}
}
+fn parse_count(expr: &Expr<'_>) -> Option<usize> {
+ // <::core::fmt::rt::v1::Count>::Param(1usize),
+ if let ExprKind::Call(ctor, [val]) = expr.kind
+ && let ExprKind::Path(QPath::TypeRelative(_, path)) = ctor.kind
+ && path.ident.name == sym::Param
+ && let ExprKind::Lit(lit) = &val.kind
+ && let LitKind::Int(pos, _) = lit.node
+ {
+ Some(pos as usize)
+ } else {
+ None
+ }
+}
+
/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)`
fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option<impl Iterator<Item = ParamPosition> + 'tcx> {
if let ExprKind::AddrOf(.., array) = fmt_arg.kind
&& let ExprKind::Array(specs) = array.kind
{
Some(specs.iter().map(|spec| {
- let mut position = ParamPosition::default();
- position.visit_expr(spec);
- position
+ if let ExprKind::Call(f, args) = spec.kind
+ && let ExprKind::Path(QPath::TypeRelative(ty, f)) = f.kind
+ && let TyKind::Path(QPath::LangItem(LangItem::FormatPlaceholder, _, _)) = ty.kind
+ && f.ident.name == sym::new
+ && let [position, _fill, _align, _flags, precision, width] = args
+ && let ExprKind::Lit(position) = &position.kind
+ && let LitKind::Int(position, _) = position.node {
+ ParamPosition {
+ value: position as usize,
+ width: parse_count(width),
+ precision: parse_count(precision),
+ }
+ } else {
+ ParamPosition::default()
+ }
}))
} else {
None
@@ -701,8 +718,8 @@ pub struct FormatSpec<'tcx> {
pub fill: Option<char>,
/// Optionally specified alignment.
pub align: Alignment,
- /// Packed version of various flags provided, see [`rustc_parse_format::Flag`].
- pub flags: u32,
+ /// Whether all flag options are set to default (no flags specified).
+ pub no_flags: bool,
/// Represents either the maximum width or the integer precision.
pub precision: Count<'tcx>,
/// The minimum width, will be padded according to `width`/`align`
@@ -718,7 +735,7 @@ impl<'tcx> FormatSpec<'tcx> {
Some(Self {
fill: spec.fill,
align: spec.align,
- flags: spec.flags,
+ no_flags: spec.sign.is_none() && !spec.alternate && !spec.zero_pad && spec.debug_hex.is_none(),
precision: Count::new(
FormatParamUsage::Precision,
spec.precision,
@@ -760,10 +777,7 @@ impl<'tcx> FormatSpec<'tcx> {
/// Has no other formatting specifiers than setting the format trait. returns true for `{}`,
/// `{foo}`, `{:?}`, but false for `{foo:5}`, `{3:.5?}`
pub fn is_default_for_trait(&self) -> bool {
- self.width.is_implied()
- && self.precision.is_implied()
- && self.align == Alignment::AlignUnknown
- && self.flags == 0
+ self.width.is_implied() && self.precision.is_implied() && self.align == Alignment::AlignUnknown && self.no_flags
}
}
@@ -890,7 +904,7 @@ impl<'tcx> FormatArgsExpn<'tcx> {
// ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg)
if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind
- && is_path_diagnostic_item(cx, ty, sym::Arguments)
+ && let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.kind
&& matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted")
{
let format_string = FormatString::new(cx, pieces)?;
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
index 9adae7733..920ce8e65 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_index::bit_set::{BitSet, HybridBitSet};
use rustc_lint::LateContext;
use rustc_middle::mir::{self, visit::Visitor as _, Mutability};
-use rustc_middle::ty::{self, visit::TypeVisitor};
+use rustc_middle::ty::{self, visit::TypeVisitor, TyCtxt};
use rustc_mir_dataflow::{impls::MaybeStorageLive, Analysis, ResultsCursor};
use std::borrow::Cow;
use std::ops::ControlFlow;
@@ -136,11 +136,11 @@ impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b,
struct ContainsRegion;
-impl TypeVisitor<'_> for ContainsRegion {
+impl TypeVisitor<TyCtxt<'_>> for ContainsRegion {
type BreakTy = ();
fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow<Self::BreakTy> {
- ControlFlow::BREAK
+ ControlFlow::Break(())
}
}
diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
index 42bdfd482..c225398ad 100644
--- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs
+++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
@@ -186,7 +186,7 @@ impl<'a> NumericLiteral<'a> {
// The exponent may have a sign, output it early, otherwise it will be
// treated as a digit
if digits.clone().next() == Some('-') {
- let _ = digits.next();
+ let _: Option<char> = digits.next();
output.push('-');
}
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 95eebab75..4aae0f728 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -115,6 +115,7 @@ pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"];
pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"];
pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"];
+pub const STD_PROCESS_COMMAND: [&str; 3] = ["std", "process", "Command"];
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"];
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index e5d7da682..1a35fe050 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -30,12 +30,14 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
ty::Clause::RegionOutlives(_)
| ty::Clause::TypeOutlives(_)
| ty::Clause::Projection(_)
- | ty::Clause::Trait(..),
+ | ty::Clause::Trait(..)
+ | ty::Clause::ConstArgHasType(..),
)
| ty::PredicateKind::WellFormed(_)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
+ ty::PredicateKind::AliasEq(..) => panic!("alias eq predicate on function: {predicate:#?}"),
ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"),
ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"),
ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"),
@@ -55,7 +57,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
// impl trait is gone in MIR, so check the return type manually
check_ty(
tcx,
- tcx.fn_sig(def_id).output().skip_binder(),
+ tcx.fn_sig(def_id).subst_identity().output().skip_binder(),
body.local_decls.iter().next().unwrap().source_info.span,
)?;
@@ -240,6 +242,7 @@ fn check_statement<'tcx>(
| StatementKind::Retag { .. }
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
+ | StatementKind::ConstEvalCounter
| StatementKind::Nop => Ok(()),
}
}
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index e7879bb19..07feadca2 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -20,7 +20,7 @@ use rustc_middle::mir::{FakeReadCause, Mutability};
use rustc_middle::ty;
use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext};
use std::borrow::Cow;
-use std::fmt::{Display, Write as _};
+use std::fmt::{self, Display, Write as _};
use std::ops::{Add, Neg, Not, Sub};
/// A helper type to build suggestion correctly handling parentheses.
@@ -157,7 +157,7 @@ impl<'a> Sugg<'a> {
| hir::ExprKind::Ret(..)
| hir::ExprKind::Struct(..)
| hir::ExprKind::Tup(..)
- | hir::ExprKind::Err => Sugg::NonParen(get_snippet(expr.span)),
+ | hir::ExprKind::Err(_) => Sugg::NonParen(get_snippet(expr.span)),
hir::ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
hir::ExprKind::Assign(lhs, rhs, _) => {
Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span))
@@ -219,6 +219,7 @@ impl<'a> Sugg<'a> {
| ast::ExprKind::Repeat(..)
| ast::ExprKind::Ret(..)
| ast::ExprKind::Yeet(..)
+ | ast::ExprKind::FormatArgs(..)
| ast::ExprKind::Struct(..)
| ast::ExprKind::Try(..)
| ast::ExprKind::TryBlock(..)
@@ -808,7 +809,10 @@ pub struct DerefClosure {
///
/// note: this only works on single line immutable closures with exactly one input parameter.
pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Option<DerefClosure> {
- if let hir::ExprKind::Closure(&Closure { fn_decl, body, .. }) = closure.kind {
+ if let hir::ExprKind::Closure(&Closure {
+ fn_decl, def_id, body, ..
+ }) = closure.kind
+ {
let closure_body = cx.tcx.hir().body(body);
// is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`)
// a type annotation is present if param `kind` is different from `TyKind::Infer`
@@ -828,10 +832,8 @@ pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Opti
applicability: Applicability::MachineApplicable,
};
- let fn_def_id = cx.tcx.hir().local_def_id(closure.hir_id);
let infcx = cx.tcx.infer_ctxt().build();
- ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results())
- .consume_body(closure_body);
+ ExprUseVisitor::new(&mut visitor, &infcx, def_id, cx.param_env, cx.typeck_results()).consume_body(closure_body);
if !visitor.suggestion_start.is_empty() {
return Some(DerefClosure {
@@ -884,7 +886,7 @@ impl<'tcx> DerefDelegate<'_, 'tcx> {
.cx
.typeck_results()
.type_dependent_def_id(parent_expr.hir_id)
- .map(|did| self.cx.tcx.fn_sig(did).skip_binder())
+ .map(|did| self.cx.tcx.fn_sig(did).subst_identity().skip_binder())
{
std::iter::once(receiver)
.chain(call_args.iter())
@@ -930,7 +932,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
if cmt.place.projections.is_empty() {
// handle item without any projection, that needs an explicit borrowing
// i.e.: suggest `&x` instead of `x`
- let _ = write!(self.suggestion_start, "{start_snip}&{ident_str}");
+ let _: fmt::Result = write!(self.suggestion_start, "{start_snip}&{ident_str}");
} else {
// cases where a parent `Call` or `MethodCall` is using the item
// i.e.: suggest `.contains(&x)` for `.find(|x| [1, 2, 3].contains(x)).is_none()`
@@ -945,7 +947,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
// given expression is the self argument and will be handled completely by the compiler
// i.e.: `|x| x.is_something()`
ExprKind::MethodCall(_, self_expr, ..) if self_expr.hir_id == cmt.hir_id => {
- let _ = write!(self.suggestion_start, "{start_snip}{ident_str_with_proj}");
+ let _: fmt::Result = write!(self.suggestion_start, "{start_snip}{ident_str_with_proj}");
self.next_pos = span.hi();
return;
},
@@ -1053,7 +1055,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
}
}
- let _ = write!(self.suggestion_start, "{start_snip}{replacement_str}");
+ let _: fmt::Result = write!(self.suggestion_start, "{start_snip}{replacement_str}");
}
self.next_pos = span.hi();
}
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 99fba4fe7..25654e695 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -17,8 +17,8 @@ use rustc_lint::LateContext;
use rustc_middle::mir::interpret::{ConstValue, Scalar};
use rustc_middle::ty::{
self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate,
- PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
- VariantDef, VariantDiscr,
+ PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+ TypeVisitor, UintTy, VariantDef, VariantDiscr,
};
use rustc_middle::ty::{GenericArg, GenericArgKind};
use rustc_span::symbol::Ident;
@@ -237,7 +237,7 @@ pub fn implements_trait_with_env<'tcx>(
kind: TypeVariableOriginKind::MiscVariable,
span: DUMMY_SP,
};
- let ty_params = tcx.mk_substs(
+ let ty_params = tcx.mk_substs_from_iter(
ty_params
.into_iter()
.map(|arg| arg.unwrap_or_else(|| infcx.next_ty_var(orig).into())),
@@ -346,7 +346,7 @@ pub fn is_non_aggregate_primitive_type(ty: Ty<'_>) -> bool {
pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
match *ty.kind() {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
- ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true,
+ ty::Ref(_, inner, _) if inner.is_str() => true,
ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type),
ty::Tuple(inner_types) => inner_types.iter().all(is_recursively_primitive_type),
_ => false,
@@ -628,7 +628,7 @@ impl<'tcx> ExprFnSig<'tcx> {
/// If the expression is function like, get the signature for it.
pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> {
if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) {
- Some(ExprFnSig::Sig(cx.tcx.fn_sig(id), Some(id)))
+ Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst_identity(), Some(id)))
} else {
ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs())
}
@@ -646,10 +646,13 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
.and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id)));
Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
},
- ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
- sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id).subst(cx.tcx, substs), cx.tcx.opt_parent(def_id))
- },
+ ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst(cx.tcx, subs), Some(id))),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => sig_from_bounds(
+ cx,
+ ty,
+ cx.tcx.item_bounds(def_id).subst(cx.tcx, substs),
+ cx.tcx.opt_parent(def_id),
+ ),
ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
ty::Dynamic(bounds, _, _) => {
let lang_items = cx.tcx.lang_items();
@@ -777,7 +780,7 @@ impl core::ops::Add<u32> for EnumValue {
#[expect(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option<EnumValue> {
if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) {
- match tcx.type_of(id).kind() {
+ match tcx.type_of(id).subst_identity().kind() {
ty::Int(_) => Some(EnumValue::Signed(match value.size().bytes() {
1 => i128::from(value.assert_bits(Size::from_bytes(1)) as u8 as i8),
2 => i128::from(value.assert_bits(Size::from_bytes(2)) as u16 as i16),
@@ -835,7 +838,7 @@ pub fn for_each_top_level_late_bound_region<B>(
index: u32,
f: F,
}
- impl<'tcx, B, F: FnMut(BoundRegion) -> ControlFlow<B>> TypeVisitor<'tcx> for V<F> {
+ impl<'tcx, B, F: FnMut(BoundRegion) -> ControlFlow<B>> TypeVisitor<TyCtxt<'tcx>> for V<F> {
type BreakTy = B;
fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
if let RegionKind::ReLateBound(idx, bound) = r.kind() && idx.as_u32() == self.index {
@@ -844,7 +847,7 @@ pub fn for_each_top_level_late_bound_region<B>(
ControlFlow::Continue(())
}
}
- fn visit_binder<T: TypeVisitable<'tcx>>(&mut self, t: &Binder<'tcx, T>) -> ControlFlow<Self::BreakTy> {
+ fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) -> ControlFlow<Self::BreakTy> {
self.index += 1;
let res = t.super_visit_with(self);
self.index -= 1;
@@ -891,16 +894,29 @@ impl AdtVariantInfo {
}
/// Gets the struct or enum variant from the given `Res`
-pub fn variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<&'tcx VariantDef> {
+pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<(AdtDef<'tcx>, &'tcx VariantDef)> {
match res {
- Res::Def(DefKind::Struct, id) => Some(cx.tcx.adt_def(id).non_enum_variant()),
- Res::Def(DefKind::Variant, id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).variant_with_id(id)),
- Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => Some(cx.tcx.adt_def(cx.tcx.parent(id)).non_enum_variant()),
+ Res::Def(DefKind::Struct, id) => {
+ let adt = cx.tcx.adt_def(id);
+ Some((adt, adt.non_enum_variant()))
+ },
+ Res::Def(DefKind::Variant, id) => {
+ let adt = cx.tcx.adt_def(cx.tcx.parent(id));
+ Some((adt, adt.variant_with_id(id)))
+ },
+ Res::Def(DefKind::Ctor(CtorOf::Struct, _), id) => {
+ let adt = cx.tcx.adt_def(cx.tcx.parent(id));
+ Some((adt, adt.non_enum_variant()))
+ },
Res::Def(DefKind::Ctor(CtorOf::Variant, _), id) => {
let var_id = cx.tcx.parent(id);
- Some(cx.tcx.adt_def(cx.tcx.parent(var_id)).variant_with_id(var_id))
+ let adt = cx.tcx.adt_def(cx.tcx.parent(var_id));
+ Some((adt, adt.variant_with_id(var_id)))
+ },
+ Res::SelfCtor(id) => {
+ let adt = cx.tcx.type_of(id).subst_identity().ty_adt_def().unwrap();
+ Some((adt, adt.non_enum_variant()))
},
- Res::SelfCtor(id) => Some(cx.tcx.type_of(id).ty_adt_def().unwrap().non_enum_variant()),
_ => None,
}
}
@@ -946,7 +962,7 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
(Ok(size), _) => size,
(Err(_), ty::Tuple(list)) => list.as_substs().types().map(|t| approx_ty_size(cx, t)).sum(),
(Err(_), ty::Array(t, n)) => {
- n.try_eval_usize(cx.tcx, cx.param_env).unwrap_or_default() * approx_ty_size(cx, *t)
+ n.try_eval_target_usize(cx.tcx, cx.param_env).unwrap_or_default() * approx_ty_size(cx, *t)
},
(Err(_), ty::Adt(def, subst)) if def.is_struct() => def
.variants()
@@ -1062,7 +1078,7 @@ pub fn make_projection<'tcx>(
tcx,
container_id,
assoc_ty,
- tcx.mk_substs(substs.into_iter().map(Into::into)),
+ tcx.mk_substs_from_iter(substs.into_iter().map(Into::into)),
)
}
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 14c01a60b..d27a20bd4 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -392,12 +392,16 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
.cx
.typeck_results()
.type_dependent_def_id(e.hir_id)
- .map_or(false, |id| self.cx.tcx.fn_sig(id).unsafety() == Unsafety::Unsafe) =>
+ .map_or(false, |id| {
+ self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe
+ }) =>
{
self.is_unsafe = true;
},
ExprKind::Call(func, _) => match *self.cx.typeck_results().expr_ty(func).peel_refs().kind() {
- ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
+ ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe => {
+ self.is_unsafe = true;
+ },
ty::FnPtr(sig) if sig.unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
_ => walk_expr(self, e),
},
@@ -661,7 +665,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
| ExprKind::Path(_)
| ExprKind::Continue(_)
| ExprKind::InlineAsm(_)
- | ExprKind::Err => (),
+ | ExprKind::Err(_) => (),
}
ControlFlow::Continue(())
}
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index c01e1062c..80eee3681 100644
--- a/src/tools/clippy/declare_clippy_lint/Cargo.toml
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "declare_clippy_lint"
-version = "0.1.68"
+version = "0.1.69"
edition = "2021"
publish = false
diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml
index de31c16b8..653121af5 100644
--- a/src/tools/clippy/lintcheck/Cargo.toml
+++ b/src/tools/clippy/lintcheck/Cargo.toml
@@ -10,8 +10,8 @@ edition = "2021"
publish = false
[dependencies]
-cargo_metadata = "0.14"
-clap = "3.2"
+cargo_metadata = "0.15.3"
+clap = "4.1.4"
crossbeam-channel = "0.5.6"
flate2 = "1.0"
rayon = "1.5.1"
diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs
index b8824024e..e0244ddce 100644
--- a/src/tools/clippy/lintcheck/src/config.rs
+++ b/src/tools/clippy/lintcheck/src/config.rs
@@ -35,7 +35,7 @@ fn get_clap_config() -> ArgMatches {
.long("markdown")
.help("Change the reports table to use markdown links"),
Arg::new("recursive")
- .long("--recursive")
+ .long("recursive")
.help("Run clippy on the dependencies of crates specified in crates-toml")
.conflicts_with("threads")
.conflicts_with("fix"),
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index bd49f0960..23c852980 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -17,9 +17,9 @@ use crate::recursive::LintcheckServer;
use std::collections::{HashMap, HashSet};
use std::env;
use std::env::consts::EXE_SUFFIX;
-use std::fmt::Write as _;
+use std::fmt::{self, Write as _};
use std::fs;
-use std::io::ErrorKind;
+use std::io::{self, ErrorKind};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::atomic::{AtomicUsize, Ordering};
@@ -145,8 +145,8 @@ impl ClippyWarning {
}
let mut output = String::from("| ");
- let _ = write!(output, "[`{file_with_pos}`]({file}#L{})", self.line);
- let _ = write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.message);
+ let _: fmt::Result = write!(output, "[`{file_with_pos}`]({file}#L{})", self.line);
+ let _: fmt::Result = write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.message);
output.push('\n');
output
} else {
@@ -632,7 +632,7 @@ fn main() {
.unwrap();
let server = config.recursive.then(|| {
- let _ = fs::remove_dir_all("target/lintcheck/shared_target_dir/recursive");
+ let _: io::Result<()> = fs::remove_dir_all("target/lintcheck/shared_target_dir/recursive");
LintcheckServer::spawn(recursive_options)
});
@@ -689,7 +689,7 @@ fn main() {
write!(text, "{}", all_msgs.join("")).unwrap();
text.push_str("\n\n### ICEs:\n");
for (cratename, msg) in &ices {
- let _ = write!(text, "{cratename}: '{msg}'");
+ let _: fmt::Result = write!(text, "{cratename}: '{msg}'");
}
println!("Writing logs to {}", config.lintcheck_results_path.display());
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 40a6f4709..cfe845ec7 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
[toolchain]
-channel = "nightly-2023-01-12"
+channel = "nightly-2023-02-25"
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index d521e8d88..dd183362f 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -209,7 +209,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
// Separate the output with an empty line
eprintln!();
- let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
+ let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
rustc_errors::ColorConfig::Auto,
None,
@@ -220,6 +220,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
None,
false,
false,
+ rustc_errors::TerminalUrl::No,
));
let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index 7a78b3262..82147eba3 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -28,7 +28,7 @@ with:
-D --deny OPT Set lint denied
-F --forbid OPT Set lint forbidden
-You can use tool lints to allow or deny lints from your code, eg.:
+You can use tool lints to allow or deny lints from your code, e.g.:
#[allow(clippy::needless_lifetimes)]
"#;
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
index 4be04f77f..837811bdf 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
@@ -1,8 +1,9 @@
// rustc-env:RUST_BACKTRACE=0
// normalize-stderr-test: "Clippy version: .*" -> "Clippy version: foo"
-// normalize-stderr-test: "internal_lints.rs:\d*:\d*" -> "internal_lints.rs"
+// normalize-stderr-test: "produce_ice.rs:\d*:\d*" -> "produce_ice.rs"
// normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints"
// normalize-stderr-test: "'rustc'" -> "'<unnamed>'"
+// normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> ""
#![deny(clippy::internal)]
#![allow(clippy::missing_clippy_version_attribute)]
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
index 2ba589066..7ed0ef027 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
@@ -1,4 +1,4 @@
-thread '<unnamed>' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs:28:9
+thread '<unnamed>' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: internal compiler error: unexpected panic
@@ -9,5 +9,3 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy
note: Clippy version: foo
-query stack during panic:
-end of query stack
diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs
index bff97d97d..89f142a15 100644
--- a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs
+++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs
@@ -16,6 +16,18 @@ fn main() {
expect_result();
}
+#[test]
+fn test_expect_option() {
+ let opt = Some(0);
+ let _ = opt.expect("");
+}
+
+#[test]
+fn test_expect_result() {
+ let res: Result<u8, ()> = Ok(0);
+ let _ = res.expect("");
+}
+
#[cfg(test)]
mod issue9612 {
// should not lint in `#[cfg(test)]` modules
diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/clippy.toml b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/clippy.toml
new file mode 100644
index 000000000..ec210a987
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/clippy.toml
@@ -0,0 +1 @@
+missing-docs-in-crate-items = true
diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs
new file mode 100644
index 000000000..830d71f61
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs
@@ -0,0 +1,59 @@
+//! this is crate
+#![allow(missing_docs)]
+#![warn(clippy::missing_docs_in_private_items)]
+
+/// this is mod
+mod my_mod {
+ /// some docs
+ fn priv_with_docs() {}
+ fn priv_no_docs() {}
+ /// some docs
+ pub(crate) fn crate_with_docs() {}
+ pub(crate) fn crate_no_docs() {}
+ /// some docs
+ pub(super) fn super_with_docs() {}
+ pub(super) fn super_no_docs() {}
+
+ mod my_sub {
+ /// some docs
+ fn sub_priv_with_docs() {}
+ fn sub_priv_no_docs() {}
+ /// some docs
+ pub(crate) fn sub_crate_with_docs() {}
+ pub(crate) fn sub_crate_no_docs() {}
+ /// some docs
+ pub(super) fn sub_super_with_docs() {}
+ pub(super) fn sub_super_no_docs() {}
+ }
+
+ /// some docs
+ pub(crate) struct CrateStructWithDocs {
+ /// some docs
+ pub(crate) crate_field_with_docs: (),
+ pub(crate) crate_field_no_docs: (),
+ /// some docs
+ priv_field_with_docs: (),
+ priv_field_no_docs: (),
+ }
+
+ pub(crate) struct CrateStructNoDocs {
+ /// some docs
+ pub(crate) crate_field_with_docs: (),
+ pub(crate) crate_field_no_docs: (),
+ /// some docs
+ priv_field_with_docs: (),
+ priv_field_no_docs: (),
+ }
+}
+
+/// some docs
+type CrateTypedefWithDocs = String;
+type CrateTypedefNoDocs = String;
+/// some docs
+pub type PubTypedefWithDocs = String;
+pub type PubTypedefNoDocs = String;
+
+fn main() {
+ my_mod::crate_with_docs();
+ my_mod::crate_no_docs();
+}
diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr
new file mode 100644
index 000000000..a47418705
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr
@@ -0,0 +1,52 @@
+error: missing documentation for a function
+ --> $DIR/pub_crate_missing_doc.rs:12:5
+ |
+LL | pub(crate) fn crate_no_docs() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
+
+error: missing documentation for a function
+ --> $DIR/pub_crate_missing_doc.rs:15:5
+ |
+LL | pub(super) fn super_no_docs() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+ --> $DIR/pub_crate_missing_doc.rs:23:9
+ |
+LL | pub(crate) fn sub_crate_no_docs() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a struct field
+ --> $DIR/pub_crate_missing_doc.rs:33:9
+ |
+LL | pub(crate) crate_field_no_docs: (),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a struct
+ --> $DIR/pub_crate_missing_doc.rs:39:5
+ |
+LL | / pub(crate) struct CrateStructNoDocs {
+LL | | /// some docs
+LL | | pub(crate) crate_field_with_docs: (),
+LL | | pub(crate) crate_field_no_docs: (),
+... |
+LL | | priv_field_no_docs: (),
+LL | | }
+ | |_____^
+
+error: missing documentation for a struct field
+ --> $DIR/pub_crate_missing_doc.rs:42:9
+ |
+LL | pub(crate) crate_field_no_docs: (),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a type alias
+ --> $DIR/pub_crate_missing_doc.rs:51:1
+ |
+LL | type CrateTypedefNoDocs = String;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index a22c6a5a0..6a246afac 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -33,6 +33,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
max-struct-bools
max-suggested-slice-pattern-length
max-trait-bounds
+ missing-docs-in-crate-items
msrv
pass-by-value-size-limit
single-char-binding-names-threshold
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs
index bc8e8c1f0..6525ea5bf 100644
--- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs
@@ -66,6 +66,12 @@ fn main() {
}
}
+#[test]
+fn test() {
+ let boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
+ let _ = boxed_slice.get(1).unwrap();
+}
+
#[cfg(test)]
mod issue9612 {
// should not lint in `#[cfg(test)]` modules
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
index 94b5ef663..8a32750e3 100644
--- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
@@ -188,10 +188,16 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
- --> $DIR/unwrap_used.rs:84:17
+ --> $DIR/unwrap_used.rs:72:13
+ |
+LL | let _ = boxed_slice.get(1).unwrap();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
+
+error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+ --> $DIR/unwrap_used.rs:90:17
|
LL | let _ = Box::new([0]).get(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&Box::new([0])[1]`
-error: aborting due to 27 previous errors
+error: aborting due to 28 previous errors
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
index 918cf81c6..2611e3a78 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
@@ -13,6 +13,9 @@
use core::num::{Saturating, Wrapping};
+const ONE: i32 = 1;
+const ZERO: i32 = 0;
+
#[derive(Clone, Copy)]
pub struct Custom;
@@ -182,6 +185,10 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
_n += &0;
_n -= 0;
_n -= &0;
+ _n += ZERO;
+ _n += &ZERO;
+ _n -= ZERO;
+ _n -= &ZERO;
_n /= 99;
_n /= &99;
_n %= 99;
@@ -190,10 +197,18 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
_n *= &0;
_n *= 1;
_n *= &1;
+ _n *= ZERO;
+ _n *= &ZERO;
+ _n *= ONE;
+ _n *= &ONE;
_n += -0;
_n += &-0;
_n -= -0;
_n -= &-0;
+ _n += -ZERO;
+ _n += &-ZERO;
+ _n -= -ZERO;
+ _n -= &-ZERO;
_n /= -99;
_n /= &-99;
_n %= -99;
@@ -208,10 +223,18 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
_n = _n + &0;
_n = 0 + _n;
_n = &0 + _n;
+ _n = _n + ZERO;
+ _n = _n + &ZERO;
+ _n = ZERO + _n;
+ _n = &ZERO + _n;
_n = _n - 0;
_n = _n - &0;
_n = 0 - _n;
_n = &0 - _n;
+ _n = _n - ZERO;
+ _n = _n - &ZERO;
+ _n = ZERO - _n;
+ _n = &ZERO - _n;
_n = _n / 99;
_n = _n / &99;
_n = _n % 99;
@@ -222,6 +245,10 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri
_n = &0 * _n;
_n = _n * 1;
_n = _n * &1;
+ _n = ZERO * _n;
+ _n = &ZERO * _n;
+ _n = _n * ONE;
+ _n = _n * &ONE;
_n = 1 * _n;
_n = &1 * _n;
_n = 23 + 85;
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
index 5e349f6b4..17a2448fb 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
@@ -1,5 +1,5 @@
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:243:5
+ --> $DIR/arithmetic_side_effects.rs:270:5
|
LL | _n += 1;
| ^^^^^^^
@@ -7,589 +7,589 @@ LL | _n += 1;
= note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:244:5
+ --> $DIR/arithmetic_side_effects.rs:271:5
|
LL | _n += &1;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:245:5
+ --> $DIR/arithmetic_side_effects.rs:272:5
|
LL | _n -= 1;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:246:5
+ --> $DIR/arithmetic_side_effects.rs:273:5
|
LL | _n -= &1;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:247:5
+ --> $DIR/arithmetic_side_effects.rs:274:5
|
LL | _n /= 0;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:248:5
+ --> $DIR/arithmetic_side_effects.rs:275:5
|
LL | _n /= &0;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:249:5
+ --> $DIR/arithmetic_side_effects.rs:276:5
|
LL | _n %= 0;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:250:5
+ --> $DIR/arithmetic_side_effects.rs:277:5
|
LL | _n %= &0;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:251:5
+ --> $DIR/arithmetic_side_effects.rs:278:5
|
LL | _n *= 2;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:252:5
+ --> $DIR/arithmetic_side_effects.rs:279:5
|
LL | _n *= &2;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:253:5
+ --> $DIR/arithmetic_side_effects.rs:280:5
|
LL | _n += -1;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:254:5
+ --> $DIR/arithmetic_side_effects.rs:281:5
|
LL | _n += &-1;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:255:5
+ --> $DIR/arithmetic_side_effects.rs:282:5
|
LL | _n -= -1;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:256:5
+ --> $DIR/arithmetic_side_effects.rs:283:5
|
LL | _n -= &-1;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:257:5
+ --> $DIR/arithmetic_side_effects.rs:284:5
|
LL | _n /= -0;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:258:5
+ --> $DIR/arithmetic_side_effects.rs:285:5
|
LL | _n /= &-0;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:259:5
+ --> $DIR/arithmetic_side_effects.rs:286:5
|
LL | _n %= -0;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:260:5
+ --> $DIR/arithmetic_side_effects.rs:287:5
|
LL | _n %= &-0;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:261:5
+ --> $DIR/arithmetic_side_effects.rs:288:5
|
LL | _n *= -2;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:262:5
+ --> $DIR/arithmetic_side_effects.rs:289:5
|
LL | _n *= &-2;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:263:5
+ --> $DIR/arithmetic_side_effects.rs:290:5
|
LL | _custom += Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:264:5
+ --> $DIR/arithmetic_side_effects.rs:291:5
|
LL | _custom += &Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:265:5
+ --> $DIR/arithmetic_side_effects.rs:292:5
|
LL | _custom -= Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:266:5
+ --> $DIR/arithmetic_side_effects.rs:293:5
|
LL | _custom -= &Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:267:5
+ --> $DIR/arithmetic_side_effects.rs:294:5
|
LL | _custom /= Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:268:5
+ --> $DIR/arithmetic_side_effects.rs:295:5
|
LL | _custom /= &Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:269:5
+ --> $DIR/arithmetic_side_effects.rs:296:5
|
LL | _custom %= Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:270:5
+ --> $DIR/arithmetic_side_effects.rs:297:5
|
LL | _custom %= &Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:271:5
+ --> $DIR/arithmetic_side_effects.rs:298:5
|
LL | _custom *= Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:272:5
+ --> $DIR/arithmetic_side_effects.rs:299:5
|
LL | _custom *= &Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:273:5
+ --> $DIR/arithmetic_side_effects.rs:300:5
|
LL | _custom += -Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:274:5
+ --> $DIR/arithmetic_side_effects.rs:301:5
|
LL | _custom += &-Custom;
| ^^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:275:5
+ --> $DIR/arithmetic_side_effects.rs:302:5
|
LL | _custom -= -Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:276:5
+ --> $DIR/arithmetic_side_effects.rs:303:5
|
LL | _custom -= &-Custom;
| ^^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:277:5
+ --> $DIR/arithmetic_side_effects.rs:304:5
|
LL | _custom /= -Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:278:5
+ --> $DIR/arithmetic_side_effects.rs:305:5
|
LL | _custom /= &-Custom;
| ^^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:279:5
+ --> $DIR/arithmetic_side_effects.rs:306:5
|
LL | _custom %= -Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:280:5
+ --> $DIR/arithmetic_side_effects.rs:307:5
|
LL | _custom %= &-Custom;
| ^^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:281:5
+ --> $DIR/arithmetic_side_effects.rs:308:5
|
LL | _custom *= -Custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:282:5
+ --> $DIR/arithmetic_side_effects.rs:309:5
|
LL | _custom *= &-Custom;
| ^^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:285:10
+ --> $DIR/arithmetic_side_effects.rs:312:10
|
LL | _n = _n + 1;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:286:10
+ --> $DIR/arithmetic_side_effects.rs:313:10
|
LL | _n = _n + &1;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:287:10
+ --> $DIR/arithmetic_side_effects.rs:314:10
|
LL | _n = 1 + _n;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:288:10
+ --> $DIR/arithmetic_side_effects.rs:315:10
|
LL | _n = &1 + _n;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:289:10
+ --> $DIR/arithmetic_side_effects.rs:316:10
|
LL | _n = _n - 1;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:290:10
+ --> $DIR/arithmetic_side_effects.rs:317:10
|
LL | _n = _n - &1;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:291:10
+ --> $DIR/arithmetic_side_effects.rs:318:10
|
LL | _n = 1 - _n;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:292:10
+ --> $DIR/arithmetic_side_effects.rs:319:10
|
LL | _n = &1 - _n;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:293:10
+ --> $DIR/arithmetic_side_effects.rs:320:10
|
LL | _n = _n / 0;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:294:10
+ --> $DIR/arithmetic_side_effects.rs:321:10
|
LL | _n = _n / &0;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:295:10
+ --> $DIR/arithmetic_side_effects.rs:322:10
|
LL | _n = _n % 0;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:296:10
+ --> $DIR/arithmetic_side_effects.rs:323:10
|
LL | _n = _n % &0;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:297:10
+ --> $DIR/arithmetic_side_effects.rs:324:10
|
LL | _n = _n * 2;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:298:10
+ --> $DIR/arithmetic_side_effects.rs:325:10
|
LL | _n = _n * &2;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:299:10
+ --> $DIR/arithmetic_side_effects.rs:326:10
|
LL | _n = 2 * _n;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:300:10
+ --> $DIR/arithmetic_side_effects.rs:327:10
|
LL | _n = &2 * _n;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:301:10
+ --> $DIR/arithmetic_side_effects.rs:328:10
|
LL | _n = 23 + &85;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:302:10
+ --> $DIR/arithmetic_side_effects.rs:329:10
|
LL | _n = &23 + 85;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:303:10
+ --> $DIR/arithmetic_side_effects.rs:330:10
|
LL | _n = &23 + &85;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:304:15
+ --> $DIR/arithmetic_side_effects.rs:331:15
|
LL | _custom = _custom + _custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:305:15
+ --> $DIR/arithmetic_side_effects.rs:332:15
|
LL | _custom = _custom + &_custom;
| ^^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:306:15
+ --> $DIR/arithmetic_side_effects.rs:333:15
|
LL | _custom = Custom + _custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:307:15
+ --> $DIR/arithmetic_side_effects.rs:334:15
|
LL | _custom = &Custom + _custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:308:15
+ --> $DIR/arithmetic_side_effects.rs:335:15
|
LL | _custom = _custom - Custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:309:15
+ --> $DIR/arithmetic_side_effects.rs:336:15
|
LL | _custom = _custom - &Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:310:15
+ --> $DIR/arithmetic_side_effects.rs:337:15
|
LL | _custom = Custom - _custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:311:15
+ --> $DIR/arithmetic_side_effects.rs:338:15
|
LL | _custom = &Custom - _custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:312:15
+ --> $DIR/arithmetic_side_effects.rs:339:15
|
LL | _custom = _custom / Custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:313:15
+ --> $DIR/arithmetic_side_effects.rs:340:15
|
LL | _custom = _custom / &Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:314:15
+ --> $DIR/arithmetic_side_effects.rs:341:15
|
LL | _custom = _custom % Custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:315:15
+ --> $DIR/arithmetic_side_effects.rs:342:15
|
LL | _custom = _custom % &Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:316:15
+ --> $DIR/arithmetic_side_effects.rs:343:15
|
LL | _custom = _custom * Custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:317:15
+ --> $DIR/arithmetic_side_effects.rs:344:15
|
LL | _custom = _custom * &Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:318:15
+ --> $DIR/arithmetic_side_effects.rs:345:15
|
LL | _custom = Custom * _custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:319:15
+ --> $DIR/arithmetic_side_effects.rs:346:15
|
LL | _custom = &Custom * _custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:320:15
+ --> $DIR/arithmetic_side_effects.rs:347:15
|
LL | _custom = Custom + &Custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:321:15
+ --> $DIR/arithmetic_side_effects.rs:348:15
|
LL | _custom = &Custom + Custom;
| ^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:322:15
+ --> $DIR/arithmetic_side_effects.rs:349:15
|
LL | _custom = &Custom + &Custom;
| ^^^^^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:325:10
+ --> $DIR/arithmetic_side_effects.rs:352:10
|
LL | _n = -_n;
| ^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:326:10
+ --> $DIR/arithmetic_side_effects.rs:353:10
|
LL | _n = -&_n;
| ^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:327:15
+ --> $DIR/arithmetic_side_effects.rs:354:15
|
LL | _custom = -_custom;
| ^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:328:15
+ --> $DIR/arithmetic_side_effects.rs:355:15
|
LL | _custom = -&_custom;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:337:5
+ --> $DIR/arithmetic_side_effects.rs:364:5
|
LL | 1 + i;
| ^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:338:5
+ --> $DIR/arithmetic_side_effects.rs:365:5
|
LL | i * 2;
| ^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:340:5
+ --> $DIR/arithmetic_side_effects.rs:367:5
|
LL | i - 2 + 2 - i;
| ^^^^^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:341:5
+ --> $DIR/arithmetic_side_effects.rs:368:5
|
LL | -i;
| ^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:342:5
+ --> $DIR/arithmetic_side_effects.rs:369:5
|
LL | i >> 1;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:343:5
+ --> $DIR/arithmetic_side_effects.rs:370:5
|
LL | i << 1;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:352:5
+ --> $DIR/arithmetic_side_effects.rs:379:5
|
LL | i += 1;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:353:5
+ --> $DIR/arithmetic_side_effects.rs:380:5
|
LL | i -= 1;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:354:5
+ --> $DIR/arithmetic_side_effects.rs:381:5
|
LL | i *= 2;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:356:5
+ --> $DIR/arithmetic_side_effects.rs:383:5
|
LL | i /= 0;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:358:5
+ --> $DIR/arithmetic_side_effects.rs:385:5
|
LL | i /= var1;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:359:5
+ --> $DIR/arithmetic_side_effects.rs:386:5
|
LL | i /= var2;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:361:5
+ --> $DIR/arithmetic_side_effects.rs:388:5
|
LL | i %= 0;
| ^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:363:5
+ --> $DIR/arithmetic_side_effects.rs:390:5
|
LL | i %= var1;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:364:5
+ --> $DIR/arithmetic_side_effects.rs:391:5
|
LL | i %= var2;
| ^^^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:365:5
+ --> $DIR/arithmetic_side_effects.rs:392:5
|
LL | i <<= 3;
| ^^^^^^^
error: arithmetic operation that can potentially result in unexpected side-effects
- --> $DIR/arithmetic_side_effects.rs:366:5
+ --> $DIR/arithmetic_side_effects.rs:393:5
|
LL | i >>= 2;
| ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
index 1e5f20e8c..a13af5652 100644
--- a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
@@ -149,3 +149,22 @@ macro_rules! almost_complete_range {
let _ = '0'..'9';
};
}
+
+#[macro_export]
+macro_rules! unsafe_macro {
+ () => {
+ unsafe {
+ *core::ptr::null::<()>();
+ *core::ptr::null::<()>();
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! needless_lifetime {
+ () => {
+ fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 {
+ unimplemented!()
+ }
+ };
+}
diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.fixed b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed
new file mode 100644
index 000000000..b8dd92906
--- /dev/null
+++ b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed
@@ -0,0 +1,171 @@
+// run-rustfix
+
+#![allow(unused, clippy::assertions_on_constants)]
+#![warn(clippy::bool_assert_comparison)]
+
+use std::ops::Not;
+
+macro_rules! a {
+ () => {
+ true
+ };
+}
+macro_rules! b {
+ () => {
+ true
+ };
+}
+
+// Implements the Not trait but with an output type
+// that's not bool. Should not suggest a rewrite
+#[derive(Debug, Clone, Copy)]
+enum ImplNotTraitWithoutBool {
+ VariantX(bool),
+ VariantY(u32),
+}
+
+impl PartialEq<bool> for ImplNotTraitWithoutBool {
+ fn eq(&self, other: &bool) -> bool {
+ match *self {
+ ImplNotTraitWithoutBool::VariantX(b) => b == *other,
+ _ => false,
+ }
+ }
+}
+
+impl Not for ImplNotTraitWithoutBool {
+ type Output = Self;
+
+ fn not(self) -> Self::Output {
+ match self {
+ ImplNotTraitWithoutBool::VariantX(b) => ImplNotTraitWithoutBool::VariantX(!b),
+ ImplNotTraitWithoutBool::VariantY(0) => ImplNotTraitWithoutBool::VariantY(1),
+ ImplNotTraitWithoutBool::VariantY(_) => ImplNotTraitWithoutBool::VariantY(0),
+ }
+ }
+}
+
+// This type implements the Not trait with an Output of
+// type bool. Using assert!(..) must be suggested
+#[derive(Debug, Clone, Copy)]
+struct ImplNotTraitWithBool;
+
+impl PartialEq<bool> for ImplNotTraitWithBool {
+ fn eq(&self, other: &bool) -> bool {
+ false
+ }
+}
+
+impl Not for ImplNotTraitWithBool {
+ type Output = bool;
+
+ fn not(self) -> Self::Output {
+ true
+ }
+}
+
+#[derive(Debug)]
+struct NonCopy;
+
+impl PartialEq<bool> for NonCopy {
+ fn eq(&self, other: &bool) -> bool {
+ false
+ }
+}
+
+impl Not for NonCopy {
+ type Output = bool;
+
+ fn not(self) -> Self::Output {
+ true
+ }
+}
+
+fn main() {
+ let a = ImplNotTraitWithoutBool::VariantX(true);
+ let b = ImplNotTraitWithBool;
+
+ assert_eq!("a".len(), 1);
+ assert!(!"a".is_empty());
+ assert!("".is_empty());
+ assert!("".is_empty());
+ assert_eq!(a!(), b!());
+ assert_eq!(a!(), "".is_empty());
+ assert_eq!("".is_empty(), b!());
+ assert_eq!(a, true);
+ assert!(b);
+
+ assert_ne!("a".len(), 1);
+ assert!("a".is_empty());
+ assert!(!"".is_empty());
+ assert!(!"".is_empty());
+ assert_ne!(a!(), b!());
+ assert_ne!(a!(), "".is_empty());
+ assert_ne!("".is_empty(), b!());
+ assert_ne!(a, true);
+ assert!(!b);
+
+ debug_assert_eq!("a".len(), 1);
+ debug_assert!(!"a".is_empty());
+ debug_assert!("".is_empty());
+ debug_assert!("".is_empty());
+ debug_assert_eq!(a!(), b!());
+ debug_assert_eq!(a!(), "".is_empty());
+ debug_assert_eq!("".is_empty(), b!());
+ debug_assert_eq!(a, true);
+ debug_assert!(b);
+
+ debug_assert_ne!("a".len(), 1);
+ debug_assert!("a".is_empty());
+ debug_assert!(!"".is_empty());
+ debug_assert!(!"".is_empty());
+ debug_assert_ne!(a!(), b!());
+ debug_assert_ne!(a!(), "".is_empty());
+ debug_assert_ne!("".is_empty(), b!());
+ debug_assert_ne!(a, true);
+ debug_assert!(!b);
+
+ // assert with error messages
+ assert_eq!("a".len(), 1, "tadam {}", 1);
+ assert_eq!("a".len(), 1, "tadam {}", true);
+ assert!(!"a".is_empty(), "tadam {}", 1);
+ assert!(!"a".is_empty(), "tadam {}", true);
+ assert!(!"a".is_empty(), "tadam {}", true);
+ assert_eq!(a, true, "tadam {}", false);
+
+ debug_assert_eq!("a".len(), 1, "tadam {}", 1);
+ debug_assert_eq!("a".len(), 1, "tadam {}", true);
+ debug_assert!(!"a".is_empty(), "tadam {}", 1);
+ debug_assert!(!"a".is_empty(), "tadam {}", true);
+ debug_assert!(!"a".is_empty(), "tadam {}", true);
+ debug_assert_eq!(a, true, "tadam {}", false);
+
+ assert!(a!());
+ assert!(b!());
+
+ use debug_assert_eq as renamed;
+ renamed!(a, true);
+ debug_assert!(b);
+
+ let non_copy = NonCopy;
+ assert_eq!(non_copy, true);
+ // changing the above to `assert!(non_copy)` would cause a `borrow of moved value`
+ println!("{non_copy:?}");
+
+ macro_rules! in_macro {
+ ($v:expr) => {{
+ assert_eq!($v, true);
+ }};
+ }
+ in_macro!(a);
+
+ assert!("".is_empty());
+ assert!("".is_empty());
+ assert!(!"requires negation".is_empty());
+ assert!(!"requires negation".is_empty());
+
+ debug_assert!("".is_empty());
+ debug_assert!("".is_empty());
+ debug_assert!(!"requires negation".is_empty());
+ debug_assert!(!"requires negation".is_empty());
+}
diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.rs b/src/tools/clippy/tests/ui/bool_assert_comparison.rs
index ec4d6f3ff..0a8ad34fd 100644
--- a/src/tools/clippy/tests/ui/bool_assert_comparison.rs
+++ b/src/tools/clippy/tests/ui/bool_assert_comparison.rs
@@ -1,3 +1,6 @@
+// run-rustfix
+
+#![allow(unused, clippy::assertions_on_constants)]
#![warn(clippy::bool_assert_comparison)]
use std::ops::Not;
@@ -15,7 +18,7 @@ macro_rules! b {
// Implements the Not trait but with an output type
// that's not bool. Should not suggest a rewrite
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
enum ImplNotTraitWithoutBool {
VariantX(bool),
VariantY(u32),
@@ -44,7 +47,7 @@ impl Not for ImplNotTraitWithoutBool {
// This type implements the Not trait with an Output of
// type bool. Using assert!(..) must be suggested
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
struct ImplNotTraitWithBool;
impl PartialEq<bool> for ImplNotTraitWithBool {
@@ -61,6 +64,23 @@ impl Not for ImplNotTraitWithBool {
}
}
+#[derive(Debug)]
+struct NonCopy;
+
+impl PartialEq<bool> for NonCopy {
+ fn eq(&self, other: &bool) -> bool {
+ false
+ }
+}
+
+impl Not for NonCopy {
+ type Output = bool;
+
+ fn not(self) -> Self::Output {
+ true
+ }
+}
+
fn main() {
let a = ImplNotTraitWithoutBool::VariantX(true);
let b = ImplNotTraitWithBool;
@@ -119,4 +139,33 @@ fn main() {
debug_assert_eq!("a".is_empty(), false, "tadam {}", true);
debug_assert_eq!(false, "a".is_empty(), "tadam {}", true);
debug_assert_eq!(a, true, "tadam {}", false);
+
+ assert_eq!(a!(), true);
+ assert_eq!(true, b!());
+
+ use debug_assert_eq as renamed;
+ renamed!(a, true);
+ renamed!(b, true);
+
+ let non_copy = NonCopy;
+ assert_eq!(non_copy, true);
+ // changing the above to `assert!(non_copy)` would cause a `borrow of moved value`
+ println!("{non_copy:?}");
+
+ macro_rules! in_macro {
+ ($v:expr) => {{
+ assert_eq!($v, true);
+ }};
+ }
+ in_macro!(a);
+
+ assert_eq!("".is_empty(), true);
+ assert_ne!("".is_empty(), false);
+ assert_ne!("requires negation".is_empty(), true);
+ assert_eq!("requires negation".is_empty(), false);
+
+ debug_assert_eq!("".is_empty(), true);
+ debug_assert_ne!("".is_empty(), false);
+ debug_assert_ne!("requires negation".is_empty(), true);
+ debug_assert_eq!("requires negation".is_empty(), false);
}
diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr
index 377d51be4..89cefc95a 100644
--- a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr
+++ b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr
@@ -1,136 +1,399 @@
error: used `assert_eq!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:69:5
+ --> $DIR/bool_assert_comparison.rs:89:5
|
LL | assert_eq!("a".is_empty(), false);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::bool-assert-comparison` implied by `-D warnings`
+help: replace it with `assert!(..)`
+ |
+LL - assert_eq!("a".is_empty(), false);
+LL + assert!(!"a".is_empty());
+ |
error: used `assert_eq!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:70:5
+ --> $DIR/bool_assert_comparison.rs:90:5
|
LL | assert_eq!("".is_empty(), true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_eq!("".is_empty(), true);
+LL + assert!("".is_empty());
+ |
error: used `assert_eq!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:71:5
+ --> $DIR/bool_assert_comparison.rs:91:5
|
LL | assert_eq!(true, "".is_empty());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_eq!(true, "".is_empty());
+LL + assert!("".is_empty());
+ |
error: used `assert_eq!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:76:5
+ --> $DIR/bool_assert_comparison.rs:96:5
|
LL | assert_eq!(b, true);
- | ^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_eq!(b, true);
+LL + assert!(b);
+ |
error: used `assert_ne!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:79:5
+ --> $DIR/bool_assert_comparison.rs:99:5
|
LL | assert_ne!("a".is_empty(), false);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_ne!("a".is_empty(), false);
+LL + assert!("a".is_empty());
+ |
error: used `assert_ne!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:80:5
+ --> $DIR/bool_assert_comparison.rs:100:5
|
LL | assert_ne!("".is_empty(), true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_ne!("".is_empty(), true);
+LL + assert!(!"".is_empty());
+ |
error: used `assert_ne!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:81:5
+ --> $DIR/bool_assert_comparison.rs:101:5
|
LL | assert_ne!(true, "".is_empty());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_ne!(true, "".is_empty());
+LL + assert!(!"".is_empty());
+ |
error: used `assert_ne!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:86:5
+ --> $DIR/bool_assert_comparison.rs:106:5
|
LL | assert_ne!(b, true);
- | ^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_ne!(b, true);
+LL + assert!(!b);
+ |
error: used `debug_assert_eq!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:89:5
+ --> $DIR/bool_assert_comparison.rs:109:5
|
LL | debug_assert_eq!("a".is_empty(), false);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_eq!("a".is_empty(), false);
+LL + debug_assert!(!"a".is_empty());
+ |
error: used `debug_assert_eq!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:90:5
+ --> $DIR/bool_assert_comparison.rs:110:5
|
LL | debug_assert_eq!("".is_empty(), true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_eq!("".is_empty(), true);
+LL + debug_assert!("".is_empty());
+ |
error: used `debug_assert_eq!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:91:5
+ --> $DIR/bool_assert_comparison.rs:111:5
|
LL | debug_assert_eq!(true, "".is_empty());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_eq!(true, "".is_empty());
+LL + debug_assert!("".is_empty());
+ |
error: used `debug_assert_eq!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:96:5
+ --> $DIR/bool_assert_comparison.rs:116:5
|
LL | debug_assert_eq!(b, true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_eq!(b, true);
+LL + debug_assert!(b);
+ |
error: used `debug_assert_ne!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:99:5
+ --> $DIR/bool_assert_comparison.rs:119:5
|
LL | debug_assert_ne!("a".is_empty(), false);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_ne!("a".is_empty(), false);
+LL + debug_assert!("a".is_empty());
+ |
error: used `debug_assert_ne!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:100:5
+ --> $DIR/bool_assert_comparison.rs:120:5
|
LL | debug_assert_ne!("".is_empty(), true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_ne!("".is_empty(), true);
+LL + debug_assert!(!"".is_empty());
+ |
error: used `debug_assert_ne!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:101:5
+ --> $DIR/bool_assert_comparison.rs:121:5
|
LL | debug_assert_ne!(true, "".is_empty());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_ne!(true, "".is_empty());
+LL + debug_assert!(!"".is_empty());
+ |
error: used `debug_assert_ne!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:106:5
+ --> $DIR/bool_assert_comparison.rs:126:5
|
LL | debug_assert_ne!(b, true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_ne!(b, true);
+LL + debug_assert!(!b);
+ |
error: used `assert_eq!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:111:5
+ --> $DIR/bool_assert_comparison.rs:131:5
|
LL | assert_eq!("a".is_empty(), false, "tadam {}", 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_eq!("a".is_empty(), false, "tadam {}", 1);
+LL + assert!(!"a".is_empty(), "tadam {}", 1);
+ |
error: used `assert_eq!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:112:5
+ --> $DIR/bool_assert_comparison.rs:132:5
|
LL | assert_eq!("a".is_empty(), false, "tadam {}", true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_eq!("a".is_empty(), false, "tadam {}", true);
+LL + assert!(!"a".is_empty(), "tadam {}", true);
+ |
error: used `assert_eq!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:113:5
+ --> $DIR/bool_assert_comparison.rs:133:5
|
LL | assert_eq!(false, "a".is_empty(), "tadam {}", true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_eq!(false, "a".is_empty(), "tadam {}", true);
+LL + assert!(!"a".is_empty(), "tadam {}", true);
+ |
error: used `debug_assert_eq!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:118:5
+ --> $DIR/bool_assert_comparison.rs:138:5
|
LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_eq!("a".is_empty(), false, "tadam {}", 1);
+LL + debug_assert!(!"a".is_empty(), "tadam {}", 1);
+ |
error: used `debug_assert_eq!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:119:5
+ --> $DIR/bool_assert_comparison.rs:139:5
|
LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_eq!("a".is_empty(), false, "tadam {}", true);
+LL + debug_assert!(!"a".is_empty(), "tadam {}", true);
+ |
error: used `debug_assert_eq!` with a literal bool
- --> $DIR/bool_assert_comparison.rs:120:5
+ --> $DIR/bool_assert_comparison.rs:140:5
|
LL | debug_assert_eq!(false, "a".is_empty(), "tadam {}", true);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `debug_assert!(..)`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_eq!(false, "a".is_empty(), "tadam {}", true);
+LL + debug_assert!(!"a".is_empty(), "tadam {}", true);
+ |
+
+error: used `assert_eq!` with a literal bool
+ --> $DIR/bool_assert_comparison.rs:143:5
+ |
+LL | assert_eq!(a!(), true);
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_eq!(a!(), true);
+LL + assert!(a!());
+ |
+
+error: used `assert_eq!` with a literal bool
+ --> $DIR/bool_assert_comparison.rs:144:5
+ |
+LL | assert_eq!(true, b!());
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_eq!(true, b!());
+LL + assert!(b!());
+ |
+
+error: used `debug_assert_eq!` with a literal bool
+ --> $DIR/bool_assert_comparison.rs:148:5
+ |
+LL | renamed!(b, true);
+ | ^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - renamed!(b, true);
+LL + debug_assert!(b);
+ |
+
+error: used `assert_eq!` with a literal bool
+ --> $DIR/bool_assert_comparison.rs:162:5
+ |
+LL | assert_eq!("".is_empty(), true);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_eq!("".is_empty(), true);
+LL + assert!("".is_empty());
+ |
+
+error: used `assert_ne!` with a literal bool
+ --> $DIR/bool_assert_comparison.rs:163:5
+ |
+LL | assert_ne!("".is_empty(), false);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_ne!("".is_empty(), false);
+LL + assert!("".is_empty());
+ |
+
+error: used `assert_ne!` with a literal bool
+ --> $DIR/bool_assert_comparison.rs:164:5
+ |
+LL | assert_ne!("requires negation".is_empty(), true);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_ne!("requires negation".is_empty(), true);
+LL + assert!(!"requires negation".is_empty());
+ |
+
+error: used `assert_eq!` with a literal bool
+ --> $DIR/bool_assert_comparison.rs:165:5
+ |
+LL | assert_eq!("requires negation".is_empty(), false);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `assert!(..)`
+ |
+LL - assert_eq!("requires negation".is_empty(), false);
+LL + assert!(!"requires negation".is_empty());
+ |
+
+error: used `debug_assert_eq!` with a literal bool
+ --> $DIR/bool_assert_comparison.rs:167:5
+ |
+LL | debug_assert_eq!("".is_empty(), true);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_eq!("".is_empty(), true);
+LL + debug_assert!("".is_empty());
+ |
+
+error: used `debug_assert_ne!` with a literal bool
+ --> $DIR/bool_assert_comparison.rs:168:5
+ |
+LL | debug_assert_ne!("".is_empty(), false);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_ne!("".is_empty(), false);
+LL + debug_assert!("".is_empty());
+ |
+
+error: used `debug_assert_ne!` with a literal bool
+ --> $DIR/bool_assert_comparison.rs:169:5
+ |
+LL | debug_assert_ne!("requires negation".is_empty(), true);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_ne!("requires negation".is_empty(), true);
+LL + debug_assert!(!"requires negation".is_empty());
+ |
+
+error: used `debug_assert_eq!` with a literal bool
+ --> $DIR/bool_assert_comparison.rs:170:5
+ |
+LL | debug_assert_eq!("requires negation".is_empty(), false);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: replace it with `debug_assert!(..)`
+ |
+LL - debug_assert_eq!("requires negation".is_empty(), false);
+LL + debug_assert!(!"requires negation".is_empty());
+ |
-error: aborting due to 22 previous errors
+error: aborting due to 33 previous errors
diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed
index 7e9f074fd..59c0baf87 100644
--- a/src/tools/clippy/tests/ui/box_default.fixed
+++ b/src/tools/clippy/tests/ui/box_default.fixed
@@ -33,6 +33,7 @@ fn main() {
let _vec4: Box<_> = Box::<Vec<bool>>::default();
let _more = ret_ty_fn();
call_ty_fn(Box::default());
+ issue_10381();
}
fn ret_ty_fn() -> Box<bool> {
@@ -65,3 +66,20 @@ fn issue_10089() {
let _ = Box::<WeirdPathed>::default();
};
}
+
+fn issue_10381() {
+ #[derive(Default)]
+ pub struct Foo {}
+ pub trait Bar {}
+ impl Bar for Foo {}
+
+ fn maybe_get_bar(i: u32) -> Option<Box<dyn Bar>> {
+ if i % 2 == 0 {
+ Some(Box::<Foo>::default())
+ } else {
+ None
+ }
+ }
+
+ assert!(maybe_get_bar(2).is_some());
+}
diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs
index 5c8d0b835..f7d832193 100644
--- a/src/tools/clippy/tests/ui/box_default.rs
+++ b/src/tools/clippy/tests/ui/box_default.rs
@@ -33,6 +33,7 @@ fn main() {
let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
let _more = ret_ty_fn();
call_ty_fn(Box::new(u8::default()));
+ issue_10381();
}
fn ret_ty_fn() -> Box<bool> {
@@ -65,3 +66,20 @@ fn issue_10089() {
let _ = Box::new(WeirdPathed::default());
};
}
+
+fn issue_10381() {
+ #[derive(Default)]
+ pub struct Foo {}
+ pub trait Bar {}
+ impl Bar for Foo {}
+
+ fn maybe_get_bar(i: u32) -> Option<Box<dyn Bar>> {
+ if i % 2 == 0 {
+ Some(Box::new(Foo::default()))
+ } else {
+ None
+ }
+ }
+
+ assert!(maybe_get_bar(2).is_some());
+}
diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr
index 249eb340f..78e17b9f0 100644
--- a/src/tools/clippy/tests/ui/box_default.stderr
+++ b/src/tools/clippy/tests/ui/box_default.stderr
@@ -73,22 +73,28 @@ LL | call_ty_fn(Box::new(u8::default()));
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
error: `Box::new(_)` of default value
- --> $DIR/box_default.rs:39:5
+ --> $DIR/box_default.rs:40:5
|
LL | Box::new(bool::default())
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<bool>::default()`
error: `Box::new(_)` of default value
- --> $DIR/box_default.rs:56:28
+ --> $DIR/box_default.rs:57:28
|
LL | let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
error: `Box::new(_)` of default value
- --> $DIR/box_default.rs:65:17
+ --> $DIR/box_default.rs:66:17
|
LL | let _ = Box::new(WeirdPathed::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()`
-error: aborting due to 15 previous errors
+error: `Box::new(_)` of default value
+ --> $DIR/box_default.rs:78:18
+ |
+LL | Some(Box::new(Foo::default()))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Foo>::default()`
+
+error: aborting due to 16 previous errors
diff --git a/src/tools/clippy/tests/ui/bytes_nth.fixed b/src/tools/clippy/tests/ui/bytes_nth.fixed
index b1fb2e16b..a35c679af 100644
--- a/src/tools/clippy/tests/ui/bytes_nth.fixed
+++ b/src/tools/clippy/tests/ui/bytes_nth.fixed
@@ -5,7 +5,7 @@
fn main() {
let s = String::from("String");
- let _ = s.as_bytes().get(3);
- let _ = &s.as_bytes().get(3);
- let _ = s[..].as_bytes().get(3);
+ let _ = s.as_bytes().get(3).copied();
+ let _ = &s.as_bytes()[3];
+ let _ = s[..].as_bytes().get(3).copied();
}
diff --git a/src/tools/clippy/tests/ui/bytes_nth.rs b/src/tools/clippy/tests/ui/bytes_nth.rs
index 034c54e6a..1ecffea53 100644
--- a/src/tools/clippy/tests/ui/bytes_nth.rs
+++ b/src/tools/clippy/tests/ui/bytes_nth.rs
@@ -6,6 +6,6 @@
fn main() {
let s = String::from("String");
let _ = s.bytes().nth(3);
- let _ = &s.bytes().nth(3);
+ let _ = &s.bytes().nth(3).unwrap();
let _ = s[..].bytes().nth(3);
}
diff --git a/src/tools/clippy/tests/ui/bytes_nth.stderr b/src/tools/clippy/tests/ui/bytes_nth.stderr
index 9851d4791..e8b150278 100644
--- a/src/tools/clippy/tests/ui/bytes_nth.stderr
+++ b/src/tools/clippy/tests/ui/bytes_nth.stderr
@@ -2,21 +2,21 @@ error: called `.bytes().nth()` on a `String`
--> $DIR/bytes_nth.rs:8:13
|
LL | let _ = s.bytes().nth(3);
- | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)`
+ | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3).copied()`
|
= note: `-D clippy::bytes-nth` implied by `-D warnings`
-error: called `.bytes().nth()` on a `String`
+error: called `.bytes().nth().unwrap()` on a `String`
--> $DIR/bytes_nth.rs:9:14
|
-LL | let _ = &s.bytes().nth(3);
- | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)`
+LL | let _ = &s.bytes().nth(3).unwrap();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.as_bytes()[3]`
error: called `.bytes().nth()` on a `str`
--> $DIR/bytes_nth.rs:10:13
|
LL | let _ = s[..].bytes().nth(3);
- | ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3)`
+ | ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3).copied()`
error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs
index e6031e9ad..8b2673c2a 100644
--- a/src/tools/clippy/tests/ui/cast.rs
+++ b/src/tools/clippy/tests/ui/cast.rs
@@ -28,6 +28,7 @@ fn main() {
1i32 as u8;
1f64 as isize;
1f64 as usize;
+ 1f32 as u32 as u16;
// Test clippy::cast_possible_wrap
1u8 as i8;
1u16 as i16;
diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr
index 0c63b4af3..451078de2 100644
--- a/src/tools/clippy/tests/ui/cast.stderr
+++ b/src/tools/clippy/tests/ui/cast.stderr
@@ -42,13 +42,24 @@ error: casting `f32` to `i32` may truncate the value
LL | 1f32 as i32;
| ^^^^^^^^^^^
|
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
= note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | i32::try_from(1f32);
+ | ~~~~~~~~~~~~~~~~~~~
error: casting `f32` to `u32` may truncate the value
--> $DIR/cast.rs:25:5
|
LL | 1f32 as u32;
| ^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | u32::try_from(1f32);
+ | ~~~~~~~~~~~~~~~~~~~
error: casting `f32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:25:5
@@ -63,30 +74,60 @@ error: casting `f64` to `f32` may truncate the value
|
LL | 1f64 as f32;
| ^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | f32::try_from(1f64);
+ | ~~~~~~~~~~~~~~~~~~~
error: casting `i32` to `i8` may truncate the value
--> $DIR/cast.rs:27:5
|
LL | 1i32 as i8;
| ^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | i8::try_from(1i32);
+ | ~~~~~~~~~~~~~~~~~~
error: casting `i32` to `u8` may truncate the value
--> $DIR/cast.rs:28:5
|
LL | 1i32 as u8;
| ^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | u8::try_from(1i32);
+ | ~~~~~~~~~~~~~~~~~~
error: casting `f64` to `isize` may truncate the value
--> $DIR/cast.rs:29:5
|
LL | 1f64 as isize;
| ^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | isize::try_from(1f64);
+ | ~~~~~~~~~~~~~~~~~~~~~
error: casting `f64` to `usize` may truncate the value
--> $DIR/cast.rs:30:5
|
LL | 1f64 as usize;
| ^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | usize::try_from(1f64);
+ | ~~~~~~~~~~~~~~~~~~~~~
error: casting `f64` to `usize` may lose the sign of the value
--> $DIR/cast.rs:30:5
@@ -94,8 +135,38 @@ error: casting `f64` to `usize` may lose the sign of the value
LL | 1f64 as usize;
| ^^^^^^^^^^^^^
+error: casting `u32` to `u16` may truncate the value
+ --> $DIR/cast.rs:31:5
+ |
+LL | 1f32 as u32 as u16;
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | u16::try_from(1f32 as u32);
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: casting `f32` to `u32` may truncate the value
+ --> $DIR/cast.rs:31:5
+ |
+LL | 1f32 as u32 as u16;
+ | ^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | u32::try_from(1f32) as u16;
+ | ~~~~~~~~~~~~~~~~~~~
+
+error: casting `f32` to `u32` may lose the sign of the value
+ --> $DIR/cast.rs:31:5
+ |
+LL | 1f32 as u32 as u16;
+ | ^^^^^^^^^^^
+
error: casting `u8` to `i8` may wrap around the value
- --> $DIR/cast.rs:32:5
+ --> $DIR/cast.rs:33:5
|
LL | 1u8 as i8;
| ^^^^^^^^^
@@ -103,61 +174,79 @@ LL | 1u8 as i8;
= note: `-D clippy::cast-possible-wrap` implied by `-D warnings`
error: casting `u16` to `i16` may wrap around the value
- --> $DIR/cast.rs:33:5
+ --> $DIR/cast.rs:34:5
|
LL | 1u16 as i16;
| ^^^^^^^^^^^
error: casting `u32` to `i32` may wrap around the value
- --> $DIR/cast.rs:34:5
+ --> $DIR/cast.rs:35:5
|
LL | 1u32 as i32;
| ^^^^^^^^^^^
error: casting `u64` to `i64` may wrap around the value
- --> $DIR/cast.rs:35:5
+ --> $DIR/cast.rs:36:5
|
LL | 1u64 as i64;
| ^^^^^^^^^^^
error: casting `usize` to `isize` may wrap around the value
- --> $DIR/cast.rs:36:5
+ --> $DIR/cast.rs:37:5
|
LL | 1usize as isize;
| ^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
- --> $DIR/cast.rs:39:5
+ --> $DIR/cast.rs:40:5
|
LL | -1i32 as u32;
| ^^^^^^^^^^^^
error: casting `isize` to `usize` may lose the sign of the value
- --> $DIR/cast.rs:41:5
+ --> $DIR/cast.rs:42:5
|
LL | -1isize as usize;
| ^^^^^^^^^^^^^^^^
error: casting `i64` to `i8` may truncate the value
- --> $DIR/cast.rs:108:5
+ --> $DIR/cast.rs:109:5
|
LL | (-99999999999i64).min(1) as i8; // should be linted because signed
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | i8::try_from((-99999999999i64).min(1)); // should be linted because signed
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: casting `u64` to `u8` may truncate the value
- --> $DIR/cast.rs:120:5
+ --> $DIR/cast.rs:121:5
|
LL | 999999u64.clamp(0, 256) as u8; // should still be linted
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | u8::try_from(999999u64.clamp(0, 256)); // should still be linted
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: casting `main::E2` to `u8` may truncate the value
- --> $DIR/cast.rs:141:21
+ --> $DIR/cast.rs:142:21
|
LL | let _ = self as u8;
| ^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | let _ = u8::try_from(self);
+ | ~~~~~~~~~~~~~~~~~~
error: casting `main::E2::B` to `u8` will truncate the value
- --> $DIR/cast.rs:142:21
+ --> $DIR/cast.rs:143:21
|
LL | let _ = Self::B as u8;
| ^^^^^^^^^^^^^
@@ -165,46 +254,82 @@ LL | let _ = Self::B as u8;
= note: `-D clippy::cast-enum-truncation` implied by `-D warnings`
error: casting `main::E5` to `i8` may truncate the value
- --> $DIR/cast.rs:178:21
+ --> $DIR/cast.rs:179:21
|
LL | let _ = self as i8;
| ^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | let _ = i8::try_from(self);
+ | ~~~~~~~~~~~~~~~~~~
error: casting `main::E5::A` to `i8` will truncate the value
- --> $DIR/cast.rs:179:21
+ --> $DIR/cast.rs:180:21
|
LL | let _ = Self::A as i8;
| ^^^^^^^^^^^^^
error: casting `main::E6` to `i16` may truncate the value
- --> $DIR/cast.rs:193:21
+ --> $DIR/cast.rs:194:21
|
LL | let _ = self as i16;
| ^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | let _ = i16::try_from(self);
+ | ~~~~~~~~~~~~~~~~~~~
error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
- --> $DIR/cast.rs:208:21
+ --> $DIR/cast.rs:209:21
|
LL | let _ = self as usize;
| ^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | let _ = usize::try_from(self);
+ | ~~~~~~~~~~~~~~~~~~~~~
error: casting `main::E10` to `u16` may truncate the value
- --> $DIR/cast.rs:249:21
+ --> $DIR/cast.rs:250:21
|
LL | let _ = self as u16;
| ^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | let _ = u16::try_from(self);
+ | ~~~~~~~~~~~~~~~~~~~
error: casting `u32` to `u8` may truncate the value
- --> $DIR/cast.rs:257:13
+ --> $DIR/cast.rs:258:13
|
LL | let c = (q >> 16) as u8;
| ^^^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | let c = u8::try_from((q >> 16));
+ | ~~~~~~~~~~~~~~~~~~~~~~~
error: casting `u32` to `u8` may truncate the value
- --> $DIR/cast.rs:260:13
+ --> $DIR/cast.rs:261:13
|
LL | let c = (q / 1000) as u8;
| ^^^^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | let c = u8::try_from((q / 1000));
+ | ~~~~~~~~~~~~~~~~~~~~~~~~
-error: aborting due to 33 previous errors
+error: aborting due to 36 previous errors
diff --git a/src/tools/clippy/tests/ui/cast_size.stderr b/src/tools/clippy/tests/ui/cast_size.stderr
index 95552f2e2..6d2d49d9e 100644
--- a/src/tools/clippy/tests/ui/cast_size.stderr
+++ b/src/tools/clippy/tests/ui/cast_size.stderr
@@ -4,7 +4,12 @@ error: casting `isize` to `i8` may truncate the value
LL | 1isize as i8;
| ^^^^^^^^^^^^
|
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
= note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | i8::try_from(1isize);
+ | ~~~~~~~~~~~~~~~~~~~~
error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
--> $DIR/cast_size.rs:15:5
@@ -37,24 +42,48 @@ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wi
|
LL | 1isize as i32;
| ^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | i32::try_from(1isize);
+ | ~~~~~~~~~~~~~~~~~~~~~
error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers
--> $DIR/cast_size.rs:20:5
|
LL | 1isize as u32;
| ^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | u32::try_from(1isize);
+ | ~~~~~~~~~~~~~~~~~~~~~
error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers
--> $DIR/cast_size.rs:21:5
|
LL | 1usize as u32;
| ^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | u32::try_from(1usize);
+ | ~~~~~~~~~~~~~~~~~~~~~
error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
--> $DIR/cast_size.rs:22:5
|
LL | 1usize as i32;
| ^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | i32::try_from(1usize);
+ | ~~~~~~~~~~~~~~~~~~~~~
error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
--> $DIR/cast_size.rs:22:5
@@ -69,18 +98,36 @@ error: casting `i64` to `isize` may truncate the value on targets with 32-bit wi
|
LL | 1i64 as isize;
| ^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | isize::try_from(1i64);
+ | ~~~~~~~~~~~~~~~~~~~~~
error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
--> $DIR/cast_size.rs:25:5
|
LL | 1i64 as usize;
| ^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | usize::try_from(1i64);
+ | ~~~~~~~~~~~~~~~~~~~~~
error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
--> $DIR/cast_size.rs:26:5
|
LL | 1u64 as isize;
| ^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | isize::try_from(1u64);
+ | ~~~~~~~~~~~~~~~~~~~~~
error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
--> $DIR/cast_size.rs:26:5
@@ -93,6 +140,12 @@ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wi
|
LL | 1u64 as usize;
| ^^^^^^^^^^^^^
+ |
+ = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
+help: ... or use `try_from` and handle the error accordingly
+ |
+LL | usize::try_from(1u64);
+ | ~~~~~~~~~~~~~~~~~~~~~
error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
--> $DIR/cast_size.rs:28:5
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2774.stderr b/src/tools/clippy/tests/ui/crashes/ice-2774.stderr
index 1f26c7f4d..c5ea0b16d 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2774.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-2774.stderr
@@ -5,6 +5,11 @@ LL | pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::needless-lifetimes` implied by `-D warnings`
+help: elide the lifetimes
+ |
+LL - pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) {
+LL + pub fn add_barfoos_to_foos(bars: &HashSet<&Bar>) {
+ |
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs b/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs
new file mode 100644
index 000000000..7f5bae60d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs
@@ -0,0 +1,17 @@
+#![allow(dead_code)]
+
+struct Foo;
+
+impl<'a> std::convert::TryFrom<&'a String> for Foo {
+ type Error = std::convert::Infallible;
+
+ fn try_from(_: &'a String) -> Result<Self, Self::Error> {
+ Ok(Foo)
+ }
+}
+
+fn find<E>(_: impl std::convert::TryInto<Foo, Error = E>) {}
+
+fn main() {
+ find(&String::new());
+}
diff --git a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr
index 875d5ab4f..0b0e0ad26 100644
--- a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr
+++ b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr
@@ -9,6 +9,11 @@ note: the lint level is defined here
|
LL | #![deny(clippy::needless_lifetimes)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: elide the lifetimes
+ |
+LL - fn baz<'a>(&'a self) -> impl Foo + 'a {
+LL + fn baz(&self) -> impl Foo + '_ {
+ |
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs
new file mode 100644
index 000000000..dd3d8b8b6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs
@@ -0,0 +1,9 @@
+// https://github.com/rust-lang/rust/issues/107147
+
+#![warn(clippy::needless_pass_by_value)]
+
+struct Foo<'a>(&'a [(); 100]);
+
+fn test(x: Foo<'_>) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr
new file mode 100644
index 000000000..7a0a64897
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.stderr
@@ -0,0 +1,15 @@
+error: this argument is passed by value, but not consumed in the function body
+ --> $DIR/needless_pass_by_value-w-late-bound.rs:7:12
+ |
+LL | fn test(x: Foo<'_>) {}
+ | ^^^^^^^ help: consider taking a reference instead: `&Foo<'_>`
+ |
+help: consider marking this type as `Copy`
+ --> $DIR/needless_pass_by_value-w-late-bound.rs:5:1
+ |
+LL | struct Foo<'a>(&'a [(); 100]);
+ | ^^^^^^^^^^^^^^
+ = note: `-D clippy::needless-pass-by-value` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
index 747801b40..ecb0bf364 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
@@ -78,7 +78,7 @@ fn test_allowed() {
/// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
-/// It can also be [`inline_link2`].
+/// It can also be [inline_link2]. A link to [StackOverflow](https://stackoverflow.com) is also acceptable.
///
/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
/// [inline_link]: https://foobar
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
index f3cf96615..11c48dd10 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
@@ -75,10 +75,10 @@ fn test_units() {
fn test_allowed() {
}
-/// This test has [a link_with_underscores][chunked-example] inside it. See #823.
+/// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
-/// It can also be [inline_link2].
+/// It can also be [inline_link2]. A link to [StackOverflow](https://stackoverflow.com) is also acceptable.
///
/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
/// [inline_link]: https://foobar
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
index 40345370c..6c67c903c 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
@@ -143,28 +143,6 @@ LL | /// `be_sure_we_got_to_the_end_of_it`
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: item in documentation is missing backticks
- --> $DIR/doc-fixable.rs:78:22
- |
-LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
- | ^^^^^^^^^^^^^^^^^^^^^
- |
-help: try
- |
-LL | /// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
- | ~~~~~~~~~~~~~~~~~~~~~~~
-
-error: item in documentation is missing backticks
- --> $DIR/doc-fixable.rs:81:21
- |
-LL | /// It can also be [inline_link2].
- | ^^^^^^^^^^^^
- |
-help: try
- |
-LL | /// It can also be [`inline_link2`].
- | ~~~~~~~~~~~~~~
-
-error: item in documentation is missing backticks
--> $DIR/doc-fixable.rs:91:5
|
LL | /// be_sure_we_got_to_the_end_of_it
@@ -329,5 +307,5 @@ help: try
LL | /// An iterator over `mycrate::Collection`'s values.
| ~~~~~~~~~~~~~~~~~~~~~
-error: aborting due to 30 previous errors
+error: aborting due to 28 previous errors
diff --git a/src/tools/clippy/tests/ui/entry.fixed b/src/tools/clippy/tests/ui/entry.fixed
index 79c29c04e..dbe09e0ff 100644
--- a/src/tools/clippy/tests/ui/entry.fixed
+++ b/src/tools/clippy/tests/ui/entry.fixed
@@ -152,4 +152,18 @@ fn hash_map<K: Eq + Hash + Copy, V: Copy>(m: &mut HashMap<K, V>, m2: &mut HashMa
});
}
+// Issue 10331
+// do not suggest a bad expansion because the compiler unrolls the first
+// occurrence of the loop
+pub fn issue_10331() {
+ let mut m = HashMap::new();
+ let mut i = 0;
+ let mut x = 0;
+ while !m.contains_key(&x) {
+ m.insert(x, i);
+ i += 1;
+ x += 1;
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/entry.rs b/src/tools/clippy/tests/ui/entry.rs
index 2d7985457..30fed34fc 100644
--- a/src/tools/clippy/tests/ui/entry.rs
+++ b/src/tools/clippy/tests/ui/entry.rs
@@ -156,4 +156,18 @@ fn hash_map<K: Eq + Hash + Copy, V: Copy>(m: &mut HashMap<K, V>, m2: &mut HashMa
}
}
+// Issue 10331
+// do not suggest a bad expansion because the compiler unrolls the first
+// occurrence of the loop
+pub fn issue_10331() {
+ let mut m = HashMap::new();
+ let mut i = 0;
+ let mut x = 0;
+ while !m.contains_key(&x) {
+ m.insert(x, i);
+ i += 1;
+ x += 1;
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
index 475fae5e8..5d40c8504 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
@@ -269,6 +269,9 @@ fn main() {
trait WithAssoc {
type Assoc: ?Sized;
+ fn to_assoc(&self) -> &Self::Assoc {
+ panic!()
+ }
}
impl WithAssoc for String {
type Assoc = str;
@@ -281,4 +284,15 @@ fn main() {
// Issue #9901
fn takes_ref(_: &i32) {}
takes_ref(*Box::new(&0i32));
+
+ // Issue #10384
+ impl<'a> WithAssoc for &'a u32 {
+ type Assoc = dyn core::fmt::Display;
+ fn to_assoc(&self) -> &Self::Assoc {
+ *self
+ }
+ }
+ fn return_dyn_assoc<'a>(x: &'a &'a u32) -> &'a <&'a u32 as WithAssoc>::Assoc {
+ *x
+ }
}
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.rs b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
index c1894258f..79e03f4d7 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.rs
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
@@ -269,6 +269,9 @@ fn main() {
trait WithAssoc {
type Assoc: ?Sized;
+ fn to_assoc(&self) -> &Self::Assoc {
+ panic!()
+ }
}
impl WithAssoc for String {
type Assoc = str;
@@ -281,4 +284,15 @@ fn main() {
// Issue #9901
fn takes_ref(_: &i32) {}
takes_ref(*Box::new(&0i32));
+
+ // Issue #10384
+ impl<'a> WithAssoc for &'a u32 {
+ type Assoc = dyn core::fmt::Display;
+ fn to_assoc(&self) -> &Self::Assoc {
+ *self
+ }
+ }
+ fn return_dyn_assoc<'a>(x: &'a &'a u32) -> &'a <&'a u32 as WithAssoc>::Assoc {
+ *x
+ }
}
diff --git a/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs b/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs
new file mode 100644
index 000000000..480174342
--- /dev/null
+++ b/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs
@@ -0,0 +1,110 @@
+#![allow(unused, clippy::needless_lifetimes)]
+#![warn(clippy::extra_unused_type_parameters)]
+
+fn unused_ty<T>(x: u8) {
+ unimplemented!()
+}
+
+fn unused_multi<T, U>(x: u8) {
+ unimplemented!()
+}
+
+fn unused_with_lt<'a, T>(x: &'a u8) {
+ unimplemented!()
+}
+
+fn used_ty<T>(x: T, y: u8) {}
+
+fn used_ref<'a, T>(x: &'a T) {}
+
+fn used_ret<T: Default>(x: u8) -> T {
+ T::default()
+}
+
+fn unused_bounded<T: Default, U>(x: U) {
+ unimplemented!();
+}
+
+fn unused_where_clause<T, U>(x: U)
+where
+ T: Default,
+{
+ unimplemented!();
+}
+
+fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {
+ unimplemented!();
+}
+
+fn used_opaque<A>(iter: impl Iterator<Item = A>) -> usize {
+ iter.count()
+}
+
+fn used_ret_opaque<A>() -> impl Iterator<Item = A> {
+ std::iter::empty()
+}
+
+fn used_vec_box<T>(x: Vec<Box<T>>) {}
+
+fn used_body<T: Default + ToString>() -> String {
+ T::default().to_string()
+}
+
+fn used_closure<T: Default + ToString>() -> impl Fn() {
+ || println!("{}", T::default().to_string())
+}
+
+struct S;
+
+impl S {
+ fn unused_ty_impl<T>(&self) {
+ unimplemented!()
+ }
+}
+
+// Don't lint on trait methods
+trait Foo {
+ fn bar<T>(&self);
+}
+
+impl Foo for S {
+ fn bar<T>(&self) {}
+}
+
+fn skip_index<A, Iter>(iter: Iter, index: usize) -> impl Iterator<Item = A>
+where
+ Iter: Iterator<Item = A>,
+{
+ iter.enumerate()
+ .filter_map(move |(i, a)| if i == index { None } else { Some(a) })
+}
+
+fn unused_opaque<A, B>(dummy: impl Default) {
+ unimplemented!()
+}
+
+mod unexported_trait_bounds {
+ mod private {
+ pub trait Private {}
+ }
+
+ fn priv_trait_bound<T: private::Private>() {
+ unimplemented!();
+ }
+
+ fn unused_with_priv_trait_bound<T: private::Private, U>() {
+ unimplemented!();
+ }
+}
+
+mod issue10319 {
+ fn assert_send<T: Send>() {}
+
+ fn assert_send_where<T>()
+ where
+ T: Send,
+ {
+ }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr b/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr
new file mode 100644
index 000000000..86c88fc9b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr
@@ -0,0 +1,75 @@
+error: type parameter goes unused in function definition
+ --> $DIR/extra_unused_type_parameters.rs:4:13
+ |
+LL | fn unused_ty<T>(x: u8) {
+ | ^^^
+ |
+ = help: consider removing the parameter
+ = note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings`
+
+error: type parameters go unused in function definition
+ --> $DIR/extra_unused_type_parameters.rs:8:16
+ |
+LL | fn unused_multi<T, U>(x: u8) {
+ | ^^^^^^
+ |
+ = help: consider removing the parameters
+
+error: type parameter goes unused in function definition
+ --> $DIR/extra_unused_type_parameters.rs:12:23
+ |
+LL | fn unused_with_lt<'a, T>(x: &'a u8) {
+ | ^
+ |
+ = help: consider removing the parameter
+
+error: type parameter goes unused in function definition
+ --> $DIR/extra_unused_type_parameters.rs:24:19
+ |
+LL | fn unused_bounded<T: Default, U>(x: U) {
+ | ^^^^^^^^^^^
+ |
+ = help: consider removing the parameter
+
+error: type parameter goes unused in function definition
+ --> $DIR/extra_unused_type_parameters.rs:28:24
+ |
+LL | fn unused_where_clause<T, U>(x: U)
+ | ^^
+ |
+ = help: consider removing the parameter
+
+error: type parameters go unused in function definition
+ --> $DIR/extra_unused_type_parameters.rs:35:16
+ |
+LL | fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {
+ | ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^
+ |
+ = help: consider removing the parameters
+
+error: type parameter goes unused in function definition
+ --> $DIR/extra_unused_type_parameters.rs:60:22
+ |
+LL | fn unused_ty_impl<T>(&self) {
+ | ^^^
+ |
+ = help: consider removing the parameter
+
+error: type parameters go unused in function definition
+ --> $DIR/extra_unused_type_parameters.rs:82:17
+ |
+LL | fn unused_opaque<A, B>(dummy: impl Default) {
+ | ^^^^^^
+ |
+ = help: consider removing the parameters
+
+error: type parameter goes unused in function definition
+ --> $DIR/extra_unused_type_parameters.rs:95:58
+ |
+LL | fn unused_with_priv_trait_bound<T: private::Private, U>() {
+ | ^
+ |
+ = help: consider removing the parameter
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/format.fixed b/src/tools/clippy/tests/ui/format.fixed
index beedf2c1d..cd2f70ee8 100644
--- a/src/tools/clippy/tests/ui/format.fixed
+++ b/src/tools/clippy/tests/ui/format.fixed
@@ -1,4 +1,5 @@
// run-rustfix
+// aux-build: proc_macro_with_span.rs
#![warn(clippy::useless_format)]
#![allow(
unused_tuple_struct_fields,
@@ -9,6 +10,8 @@
clippy::uninlined_format_args
)]
+extern crate proc_macro_with_span;
+
struct Foo(pub String);
macro_rules! foo {
@@ -87,4 +90,7 @@ fn main() {
let _ = abc.to_string();
let xx = "xx";
let _ = xx.to_string();
+
+ // Issue #10148
+ println!(proc_macro_with_span::with_span!(""something ""));
}
diff --git a/src/tools/clippy/tests/ui/format.rs b/src/tools/clippy/tests/ui/format.rs
index e805f1818..c22345a79 100644
--- a/src/tools/clippy/tests/ui/format.rs
+++ b/src/tools/clippy/tests/ui/format.rs
@@ -1,4 +1,5 @@
// run-rustfix
+// aux-build: proc_macro_with_span.rs
#![warn(clippy::useless_format)]
#![allow(
unused_tuple_struct_fields,
@@ -9,6 +10,8 @@
clippy::uninlined_format_args
)]
+extern crate proc_macro_with_span;
+
struct Foo(pub String);
macro_rules! foo {
@@ -89,4 +92,7 @@ fn main() {
let _ = format!("{abc}");
let xx = "xx";
let _ = format!("{xx}");
+
+ // Issue #10148
+ println!(proc_macro_with_span::with_span!(""something ""));
}
diff --git a/src/tools/clippy/tests/ui/format.stderr b/src/tools/clippy/tests/ui/format.stderr
index 0ef0ac655..a0e5d5c8a 100644
--- a/src/tools/clippy/tests/ui/format.stderr
+++ b/src/tools/clippy/tests/ui/format.stderr
@@ -1,5 +1,5 @@
error: useless use of `format!`
- --> $DIR/format.rs:19:5
+ --> $DIR/format.rs:22:5
|
LL | format!("foo");
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
@@ -7,19 +7,19 @@ LL | format!("foo");
= note: `-D clippy::useless-format` implied by `-D warnings`
error: useless use of `format!`
- --> $DIR/format.rs:20:5
+ --> $DIR/format.rs:23:5
|
LL | format!("{{}}");
| ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:21:5
+ --> $DIR/format.rs:24:5
|
LL | format!("{{}} abc {{}}");
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:22:5
+ --> $DIR/format.rs:25:5
|
LL | / format!(
LL | | r##"foo {{}}
@@ -34,67 +34,67 @@ LL ~ " bar"##.to_string();
|
error: useless use of `format!`
- --> $DIR/format.rs:27:13
+ --> $DIR/format.rs:30:13
|
LL | let _ = format!("");
| ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
error: useless use of `format!`
- --> $DIR/format.rs:29:5
+ --> $DIR/format.rs:32:5
|
LL | format!("{}", "foo");
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:37:5
+ --> $DIR/format.rs:40:5
|
LL | format!("{}", arg);
| ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:67:5
+ --> $DIR/format.rs:70:5
|
LL | format!("{}", 42.to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:69:5
+ --> $DIR/format.rs:72:5
|
LL | format!("{}", x.display().to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:73:18
+ --> $DIR/format.rs:76:18
|
LL | let _ = Some(format!("{}", a + "bar"));
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
error: useless use of `format!`
- --> $DIR/format.rs:77:22
+ --> $DIR/format.rs:80:22
|
LL | let _s: String = format!("{}", &*v.join("/n"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:83:13
+ --> $DIR/format.rs:86:13
|
LL | let _ = format!("{x}");
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:85:13
+ --> $DIR/format.rs:88:13
|
LL | let _ = format!("{y}", y = x);
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:89:13
+ --> $DIR/format.rs:92:13
|
LL | let _ = format!("{abc}");
| ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:91:13
+ --> $DIR/format.rs:94:13
|
LL | let _ = format!("{xx}");
| ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()`
diff --git a/src/tools/clippy/tests/ui/impl_trait_in_params.rs b/src/tools/clippy/tests/ui/impl_trait_in_params.rs
new file mode 100644
index 000000000..07560101a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/impl_trait_in_params.rs
@@ -0,0 +1,17 @@
+#![allow(unused)]
+#![warn(clippy::impl_trait_in_params)]
+
+pub trait Trait {}
+pub trait AnotherTrait<T> {}
+
+// Should warn
+pub fn a(_: impl Trait) {}
+pub fn c<C: Trait>(_: C, _: impl Trait) {}
+fn d(_: impl AnotherTrait<u32>) {}
+
+// Shouldn't warn
+
+pub fn b<B: Trait>(_: B) {}
+fn e<T: AnotherTrait<u32>>(_: T) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/impl_trait_in_params.stderr b/src/tools/clippy/tests/ui/impl_trait_in_params.stderr
new file mode 100644
index 000000000..acfcc2144
--- /dev/null
+++ b/src/tools/clippy/tests/ui/impl_trait_in_params.stderr
@@ -0,0 +1,25 @@
+error: '`impl Trait` used as a function parameter'
+ --> $DIR/impl_trait_in_params.rs:8:13
+ |
+LL | pub fn a(_: impl Trait) {}
+ | ^^^^^^^^^^
+ |
+ = note: `-D clippy::impl-trait-in-params` implied by `-D warnings`
+help: add a type paremeter
+ |
+LL | pub fn a<{ /* Generic name */ }: Trait>(_: impl Trait) {}
+ | +++++++++++++++++++++++++++++++
+
+error: '`impl Trait` used as a function parameter'
+ --> $DIR/impl_trait_in_params.rs:9:29
+ |
+LL | pub fn c<C: Trait>(_: C, _: impl Trait) {}
+ | ^^^^^^^^^^
+ |
+help: add a type paremeter
+ |
+LL | pub fn c<C: Trait, { /* Generic name */ }: Trait>(_: C, _: impl Trait) {}
+ | +++++++++++++++++++++++++++++++
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/large_digit_groups.fixed b/src/tools/clippy/tests/ui/large_digit_groups.fixed
index 3430c137e..ea18dac06 100644
--- a/src/tools/clippy/tests/ui/large_digit_groups.fixed
+++ b/src/tools/clippy/tests/ui/large_digit_groups.fixed
@@ -11,7 +11,7 @@ fn main() {
let _good = (
0b1011_i64,
0o1_234_u32,
- 0x0123_4567,
+ 0x1_234_567,
1_2345_6789,
1234_f32,
1_234.12_f32,
@@ -19,7 +19,7 @@ fn main() {
1.123_4_f32,
);
let _bad = (
- 0b11_0110_i64,
+ 0b1_10110_i64,
0xdead_beef_usize,
123_456_f32,
123_456.12_f32,
diff --git a/src/tools/clippy/tests/ui/large_digit_groups.stderr b/src/tools/clippy/tests/ui/large_digit_groups.stderr
index 13d108b56..19c0fae98 100644
--- a/src/tools/clippy/tests/ui/large_digit_groups.stderr
+++ b/src/tools/clippy/tests/ui/large_digit_groups.stderr
@@ -1,22 +1,10 @@
-error: digits of hex or binary literal not grouped by four
- --> $DIR/large_digit_groups.rs:14:9
- |
-LL | 0x1_234_567,
- | ^^^^^^^^^^^ help: consider: `0x0123_4567`
- |
- = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
-
-error: digits of hex or binary literal not grouped by four
- --> $DIR/large_digit_groups.rs:22:9
- |
-LL | 0b1_10110_i64,
- | ^^^^^^^^^^^^^ help: consider: `0b11_0110_i64`
-
-error: digits of hex or binary literal not grouped by four
+error: digits of hex, binary or octal literal not in groups of equal size
--> $DIR/large_digit_groups.rs:23:9
|
LL | 0xd_e_adbee_f_usize,
| ^^^^^^^^^^^^^^^^^^^ help: consider: `0xdead_beef_usize`
+ |
+ = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
error: digit groups should be smaller
--> $DIR/large_digit_groups.rs:24:9
@@ -44,5 +32,5 @@ error: digit groups should be smaller
LL | 1_23456.12345_6_f64,
| ^^^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_456_f64`
-error: aborting due to 7 previous errors
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/len_without_is_empty.rs b/src/tools/clippy/tests/ui/len_without_is_empty.rs
index 78397c2af..b5dec6c46 100644
--- a/src/tools/clippy/tests/ui/len_without_is_empty.rs
+++ b/src/tools/clippy/tests/ui/len_without_is_empty.rs
@@ -282,4 +282,50 @@ impl AsyncLen {
}
}
+// issue #9520
+pub struct NonStandardLenAndIsEmptySignature;
+impl NonStandardLenAndIsEmptySignature {
+ // don't lint
+ pub fn len(&self, something: usize) -> usize {
+ something
+ }
+
+ pub fn is_empty(&self, something: usize) -> bool {
+ something == 0
+ }
+}
+
+// test case for #9520 with generics in the function signature
+pub trait TestResource {
+ type NonStandardSignatureWithGenerics: Copy;
+ fn lookup_content(&self, item: Self::NonStandardSignatureWithGenerics) -> Result<Option<&[u8]>, String>;
+}
+pub struct NonStandardSignatureWithGenerics(u32);
+impl NonStandardSignatureWithGenerics {
+ pub fn is_empty<T, U>(self, resource: &T) -> bool
+ where
+ T: TestResource<NonStandardSignatureWithGenerics = U>,
+ U: Copy + From<NonStandardSignatureWithGenerics>,
+ {
+ if let Ok(Some(content)) = resource.lookup_content(self.into()) {
+ content.is_empty()
+ } else {
+ true
+ }
+ }
+
+ // test case for #9520 with generics in the function signature
+ pub fn len<T, U>(self, resource: &T) -> usize
+ where
+ T: TestResource<NonStandardSignatureWithGenerics = U>,
+ U: Copy + From<NonStandardSignatureWithGenerics>,
+ {
+ if let Ok(Some(content)) = resource.lookup_content(self.into()) {
+ content.len()
+ } else {
+ 0_usize
+ }
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.rs b/src/tools/clippy/tests/ui/let_underscore_untyped.rs
new file mode 100644
index 000000000..bcb33c5c7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_underscore_untyped.rs
@@ -0,0 +1,54 @@
+#![allow(unused)]
+#![warn(clippy::let_underscore_untyped)]
+
+use std::future::Future;
+use std::{boxed::Box, fmt::Display};
+
+fn a() -> u32 {
+ 1
+}
+
+fn b<T>(x: T) -> T {
+ x
+}
+
+fn c() -> impl Display {
+ 1
+}
+
+fn d(x: &u32) -> &u32 {
+ x
+}
+
+fn e() -> Result<u32, ()> {
+ Ok(1)
+}
+
+fn f() -> Box<dyn Display> {
+ Box::new(1)
+}
+
+fn main() {
+ let _ = a();
+ let _ = b(1);
+ let _ = c();
+ let _ = d(&1);
+ let _ = e();
+ let _ = f();
+
+ _ = a();
+ _ = b(1);
+ _ = c();
+ _ = d(&1);
+ _ = e();
+ _ = f();
+
+ let _: u32 = a();
+ let _: u32 = b(1);
+ let _: &u32 = d(&1);
+ let _: Result<_, _> = e();
+ let _: Box<_> = f();
+
+ #[allow(clippy::let_underscore_untyped)]
+ let _ = a();
+}
diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
new file mode 100644
index 000000000..36c3d1214
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
@@ -0,0 +1,51 @@
+error: non-binding `let` without a type annotation
+ --> $DIR/let_underscore_untyped.rs:32:5
+ |
+LL | let _ = a();
+ | ^^^^^^^^^^^^
+ |
+ = help: consider adding a type annotation or removing the `let` keyword
+ = note: `-D clippy::let-underscore-untyped` implied by `-D warnings`
+
+error: non-binding `let` without a type annotation
+ --> $DIR/let_underscore_untyped.rs:33:5
+ |
+LL | let _ = b(1);
+ | ^^^^^^^^^^^^^
+ |
+ = help: consider adding a type annotation or removing the `let` keyword
+
+error: non-binding `let` without a type annotation
+ --> $DIR/let_underscore_untyped.rs:34:5
+ |
+LL | let _ = c();
+ | ^^^^^^^^^^^^
+ |
+ = help: consider adding a type annotation or removing the `let` keyword
+
+error: non-binding `let` without a type annotation
+ --> $DIR/let_underscore_untyped.rs:35:5
+ |
+LL | let _ = d(&1);
+ | ^^^^^^^^^^^^^^
+ |
+ = help: consider adding a type annotation or removing the `let` keyword
+
+error: non-binding `let` without a type annotation
+ --> $DIR/let_underscore_untyped.rs:36:5
+ |
+LL | let _ = e();
+ | ^^^^^^^^^^^^
+ |
+ = help: consider adding a type annotation or removing the `let` keyword
+
+error: non-binding `let` without a type annotation
+ --> $DIR/let_underscore_untyped.rs:37:5
+ |
+LL | let _ = f();
+ | ^^^^^^^^^^^^
+ |
+ = help: consider adding a type annotation or removing the `let` keyword
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/literals.stderr b/src/tools/clippy/tests/ui/literals.stderr
index 603d47bac..9bc7948c7 100644
--- a/src/tools/clippy/tests/ui/literals.stderr
+++ b/src/tools/clippy/tests/ui/literals.stderr
@@ -121,7 +121,7 @@ error: digits grouped inconsistently by underscores
LL | let fail23 = 3__16___23;
| ^^^^^^^^^^ help: consider: `31_623`
-error: digits of hex or binary literal not grouped by four
+error: digits of hex, binary or octal literal not in groups of equal size
--> $DIR/literals.rs:38:18
|
LL | let fail24 = 0xAB_ABC_AB;
@@ -129,12 +129,6 @@ LL | let fail24 = 0xAB_ABC_AB;
|
= note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
-error: digits of hex or binary literal not grouped by four
- --> $DIR/literals.rs:39:18
- |
-LL | let fail25 = 0b01_100_101;
- | ^^^^^^^^^^^^ help: consider: `0b0110_0101`
-
error: this is a decimal constant
--> $DIR/literals.rs:46:13
|
@@ -168,5 +162,5 @@ help: if you mean to use a decimal constant, remove the `0` to avoid confusion
LL | let _ = 89;
| ~~
-error: aborting due to 21 previous errors
+error: aborting due to 20 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
index 638320dd6..8c7e919bf 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
@@ -29,9 +29,7 @@ fn main() {
panic!("qaqaq{:?}", a);
}
assert!(a.is_empty(), "qaqaq{:?}", a);
- if !a.is_empty() {
- panic!("qwqwq");
- }
+ assert!(a.is_empty(), "qwqwq");
if a.len() == 3 {
println!("qwq");
println!("qwq");
@@ -46,21 +44,11 @@ fn main() {
println!("qwq");
}
let b = vec![1, 2, 3];
- if b.is_empty() {
- panic!("panic1");
- }
- if b.is_empty() && a.is_empty() {
- panic!("panic2");
- }
- if a.is_empty() && !b.is_empty() {
- panic!("panic3");
- }
- if b.is_empty() || a.is_empty() {
- panic!("panic4");
- }
- if a.is_empty() || !b.is_empty() {
- panic!("panic5");
- }
+ assert!(!b.is_empty(), "panic1");
+ assert!(!(b.is_empty() && a.is_empty()), "panic2");
+ assert!(!(a.is_empty() && !b.is_empty()), "panic3");
+ assert!(!(b.is_empty() || a.is_empty()), "panic4");
+ assert!(!(a.is_empty() || !b.is_empty()), "panic5");
assert!(!a.is_empty(), "with expansion {}", one!());
if a.is_empty() {
let _ = 0;
@@ -71,12 +59,11 @@ fn main() {
fn issue7730(a: u8) {
// Suggestion should preserve comment
- if a > 2 {
- // comment
- /* this is a
+ // comment
+/* this is a
multiline
comment */
- /// Doc comment
- panic!("panic with comment") // comment after `panic!`
- }
+/// Doc comment
+// comment after `panic!`
+assert!(!(a > 2), "panic with comment");
}
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
index 1f2e1e308..3555ac292 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
@@ -9,6 +9,54 @@ LL | | }
= note: `-D clippy::manual-assert` implied by `-D warnings`
error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:34:5
+ |
+LL | / if !a.is_empty() {
+LL | | panic!("qwqwq");
+LL | | }
+ | |_____^ help: try instead: `assert!(a.is_empty(), "qwqwq");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:51:5
+ |
+LL | / if b.is_empty() {
+LL | | panic!("panic1");
+LL | | }
+ | |_____^ help: try instead: `assert!(!b.is_empty(), "panic1");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:54:5
+ |
+LL | / if b.is_empty() && a.is_empty() {
+LL | | panic!("panic2");
+LL | | }
+ | |_____^ help: try instead: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:57:5
+ |
+LL | / if a.is_empty() && !b.is_empty() {
+LL | | panic!("panic3");
+LL | | }
+ | |_____^ help: try instead: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:60:5
+ |
+LL | / if b.is_empty() || a.is_empty() {
+LL | | panic!("panic4");
+LL | | }
+ | |_____^ help: try instead: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:63:5
+ |
+LL | / if a.is_empty() || !b.is_empty() {
+LL | | panic!("panic5");
+LL | | }
+ | |_____^ help: try instead: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
+
+error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:66:5
|
LL | / if a.is_empty() {
@@ -16,5 +64,22 @@ LL | | panic!("with expansion {}", one!())
LL | | }
| |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());`
-error: aborting due to 2 previous errors
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:78:5
+ |
+LL | / if a > 2 {
+LL | | // comment
+LL | | /* this is a
+LL | | multiline
+... |
+LL | | panic!("panic with comment") // comment after `panic!`
+LL | | }
+ | |_____^
+ |
+help: try instead
+ |
+LL | assert!(!(a > 2), "panic with comment");
+ |
+
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_let_else.rs b/src/tools/clippy/tests/ui/manual_let_else.rs
index 48a162c13..d175597a4 100644
--- a/src/tools/clippy/tests/ui/manual_let_else.rs
+++ b/src/tools/clippy/tests/ui/manual_let_else.rs
@@ -248,4 +248,15 @@ fn not_fire() {
Some(value) => value,
_ => macro_call!(),
};
+
+ // Issue 10296
+ // The let/else block in the else part is not divergent despite the presence of return
+ let _x = if let Some(x) = Some(1) {
+ x
+ } else {
+ let Some(_z) = Some(3) else {
+ return
+ };
+ 1
+ };
}
diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.rs b/src/tools/clippy/tests/ui/manual_let_else_match.rs
index 28caed9d7..73b746791 100644
--- a/src/tools/clippy/tests/ui/manual_let_else_match.rs
+++ b/src/tools/clippy/tests/ui/manual_let_else_match.rs
@@ -42,13 +42,13 @@ fn fire() {
loop {
// More complex pattern for the identity arm and diverging arm
let v = match h() {
- (Some(_), Some(_)) | (None, None) => continue,
(Some(v), None) | (None, Some(v)) => v,
+ (Some(_), Some(_)) | (None, None) => continue,
};
// Custom enums are supported as long as the "else" arm is a simple _
let v = match build_enum() {
- _ => continue,
Variant::Bar(v) | Variant::Baz(v) => v,
+ _ => continue,
};
}
@@ -71,6 +71,12 @@ fn fire() {
Variant::Bar(_) | Variant::Baz(_) => (),
_ => return,
};
+
+ let data = [1_u8, 2, 3, 4, 0, 0, 0, 0];
+ let data = match data.as_slice() {
+ [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0] => data,
+ _ => return,
+ };
}
fn not_fire() {
@@ -125,4 +131,23 @@ fn not_fire() {
Ok(v) | Err(Variant::Bar(v) | Variant::Baz(v)) => v,
Err(Variant::Foo) => return,
};
+
+ // Issue 10241
+ // The non-divergent arm arrives in second position and
+ // may cover values already matched in the first arm.
+ let v = match h() {
+ (Some(_), Some(_)) | (None, None) => return,
+ (Some(v), _) | (None, Some(v)) => v,
+ };
+
+ let v = match build_enum() {
+ _ => return,
+ Variant::Bar(v) | Variant::Baz(v) => v,
+ };
+
+ let data = [1_u8, 2, 3, 4, 0, 0, 0, 0];
+ let data = match data.as_slice() {
+ [] | [0, 0] => return,
+ [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ ..] => data,
+ };
}
diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.stderr b/src/tools/clippy/tests/ui/manual_let_else_match.stderr
index cd5e9a9ac..7abaa0b85 100644
--- a/src/tools/clippy/tests/ui/manual_let_else_match.stderr
+++ b/src/tools/clippy/tests/ui/manual_let_else_match.stderr
@@ -22,8 +22,8 @@ error: this could be rewritten as `let...else`
--> $DIR/manual_let_else_match.rs:44:9
|
LL | / let v = match h() {
-LL | | (Some(_), Some(_)) | (None, None) => continue,
LL | | (Some(v), None) | (None, Some(v)) => v,
+LL | | (Some(_), Some(_)) | (None, None) => continue,
LL | | };
| |__________^ help: consider writing: `let ((Some(v), None) | (None, Some(v))) = h() else { continue };`
@@ -31,8 +31,8 @@ error: this could be rewritten as `let...else`
--> $DIR/manual_let_else_match.rs:49:9
|
LL | / let v = match build_enum() {
-LL | | _ => continue,
LL | | Variant::Bar(v) | Variant::Baz(v) => v,
+LL | | _ => continue,
LL | | };
| |__________^ help: consider writing: `let (Variant::Bar(v) | Variant::Baz(v)) = build_enum() else { continue };`
@@ -63,5 +63,14 @@ LL | | _ => return,
LL | | };
| |______^ help: consider writing: `let (Variant::Bar(_) | Variant::Baz(_)) = f else { return };`
-error: aborting due to 7 previous errors
+error: this could be rewritten as `let...else`
+ --> $DIR/manual_let_else_match.rs:76:5
+ |
+LL | / let data = match data.as_slice() {
+LL | | [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0] => data,
+LL | | _ => return,
+LL | | };
+ | |______^ help: consider writing: `let ([data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0]) = data.as_slice() else { return };`
+
+error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
index 53628ef65..8e2f11389 100644
--- a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
+++ b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
@@ -1,6 +1,7 @@
// run-rustfix
#![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::let_underscore_untyped)]
#![allow(clippy::missing_docs_in_private_items)]
#![allow(clippy::map_identity)]
#![allow(clippy::redundant_closure)]
diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.rs b/src/tools/clippy/tests/ui/map_flatten_fixable.rs
index 76016c8ed..a783a99c4 100644
--- a/src/tools/clippy/tests/ui/map_flatten_fixable.rs
+++ b/src/tools/clippy/tests/ui/map_flatten_fixable.rs
@@ -1,6 +1,7 @@
// run-rustfix
#![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::let_underscore_untyped)]
#![allow(clippy::missing_docs_in_private_items)]
#![allow(clippy::map_identity)]
#![allow(clippy::redundant_closure)]
diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
index b6b0c4d09..c91f0b9ae 100644
--- a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
+++ b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
@@ -1,5 +1,5 @@
error: called `map(..).flatten()` on `Iterator`
- --> $DIR/map_flatten_fixable.rs:17:47
+ --> $DIR/map_flatten_fixable.rs:18:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id)`
@@ -7,43 +7,43 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll
= note: `-D clippy::map-flatten` implied by `-D warnings`
error: called `map(..).flatten()` on `Iterator`
- --> $DIR/map_flatten_fixable.rs:18:47
+ --> $DIR/map_flatten_fixable.rs:19:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_ref)`
error: called `map(..).flatten()` on `Iterator`
- --> $DIR/map_flatten_fixable.rs:19:47
+ --> $DIR/map_flatten_fixable.rs:20:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_closure)`
error: called `map(..).flatten()` on `Iterator`
- --> $DIR/map_flatten_fixable.rs:20:47
+ --> $DIR/map_flatten_fixable.rs:21:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(|x| x.checked_add(1))`
error: called `map(..).flatten()` on `Iterator`
- --> $DIR/map_flatten_fixable.rs:23:47
+ --> $DIR/map_flatten_fixable.rs:24:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| 0..x)`
error: called `map(..).flatten()` on `Option`
- --> $DIR/map_flatten_fixable.rs:26:40
+ --> $DIR/map_flatten_fixable.rs:27:40
|
LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
| ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)`
error: called `map(..).flatten()` on `Result`
- --> $DIR/map_flatten_fixable.rs:29:42
+ --> $DIR/map_flatten_fixable.rs:30:42
|
LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten();
| ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)`
error: called `map(..).flatten()` on `Iterator`
- --> $DIR/map_flatten_fixable.rs:38:10
+ --> $DIR/map_flatten_fixable.rs:39:10
|
LL | .map(|n| match n {
| __________^
@@ -72,7 +72,7 @@ LL ~ });
|
error: called `map(..).flatten()` on `Option`
- --> $DIR/map_flatten_fixable.rs:58:10
+ --> $DIR/map_flatten_fixable.rs:59:10
|
LL | .map(|_| {
| __________^
diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed
index fc252cdd3..9fd3739b6 100644
--- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed
+++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed
@@ -123,7 +123,7 @@ fn main() {
Enum::A => (),
Enum::B => (),
Enum::C => (),
- _ => (),
+ Enum::__Private => (),
}
match Enum::A {
Enum::A => (),
diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr
index 6fa313dc9..105b4c4b4 100644
--- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr
+++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr
@@ -49,10 +49,16 @@ LL | _ => (),
| ^ help: try this: `Color::Blue`
error: wildcard matches only a single variant and will also match any future added variants
+ --> $DIR/match_wildcard_for_single_variants.rs:126:13
+ |
+LL | _ => (),
+ | ^ help: try this: `Enum::__Private`
+
+error: wildcard matches only a single variant and will also match any future added variants
--> $DIR/match_wildcard_for_single_variants.rs:153:13
|
LL | _ => 2,
| ^ help: try this: `Foo::B`
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs
index 6f22366ea..1519e4da9 100644
--- a/src/tools/clippy/tests/ui/methods.rs
+++ b/src/tools/clippy/tests/ui/methods.rs
@@ -4,6 +4,7 @@
#![allow(
clippy::disallowed_names,
clippy::default_trait_access,
+ clippy::let_underscore_untyped,
clippy::missing_docs_in_private_items,
clippy::missing_safety_doc,
clippy::non_ascii_literal,
diff --git a/src/tools/clippy/tests/ui/methods.stderr b/src/tools/clippy/tests/ui/methods.stderr
index b63672dd6..4643e09e2 100644
--- a/src/tools/clippy/tests/ui/methods.stderr
+++ b/src/tools/clippy/tests/ui/methods.stderr
@@ -1,5 +1,5 @@
error: methods called `new` usually return `Self`
- --> $DIR/methods.rs:104:5
+ --> $DIR/methods.rs:105:5
|
LL | / fn new() -> i32 {
LL | | 0
@@ -9,7 +9,7 @@ LL | | }
= note: `-D clippy::new-ret-no-self` implied by `-D warnings`
error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
- --> $DIR/methods.rs:125:13
+ --> $DIR/methods.rs:126:13
|
LL | let _ = v.iter().filter(|&x| {
| _____________^
diff --git a/src/tools/clippy/tests/ui/missing_doc_impl.stderr b/src/tools/clippy/tests/ui/missing_doc_impl.stderr
index f22fa19db..b410f56e1 100644
--- a/src/tools/clippy/tests/ui/missing_doc_impl.stderr
+++ b/src/tools/clippy/tests/ui/missing_doc_impl.stderr
@@ -51,13 +51,13 @@ LL | | fn foo_with_impl(&self) {}
LL | | }
| |_^
-error: missing documentation for an associated function
+error: missing documentation for a method
--> $DIR/missing_doc_impl.rs:44:5
|
LL | fn foo(&self);
| ^^^^^^^^^^^^^^
-error: missing documentation for an associated function
+error: missing documentation for a method
--> $DIR/missing_doc_impl.rs:45:5
|
LL | fn foo_with_impl(&self) {}
diff --git a/src/tools/clippy/tests/ui/module_name_repetitions.stderr b/src/tools/clippy/tests/ui/module_name_repetitions.stderr
index 3f343a3e4..277801194 100644
--- a/src/tools/clippy/tests/ui/module_name_repetitions.stderr
+++ b/src/tools/clippy/tests/ui/module_name_repetitions.stderr
@@ -1,34 +1,34 @@
error: item name starts with its containing module's name
- --> $DIR/module_name_repetitions.rs:8:5
+ --> $DIR/module_name_repetitions.rs:8:12
|
LL | pub fn foo_bar() {}
- | ^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^
|
= note: `-D clippy::module-name-repetitions` implied by `-D warnings`
error: item name ends with its containing module's name
- --> $DIR/module_name_repetitions.rs:9:5
+ --> $DIR/module_name_repetitions.rs:9:12
|
LL | pub fn bar_foo() {}
- | ^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^
error: item name starts with its containing module's name
- --> $DIR/module_name_repetitions.rs:10:5
+ --> $DIR/module_name_repetitions.rs:10:16
|
LL | pub struct FooCake;
- | ^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^
error: item name ends with its containing module's name
- --> $DIR/module_name_repetitions.rs:11:5
+ --> $DIR/module_name_repetitions.rs:11:14
|
LL | pub enum CakeFoo {}
- | ^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^
error: item name starts with its containing module's name
- --> $DIR/module_name_repetitions.rs:12:5
+ --> $DIR/module_name_repetitions.rs:12:16
|
LL | pub struct Foo7Bar;
- | ^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^
error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
new file mode 100644
index 000000000..4511bc99c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
@@ -0,0 +1,119 @@
+// aux-build:macro_rules.rs
+#![allow(unused)]
+#![allow(deref_nullptr)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(clippy::drop_copy)]
+#![warn(clippy::multiple_unsafe_ops_per_block)]
+
+#[macro_use]
+extern crate macro_rules;
+
+use core::arch::asm;
+
+fn raw_ptr() -> *const () {
+ core::ptr::null()
+}
+
+unsafe fn not_very_safe() {}
+
+struct Sample;
+
+impl Sample {
+ unsafe fn not_very_safe(&self) {}
+}
+
+#[allow(non_upper_case_globals)]
+const sample: Sample = Sample;
+
+union U {
+ i: i32,
+ u: u32,
+}
+
+static mut STATIC: i32 = 0;
+
+fn test1() {
+ unsafe {
+ STATIC += 1;
+ not_very_safe();
+ }
+}
+
+fn test2() {
+ let u = U { i: 0 };
+
+ unsafe {
+ drop(u.u);
+ *raw_ptr();
+ }
+}
+
+fn test3() {
+ unsafe {
+ asm!("nop");
+ sample.not_very_safe();
+ STATIC = 0;
+ }
+}
+
+fn test_all() {
+ let u = U { i: 0 };
+ unsafe {
+ drop(u.u);
+ drop(STATIC);
+ sample.not_very_safe();
+ not_very_safe();
+ *raw_ptr();
+ asm!("nop");
+ }
+}
+
+// no lint
+fn correct1() {
+ unsafe {
+ STATIC += 1;
+ }
+}
+
+// no lint
+fn correct2() {
+ unsafe {
+ STATIC += 1;
+ }
+
+ unsafe {
+ *raw_ptr();
+ }
+}
+
+// no lint
+fn correct3() {
+ let u = U { u: 0 };
+
+ unsafe {
+ not_very_safe();
+ }
+
+ unsafe {
+ drop(u.i);
+ }
+}
+
+// tests from the issue (https://github.com/rust-lang/rust-clippy/issues/10064)
+
+unsafe fn read_char_bad(ptr: *const u8) -> char {
+ unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+}
+
+// no lint
+unsafe fn read_char_good(ptr: *const u8) -> char {
+ let int_value = unsafe { *ptr.cast::<u32>() };
+ unsafe { core::char::from_u32_unchecked(int_value) }
+}
+
+// no lint
+fn issue10259() {
+ unsafe_macro!();
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr
new file mode 100644
index 000000000..303aeb7ae
--- /dev/null
+++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr
@@ -0,0 +1,129 @@
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+ --> $DIR/multiple_unsafe_ops_per_block.rs:36:5
+ |
+LL | / unsafe {
+LL | | STATIC += 1;
+LL | | not_very_safe();
+LL | | }
+ | |_____^
+ |
+note: modification of a mutable static occurs here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:37:9
+ |
+LL | STATIC += 1;
+ | ^^^^^^^^^^^
+note: unsafe function call occurs here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:38:9
+ |
+LL | not_very_safe();
+ | ^^^^^^^^^^^^^^^
+ = note: `-D clippy::multiple-unsafe-ops-per-block` implied by `-D warnings`
+
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+ --> $DIR/multiple_unsafe_ops_per_block.rs:45:5
+ |
+LL | / unsafe {
+LL | | drop(u.u);
+LL | | *raw_ptr();
+LL | | }
+ | |_____^
+ |
+note: union field access occurs here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:46:14
+ |
+LL | drop(u.u);
+ | ^^^
+note: raw pointer dereference occurs here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:47:9
+ |
+LL | *raw_ptr();
+ | ^^^^^^^^^^
+
+error: this `unsafe` block contains 3 unsafe operations, expected only one
+ --> $DIR/multiple_unsafe_ops_per_block.rs:52:5
+ |
+LL | / unsafe {
+LL | | asm!("nop");
+LL | | sample.not_very_safe();
+LL | | STATIC = 0;
+LL | | }
+ | |_____^
+ |
+note: inline assembly used here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:53:9
+ |
+LL | asm!("nop");
+ | ^^^^^^^^^^^
+note: unsafe method call occurs here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:54:9
+ |
+LL | sample.not_very_safe();
+ | ^^^^^^^^^^^^^^^^^^^^^^
+note: modification of a mutable static occurs here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:55:9
+ |
+LL | STATIC = 0;
+ | ^^^^^^^^^^
+
+error: this `unsafe` block contains 6 unsafe operations, expected only one
+ --> $DIR/multiple_unsafe_ops_per_block.rs:61:5
+ |
+LL | / unsafe {
+LL | | drop(u.u);
+LL | | drop(STATIC);
+LL | | sample.not_very_safe();
+... |
+LL | | asm!("nop");
+LL | | }
+ | |_____^
+ |
+note: union field access occurs here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:62:14
+ |
+LL | drop(u.u);
+ | ^^^
+note: access of a mutable static occurs here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:63:14
+ |
+LL | drop(STATIC);
+ | ^^^^^^
+note: unsafe method call occurs here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:64:9
+ |
+LL | sample.not_very_safe();
+ | ^^^^^^^^^^^^^^^^^^^^^^
+note: unsafe function call occurs here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:65:9
+ |
+LL | not_very_safe();
+ | ^^^^^^^^^^^^^^^
+note: raw pointer dereference occurs here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:66:9
+ |
+LL | *raw_ptr();
+ | ^^^^^^^^^^
+note: inline assembly used here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:67:9
+ |
+LL | asm!("nop");
+ | ^^^^^^^^^^^
+
+error: this `unsafe` block contains 2 unsafe operations, expected only one
+ --> $DIR/multiple_unsafe_ops_per_block.rs:105:5
+ |
+LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: unsafe function call occurs here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:105:14
+ |
+LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: raw pointer dereference occurs here
+ --> $DIR/multiple_unsafe_ops_per_block.rs:105:39
+ |
+LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed
index 04a74a009..bbbb3cf62 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.fixed
+++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed
@@ -84,7 +84,7 @@ pub unsafe fn mutates_static() -> usize {
}
#[no_mangle]
-pub fn unmangled(i: bool) -> bool {
+pub extern "C" fn unmangled(i: bool) -> bool {
!i
}
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.rs b/src/tools/clippy/tests/ui/must_use_candidates.rs
index f04122f4e..94d3c83bd 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.rs
+++ b/src/tools/clippy/tests/ui/must_use_candidates.rs
@@ -84,7 +84,7 @@ pub unsafe fn mutates_static() -> usize {
}
#[no_mangle]
-pub fn unmangled(i: bool) -> bool {
+pub extern "C" fn unmangled(i: bool) -> bool {
!i
}
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
new file mode 100644
index 000000000..f0f1f9298
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
@@ -0,0 +1,548 @@
+// run-rustfix
+// aux-build:macro_rules.rs
+
+#![warn(clippy::needless_lifetimes)]
+#![allow(
+ unused,
+ clippy::boxed_local,
+ clippy::extra_unused_type_parameters,
+ clippy::needless_pass_by_value,
+ clippy::unnecessary_wraps,
+ dyn_drop,
+ clippy::get_first
+)]
+
+#[macro_use]
+extern crate macro_rules;
+
+fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {}
+
+fn distinct_and_static(_x: &u8, _y: &u8, _z: &'static u8) {}
+
+// No error; same lifetime on two params.
+fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) {}
+
+// No error; static involved.
+fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) {}
+
+fn mut_and_static_input(_x: &mut u8, _y: &'static str) {}
+
+fn in_and_out(x: &u8, _y: u8) -> &u8 {
+ x
+}
+
+// No error; multiple input refs.
+fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 {
+ x
+}
+
+// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
+// fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8
+// ^^^
+fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 {
+ x
+}
+
+// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
+// fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8
+// ^^^
+fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 {
+ y
+}
+
+// No error; multiple input refs
+async fn func<'a>(args: &[&'a str]) -> Option<&'a str> {
+ args.get(0).cloned()
+}
+
+// No error; static involved.
+fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 {
+ x
+}
+
+// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
+// fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()>
+// ^^^
+fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> {
+ Ok(x)
+}
+
+// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
+// fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()>
+// ^^^
+fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> {
+ Ok(y)
+}
+
+// No error; two input refs.
+fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 {
+ x.unwrap()
+}
+
+fn deep_reference_3(x: &u8, _y: u8) -> Result<&u8, ()> {
+ Ok(x)
+}
+
+// Where-clause, but without lifetimes.
+fn where_clause_without_lt<T>(x: &u8, _y: u8) -> Result<&u8, ()>
+where
+ T: Copy,
+{
+ Ok(x)
+}
+
+type Ref<'r> = &'r u8;
+
+// No error; same lifetime on two params.
+fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {}
+
+fn lifetime_param_2(_x: Ref<'_>, _y: &u8) {}
+
+// No error; bounded lifetime.
+fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {}
+
+// No error; bounded lifetime.
+fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8)
+where
+ 'b: 'a,
+{
+}
+
+struct Lt<'a, I: 'static> {
+ x: &'a I,
+}
+
+// No error; fn bound references `'a`.
+fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
+where
+ F: Fn(Lt<'a, I>) -> Lt<'a, I>,
+{
+ unreachable!()
+}
+
+fn fn_bound_2<F, I>(_m: Lt<'_, I>, _f: F) -> Lt<'_, I>
+where
+ for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>,
+{
+ unreachable!()
+}
+
+// No error; see below.
+fn fn_bound_3<'a, F: FnOnce(&'a i32)>(x: &'a i32, f: F) {
+ f(x);
+}
+
+fn fn_bound_3_cannot_elide() {
+ let x = 42;
+ let p = &x;
+ let mut q = &x;
+ // This will fail if we elide lifetimes of `fn_bound_3`.
+ fn_bound_3(p, |y| q = y);
+}
+
+// No error; multiple input refs.
+fn fn_bound_4<'a, F: FnOnce() -> &'a ()>(cond: bool, x: &'a (), f: F) -> &'a () {
+ if cond { x } else { f() }
+}
+
+struct X {
+ x: u8,
+}
+
+impl X {
+ fn self_and_out(&self) -> &u8 {
+ &self.x
+ }
+
+ // Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
+ // fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8
+ // ^^^
+ fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 {
+ &self.x
+ }
+
+ // Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
+ // fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8
+ // ^^^^^
+ fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 {
+ x
+ }
+
+ fn distinct_self_and_in(&self, _x: &u8) {}
+
+ // No error; same lifetimes on two params.
+ fn self_and_same_in<'s>(&'s self, _x: &'s u8) {}
+}
+
+struct Foo<'a>(&'a u8);
+
+impl<'a> Foo<'a> {
+ // No error; lifetime `'a` not defined in method.
+ fn self_shared_lifetime(&self, _: &'a u8) {}
+ // No error; bounds exist.
+ fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {}
+}
+
+fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 {
+ unimplemented!()
+}
+
+fn struct_with_lt(_foo: Foo<'_>) -> &str {
+ unimplemented!()
+}
+
+// No warning; two input lifetimes (named on the reference, anonymous on `Foo`).
+fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str {
+ unimplemented!()
+}
+
+// No warning; two input lifetimes (anonymous on the reference, named on `Foo`).
+fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str {
+ unimplemented!()
+}
+
+// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is
+// valid:
+// fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str
+// ^^
+fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str {
+ unimplemented!()
+}
+
+// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is
+// valid:
+// fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str
+// ^^^^
+fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str {
+ unimplemented!()
+}
+
+trait WithLifetime<'a> {}
+
+type WithLifetimeAlias<'a> = dyn WithLifetime<'a>;
+
+// Should not warn because it won't build without the lifetime.
+fn trait_obj_elided<'a>(_arg: &'a dyn WithLifetime) -> &'a str {
+ unimplemented!()
+}
+
+// Should warn because there is no lifetime on `Drop`, so this would be
+// unambiguous if we elided the lifetime.
+fn trait_obj_elided2(_arg: &dyn Drop) -> &str {
+ unimplemented!()
+}
+
+type FooAlias<'a> = Foo<'a>;
+
+fn alias_with_lt(_foo: FooAlias<'_>) -> &str {
+ unimplemented!()
+}
+
+// No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`).
+fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str {
+ unimplemented!()
+}
+
+// No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`).
+fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str {
+ unimplemented!()
+}
+
+// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is
+// valid:
+// fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str
+// ^^
+fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str {
+ unimplemented!()
+}
+
+// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is
+// valid:
+// fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str
+// ^^^^^^^^^
+fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str {
+ unimplemented!()
+}
+
+fn named_input_elided_output(_arg: &str) -> &str {
+ unimplemented!()
+}
+
+fn elided_input_named_output<'a>(_arg: &str) -> &'a str {
+ unimplemented!()
+}
+
+fn trait_bound_ok<T: WithLifetime<'static>>(_: &u8, _: T) {
+ unimplemented!()
+}
+fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) {
+ unimplemented!()
+}
+
+// Don't warn on these; see issue #292.
+fn trait_bound_bug<'a, T: WithLifetime<'a>>() {
+ unimplemented!()
+}
+
+// See issue #740.
+struct Test {
+ vec: Vec<usize>,
+}
+
+impl Test {
+ fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = usize> + 'a> {
+ unimplemented!()
+ }
+}
+
+trait LintContext<'a> {}
+
+fn f<'a, T: LintContext<'a>>(_: &T) {}
+
+fn test<'a>(x: &'a [u8]) -> u8 {
+ let y: &'a u8 = &x[5];
+ *y
+}
+
+// Issue #3284: give hint regarding lifetime in return type.
+struct Cow<'a> {
+ x: &'a str,
+}
+fn out_return_type_lts(e: &str) -> Cow<'_> {
+ unimplemented!()
+}
+
+// Make sure we still warn on implementations
+mod issue4291 {
+ trait BadTrait {
+ fn needless_lt(x: &u8) {}
+ }
+
+ impl BadTrait for () {
+ fn needless_lt(_x: &u8) {}
+ }
+}
+
+mod issue2944 {
+ trait Foo {}
+ struct Bar;
+ struct Baz<'a> {
+ bar: &'a Bar,
+ }
+
+ impl<'a> Foo for Baz<'a> {}
+ impl Bar {
+ fn baz(&self) -> impl Foo + '_ {
+ Baz { bar: self }
+ }
+ }
+}
+
+mod nested_elision_sites {
+ // issue #issue2944
+
+ // closure trait bounds subject to nested elision
+ // don't lint because they refer to outer lifetimes
+ fn trait_fn<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
+ move || i
+ }
+ fn trait_fn_mut<'a>(i: &'a i32) -> impl FnMut() -> &'a i32 {
+ move || i
+ }
+ fn trait_fn_once<'a>(i: &'a i32) -> impl FnOnce() -> &'a i32 {
+ move || i
+ }
+
+ // don't lint
+ fn impl_trait_in_input_position<'a>(f: impl Fn() -> &'a i32) -> &'a i32 {
+ f()
+ }
+ fn impl_trait_in_output_position<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
+ move || i
+ }
+ // lint
+ fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
+ f(i)
+ }
+ fn impl_trait_elidable_nested_anonymous_lifetimes(i: &i32, f: impl Fn(&i32) -> &i32) -> &i32 {
+ f(i)
+ }
+
+ // don't lint
+ fn generics_not_elidable<'a, T: Fn() -> &'a i32>(f: T) -> &'a i32 {
+ f()
+ }
+ // lint
+ fn generics_elidable<T: Fn(&i32) -> &i32>(i: &i32, f: T) -> &i32 {
+ f(i)
+ }
+
+ // don't lint
+ fn where_clause_not_elidable<'a, T>(f: T) -> &'a i32
+ where
+ T: Fn() -> &'a i32,
+ {
+ f()
+ }
+ // lint
+ fn where_clause_elidadable<T>(i: &i32, f: T) -> &i32
+ where
+ T: Fn(&i32) -> &i32,
+ {
+ f(i)
+ }
+
+ // don't lint
+ fn pointer_fn_in_input_position<'a>(f: fn(&'a i32) -> &'a i32, i: &'a i32) -> &'a i32 {
+ f(i)
+ }
+ fn pointer_fn_in_output_position<'a>(_: &'a i32) -> fn(&'a i32) -> &'a i32 {
+ |i| i
+ }
+ // lint
+ fn pointer_fn_elidable(i: &i32, f: fn(&i32) -> &i32) -> &i32 {
+ f(i)
+ }
+
+ // don't lint
+ fn nested_fn_pointer_1<'a>(_: &'a i32) -> fn(fn(&'a i32) -> &'a i32) -> i32 {
+ |f| 42
+ }
+ fn nested_fn_pointer_2<'a>(_: &'a i32) -> impl Fn(fn(&'a i32)) {
+ |f| ()
+ }
+
+ // lint
+ fn nested_fn_pointer_3(_: &i32) -> fn(fn(&i32) -> &i32) -> i32 {
+ |f| 42
+ }
+ fn nested_fn_pointer_4(_: &i32) -> impl Fn(fn(&i32)) {
+ |f| ()
+ }
+}
+
+mod issue6159 {
+ use std::ops::Deref;
+ pub fn apply_deref<'a, T, F, R>(x: &'a T, f: F) -> R
+ where
+ T: Deref,
+ F: FnOnce(&'a T::Target) -> R,
+ {
+ f(x.deref())
+ }
+}
+
+mod issue7296 {
+ use std::rc::Rc;
+ use std::sync::Arc;
+
+ struct Foo;
+ impl Foo {
+ fn implicit(&self) -> &() {
+ &()
+ }
+ fn implicit_mut(&mut self) -> &() {
+ &()
+ }
+
+ fn explicit<'a>(self: &'a Arc<Self>) -> &'a () {
+ &()
+ }
+ fn explicit_mut<'a>(self: &'a mut Rc<Self>) -> &'a () {
+ &()
+ }
+
+ fn lifetime_elsewhere(self: Box<Self>, here: &()) -> &() {
+ &()
+ }
+ }
+
+ trait Bar {
+ fn implicit(&self) -> &();
+ fn implicit_provided(&self) -> &() {
+ &()
+ }
+
+ fn explicit<'a>(self: &'a Arc<Self>) -> &'a ();
+ fn explicit_provided<'a>(self: &'a Arc<Self>) -> &'a () {
+ &()
+ }
+
+ fn lifetime_elsewhere(self: Box<Self>, here: &()) -> &();
+ fn lifetime_elsewhere_provided(self: Box<Self>, here: &()) -> &() {
+ &()
+ }
+ }
+}
+
+mod pr_9743_false_negative_fix {
+ #![allow(unused)]
+
+ fn foo(x: &u8, y: &'_ u8) {}
+
+ fn bar(x: &u8, y: &'_ u8, z: &'_ u8) {}
+}
+
+mod pr_9743_output_lifetime_checks {
+ #![allow(unused)]
+
+ // lint: only one input
+ fn one_input(x: &u8) -> &u8 {
+ unimplemented!()
+ }
+
+ // lint: multiple inputs, output would not be elided
+ fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8) -> &'b u8 {
+ unimplemented!()
+ }
+
+ // don't lint: multiple inputs, output would be elided (which would create an ambiguity)
+ fn multiple_inputs_output_would_be_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'a u8 {
+ unimplemented!()
+ }
+}
+
+mod in_macro {
+ macro_rules! local_one_input_macro {
+ () => {
+ fn one_input(x: &u8) -> &u8 {
+ unimplemented!()
+ }
+ };
+ }
+
+ // lint local macro expands to function with needless lifetimes
+ local_one_input_macro!();
+
+ // no lint on external macro
+ macro_rules::needless_lifetime!();
+
+ macro_rules! expanded_lifetime {
+ ($l:lifetime) => {
+ fn f<$l>(arg: &$l str) -> &$l str {
+ arg
+ }
+ }
+ }
+
+ expanded_lifetime!('a);
+}
+
+mod issue5787 {
+ use std::sync::MutexGuard;
+
+ struct Foo;
+
+ impl Foo {
+ // doesn't get linted without async
+ pub async fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
+ guard
+ }
+ }
+
+ async fn foo<'a>(_x: &i32, y: &'a str) -> &'a str {
+ y
+ }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs
index 2efc93675..ddfd10430 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs
@@ -1,13 +1,20 @@
+// run-rustfix
+// aux-build:macro_rules.rs
+
#![warn(clippy::needless_lifetimes)]
#![allow(
- dead_code,
+ unused,
clippy::boxed_local,
+ clippy::extra_unused_type_parameters,
clippy::needless_pass_by_value,
clippy::unnecessary_wraps,
dyn_drop,
clippy::get_first
)]
+#[macro_use]
+extern crate macro_rules;
+
fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
@@ -495,4 +502,47 @@ mod pr_9743_output_lifetime_checks {
}
}
+mod in_macro {
+ macro_rules! local_one_input_macro {
+ () => {
+ fn one_input<'a>(x: &'a u8) -> &'a u8 {
+ unimplemented!()
+ }
+ };
+ }
+
+ // lint local macro expands to function with needless lifetimes
+ local_one_input_macro!();
+
+ // no lint on external macro
+ macro_rules::needless_lifetime!();
+
+ macro_rules! expanded_lifetime {
+ ($l:lifetime) => {
+ fn f<$l>(arg: &$l str) -> &$l str {
+ arg
+ }
+ }
+ }
+
+ expanded_lifetime!('a);
+}
+
+mod issue5787 {
+ use std::sync::MutexGuard;
+
+ struct Foo;
+
+ impl Foo {
+ // doesn't get linted without async
+ pub async fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
+ guard
+ }
+ }
+
+ async fn foo<'a>(_x: &i32, y: &'a str) -> &'a str {
+ y
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
index 5a7cf13c8..4e3c8f20d 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
@@ -1,316 +1,559 @@
error: the following explicit lifetimes could be elided: 'a, 'b
- --> $DIR/needless_lifetimes.rs:11:1
+ --> $DIR/needless_lifetimes.rs:18:1
|
LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::needless-lifetimes` implied by `-D warnings`
+help: elide the lifetimes
+ |
+LL - fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
+LL + fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {}
+ |
error: the following explicit lifetimes could be elided: 'a, 'b
- --> $DIR/needless_lifetimes.rs:13:1
+ --> $DIR/needless_lifetimes.rs:20:1
|
LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
+LL + fn distinct_and_static(_x: &u8, _y: &u8, _z: &'static u8) {}
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:23:1
+ --> $DIR/needless_lifetimes.rs:30:1
|
LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
+LL + fn in_and_out(x: &u8, _y: u8) -> &u8 {
+ |
error: the following explicit lifetimes could be elided: 'b
- --> $DIR/needless_lifetimes.rs:35:1
+ --> $DIR/needless_lifetimes.rs:42:1
|
LL | fn multiple_in_and_out_2a<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn multiple_in_and_out_2a<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 {
+LL + fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:42:1
+ --> $DIR/needless_lifetimes.rs:49:1
|
LL | fn multiple_in_and_out_2b<'a, 'b>(_x: &'a u8, y: &'b u8) -> &'b u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn multiple_in_and_out_2b<'a, 'b>(_x: &'a u8, y: &'b u8) -> &'b u8 {
+LL + fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 {
+ |
error: the following explicit lifetimes could be elided: 'b
- --> $DIR/needless_lifetimes.rs:59:1
+ --> $DIR/needless_lifetimes.rs:66:1
|
LL | fn deep_reference_1a<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn deep_reference_1a<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> {
+LL + fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:66:1
+ --> $DIR/needless_lifetimes.rs:73:1
|
LL | fn deep_reference_1b<'a, 'b>(_x: &'a u8, y: &'b u8) -> Result<&'b u8, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn deep_reference_1b<'a, 'b>(_x: &'a u8, y: &'b u8) -> Result<&'b u8, ()> {
+LL + fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:75:1
+ --> $DIR/needless_lifetimes.rs:82:1
|
LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
+LL + fn deep_reference_3(x: &u8, _y: u8) -> Result<&u8, ()> {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:80:1
+ --> $DIR/needless_lifetimes.rs:87:1
|
LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
+LL + fn where_clause_without_lt<T>(x: &u8, _y: u8) -> Result<&u8, ()>
+ |
error: the following explicit lifetimes could be elided: 'a, 'b
- --> $DIR/needless_lifetimes.rs:92:1
+ --> $DIR/needless_lifetimes.rs:99:1
|
LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: replace with `'_` in generic arguments such as here
- --> $DIR/needless_lifetimes.rs:92:37
+help: elide the lifetimes
+ |
+LL - fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
+LL + fn lifetime_param_2(_x: Ref<'_>, _y: &u8) {}
|
-LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
- | ^^
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:116:1
+ --> $DIR/needless_lifetimes.rs:123:1
|
LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: replace with `'_` in generic arguments such as here
- --> $DIR/needless_lifetimes.rs:116:32
+help: elide the lifetimes
+ |
+LL - fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
+LL + fn fn_bound_2<F, I>(_m: Lt<'_, I>, _f: F) -> Lt<'_, I>
|
-LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
- | ^^
error: the following explicit lifetimes could be elided: 's
- --> $DIR/needless_lifetimes.rs:146:5
+ --> $DIR/needless_lifetimes.rs:153:5
|
LL | fn self_and_out<'s>(&'s self) -> &'s u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn self_and_out<'s>(&'s self) -> &'s u8 {
+LL + fn self_and_out(&self) -> &u8 {
+ |
error: the following explicit lifetimes could be elided: 't
- --> $DIR/needless_lifetimes.rs:153:5
+ --> $DIR/needless_lifetimes.rs:160:5
|
LL | fn self_and_in_out_1<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn self_and_in_out_1<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 {
+LL + fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 {
+ |
error: the following explicit lifetimes could be elided: 's
- --> $DIR/needless_lifetimes.rs:160:5
+ --> $DIR/needless_lifetimes.rs:167:5
|
LL | fn self_and_in_out_2<'s, 't>(&'s self, x: &'t u8) -> &'t u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn self_and_in_out_2<'s, 't>(&'s self, x: &'t u8) -> &'t u8 {
+LL + fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 {
+ |
error: the following explicit lifetimes could be elided: 's, 't
- --> $DIR/needless_lifetimes.rs:164:5
+ --> $DIR/needless_lifetimes.rs:171:5
|
LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
+LL + fn distinct_self_and_in(&self, _x: &u8) {}
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:183:1
+ --> $DIR/needless_lifetimes.rs:190:1
|
LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: replace with `'_` in generic arguments such as here
- --> $DIR/needless_lifetimes.rs:183:33
+help: elide the lifetimes
+ |
+LL - fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
+LL + fn struct_with_lt(_foo: Foo<'_>) -> &str {
|
-LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
- | ^^
error: the following explicit lifetimes could be elided: 'b
- --> $DIR/needless_lifetimes.rs:201:1
+ --> $DIR/needless_lifetimes.rs:208:1
|
LL | fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: replace with `'_` in generic arguments such as here
- --> $DIR/needless_lifetimes.rs:201:43
+help: elide the lifetimes
+ |
+LL - fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str {
+LL + fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str {
|
-LL | fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str {
- | ^^
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:209:1
+ --> $DIR/needless_lifetimes.rs:216:1
|
LL | fn struct_with_lt4b<'a, 'b>(_foo: &'a Foo<'b>) -> &'b str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn struct_with_lt4b<'a, 'b>(_foo: &'a Foo<'b>) -> &'b str {
+LL + fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:224:1
+ --> $DIR/needless_lifetimes.rs:231:1
|
LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
+LL + fn trait_obj_elided2(_arg: &dyn Drop) -> &str {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:230:1
+ --> $DIR/needless_lifetimes.rs:237:1
|
LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: replace with `'_` in generic arguments such as here
- --> $DIR/needless_lifetimes.rs:230:37
+help: elide the lifetimes
+ |
+LL - fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
+LL + fn alias_with_lt(_foo: FooAlias<'_>) -> &str {
|
-LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
- | ^^
error: the following explicit lifetimes could be elided: 'b
- --> $DIR/needless_lifetimes.rs:248:1
+ --> $DIR/needless_lifetimes.rs:255:1
|
LL | fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: replace with `'_` in generic arguments such as here
- --> $DIR/needless_lifetimes.rs:248:47
+help: elide the lifetimes
+ |
+LL - fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str {
+LL + fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str {
|
-LL | fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str {
- | ^^
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:256:1
+ --> $DIR/needless_lifetimes.rs:263:1
|
LL | fn alias_with_lt4b<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'b str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn alias_with_lt4b<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'b str {
+LL + fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:260:1
+ --> $DIR/needless_lifetimes.rs:267:1
|
LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
+LL + fn named_input_elided_output(_arg: &str) -> &str {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:268:1
+ --> $DIR/needless_lifetimes.rs:275:1
|
LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
+LL + fn trait_bound_ok<T: WithLifetime<'static>>(_: &u8, _: T) {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:304:1
+ --> $DIR/needless_lifetimes.rs:311:1
|
LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: replace with `'_` in generic arguments such as here
- --> $DIR/needless_lifetimes.rs:304:47
+help: elide the lifetimes
+ |
+LL - fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
+LL + fn out_return_type_lts(e: &str) -> Cow<'_> {
|
-LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
- | ^^
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:311:9
+ --> $DIR/needless_lifetimes.rs:318:9
|
LL | fn needless_lt<'a>(x: &'a u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn needless_lt<'a>(x: &'a u8) {}
+LL + fn needless_lt(x: &u8) {}
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:315:9
+ --> $DIR/needless_lifetimes.rs:322:9
|
LL | fn needless_lt<'a>(_x: &'a u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn needless_lt<'a>(_x: &'a u8) {}
+LL + fn needless_lt(_x: &u8) {}
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:328:9
+ --> $DIR/needless_lifetimes.rs:335:9
|
LL | fn baz<'a>(&'a self) -> impl Foo + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn baz<'a>(&'a self) -> impl Foo + 'a {
+LL + fn baz(&self) -> impl Foo + '_ {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:360:5
+ --> $DIR/needless_lifetimes.rs:367:5
|
LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
+LL + fn impl_trait_elidable_nested_anonymous_lifetimes(i: &i32, f: impl Fn(&i32) -> &i32) -> &i32 {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:369:5
+ --> $DIR/needless_lifetimes.rs:376:5
|
LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
+LL + fn generics_elidable<T: Fn(&i32) -> &i32>(i: &i32, f: T) -> &i32 {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:381:5
+ --> $DIR/needless_lifetimes.rs:388:5
|
LL | fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
+LL + fn where_clause_elidadable<T>(i: &i32, f: T) -> &i32
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:396:5
+ --> $DIR/needless_lifetimes.rs:403:5
|
LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
+LL + fn pointer_fn_elidable(i: &i32, f: fn(&i32) -> &i32) -> &i32 {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:409:5
+ --> $DIR/needless_lifetimes.rs:416:5
|
LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
+LL + fn nested_fn_pointer_3(_: &i32) -> fn(fn(&i32) -> &i32) -> i32 {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:412:5
+ --> $DIR/needless_lifetimes.rs:419:5
|
LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
+LL + fn nested_fn_pointer_4(_: &i32) -> impl Fn(fn(&i32)) {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:434:9
+ --> $DIR/needless_lifetimes.rs:441:9
|
LL | fn implicit<'a>(&'a self) -> &'a () {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn implicit<'a>(&'a self) -> &'a () {
+LL + fn implicit(&self) -> &() {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:437:9
+ --> $DIR/needless_lifetimes.rs:444:9
|
LL | fn implicit_mut<'a>(&'a mut self) -> &'a () {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn implicit_mut<'a>(&'a mut self) -> &'a () {
+LL + fn implicit_mut(&mut self) -> &() {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:448:9
+ --> $DIR/needless_lifetimes.rs:455:9
|
LL | fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
+LL + fn lifetime_elsewhere(self: Box<Self>, here: &()) -> &() {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:454:9
+ --> $DIR/needless_lifetimes.rs:461:9
|
LL | fn implicit<'a>(&'a self) -> &'a ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn implicit<'a>(&'a self) -> &'a ();
+LL + fn implicit(&self) -> &();
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:455:9
+ --> $DIR/needless_lifetimes.rs:462:9
|
LL | fn implicit_provided<'a>(&'a self) -> &'a () {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn implicit_provided<'a>(&'a self) -> &'a () {
+LL + fn implicit_provided(&self) -> &() {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:464:9
+ --> $DIR/needless_lifetimes.rs:471:9
|
LL | fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
+LL + fn lifetime_elsewhere(self: Box<Self>, here: &()) -> &();
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:465:9
+ --> $DIR/needless_lifetimes.rs:472:9
|
LL | fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
+LL + fn lifetime_elsewhere_provided(self: Box<Self>, here: &()) -> &() {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:474:5
+ --> $DIR/needless_lifetimes.rs:481:5
|
LL | fn foo<'a>(x: &'a u8, y: &'_ u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn foo<'a>(x: &'a u8, y: &'_ u8) {}
+LL + fn foo(x: &u8, y: &'_ u8) {}
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:476:5
+ --> $DIR/needless_lifetimes.rs:483:5
|
LL | fn bar<'a>(x: &'a u8, y: &'_ u8, z: &'_ u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn bar<'a>(x: &'a u8, y: &'_ u8, z: &'_ u8) {}
+LL + fn bar(x: &u8, y: &'_ u8, z: &'_ u8) {}
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:483:5
+ --> $DIR/needless_lifetimes.rs:490:5
|
LL | fn one_input<'a>(x: &'a u8) -> &'a u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn one_input<'a>(x: &'a u8) -> &'a u8 {
+LL + fn one_input(x: &u8) -> &u8 {
+ |
error: the following explicit lifetimes could be elided: 'a
- --> $DIR/needless_lifetimes.rs:488:5
+ --> $DIR/needless_lifetimes.rs:495:5
|
LL | fn multiple_inputs_output_not_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'b u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: elide the lifetimes
+ |
+LL - fn multiple_inputs_output_not_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'b u8 {
+LL + fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8) -> &'b u8 {
+ |
+
+error: the following explicit lifetimes could be elided: 'a
+ --> $DIR/needless_lifetimes.rs:508:13
+ |
+LL | fn one_input<'a>(x: &'a u8) -> &'a u8 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | local_one_input_macro!();
+ | ------------------------ in this macro invocation
+ |
+ = note: this error originates in the macro `local_one_input_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: elide the lifetimes
+ |
+LL - fn one_input<'a>(x: &'a u8) -> &'a u8 {
+LL + fn one_input(x: &u8) -> &u8 {
+ |
-error: aborting due to 45 previous errors
+error: aborting due to 46 previous errors
diff --git a/src/tools/clippy/tests/ui/needless_range_loop.stderr b/src/tools/clippy/tests/ui/needless_range_loop.stderr
index b31544ec3..cffa19bec 100644
--- a/src/tools/clippy/tests/ui/needless_range_loop.stderr
+++ b/src/tools/clippy/tests/ui/needless_range_loop.stderr
@@ -49,7 +49,7 @@ error: the loop variable `i` is used to index `vec`
LL | for i in 0..vec.len() {
| ^^^^^^^^^^^^
|
-help: consider using an iterator
+help: consider using an iterator and enumerate()
|
LL | for (i, <item>) in vec.iter().enumerate() {
| ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
@@ -126,7 +126,7 @@ error: the loop variable `i` is used to index `vec`
LL | for i in 5..vec.len() {
| ^^^^^^^^^^^^
|
-help: consider using an iterator
+help: consider using an iterator and enumerate()
|
LL | for (i, <item>) in vec.iter().enumerate().skip(5) {
| ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -137,7 +137,7 @@ error: the loop variable `i` is used to index `vec`
LL | for i in 5..10 {
| ^^^^^
|
-help: consider using an iterator
+help: consider using an iterator and enumerate()
|
LL | for (i, <item>) in vec.iter().enumerate().take(10).skip(5) {
| ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -148,7 +148,7 @@ error: the loop variable `i` is used to index `vec`
LL | for i in 0..vec.len() {
| ^^^^^^^^^^^^
|
-help: consider using an iterator
+help: consider using an iterator and enumerate()
|
LL | for (i, <item>) in vec.iter_mut().enumerate() {
| ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index ab1c0e590..0f525dd29 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -31,6 +31,16 @@ fn test_no_semicolon() -> bool {
true
}
+#[rustfmt::skip]
+fn test_multiple_semicolon() -> bool {
+ true
+}
+
+#[rustfmt::skip]
+fn test_multiple_semicolon_with_spaces() -> bool {
+ true
+}
+
fn test_if_block() -> bool {
if true {
true
@@ -287,4 +297,14 @@ fn issue10051() -> Result<String, String> {
}
}
+mod issue10049 {
+ fn single() -> u32 {
+ if true { 1 } else { 2 }
+ }
+
+ fn multiple(b1: bool, b2: bool, b3: bool) -> u32 {
+ (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 })
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index abed338bb..a1db8375d 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -31,6 +31,16 @@ fn test_no_semicolon() -> bool {
return true;
}
+#[rustfmt::skip]
+fn test_multiple_semicolon() -> bool {
+ return true;;;
+}
+
+#[rustfmt::skip]
+fn test_multiple_semicolon_with_spaces() -> bool {
+ return true;; ; ;
+}
+
fn test_if_block() -> bool {
if true {
return true;
@@ -297,4 +307,14 @@ fn issue10051() -> Result<String, String> {
}
}
+mod issue10049 {
+ fn single() -> u32 {
+ return if true { 1 } else { 2 };
+ }
+
+ fn multiple(b1: bool, b2: bool, b3: bool) -> u32 {
+ return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 };
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr
index 52eabf6e1..87d0cd3e1 100644
--- a/src/tools/clippy/tests/ui/needless_return.stderr
+++ b/src/tools/clippy/tests/ui/needless_return.stderr
@@ -16,7 +16,23 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:36:9
+ --> $DIR/needless_return.rs:36:5
+ |
+LL | return true;;;
+ | ^^^^^^^^^^^
+ |
+ = help: remove `return`
+
+error: unneeded `return` statement
+ --> $DIR/needless_return.rs:41:5
+ |
+LL | return true;; ; ;
+ | ^^^^^^^^^^^
+ |
+ = help: remove `return`
+
+error: unneeded `return` statement
+ --> $DIR/needless_return.rs:46:9
|
LL | return true;
| ^^^^^^^^^^^
@@ -24,7 +40,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:38:9
+ --> $DIR/needless_return.rs:48:9
|
LL | return false;
| ^^^^^^^^^^^^
@@ -32,7 +48,7 @@ LL | return false;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:44:17
+ --> $DIR/needless_return.rs:54:17
|
LL | true => return false,
| ^^^^^^^^^^^^
@@ -40,7 +56,7 @@ LL | true => return false,
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:46:13
+ --> $DIR/needless_return.rs:56:13
|
LL | return true;
| ^^^^^^^^^^^
@@ -48,7 +64,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:53:9
+ --> $DIR/needless_return.rs:63:9
|
LL | return true;
| ^^^^^^^^^^^
@@ -56,7 +72,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:55:16
+ --> $DIR/needless_return.rs:65:16
|
LL | let _ = || return true;
| ^^^^^^^^^^^
@@ -64,7 +80,7 @@ LL | let _ = || return true;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:59:5
+ --> $DIR/needless_return.rs:69:5
|
LL | return the_answer!();
| ^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +88,7 @@ LL | return the_answer!();
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:62:21
+ --> $DIR/needless_return.rs:72:21
|
LL | fn test_void_fun() {
| _____________________^
@@ -82,7 +98,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:67:11
+ --> $DIR/needless_return.rs:77:11
|
LL | if b {
| ___________^
@@ -92,7 +108,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:69:13
+ --> $DIR/needless_return.rs:79:13
|
LL | } else {
| _____________^
@@ -102,7 +118,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:77:14
+ --> $DIR/needless_return.rs:87:14
|
LL | _ => return,
| ^^^^^^
@@ -110,7 +126,7 @@ LL | _ => return,
= help: replace `return` with a unit value
error: unneeded `return` statement
- --> $DIR/needless_return.rs:85:24
+ --> $DIR/needless_return.rs:95:24
|
LL | let _ = 42;
| ________________________^
@@ -120,7 +136,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:88:14
+ --> $DIR/needless_return.rs:98:14
|
LL | _ => return,
| ^^^^^^
@@ -128,7 +144,7 @@ LL | _ => return,
= help: replace `return` with a unit value
error: unneeded `return` statement
- --> $DIR/needless_return.rs:101:9
+ --> $DIR/needless_return.rs:111:9
|
LL | return String::from("test");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -136,7 +152,7 @@ LL | return String::from("test");
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:103:9
+ --> $DIR/needless_return.rs:113:9
|
LL | return String::new();
| ^^^^^^^^^^^^^^^^^^^^
@@ -144,7 +160,7 @@ LL | return String::new();
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:125:32
+ --> $DIR/needless_return.rs:135:32
|
LL | bar.unwrap_or_else(|_| return)
| ^^^^^^
@@ -152,7 +168,7 @@ LL | bar.unwrap_or_else(|_| return)
= help: replace `return` with an empty block
error: unneeded `return` statement
- --> $DIR/needless_return.rs:129:21
+ --> $DIR/needless_return.rs:139:21
|
LL | let _ = || {
| _____________________^
@@ -162,7 +178,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:132:20
+ --> $DIR/needless_return.rs:142:20
|
LL | let _ = || return;
| ^^^^^^
@@ -170,7 +186,7 @@ LL | let _ = || return;
= help: replace `return` with an empty block
error: unneeded `return` statement
- --> $DIR/needless_return.rs:138:32
+ --> $DIR/needless_return.rs:148:32
|
LL | res.unwrap_or_else(|_| return Foo)
| ^^^^^^^^^^
@@ -178,7 +194,7 @@ LL | res.unwrap_or_else(|_| return Foo)
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:147:5
+ --> $DIR/needless_return.rs:157:5
|
LL | return true;
| ^^^^^^^^^^^
@@ -186,7 +202,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:151:5
+ --> $DIR/needless_return.rs:161:5
|
LL | return true;
| ^^^^^^^^^^^
@@ -194,7 +210,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:156:9
+ --> $DIR/needless_return.rs:166:9
|
LL | return true;
| ^^^^^^^^^^^
@@ -202,7 +218,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:158:9
+ --> $DIR/needless_return.rs:168:9
|
LL | return false;
| ^^^^^^^^^^^^
@@ -210,7 +226,7 @@ LL | return false;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:164:17
+ --> $DIR/needless_return.rs:174:17
|
LL | true => return false,
| ^^^^^^^^^^^^
@@ -218,7 +234,7 @@ LL | true => return false,
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:166:13
+ --> $DIR/needless_return.rs:176:13
|
LL | return true;
| ^^^^^^^^^^^
@@ -226,7 +242,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:173:9
+ --> $DIR/needless_return.rs:183:9
|
LL | return true;
| ^^^^^^^^^^^
@@ -234,7 +250,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:175:16
+ --> $DIR/needless_return.rs:185:16
|
LL | let _ = || return true;
| ^^^^^^^^^^^
@@ -242,7 +258,7 @@ LL | let _ = || return true;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:179:5
+ --> $DIR/needless_return.rs:189:5
|
LL | return the_answer!();
| ^^^^^^^^^^^^^^^^^^^^
@@ -250,7 +266,7 @@ LL | return the_answer!();
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:182:33
+ --> $DIR/needless_return.rs:192:33
|
LL | async fn async_test_void_fun() {
| _________________________________^
@@ -260,7 +276,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:187:11
+ --> $DIR/needless_return.rs:197:11
|
LL | if b {
| ___________^
@@ -270,7 +286,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:189:13
+ --> $DIR/needless_return.rs:199:13
|
LL | } else {
| _____________^
@@ -280,7 +296,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:197:14
+ --> $DIR/needless_return.rs:207:14
|
LL | _ => return,
| ^^^^^^
@@ -288,7 +304,7 @@ LL | _ => return,
= help: replace `return` with a unit value
error: unneeded `return` statement
- --> $DIR/needless_return.rs:210:9
+ --> $DIR/needless_return.rs:220:9
|
LL | return String::from("test");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -296,7 +312,7 @@ LL | return String::from("test");
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:212:9
+ --> $DIR/needless_return.rs:222:9
|
LL | return String::new();
| ^^^^^^^^^^^^^^^^^^^^
@@ -304,7 +320,7 @@ LL | return String::new();
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:228:5
+ --> $DIR/needless_return.rs:238:5
|
LL | return format!("Hello {}", "world!");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -312,7 +328,7 @@ LL | return format!("Hello {}", "world!");
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:239:9
+ --> $DIR/needless_return.rs:249:9
|
LL | return true;
| ^^^^^^^^^^^
@@ -320,7 +336,7 @@ LL | return true;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:241:9
+ --> $DIR/needless_return.rs:251:9
|
LL | return false;
| ^^^^^^^^^^^^
@@ -328,7 +344,7 @@ LL | return false;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:248:13
+ --> $DIR/needless_return.rs:258:13
|
LL | return 10;
| ^^^^^^^^^
@@ -336,7 +352,7 @@ LL | return 10;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:251:13
+ --> $DIR/needless_return.rs:261:13
|
LL | return 100;
| ^^^^^^^^^^
@@ -344,7 +360,7 @@ LL | return 100;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:259:9
+ --> $DIR/needless_return.rs:269:9
|
LL | return 0;
| ^^^^^^^^
@@ -352,7 +368,7 @@ LL | return 0;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:266:13
+ --> $DIR/needless_return.rs:276:13
|
LL | return *(x as *const isize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -360,7 +376,7 @@ LL | return *(x as *const isize);
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:268:13
+ --> $DIR/needless_return.rs:278:13
|
LL | return !*(x as *const isize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -368,7 +384,7 @@ LL | return !*(x as *const isize);
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:275:20
+ --> $DIR/needless_return.rs:285:20
|
LL | let _ = 42;
| ____________________^
@@ -379,7 +395,7 @@ LL | | return;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:282:20
+ --> $DIR/needless_return.rs:292:20
|
LL | let _ = 42; return;
| ^^^^^^^
@@ -387,7 +403,7 @@ LL | let _ = 42; return;
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:294:9
+ --> $DIR/needless_return.rs:304:9
|
LL | return Ok(format!("ok!"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -395,12 +411,28 @@ LL | return Ok(format!("ok!"));
= help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:296:9
+ --> $DIR/needless_return.rs:306:9
|
LL | return Err(format!("err!"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: remove `return`
-error: aborting due to 48 previous errors
+error: unneeded `return` statement
+ --> $DIR/needless_return.rs:312:9
+ |
+LL | return if true { 1 } else { 2 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: remove `return`
+
+error: unneeded `return` statement
+ --> $DIR/needless_return.rs:316:9
+ |
+LL | return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: remove `return` and wrap the sequence with parentheses
+
+error: aborting due to 52 previous errors
diff --git a/src/tools/clippy/tests/ui/never_loop.rs b/src/tools/clippy/tests/ui/never_loop.rs
index 28e8f459d..29821ff96 100644
--- a/src/tools/clippy/tests/ui/never_loop.rs
+++ b/src/tools/clippy/tests/ui/never_loop.rs
@@ -250,6 +250,51 @@ pub fn test20() {
}
}
+pub fn test21() {
+ loop {
+ 'a: {
+ {}
+ break 'a;
+ }
+ }
+}
+
+// Issue 10304: code after break from block was not considered
+// unreachable code and was considered for further analysis of
+// whether the loop would ever be executed or not.
+pub fn test22() {
+ for _ in 0..10 {
+ 'block: {
+ break 'block;
+ return;
+ }
+ println!("looped");
+ }
+}
+
+pub fn test23() {
+ for _ in 0..10 {
+ 'block: {
+ for _ in 0..20 {
+ break 'block;
+ }
+ }
+ println!("looped");
+ }
+}
+
+pub fn test24() {
+ 'a: for _ in 0..10 {
+ 'b: {
+ let x = Some(1);
+ match x {
+ None => break 'a,
+ Some(_) => break 'b,
+ }
+ }
+ }
+}
+
fn main() {
test1();
test2();
diff --git a/src/tools/clippy/tests/ui/never_loop.stderr b/src/tools/clippy/tests/ui/never_loop.stderr
index b7029bf8b..704d44864 100644
--- a/src/tools/clippy/tests/ui/never_loop.stderr
+++ b/src/tools/clippy/tests/ui/never_loop.stderr
@@ -126,5 +126,18 @@ LL | | }
LL | | }
| |_____^
-error: aborting due to 11 previous errors
+error: this loop never actually loops
+ --> $DIR/never_loop.rs:278:13
+ |
+LL | / for _ in 0..20 {
+LL | | break 'block;
+LL | | }
+ | |_____________^
+ |
+help: if you need the first element of the iterator, try writing
+ |
+LL | if let Some(_) = (0..20).next() {
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/new_without_default.rs b/src/tools/clippy/tests/ui/new_without_default.rs
index 65809023f..7803418cb 100644
--- a/src/tools/clippy/tests/ui/new_without_default.rs
+++ b/src/tools/clippy/tests/ui/new_without_default.rs
@@ -1,4 +1,9 @@
-#![allow(dead_code, clippy::missing_safety_doc, clippy::extra_unused_lifetimes)]
+#![allow(
+ dead_code,
+ clippy::missing_safety_doc,
+ clippy::extra_unused_lifetimes,
+ clippy::extra_unused_type_parameters
+)]
#![warn(clippy::new_without_default)]
pub struct Foo;
diff --git a/src/tools/clippy/tests/ui/new_without_default.stderr b/src/tools/clippy/tests/ui/new_without_default.stderr
index 212a69ab9..583dd327d 100644
--- a/src/tools/clippy/tests/ui/new_without_default.stderr
+++ b/src/tools/clippy/tests/ui/new_without_default.stderr
@@ -1,5 +1,5 @@
error: you should consider adding a `Default` implementation for `Foo`
- --> $DIR/new_without_default.rs:7:5
+ --> $DIR/new_without_default.rs:12:5
|
LL | / pub fn new() -> Foo {
LL | | Foo
@@ -17,7 +17,7 @@ LL + }
|
error: you should consider adding a `Default` implementation for `Bar`
- --> $DIR/new_without_default.rs:15:5
+ --> $DIR/new_without_default.rs:20:5
|
LL | / pub fn new() -> Self {
LL | | Bar
@@ -34,7 +34,7 @@ LL + }
|
error: you should consider adding a `Default` implementation for `LtKo<'c>`
- --> $DIR/new_without_default.rs:79:5
+ --> $DIR/new_without_default.rs:84:5
|
LL | / pub fn new() -> LtKo<'c> {
LL | | unimplemented!()
@@ -51,7 +51,7 @@ LL + }
|
error: you should consider adding a `Default` implementation for `NewNotEqualToDerive`
- --> $DIR/new_without_default.rs:172:5
+ --> $DIR/new_without_default.rs:177:5
|
LL | / pub fn new() -> Self {
LL | | NewNotEqualToDerive { foo: 1 }
@@ -68,7 +68,7 @@ LL + }
|
error: you should consider adding a `Default` implementation for `FooGenerics<T>`
- --> $DIR/new_without_default.rs:180:5
+ --> $DIR/new_without_default.rs:185:5
|
LL | / pub fn new() -> Self {
LL | | Self(Default::default())
@@ -85,7 +85,7 @@ LL + }
|
error: you should consider adding a `Default` implementation for `BarGenerics<T>`
- --> $DIR/new_without_default.rs:187:5
+ --> $DIR/new_without_default.rs:192:5
|
LL | / pub fn new() -> Self {
LL | | Self(Default::default())
@@ -102,7 +102,7 @@ LL + }
|
error: you should consider adding a `Default` implementation for `Foo<T>`
- --> $DIR/new_without_default.rs:198:9
+ --> $DIR/new_without_default.rs:203:9
|
LL | / pub fn new() -> Self {
LL | | todo!()
diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.fixed b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.fixed
new file mode 100644
index 000000000..d18dec22a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.fixed
@@ -0,0 +1,48 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::no_mangle_with_rust_abi)]
+
+#[no_mangle]
+extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
+
+#[no_mangle]
+pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
+
+/// # Safety
+/// This function shouldn't be called unless the horsemen are ready
+#[no_mangle]
+pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
+
+/// # Safety
+/// This function shouldn't be called unless the horsemen are ready
+#[no_mangle]
+unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
+
+#[no_mangle]
+extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
+ arg_one: u32,
+ arg_two: usize,
+) -> u32 {
+ 0
+}
+
+// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"`
+#[no_mangle]
+#[rustfmt::skip]
+extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {}
+
+fn rust_abi_fn_again(arg_one: u32, arg_two: usize) {}
+
+#[no_mangle]
+extern "C" fn c_abi_fn(arg_one: u32, arg_two: usize) {}
+
+extern "C" fn c_abi_fn_again(arg_one: u32, arg_two: usize) {}
+
+extern "C" {
+ fn c_abi_in_block(arg_one: u32, arg_two: usize);
+}
+
+fn main() {
+ // test code goes here
+}
diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs
new file mode 100644
index 000000000..481e1b6d9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs
@@ -0,0 +1,48 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::no_mangle_with_rust_abi)]
+
+#[no_mangle]
+fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
+
+#[no_mangle]
+pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
+
+/// # Safety
+/// This function shouldn't be called unless the horsemen are ready
+#[no_mangle]
+pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
+
+/// # Safety
+/// This function shouldn't be called unless the horsemen are ready
+#[no_mangle]
+unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
+
+#[no_mangle]
+fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
+ arg_one: u32,
+ arg_two: usize,
+) -> u32 {
+ 0
+}
+
+// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"`
+#[no_mangle]
+#[rustfmt::skip]
+extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {}
+
+fn rust_abi_fn_again(arg_one: u32, arg_two: usize) {}
+
+#[no_mangle]
+extern "C" fn c_abi_fn(arg_one: u32, arg_two: usize) {}
+
+extern "C" fn c_abi_fn_again(arg_one: u32, arg_two: usize) {}
+
+extern "C" {
+ fn c_abi_in_block(arg_one: u32, arg_two: usize);
+}
+
+fn main() {
+ // test code goes here
+}
diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr
new file mode 100644
index 000000000..71517d318
--- /dev/null
+++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr
@@ -0,0 +1,45 @@
+error: attribute #[no_mangle] set on a Rust ABI function
+ --> $DIR/no_mangle_with_rust_abi.rs:7:1
+ |
+LL | fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `extern "C" fn rust_abi_fn_one(arg_one: u32, arg_two: usize)`
+ |
+ = note: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings`
+
+error: attribute #[no_mangle] set on a Rust ABI function
+ --> $DIR/no_mangle_with_rust_abi.rs:10:1
+ |
+LL | pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `pub extern "C" fn rust_abi_fn_two(arg_one: u32, arg_two: usize)`
+
+error: attribute #[no_mangle] set on a Rust ABI function
+ --> $DIR/no_mangle_with_rust_abi.rs:15:1
+ |
+LL | pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `pub unsafe extern "C" fn rust_abi_fn_three(arg_one: u32, arg_two: usize)`
+
+error: attribute #[no_mangle] set on a Rust ABI function
+ --> $DIR/no_mangle_with_rust_abi.rs:20:1
+ |
+LL | unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe extern "C" fn rust_abi_fn_four(arg_one: u32, arg_two: usize)`
+
+error: attribute #[no_mangle] set on a Rust ABI function
+ --> $DIR/no_mangle_with_rust_abi.rs:23:1
+ |
+LL | / fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
+LL | | arg_one: u32,
+LL | | arg_two: usize,
+LL | | ) -> u32 {
+ | |________^
+ |
+help: try
+ |
+LL + extern "C" fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines(
+LL + arg_one: u32,
+LL + arg_two: usize,
+LL ~ ) -> u32 {
+ |
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/question_mark_used.rs b/src/tools/clippy/tests/ui/question_mark_used.rs
new file mode 100644
index 000000000..8c3ef7896
--- /dev/null
+++ b/src/tools/clippy/tests/ui/question_mark_used.rs
@@ -0,0 +1,15 @@
+// non rustfixable
+#![allow(unreachable_code)]
+#![allow(dead_code)]
+#![warn(clippy::question_mark_used)]
+
+fn other_function() -> Option<i32> {
+ Some(32)
+}
+
+fn my_function() -> Option<i32> {
+ other_function()?;
+ None
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/question_mark_used.stderr b/src/tools/clippy/tests/ui/question_mark_used.stderr
new file mode 100644
index 000000000..8b5fcbcdb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/question_mark_used.stderr
@@ -0,0 +1,11 @@
+error: question mark operator was used
+ --> $DIR/question_mark_used.rs:11:5
+ |
+LL | other_function()?;
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using a custom macro or match expression
+ = note: `-D clippy::question-mark-used` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/redundant_field_names.fixed b/src/tools/clippy/tests/ui/redundant_field_names.fixed
index ec7f8ae92..276266a2d 100644
--- a/src/tools/clippy/tests/ui/redundant_field_names.fixed
+++ b/src/tools/clippy/tests/ui/redundant_field_names.fixed
@@ -1,7 +1,7 @@
// run-rustfix
#![warn(clippy::redundant_field_names)]
-#![allow(clippy::no_effect, dead_code, unused_variables)]
+#![allow(clippy::extra_unused_type_parameters, clippy::no_effect, dead_code, unused_variables)]
#[macro_use]
extern crate derive_new;
diff --git a/src/tools/clippy/tests/ui/redundant_field_names.rs b/src/tools/clippy/tests/ui/redundant_field_names.rs
index 73122016c..f674141c1 100644
--- a/src/tools/clippy/tests/ui/redundant_field_names.rs
+++ b/src/tools/clippy/tests/ui/redundant_field_names.rs
@@ -1,7 +1,7 @@
// run-rustfix
#![warn(clippy::redundant_field_names)]
-#![allow(clippy::no_effect, dead_code, unused_variables)]
+#![allow(clippy::extra_unused_type_parameters, clippy::no_effect, dead_code, unused_variables)]
#[macro_use]
extern crate derive_new;
diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs
index f0e1a8128..ab8ac97a0 100644
--- a/src/tools/clippy/tests/ui/regex.rs
+++ b/src/tools/clippy/tests/ui/regex.rs
@@ -36,6 +36,10 @@ fn syntax_error() {
let raw_string_error = Regex::new(r"[...\/...]");
let raw_string_error = Regex::new(r#"[...\/...]"#);
+
+ let escaped_string_span = Regex::new("\\b\\c");
+
+ let aux_span = Regex::new("(?ixi)");
}
fn trivial_regex() {
diff --git a/src/tools/clippy/tests/ui/regex.stderr b/src/tools/clippy/tests/ui/regex.stderr
index 2424644c6..c2440f39e 100644
--- a/src/tools/clippy/tests/ui/regex.stderr
+++ b/src/tools/clippy/tests/ui/regex.stderr
@@ -29,7 +29,10 @@ error: regex syntax error: invalid character class range, the start must be <= t
LL | let some_unicode = Regex::new("[é-è]");
| ^^^
-error: regex syntax error on position 0: unclosed group
+error: regex parse error:
+ (
+ ^
+ error: unclosed group
--> $DIR/regex.rs:18:33
|
LL | let some_regex = Regex::new(OPENING_PAREN);
@@ -43,25 +46,37 @@ LL | let binary_pipe_in_wrong_position = BRegex::new("|");
|
= help: the regex is unlikely to be useful as it is
-error: regex syntax error on position 0: unclosed group
+error: regex parse error:
+ (
+ ^
+ error: unclosed group
--> $DIR/regex.rs:21:41
|
LL | let some_binary_regex = BRegex::new(OPENING_PAREN);
| ^^^^^^^^^^^^^
-error: regex syntax error on position 0: unclosed group
+error: regex parse error:
+ (
+ ^
+ error: unclosed group
--> $DIR/regex.rs:22:56
|
LL | let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN);
| ^^^^^^^^^^^^^
-error: regex syntax error on position 0: unclosed group
+error: regex parse error:
+ (
+ ^
+ error: unclosed group
--> $DIR/regex.rs:34:37
|
LL | let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]);
| ^^^^^^^^^^^^^
-error: regex syntax error on position 0: unclosed group
+error: regex parse error:
+ (
+ ^
+ error: unclosed group
--> $DIR/regex.rs:35:39
|
LL | let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]);
@@ -79,8 +94,25 @@ error: regex syntax error: unrecognized escape sequence
LL | let raw_string_error = Regex::new(r#"[...//...]"#);
| ^^
+error: regex parse error:
+ /b/c
+ ^^
+ error: unrecognized escape sequence
+ --> $DIR/regex.rs:40:42
+ |
+LL | let escaped_string_span = Regex::new("/b/c");
+ | ^^^^^^^^
+ |
+ = help: consider using a raw string literal: `r".."`
+
+error: regex syntax error: duplicate flag
+ --> $DIR/regex.rs:42:34
+ |
+LL | let aux_span = Regex::new("(?ixi)");
+ | ^ ^
+
error: trivial regex
- --> $DIR/regex.rs:42:33
+ --> $DIR/regex.rs:46:33
|
LL | let trivial_eq = Regex::new("^foobar$");
| ^^^^^^^^^^
@@ -88,7 +120,7 @@ LL | let trivial_eq = Regex::new("^foobar$");
= help: consider using `==` on `str`s
error: trivial regex
- --> $DIR/regex.rs:44:48
+ --> $DIR/regex.rs:48:48
|
LL | let trivial_eq_builder = RegexBuilder::new("^foobar$");
| ^^^^^^^^^^
@@ -96,7 +128,7 @@ LL | let trivial_eq_builder = RegexBuilder::new("^foobar$");
= help: consider using `==` on `str`s
error: trivial regex
- --> $DIR/regex.rs:46:42
+ --> $DIR/regex.rs:50:42
|
LL | let trivial_starts_with = Regex::new("^foobar");
| ^^^^^^^^^
@@ -104,7 +136,7 @@ LL | let trivial_starts_with = Regex::new("^foobar");
= help: consider using `str::starts_with`
error: trivial regex
- --> $DIR/regex.rs:48:40
+ --> $DIR/regex.rs:52:40
|
LL | let trivial_ends_with = Regex::new("foobar$");
| ^^^^^^^^^
@@ -112,7 +144,7 @@ LL | let trivial_ends_with = Regex::new("foobar$");
= help: consider using `str::ends_with`
error: trivial regex
- --> $DIR/regex.rs:50:39
+ --> $DIR/regex.rs:54:39
|
LL | let trivial_contains = Regex::new("foobar");
| ^^^^^^^^
@@ -120,7 +152,7 @@ LL | let trivial_contains = Regex::new("foobar");
= help: consider using `str::contains`
error: trivial regex
- --> $DIR/regex.rs:52:39
+ --> $DIR/regex.rs:56:39
|
LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX);
| ^^^^^^^^^^^^^^^^
@@ -128,7 +160,7 @@ LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX);
= help: consider using `str::contains`
error: trivial regex
- --> $DIR/regex.rs:54:40
+ --> $DIR/regex.rs:58:40
|
LL | let trivial_backslash = Regex::new("a/.b");
| ^^^^^^^
@@ -136,7 +168,7 @@ LL | let trivial_backslash = Regex::new("a/.b");
= help: consider using `str::contains`
error: trivial regex
- --> $DIR/regex.rs:57:36
+ --> $DIR/regex.rs:61:36
|
LL | let trivial_empty = Regex::new("");
| ^^
@@ -144,7 +176,7 @@ LL | let trivial_empty = Regex::new("");
= help: the regex is unlikely to be useful as it is
error: trivial regex
- --> $DIR/regex.rs:59:36
+ --> $DIR/regex.rs:63:36
|
LL | let trivial_empty = Regex::new("^");
| ^^^
@@ -152,7 +184,7 @@ LL | let trivial_empty = Regex::new("^");
= help: the regex is unlikely to be useful as it is
error: trivial regex
- --> $DIR/regex.rs:61:36
+ --> $DIR/regex.rs:65:36
|
LL | let trivial_empty = Regex::new("^$");
| ^^^^
@@ -160,12 +192,12 @@ LL | let trivial_empty = Regex::new("^$");
= help: consider using `str::is_empty`
error: trivial regex
- --> $DIR/regex.rs:63:44
+ --> $DIR/regex.rs:67:44
|
LL | let binary_trivial_empty = BRegex::new("^$");
| ^^^^
|
= help: consider using `str::is_empty`
-error: aborting due to 23 previous errors
+error: aborting due to 25 previous errors
diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed
index 713cff604..dc24d447c 100644
--- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed
+++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed
@@ -26,7 +26,7 @@ fn seek_to_start_false_method(t: &mut StructWithSeekMethod) {
// This should NOT trigger clippy warning because
// StructWithSeekMethod does not implement std::io::Seek;
-fn seek_to_start_method_owned_false<T>(mut t: StructWithSeekMethod) {
+fn seek_to_start_method_owned_false(mut t: StructWithSeekMethod) {
t.seek(SeekFrom::Start(0));
}
@@ -38,7 +38,7 @@ fn seek_to_start_false_trait(t: &mut StructWithSeekTrait) {
// This should NOT trigger clippy warning because
// StructWithSeekMethod does not implement std::io::Seek;
-fn seek_to_start_false_trait_owned<T>(mut t: StructWithSeekTrait) {
+fn seek_to_start_false_trait_owned(mut t: StructWithSeekTrait) {
t.seek(SeekFrom::Start(0));
}
diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs
index 467003a1a..4adde2c40 100644
--- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs
+++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs
@@ -26,7 +26,7 @@ fn seek_to_start_false_method(t: &mut StructWithSeekMethod) {
// This should NOT trigger clippy warning because
// StructWithSeekMethod does not implement std::io::Seek;
-fn seek_to_start_method_owned_false<T>(mut t: StructWithSeekMethod) {
+fn seek_to_start_method_owned_false(mut t: StructWithSeekMethod) {
t.seek(SeekFrom::Start(0));
}
@@ -38,7 +38,7 @@ fn seek_to_start_false_trait(t: &mut StructWithSeekTrait) {
// This should NOT trigger clippy warning because
// StructWithSeekMethod does not implement std::io::Seek;
-fn seek_to_start_false_trait_owned<T>(mut t: StructWithSeekTrait) {
+fn seek_to_start_false_trait_owned(mut t: StructWithSeekTrait) {
t.seek(SeekFrom::Start(0));
}
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.fixed b/src/tools/clippy/tests/ui/significant_drop_tightening.fixed
new file mode 100644
index 000000000..da998c610
--- /dev/null
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.fixed
@@ -0,0 +1,84 @@
+// run-rustfix
+
+#![warn(clippy::significant_drop_tightening)]
+
+use std::sync::Mutex;
+
+pub fn complex_return_triggers_the_lint() -> i32 {
+ fn foo() -> i32 {
+ 1
+ }
+ let mutex = Mutex::new(1);
+ let lock = mutex.lock().unwrap();
+ let _ = *lock;
+ let _ = *lock;
+ drop(lock);
+ foo()
+}
+
+pub fn path_return_can_be_ignored() -> i32 {
+ let mutex = Mutex::new(1);
+ let lock = mutex.lock().unwrap();
+ let rslt = *lock;
+ let _ = *lock;
+ rslt
+}
+
+pub fn post_bindings_can_be_ignored() {
+ let mutex = Mutex::new(1);
+ let lock = mutex.lock().unwrap();
+ let rslt = *lock;
+ let another = rslt;
+ let _ = another;
+}
+
+pub fn unnecessary_contention_with_multiple_owned_results() {
+ {
+ let mutex = Mutex::new(1i32);
+ let lock = mutex.lock().unwrap();
+ let _ = lock.abs();
+ let _ = lock.is_positive();
+ }
+
+ {
+ let mutex = Mutex::new(1i32);
+ let lock = mutex.lock().unwrap();
+ let rslt0 = lock.abs();
+ let rslt1 = lock.is_positive();
+ drop(lock);
+ do_heavy_computation_that_takes_time((rslt0, rslt1));
+ }
+}
+
+pub fn unnecessary_contention_with_single_owned_results() {
+ {
+ let mutex = Mutex::new(1i32);
+ let lock = mutex.lock().unwrap();
+ let _ = lock.abs();
+ }
+ {
+ let mutex = Mutex::new(vec![1i32]);
+ let mut lock = mutex.lock().unwrap();
+ lock.clear();
+ }
+
+ {
+ let mutex = Mutex::new(1i32);
+
+ let rslt0 = mutex.lock().unwrap().abs();
+
+ do_heavy_computation_that_takes_time(rslt0);
+ }
+ {
+ let mutex = Mutex::new(vec![1i32]);
+
+ mutex.lock().unwrap().clear();
+
+ do_heavy_computation_that_takes_time(());
+ }
+}
+
+// Marker used for illustration purposes.
+pub fn do_heavy_computation_that_takes_time<T>(_: T) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.rs b/src/tools/clippy/tests/ui/significant_drop_tightening.rs
new file mode 100644
index 000000000..83823f95f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.rs
@@ -0,0 +1,80 @@
+// run-rustfix
+
+#![warn(clippy::significant_drop_tightening)]
+
+use std::sync::Mutex;
+
+pub fn complex_return_triggers_the_lint() -> i32 {
+ fn foo() -> i32 {
+ 1
+ }
+ let mutex = Mutex::new(1);
+ let lock = mutex.lock().unwrap();
+ let _ = *lock;
+ let _ = *lock;
+ foo()
+}
+
+pub fn path_return_can_be_ignored() -> i32 {
+ let mutex = Mutex::new(1);
+ let lock = mutex.lock().unwrap();
+ let rslt = *lock;
+ let _ = *lock;
+ rslt
+}
+
+pub fn post_bindings_can_be_ignored() {
+ let mutex = Mutex::new(1);
+ let lock = mutex.lock().unwrap();
+ let rslt = *lock;
+ let another = rslt;
+ let _ = another;
+}
+
+pub fn unnecessary_contention_with_multiple_owned_results() {
+ {
+ let mutex = Mutex::new(1i32);
+ let lock = mutex.lock().unwrap();
+ let _ = lock.abs();
+ let _ = lock.is_positive();
+ }
+
+ {
+ let mutex = Mutex::new(1i32);
+ let lock = mutex.lock().unwrap();
+ let rslt0 = lock.abs();
+ let rslt1 = lock.is_positive();
+ do_heavy_computation_that_takes_time((rslt0, rslt1));
+ }
+}
+
+pub fn unnecessary_contention_with_single_owned_results() {
+ {
+ let mutex = Mutex::new(1i32);
+ let lock = mutex.lock().unwrap();
+ let _ = lock.abs();
+ }
+ {
+ let mutex = Mutex::new(vec![1i32]);
+ let mut lock = mutex.lock().unwrap();
+ lock.clear();
+ }
+
+ {
+ let mutex = Mutex::new(1i32);
+ let lock = mutex.lock().unwrap();
+ let rslt0 = lock.abs();
+ do_heavy_computation_that_takes_time(rslt0);
+ }
+ {
+ let mutex = Mutex::new(vec![1i32]);
+ let mut lock = mutex.lock().unwrap();
+ lock.clear();
+ do_heavy_computation_that_takes_time(());
+ }
+}
+
+// Marker used for illustration purposes.
+pub fn do_heavy_computation_that_takes_time<T>(_: T) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
new file mode 100644
index 000000000..ab8ce356e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
@@ -0,0 +1,94 @@
+error: temporary with significant `Drop` can be early dropped
+ --> $DIR/significant_drop_tightening.rs:12:9
+ |
+LL | pub fn complex_return_triggers_the_lint() -> i32 {
+ | __________________________________________________-
+LL | | fn foo() -> i32 {
+LL | | 1
+LL | | }
+LL | | let mutex = Mutex::new(1);
+LL | | let lock = mutex.lock().unwrap();
+ | | ^^^^
+... |
+LL | | foo()
+LL | | }
+ | |_- temporary `lock` is currently being dropped at the end of its contained scope
+ |
+ = note: this might lead to unnecessary resource contention
+ = note: `-D clippy::significant-drop-tightening` implied by `-D warnings`
+help: drop the temporary after the end of its last usage
+ |
+LL ~ let _ = *lock;
+LL + drop(lock);
+ |
+
+error: temporary with significant `Drop` can be early dropped
+ --> $DIR/significant_drop_tightening.rs:44:13
+ |
+LL | / {
+LL | | let mutex = Mutex::new(1i32);
+LL | | let lock = mutex.lock().unwrap();
+ | | ^^^^
+LL | | let rslt0 = lock.abs();
+LL | | let rslt1 = lock.is_positive();
+LL | | do_heavy_computation_that_takes_time((rslt0, rslt1));
+LL | | }
+ | |_____- temporary `lock` is currently being dropped at the end of its contained scope
+ |
+ = note: this might lead to unnecessary resource contention
+help: drop the temporary after the end of its last usage
+ |
+LL ~ let rslt1 = lock.is_positive();
+LL + drop(lock);
+ |
+
+error: temporary with significant `Drop` can be early dropped
+ --> $DIR/significant_drop_tightening.rs:65:13
+ |
+LL | / {
+LL | | let mutex = Mutex::new(1i32);
+LL | | let lock = mutex.lock().unwrap();
+ | | ^^^^
+LL | | let rslt0 = lock.abs();
+LL | | do_heavy_computation_that_takes_time(rslt0);
+LL | | }
+ | |_____- temporary `lock` is currently being dropped at the end of its contained scope
+ |
+ = note: this might lead to unnecessary resource contention
+help: merge the temporary construction with its single usage
+ |
+LL ~
+LL + let rslt0 = mutex.lock().unwrap().abs();
+ |
+help: remove separated single usage
+ |
+LL - let rslt0 = lock.abs();
+LL +
+ |
+
+error: temporary with significant `Drop` can be early dropped
+ --> $DIR/significant_drop_tightening.rs:71:17
+ |
+LL | / {
+LL | | let mutex = Mutex::new(vec![1i32]);
+LL | | let mut lock = mutex.lock().unwrap();
+ | | ^^^^
+LL | | lock.clear();
+LL | | do_heavy_computation_that_takes_time(());
+LL | | }
+ | |_____- temporary `lock` is currently being dropped at the end of its contained scope
+ |
+ = note: this might lead to unnecessary resource contention
+help: merge the temporary construction with its single usage
+ |
+LL ~
+LL + mutex.lock().unwrap().clear();
+ |
+help: remove separated single usage
+ |
+LL - lock.clear();
+LL +
+ |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/suspicious_command_arg_space.rs b/src/tools/clippy/tests/ui/suspicious_command_arg_space.rs
new file mode 100644
index 000000000..bdc6113a2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_command_arg_space.rs
@@ -0,0 +1,10 @@
+fn main() {
+ // Things it should warn about:
+ std::process::Command::new("echo").arg("-n hello").spawn().unwrap();
+ std::process::Command::new("cat").arg("--number file").spawn().unwrap();
+
+ // Things it should not warn about:
+ std::process::Command::new("echo").arg("hello world").spawn().unwrap();
+ std::process::Command::new("a").arg("--fmt=%a %b %c").spawn().unwrap();
+ std::process::Command::new("b").arg("-ldflags=-s -w").spawn().unwrap();
+}
diff --git a/src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr b/src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr
new file mode 100644
index 000000000..9bc0ca93a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_command_arg_space.stderr
@@ -0,0 +1,25 @@
+error: single argument that looks like it should be multiple arguments
+ --> $DIR/suspicious_command_arg_space.rs:3:44
+ |
+LL | std::process::Command::new("echo").arg("-n hello").spawn().unwrap();
+ | ^^^^^^^^^^
+ |
+ = note: `-D clippy::suspicious-command-arg-space` implied by `-D warnings`
+help: consider splitting the argument
+ |
+LL | std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap();
+ | ~~~~ ~~~~~~~~~~~~~~~
+
+error: single argument that looks like it should be multiple arguments
+ --> $DIR/suspicious_command_arg_space.rs:4:43
+ |
+LL | std::process::Command::new("cat").arg("--number file").spawn().unwrap();
+ | ^^^^^^^^^^^^^^^
+ |
+help: consider splitting the argument
+ |
+LL | std::process::Command::new("cat").args(["--number", "file"]).spawn().unwrap();
+ | ~~~~ ~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/suspicious_to_owned.stderr b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr
index dec3f50d6..c4ec7aa88 100644
--- a/src/tools/clippy/tests/ui/suspicious_to_owned.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr
@@ -2,27 +2,62 @@ error: this `to_owned` call clones the Cow<'_, str> itself and does not cause th
--> $DIR/suspicious_to_owned.rs:16:13
|
LL | let _ = cow.to_owned();
- | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+ | ^^^^^^^^^^^^^^
|
= note: `-D clippy::suspicious-to-owned` implied by `-D warnings`
+help: depending on intent, either make the Cow an Owned variant
+ |
+LL | let _ = cow.into_owned();
+ | ~~~~~~~~~~~~~~~~
+help: or clone the Cow itself
+ |
+LL | let _ = cow.clone();
+ | ~~~~~~~~~~~
error: this `to_owned` call clones the Cow<'_, [char; 3]> itself and does not cause the Cow<'_, [char; 3]> contents to become owned
--> $DIR/suspicious_to_owned.rs:26:13
|
LL | let _ = cow.to_owned();
- | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+ | ^^^^^^^^^^^^^^
+ |
+help: depending on intent, either make the Cow an Owned variant
+ |
+LL | let _ = cow.into_owned();
+ | ~~~~~~~~~~~~~~~~
+help: or clone the Cow itself
+ |
+LL | let _ = cow.clone();
+ | ~~~~~~~~~~~
error: this `to_owned` call clones the Cow<'_, Vec<char>> itself and does not cause the Cow<'_, Vec<char>> contents to become owned
--> $DIR/suspicious_to_owned.rs:36:13
|
LL | let _ = cow.to_owned();
- | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+ | ^^^^^^^^^^^^^^
+ |
+help: depending on intent, either make the Cow an Owned variant
+ |
+LL | let _ = cow.into_owned();
+ | ~~~~~~~~~~~~~~~~
+help: or clone the Cow itself
+ |
+LL | let _ = cow.clone();
+ | ~~~~~~~~~~~
error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned
--> $DIR/suspicious_to_owned.rs:46:13
|
LL | let _ = cow.to_owned();
- | ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+ | ^^^^^^^^^^^^^^
+ |
+help: depending on intent, either make the Cow an Owned variant
+ |
+LL | let _ = cow.into_owned();
+ | ~~~~~~~~~~~~~~~~
+help: or clone the Cow itself
+ |
+LL | let _ = cow.clone();
+ | ~~~~~~~~~~~
error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type
--> $DIR/suspicious_to_owned.rs:60:13
diff --git a/src/tools/clippy/tests/ui/swap.fixed b/src/tools/clippy/tests/ui/swap.fixed
index 805a2ba5a..fa89706a8 100644
--- a/src/tools/clippy/tests/ui/swap.fixed
+++ b/src/tools/clippy/tests/ui/swap.fixed
@@ -7,7 +7,8 @@
clippy::redundant_clone,
redundant_semicolons,
dead_code,
- unused_assignments
+ unused_assignments,
+ unused_variables
)]
struct Foo(u32);
@@ -121,6 +122,27 @@ fn main() {
std::mem::swap(&mut c.0, &mut a);
; std::mem::swap(&mut c.0, &mut a);
+
+ std::mem::swap(&mut a, &mut b);
+
+ let mut c = 1;
+ let mut d = 2;
+ std::mem::swap(&mut d, &mut c);
+
+ let mut b = 1;
+ std::mem::swap(&mut a, &mut b);
+
+ let b = 1;
+ let a = 2;
+
+ let t = b;
+ let b = a;
+ let a = t;
+
+ let mut b = 1;
+ let mut a = 2;
+
+ std::mem::swap(&mut b, &mut a);
}
fn issue_8154() {
diff --git a/src/tools/clippy/tests/ui/swap.rs b/src/tools/clippy/tests/ui/swap.rs
index a8c878479..ef8a81c83 100644
--- a/src/tools/clippy/tests/ui/swap.rs
+++ b/src/tools/clippy/tests/ui/swap.rs
@@ -7,7 +7,8 @@
clippy::redundant_clone,
redundant_semicolons,
dead_code,
- unused_assignments
+ unused_assignments,
+ unused_variables
)]
struct Foo(u32);
@@ -143,6 +144,32 @@ fn main() {
; let t = c.0;
c.0 = a;
a = t;
+
+ let a = b;
+ let b = a;
+
+ let mut c = 1;
+ let mut d = 2;
+ d = c;
+ c = d;
+
+ let mut b = 1;
+ let a = b;
+ b = a;
+
+ let b = 1;
+ let a = 2;
+
+ let t = b;
+ let b = a;
+ let a = t;
+
+ let mut b = 1;
+ let mut a = 2;
+
+ let t = b;
+ b = a;
+ a = t;
}
fn issue_8154() {
diff --git a/src/tools/clippy/tests/ui/swap.stderr b/src/tools/clippy/tests/ui/swap.stderr
index ee4b7a508..f0acbfe25 100644
--- a/src/tools/clippy/tests/ui/swap.stderr
+++ b/src/tools/clippy/tests/ui/swap.stderr
@@ -1,5 +1,5 @@
error: this looks like you are swapping `bar.a` and `bar.b` manually
- --> $DIR/swap.rs:24:5
+ --> $DIR/swap.rs:25:5
|
LL | / let temp = bar.a;
LL | | bar.a = bar.b;
@@ -10,7 +10,7 @@ LL | | bar.b = temp;
= note: `-D clippy::manual-swap` implied by `-D warnings`
error: this looks like you are swapping elements of `foo` manually
- --> $DIR/swap.rs:36:5
+ --> $DIR/swap.rs:37:5
|
LL | / let temp = foo[0];
LL | | foo[0] = foo[1];
@@ -18,7 +18,7 @@ LL | | foo[1] = temp;
| |_________________^ help: try: `foo.swap(0, 1)`
error: this looks like you are swapping elements of `foo` manually
- --> $DIR/swap.rs:45:5
+ --> $DIR/swap.rs:46:5
|
LL | / let temp = foo[0];
LL | | foo[0] = foo[1];
@@ -26,7 +26,7 @@ LL | | foo[1] = temp;
| |_________________^ help: try: `foo.swap(0, 1)`
error: this looks like you are swapping elements of `foo` manually
- --> $DIR/swap.rs:64:5
+ --> $DIR/swap.rs:65:5
|
LL | / let temp = foo[0];
LL | | foo[0] = foo[1];
@@ -34,7 +34,7 @@ LL | | foo[1] = temp;
| |_________________^ help: try: `foo.swap(0, 1)`
error: this looks like you are swapping `a` and `b` manually
- --> $DIR/swap.rs:75:5
+ --> $DIR/swap.rs:76:5
|
LL | / a ^= b;
LL | | b ^= a;
@@ -42,7 +42,7 @@ LL | | a ^= b;
| |___________^ help: try: `std::mem::swap(&mut a, &mut b)`
error: this looks like you are swapping `bar.a` and `bar.b` manually
- --> $DIR/swap.rs:83:5
+ --> $DIR/swap.rs:84:5
|
LL | / bar.a ^= bar.b;
LL | | bar.b ^= bar.a;
@@ -50,7 +50,7 @@ LL | | bar.a ^= bar.b;
| |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b)`
error: this looks like you are swapping elements of `foo` manually
- --> $DIR/swap.rs:91:5
+ --> $DIR/swap.rs:92:5
|
LL | / foo[0] ^= foo[1];
LL | | foo[1] ^= foo[0];
@@ -58,7 +58,7 @@ LL | | foo[0] ^= foo[1];
| |_____________________^ help: try: `foo.swap(0, 1)`
error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually
- --> $DIR/swap.rs:120:5
+ --> $DIR/swap.rs:121:5
|
LL | / let temp = foo[0][1];
LL | | foo[0][1] = bar[1][0];
@@ -68,7 +68,7 @@ LL | | bar[1][0] = temp;
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are swapping `a` and `b` manually
- --> $DIR/swap.rs:134:7
+ --> $DIR/swap.rs:135:7
|
LL | ; let t = a;
| _______^
@@ -79,7 +79,7 @@ LL | | b = t;
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are swapping `c.0` and `a` manually
- --> $DIR/swap.rs:143:7
+ --> $DIR/swap.rs:144:7
|
LL | ; let t = c.0;
| _______^
@@ -89,8 +89,18 @@ LL | | a = t;
|
= note: or maybe you should use `std::mem::replace`?
+error: this looks like you are swapping `b` and `a` manually
+ --> $DIR/swap.rs:170:5
+ |
+LL | / let t = b;
+LL | | b = a;
+LL | | a = t;
+ | |_________^ help: try: `std::mem::swap(&mut b, &mut a)`
+ |
+ = note: or maybe you should use `std::mem::replace`?
+
error: this looks like you are trying to swap `a` and `b`
- --> $DIR/swap.rs:131:5
+ --> $DIR/swap.rs:132:5
|
LL | / a = b;
LL | | b = a;
@@ -100,7 +110,7 @@ LL | | b = a;
= note: `-D clippy::almost-swapped` implied by `-D warnings`
error: this looks like you are trying to swap `c.0` and `a`
- --> $DIR/swap.rs:140:5
+ --> $DIR/swap.rs:141:5
|
LL | / c.0 = a;
LL | | a = c.0;
@@ -108,8 +118,35 @@ LL | | a = c.0;
|
= note: or maybe you should use `std::mem::replace`?
+error: this looks like you are trying to swap `a` and `b`
+ --> $DIR/swap.rs:148:5
+ |
+LL | / let a = b;
+LL | | let b = a;
+ | |_____________^ help: try: `std::mem::swap(&mut a, &mut b)`
+ |
+ = note: or maybe you should use `std::mem::replace`?
+
+error: this looks like you are trying to swap `d` and `c`
+ --> $DIR/swap.rs:153:5
+ |
+LL | / d = c;
+LL | | c = d;
+ | |_________^ help: try: `std::mem::swap(&mut d, &mut c)`
+ |
+ = note: or maybe you should use `std::mem::replace`?
+
+error: this looks like you are trying to swap `a` and `b`
+ --> $DIR/swap.rs:157:5
+ |
+LL | / let a = b;
+LL | | b = a;
+ | |_________^ help: try: `std::mem::swap(&mut a, &mut b)`
+ |
+ = note: or maybe you should use `std::mem::replace`?
+
error: this looks like you are swapping `s.0.x` and `s.0.y` manually
- --> $DIR/swap.rs:178:5
+ --> $DIR/swap.rs:205:5
|
LL | / let t = s.0.x;
LL | | s.0.x = s.0.y;
@@ -118,5 +155,5 @@ LL | | s.0.y = t;
|
= note: or maybe you should use `std::mem::replace`?
-error: aborting due to 13 previous errors
+error: aborting due to 17 previous errors
diff --git a/src/tools/clippy/tests/ui/track-diagnostics.stderr b/src/tools/clippy/tests/ui/track-diagnostics.stderr
index ec3031862..39418d359 100644
--- a/src/tools/clippy/tests/ui/track-diagnostics.stderr
+++ b/src/tools/clippy/tests/ui/track-diagnostics.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/track-diagnostics.rs:LL:CC
|
LL | const S: A = B;
- | ^ expected struct `A`, found struct `B`
+ | ^ expected `A`, found `B`
-Ztrack-diagnostics: created at compiler/rustc_infer/src/infer/error_reporting/mod.rs:LL:CC
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs
new file mode 100644
index 000000000..a38406782
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs
@@ -0,0 +1,41 @@
+#![warn(clippy::transmute_int_to_non_zero)]
+
+use core::num::*;
+
+fn main() {
+ let int_u8: u8 = 1;
+ let int_u16: u16 = 1;
+ let int_u32: u32 = 1;
+ let int_u64: u64 = 1;
+ let int_u128: u128 = 1;
+
+ let int_i8: i8 = 1;
+ let int_i16: i16 = 1;
+ let int_i32: i32 = 1;
+ let int_i64: i64 = 1;
+ let int_i128: i128 = 1;
+
+ let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) };
+ let _: NonZeroU16 = unsafe { std::mem::transmute(int_u16) };
+ let _: NonZeroU32 = unsafe { std::mem::transmute(int_u32) };
+ let _: NonZeroU64 = unsafe { std::mem::transmute(int_u64) };
+ let _: NonZeroU128 = unsafe { std::mem::transmute(int_u128) };
+
+ let _: NonZeroI8 = unsafe { std::mem::transmute(int_i8) };
+ let _: NonZeroI16 = unsafe { std::mem::transmute(int_i16) };
+ let _: NonZeroI32 = unsafe { std::mem::transmute(int_i32) };
+ let _: NonZeroI64 = unsafe { std::mem::transmute(int_i64) };
+ let _: NonZeroI128 = unsafe { std::mem::transmute(int_i128) };
+
+ let _: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(int_u8) };
+ let _: NonZeroU16 = unsafe { NonZeroU16::new_unchecked(int_u16) };
+ let _: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(int_u32) };
+ let _: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(int_u64) };
+ let _: NonZeroU128 = unsafe { NonZeroU128::new_unchecked(int_u128) };
+
+ let _: NonZeroI8 = unsafe { NonZeroI8::new_unchecked(int_i8) };
+ let _: NonZeroI16 = unsafe { NonZeroI16::new_unchecked(int_i16) };
+ let _: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(int_i32) };
+ let _: NonZeroI64 = unsafe { NonZeroI64::new_unchecked(int_i64) };
+ let _: NonZeroI128 = unsafe { NonZeroI128::new_unchecked(int_i128) };
+}
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr
new file mode 100644
index 000000000..33f8ce79e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr
@@ -0,0 +1,64 @@
+error: transmute from a `u8` to a `NonZeroU8`
+ --> $DIR/transmute_int_to_non_zero.rs:18:33
+ |
+LL | let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU8::new_unchecked(int_u8)`
+ |
+ = note: `-D clippy::transmute-int-to-non-zero` implied by `-D warnings`
+
+error: transmute from a `u16` to a `NonZeroU16`
+ --> $DIR/transmute_int_to_non_zero.rs:19:34
+ |
+LL | let _: NonZeroU16 = unsafe { std::mem::transmute(int_u16) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU16::new_unchecked(int_u16)`
+
+error: transmute from a `u32` to a `NonZeroU32`
+ --> $DIR/transmute_int_to_non_zero.rs:20:34
+ |
+LL | let _: NonZeroU32 = unsafe { std::mem::transmute(int_u32) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU32::new_unchecked(int_u32)`
+
+error: transmute from a `u64` to a `NonZeroU64`
+ --> $DIR/transmute_int_to_non_zero.rs:21:34
+ |
+LL | let _: NonZeroU64 = unsafe { std::mem::transmute(int_u64) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU64::new_unchecked(int_u64)`
+
+error: transmute from a `u128` to a `NonZeroU128`
+ --> $DIR/transmute_int_to_non_zero.rs:22:35
+ |
+LL | let _: NonZeroU128 = unsafe { std::mem::transmute(int_u128) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU128::new_unchecked(int_u128)`
+
+error: transmute from a `i8` to a `NonZeroI8`
+ --> $DIR/transmute_int_to_non_zero.rs:24:33
+ |
+LL | let _: NonZeroI8 = unsafe { std::mem::transmute(int_i8) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI8::new_unchecked(int_i8)`
+
+error: transmute from a `i16` to a `NonZeroI16`
+ --> $DIR/transmute_int_to_non_zero.rs:25:34
+ |
+LL | let _: NonZeroI16 = unsafe { std::mem::transmute(int_i16) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI16::new_unchecked(int_i16)`
+
+error: transmute from a `i32` to a `NonZeroI32`
+ --> $DIR/transmute_int_to_non_zero.rs:26:34
+ |
+LL | let _: NonZeroI32 = unsafe { std::mem::transmute(int_i32) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI32::new_unchecked(int_i32)`
+
+error: transmute from a `i64` to a `NonZeroI64`
+ --> $DIR/transmute_int_to_non_zero.rs:27:34
+ |
+LL | let _: NonZeroI64 = unsafe { std::mem::transmute(int_i64) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI64::new_unchecked(int_i64)`
+
+error: transmute from a `i128` to a `NonZeroI128`
+ --> $DIR/transmute_int_to_non_zero.rs:28:35
+ |
+LL | let _: NonZeroI128 = unsafe { std::mem::transmute(int_i128) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI128::new_unchecked(int_i128)`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
index 7263abac1..55307506e 100644
--- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
+++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
@@ -51,6 +51,8 @@ fn main() {
// e is a function pointer type and U is an integer; fptr-addr-cast
let _usize_from_fn_ptr_transmute = unsafe { foo as usize };
let _usize_from_fn_ptr = foo as *const usize;
+
+ let _usize_from_ref = unsafe { &1u32 as *const u32 as usize };
}
// If a ref-to-ptr cast of this form where the pointer type points to a type other
diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
index d8e4421d4..e7360f3f9 100644
--- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
+++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
@@ -51,6 +51,8 @@ fn main() {
// e is a function pointer type and U is an integer; fptr-addr-cast
let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) };
let _usize_from_fn_ptr = foo as *const usize;
+
+ let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) };
}
// If a ref-to-ptr cast of this form where the pointer type points to a type other
diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr
index de9418c8d..e862fcb67 100644
--- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr
+++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr
@@ -46,11 +46,17 @@ error: transmute from `fn(usize) -> u8` to `usize` which could be expressed as a
LL | let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as usize`
+error: transmute from `*const u32` to `usize` which could be expressed as a pointer cast instead
+ --> $DIR/transmutes_expressible_as_ptr_casts.rs:55:36
+ |
+LL | let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&1u32 as *const u32 as usize`
+
error: transmute from a reference to a pointer
- --> $DIR/transmutes_expressible_as_ptr_casts.rs:64:14
+ --> $DIR/transmutes_expressible_as_ptr_casts.rs:66:14
|
LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8`
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs b/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs
index 2eca1f470..8b4613b3f 100644
--- a/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs
+++ b/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs
@@ -1,4 +1,5 @@
#![deny(clippy::type_repetition_in_bounds)]
+#![allow(clippy::extra_unused_type_parameters)]
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
diff --git a/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr b/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
index 70d700c1c..a90df03c0 100644
--- a/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
+++ b/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
@@ -1,5 +1,5 @@
error: this type has already been used as a bound predicate
- --> $DIR/type_repetition_in_bounds.rs:8:5
+ --> $DIR/type_repetition_in_bounds.rs:9:5
|
LL | T: Clone,
| ^^^^^^^^
@@ -12,7 +12,7 @@ LL | #![deny(clippy::type_repetition_in_bounds)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this type has already been used as a bound predicate
- --> $DIR/type_repetition_in_bounds.rs:25:5
+ --> $DIR/type_repetition_in_bounds.rs:26:5
|
LL | Self: Copy + Default + Ord,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL | Self: Copy + Default + Ord,
= help: consider combining the bounds: `Self: Clone + Copy + Default + Ord`
error: this type has already been used as a bound predicate
- --> $DIR/type_repetition_in_bounds.rs:85:5
+ --> $DIR/type_repetition_in_bounds.rs:86:5
|
LL | T: Clone,
| ^^^^^^^^
@@ -28,7 +28,7 @@ LL | T: Clone,
= help: consider combining the bounds: `T: ?Sized + Clone`
error: this type has already been used as a bound predicate
- --> $DIR/type_repetition_in_bounds.rs:90:5
+ --> $DIR/type_repetition_in_bounds.rs:91:5
|
LL | T: ?Sized,
| ^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.fixed b/src/tools/clippy/tests/ui/uninlined_format_args.fixed
index 9d08e80cf..cbd5cc5fc 100644
--- a/src/tools/clippy/tests/ui/uninlined_format_args.fixed
+++ b/src/tools/clippy/tests/ui/uninlined_format_args.fixed
@@ -174,3 +174,7 @@ fn _meets_msrv() {
let local_i32 = 1;
println!("expand='{local_i32}'");
}
+
+fn _do_not_fire() {
+ println!("{:?}", None::<()>);
+}
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.rs b/src/tools/clippy/tests/ui/uninlined_format_args.rs
index 35b3677a8..cf0ea5be4 100644
--- a/src/tools/clippy/tests/ui/uninlined_format_args.rs
+++ b/src/tools/clippy/tests/ui/uninlined_format_args.rs
@@ -179,3 +179,7 @@ fn _meets_msrv() {
let local_i32 = 1;
println!("expand='{}'", local_i32);
}
+
+fn _do_not_fire() {
+ println!("{:?}", None::<()>);
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs b/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs
index 7fefea705..89fedb145 100644
--- a/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs
@@ -48,4 +48,21 @@ fn unnecessary_on_stmt_and_expr() -> u32 {
24
}
+mod issue_10084 {
+ unsafe fn bar() -> i32 {
+ 42
+ }
+
+ macro_rules! foo {
+ () => {
+ // SAFETY: This is necessary
+ unsafe { bar() }
+ };
+ }
+
+ fn main() {
+ foo!();
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/unreadable_literal.fixed b/src/tools/clippy/tests/ui/unreadable_literal.fixed
index a67363b09..13e5feb19 100644
--- a/src/tools/clippy/tests/ui/unreadable_literal.fixed
+++ b/src/tools/clippy/tests/ui/unreadable_literal.fixed
@@ -23,7 +23,7 @@ fn main() {
let _good = (
0b1011_i64,
0o1_234_u32,
- 0x0123_4567,
+ 0x1_234_567,
65536,
1_2345_6789,
1234_f32,
diff --git a/src/tools/clippy/tests/ui/unreadable_literal.stderr b/src/tools/clippy/tests/ui/unreadable_literal.stderr
index b51130c6a..450121b1c 100644
--- a/src/tools/clippy/tests/ui/unreadable_literal.stderr
+++ b/src/tools/clippy/tests/ui/unreadable_literal.stderr
@@ -1,11 +1,3 @@
-error: digits of hex or binary literal not grouped by four
- --> $DIR/unreadable_literal.rs:26:9
- |
-LL | 0x1_234_567,
- | ^^^^^^^^^^^ help: consider: `0x0123_4567`
- |
- = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
-
error: long literal lacking separators
--> $DIR/unreadable_literal.rs:34:17
|
@@ -68,5 +60,5 @@ error: long literal lacking separators
LL | let _fail5 = 1.100300400;
| ^^^^^^^^^^^ help: consider: `1.100_300_400`
-error: aborting due to 11 previous errors
+error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/unused_io_amount.rs b/src/tools/clippy/tests/ui/unused_io_amount.rs
index 4b0595581..8d3e094b7 100644
--- a/src/tools/clippy/tests/ui/unused_io_amount.rs
+++ b/src/tools/clippy/tests/ui/unused_io_amount.rs
@@ -63,6 +63,14 @@ fn combine_or(file: &str) -> Result<(), Error> {
Ok(())
}
+fn is_ok_err<T: io::Read + io::Write>(s: &mut T) {
+ s.write(b"ok").is_ok();
+ s.write(b"err").is_err();
+ let mut buf = [0u8; 0];
+ s.read(&mut buf).is_ok();
+ s.read(&mut buf).is_err();
+}
+
async fn bad_async_write<W: AsyncWrite + Unpin>(w: &mut W) {
w.write(b"hello world").await.unwrap();
}
diff --git a/src/tools/clippy/tests/ui/unused_io_amount.stderr b/src/tools/clippy/tests/ui/unused_io_amount.stderr
index 7ba7e09c0..0865c5213 100644
--- a/src/tools/clippy/tests/ui/unused_io_amount.stderr
+++ b/src/tools/clippy/tests/ui/unused_io_amount.stderr
@@ -82,13 +82,45 @@ LL | | .expect("error");
error: written amount is not handled
--> $DIR/unused_io_amount.rs:67:5
|
+LL | s.write(b"ok").is_ok();
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: use `Write::write_all` instead, or handle partial writes
+
+error: written amount is not handled
+ --> $DIR/unused_io_amount.rs:68:5
+ |
+LL | s.write(b"err").is_err();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: use `Write::write_all` instead, or handle partial writes
+
+error: read amount is not handled
+ --> $DIR/unused_io_amount.rs:70:5
+ |
+LL | s.read(&mut buf).is_ok();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: use `Read::read_exact` instead, or handle partial reads
+
+error: read amount is not handled
+ --> $DIR/unused_io_amount.rs:71:5
+ |
+LL | s.read(&mut buf).is_err();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: use `Read::read_exact` instead, or handle partial reads
+
+error: written amount is not handled
+ --> $DIR/unused_io_amount.rs:75:5
+ |
LL | w.write(b"hello world").await.unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: use `AsyncWriteExt::write_all` instead, or handle partial writes
error: read amount is not handled
- --> $DIR/unused_io_amount.rs:72:5
+ --> $DIR/unused_io_amount.rs:80:5
|
LL | r.read(&mut buf[..]).await.unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -96,7 +128,7 @@ LL | r.read(&mut buf[..]).await.unwrap();
= help: use `AsyncReadExt::read_exact` instead, or handle partial reads
error: written amount is not handled
- --> $DIR/unused_io_amount.rs:85:9
+ --> $DIR/unused_io_amount.rs:93:9
|
LL | w.write(b"hello world").await?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +136,7 @@ LL | w.write(b"hello world").await?;
= help: use `AsyncWriteExt::write_all` instead, or handle partial writes
error: read amount is not handled
- --> $DIR/unused_io_amount.rs:93:9
+ --> $DIR/unused_io_amount.rs:101:9
|
LL | r.read(&mut buf[..]).await.or(Err(Error::Kind))?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,7 +144,7 @@ LL | r.read(&mut buf[..]).await.or(Err(Error::Kind))?;
= help: use `AsyncReadExt::read_exact` instead, or handle partial reads
error: written amount is not handled
- --> $DIR/unused_io_amount.rs:101:5
+ --> $DIR/unused_io_amount.rs:109:5
|
LL | w.write(b"hello world").await.unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -120,12 +152,12 @@ LL | w.write(b"hello world").await.unwrap();
= help: use `AsyncWriteExt::write_all` instead, or handle partial writes
error: read amount is not handled
- --> $DIR/unused_io_amount.rs:106:5
+ --> $DIR/unused_io_amount.rs:114:5
|
LL | r.read(&mut buf[..]).await.unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: use `AsyncReadExt::read_exact` instead, or handle partial reads
-error: aborting due to 16 previous errors
+error: aborting due to 20 previous errors
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
index 236074978..293bf75a7 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
@@ -96,7 +96,7 @@ fn main() {
}
match Enum::A {
Enum::A => (),
- Enum::B | _ => (),
+ Enum::B | Enum::__Private => (),
}
}
}
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
index efecc9576..30d29aa4e 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
@@ -34,11 +34,11 @@ error: wildcard matches known variants and will also match future added variants
LL | _ => {},
| ^ help: try this: `ErrorKind::PermissionDenied | _`
-error: wildcard matches known variants and will also match future added variants
+error: wildcard match will also match any future added variants
--> $DIR/wildcard_enum_match_arm.rs:99:13
|
LL | _ => (),
- | ^ help: try this: `Enum::B | _`
+ | ^ help: try this: `Enum::B | Enum::__Private`
error: aborting due to 6 previous errors